summaryrefslogtreecommitdiff
path: root/sc/source/core/data
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/core/data')
-rw-r--r--sc/source/core/data/PivotTableFormatOutput.cxx441
-rw-r--r--sc/source/core/data/SolverSettings.cxx804
-rw-r--r--sc/source/core/data/attarray.cxx643
-rw-r--r--sc/source/core/data/attrib.cxx60
-rw-r--r--sc/source/core/data/autonamecache.cxx2
-rw-r--r--sc/source/core/data/bcaslot.cxx382
-rw-r--r--sc/source/core/data/bigrange.cxx6
-rw-r--r--sc/source/core/data/broadcast.cxx159
-rw-r--r--sc/source/core/data/cellvalue.cxx303
-rw-r--r--sc/source/core/data/cellvalues.cxx7
-rw-r--r--sc/source/core/data/clipcontext.cxx110
-rw-r--r--sc/source/core/data/colorscale.cxx308
-rw-r--r--sc/source/core/data/column.cxx430
-rw-r--r--sc/source/core/data/column2.cxx781
-rw-r--r--sc/source/core/data/column3.cxx598
-rw-r--r--sc/source/core/data/column4.cxx336
-rw-r--r--sc/source/core/data/columniterator.cxx2
-rw-r--r--sc/source/core/data/columnspanset.cxx72
-rw-r--r--sc/source/core/data/compressedarray.cxx5
-rw-r--r--sc/source/core/data/conditio.cxx266
-rw-r--r--sc/source/core/data/dbdocutl.cxx3
-rw-r--r--sc/source/core/data/dociter.cxx1291
-rw-r--r--sc/source/core/data/docpool.cxx456
-rw-r--r--sc/source/core/data/documen2.cxx329
-rw-r--r--sc/source/core/data/documen3.cxx458
-rw-r--r--sc/source/core/data/documen4.cxx199
-rw-r--r--sc/source/core/data/documen5.cxx71
-rw-r--r--sc/source/core/data/documen6.cxx10
-rw-r--r--sc/source/core/data/documen7.cxx110
-rw-r--r--sc/source/core/data/documen8.cxx85
-rw-r--r--sc/source/core/data/documen9.cxx120
-rw-r--r--sc/source/core/data/document.cxx2447
-rw-r--r--sc/source/core/data/document10.cxx99
-rw-r--r--sc/source/core/data/documentimport.cxx118
-rw-r--r--sc/source/core/data/dpcache.cxx89
-rw-r--r--sc/source/core/data/dpdimsave.cxx37
-rw-r--r--sc/source/core/data/dpfilteredcache.cxx13
-rw-r--r--sc/source/core/data/dpgroup.cxx38
-rw-r--r--sc/source/core/data/dpitemdata.cxx8
-rw-r--r--sc/source/core/data/dpobject.cxx736
-rw-r--r--sc/source/core/data/dpoutput.cxx945
-rw-r--r--sc/source/core/data/dpoutputgeometry.cxx4
-rw-r--r--sc/source/core/data/dpresfilter.cxx65
-rw-r--r--sc/source/core/data/dpsave.cxx231
-rw-r--r--sc/source/core/data/dpsdbtab.cxx8
-rw-r--r--sc/source/core/data/dpshttab.cxx17
-rw-r--r--sc/source/core/data/dptabres.cxx40
-rw-r--r--sc/source/core/data/dptabsrc.cxx354
-rw-r--r--sc/source/core/data/dputil.cxx34
-rw-r--r--sc/source/core/data/drawpage.cxx2
-rw-r--r--sc/source/core/data/drwlayer.cxx979
-rw-r--r--sc/source/core/data/edittextiterator.cxx1
-rw-r--r--sc/source/core/data/fillinfo.cxx395
-rw-r--r--sc/source/core/data/formulacell.cxx402
-rw-r--r--sc/source/core/data/funcdesc.cxx124
-rw-r--r--sc/source/core/data/global.cxx263
-rw-r--r--sc/source/core/data/global2.cxx45
-rw-r--r--sc/source/core/data/globalx.cxx8
-rw-r--r--sc/source/core/data/grouptokenconverter.cxx5
-rw-r--r--sc/source/core/data/listenercontext.cxx13
-rw-r--r--sc/source/core/data/markarr.cxx12
-rw-r--r--sc/source/core/data/markdata.cxx75
-rw-r--r--sc/source/core/data/markmulti.cxx49
-rw-r--r--sc/source/core/data/mtvelements.cxx31
-rw-r--r--sc/source/core/data/pagepar.cxx8
-rw-r--r--sc/source/core/data/patattr.cxx1452
-rw-r--r--sc/source/core/data/pivot2.cxx5
-rw-r--r--sc/source/core/data/poolcach.cxx79
-rw-r--r--sc/source/core/data/poolhelp.cxx11
-rw-r--r--sc/source/core/data/postit.cxx754
-rw-r--r--sc/source/core/data/queryevaluator.cxx897
-rw-r--r--sc/source/core/data/queryiter.cxx1624
-rw-r--r--sc/source/core/data/refupdatecontext.cxx3
-rw-r--r--sc/source/core/data/segmenttree.cxx40
-rw-r--r--sc/source/core/data/simpleformulacalc.cxx14
-rw-r--r--sc/source/core/data/sortparam.cxx54
-rw-r--r--sc/source/core/data/stlpool.cxx115
-rw-r--r--sc/source/core/data/stlsheet.cxx108
-rw-r--r--sc/source/core/data/table1.cxx457
-rw-r--r--sc/source/core/data/table2.cxx628
-rw-r--r--sc/source/core/data/table3.cxx1526
-rw-r--r--sc/source/core/data/table4.cxx496
-rw-r--r--sc/source/core/data/table5.cxx157
-rw-r--r--sc/source/core/data/table6.cxx107
-rw-r--r--sc/source/core/data/table7.cxx70
-rw-r--r--sc/source/core/data/tabprotection.cxx38
-rw-r--r--sc/source/core/data/validat.cxx223
87 files changed, 15147 insertions, 10253 deletions
diff --git a/sc/source/core/data/PivotTableFormatOutput.cxx b/sc/source/core/data/PivotTableFormatOutput.cxx
new file mode 100644
index 000000000000..c9073d6be07b
--- /dev/null
+++ b/sc/source/core/data/PivotTableFormatOutput.cxx
@@ -0,0 +1,441 @@
+/* -*- 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/.
+ */
+
+#include <pivot/PivotTableFormatOutput.hxx>
+#include <pivot/DPOutLevelData.hxx>
+
+#include <dpoutput.hxx>
+#include <dpobject.hxx>
+#include <dptabdat.hxx>
+#include <dpcache.hxx>
+#include <document.hxx>
+
+#include <com/sun/star/sheet/MemberResultFlags.hpp>
+
+namespace sc
+{
+namespace
+{
+class NameResolver
+{
+private:
+ ScDPTableData& mrTableData;
+ ScDPCache const& mrCache;
+
+ std::unordered_map<sal_Int32, std::vector<OUString>> maNameCache;
+
+ void fillNamesForDimension(std::vector<OUString>& rNames, sal_Int32 nDimension)
+ {
+ for (const auto& rItemData : mrCache.GetDimMemberValues(nDimension))
+ {
+ OUString sFormattedName;
+ if (rItemData.HasStringData() || rItemData.IsEmpty())
+ sFormattedName = rItemData.GetString();
+ else
+ sFormattedName = ScDPObject::GetFormattedString(&mrTableData, nDimension,
+ rItemData.GetValue());
+ rNames.push_back(sFormattedName);
+ }
+ }
+
+public:
+ NameResolver(ScDPTableData& rTableData, ScDPCache const& rCache)
+ : mrTableData(rTableData)
+ , mrCache(rCache)
+ {
+ }
+
+ OUString getNameForIndex(sal_uInt32 nIndex, sal_Int32 nDimension)
+ {
+ auto iterator = maNameCache.find(nDimension);
+ if (iterator == maNameCache.end())
+ {
+ std::vector<OUString> aNames;
+ fillNamesForDimension(aNames, nDimension);
+ iterator = maNameCache.emplace(nDimension, aNames).first;
+ }
+
+ const std::vector<OUString>& rNames = iterator->second;
+ if (nIndex >= rNames.size())
+ return OUString();
+ return rNames[nIndex];
+ }
+};
+
+void initLines(std::vector<LineData>& rLines, std::vector<ScDPOutLevelData> const& rFields)
+{
+ for (size_t i = 0; i < rFields.size(); i++)
+ {
+ size_t nFieldLength(rFields[i].maResult.getLength());
+ if (rLines.size() < nFieldLength)
+ rLines.resize(nFieldLength);
+
+ for (LineData& rLineData : rLines)
+ {
+ rLineData.maFields.resize(rFields.size());
+ }
+ }
+}
+
+Selection const* findSelection(PivotTableFormat const& rFormat, tools::Long nDimension)
+{
+ for (Selection const& rSelection : rFormat.getSelections())
+ {
+ if (rSelection.nField == nDimension)
+ return &rSelection;
+ }
+ return nullptr;
+}
+
+void fillOutputFieldFromSelection(FormatOutputField& rOutputField, Selection const& rSelection,
+ size_t nSelectionIndex, NameResolver& rNameResolver)
+{
+ if (rSelection.nIndices.empty())
+ {
+ rOutputField.bMatchesAll = true;
+ }
+ else
+ {
+ if (rSelection.nIndices.size() > 1 && rSelection.nIndices.size() > nSelectionIndex)
+ rOutputField.nIndex = rSelection.nIndices[nSelectionIndex];
+ else
+ rOutputField.nIndex = rSelection.nIndices[0];
+
+ if (rOutputField.nDimension == -2)
+ rOutputField.aName = "DATA";
+ else
+ rOutputField.aName
+ = rNameResolver.getNameForIndex(rOutputField.nIndex, rOutputField.nDimension);
+ }
+ rOutputField.bSet = true;
+}
+
+void initFormatOutputField(size_t nSelectionIndex, std::vector<FormatOutputField>& rOutputFields,
+ std::vector<ScDPOutLevelData> const& rFields,
+ PivotTableFormat const& rFormat, NameResolver& rNameResolver)
+{
+ rOutputFields.resize(rFields.size());
+ for (size_t i = 0; i < rOutputFields.size(); i++)
+ {
+ FormatOutputField& rOutputField = rOutputFields[i];
+ if (!rFields[i].mbDataLayout)
+ rOutputField.nDimension = rFields[i].mnDim;
+
+ Selection const* pSelection = findSelection(rFormat, rOutputField.nDimension);
+ if (pSelection == nullptr)
+ continue;
+
+ fillOutputFieldFromSelection(rOutputField, *pSelection, nSelectionIndex, rNameResolver);
+ }
+}
+
+} // end anonymous namespace
+
+void FormatOutput::prepare(SCTAB nTab, std::vector<ScDPOutLevelData> const& rColumnFields,
+ std::vector<ScDPOutLevelData> const& rRowFields,
+ bool bColumnFieldIsDataOnly)
+{
+ if (!mpFormats)
+ return;
+
+ // initialize row and column lines, so the number of fields matches the pivot table output
+ initLines(maRowLines, rRowFields);
+
+ if (rColumnFields.size() == 0 && bColumnFieldIsDataOnly)
+ {
+ maColumnLines.resize(1);
+ maColumnLines[0].maFields.resize(1);
+ }
+ else
+ {
+ initLines(maColumnLines, rColumnFields);
+ }
+
+ // check the table data exists
+ auto* pTableData = mrObject.GetTableData();
+ if (!pTableData)
+ return;
+
+ ScDPFilteredCache const& rFilteredCache = pTableData->GetCacheTable();
+ ScDPCache const& rCache = rFilteredCache.getCache();
+
+ NameResolver aNameResolver(*pTableData, rCache);
+
+ // Initialize format output entries (FormatOutputEntry) and set the data already available from output fields
+ // (rColumnFields and rRowFields) and the pivot table format list (PivotTableFormat).
+
+ for (PivotTableFormat const& rFormat : mpFormats->getVector())
+ {
+ size_t nMaxNumberOfIndices = 1;
+ for (auto const& rSelection : rFormat.aSelections)
+ {
+ if (rSelection.nIndices.size() > 1)
+ nMaxNumberOfIndices = rSelection.nIndices.size();
+ }
+
+ for (size_t nSelectionIndex = 0; nSelectionIndex < nMaxNumberOfIndices; nSelectionIndex++)
+ {
+ sc::FormatOutputEntry aEntry;
+ aEntry.pPattern = rFormat.pPattern;
+ aEntry.onTab = nTab;
+ aEntry.eType = rFormat.eType;
+
+ initFormatOutputField(nSelectionIndex, aEntry.aRowOutputFields, rRowFields, rFormat,
+ aNameResolver);
+
+ // If column fields list is empty, but there is a data field in columns that is not part of column fields
+ if (rColumnFields.size() == 0 && bColumnFieldIsDataOnly)
+ {
+ // Initialize column output fields to have 1 data output field
+ aEntry.aColumnOutputFields.resize(1);
+ FormatOutputField& rOutputField = aEntry.aColumnOutputFields[0];
+ rOutputField.nDimension = -2;
+ Selection const* pSelection = findSelection(rFormat, -2);
+ if (pSelection)
+ fillOutputFieldFromSelection(rOutputField, *pSelection, nSelectionIndex,
+ aNameResolver);
+ }
+ else
+ {
+ initFormatOutputField(nSelectionIndex, aEntry.aColumnOutputFields, rColumnFields,
+ rFormat, aNameResolver);
+ }
+
+ maFormatOutputEntries.push_back(aEntry);
+ }
+ }
+}
+
+void FormatOutput::insertEmptyDataColumn(SCCOL nColPos, SCROW nRowPos)
+{
+ if (!mpFormats)
+ return;
+
+ LineData& rLine = maColumnLines[0];
+ rLine.oLine = nColPos;
+ rLine.oPosition = nRowPos;
+
+ FieldData& rFieldData = rLine.maFields[0];
+ rFieldData.nIndex = 0;
+ rFieldData.bIsSet = true;
+}
+
+namespace
+{
+void fillLineAndFieldData(std::vector<LineData>& rLineDataVector, size_t nFieldIndex,
+ ScDPOutLevelData const& rField, tools::Long nMemberIndex,
+ sheet::MemberResult const& rMember, SCCOLROW nLine, SCCOLROW nPosition)
+{
+ LineData& rLine = rLineDataVector[nMemberIndex];
+ rLine.oLine = nLine;
+ rLine.oPosition = nPosition;
+
+ FieldData& rFieldData = rLine.maFields[nFieldIndex];
+ if (!rField.mbDataLayout)
+ rFieldData.mnDimension = rField.mnDim;
+ rFieldData.aName = rMember.Name;
+ rFieldData.nIndex = nMemberIndex;
+ rFieldData.bIsSet = true;
+ rFieldData.bIsMember = rMember.Flags & sheet::MemberResultFlags::HASMEMBER;
+ rFieldData.bSubtotal = rMember.Flags & sheet::MemberResultFlags::SUBTOTAL;
+ rFieldData.bContinue = rMember.Flags & sheet::MemberResultFlags::CONTINUE;
+
+ // Search previous entries for the name / value
+ if (rFieldData.bContinue)
+ {
+ tools::Long nCurrent = nMemberIndex - 1;
+ while (nCurrent >= 0 && rLineDataVector[nCurrent].maFields[nFieldIndex].bContinue)
+ nCurrent--;
+
+ if (nCurrent >= 0)
+ {
+ FieldData& rCurrentFieldData = rLineDataVector[nCurrent].maFields[nFieldIndex];
+ rFieldData.aName = rCurrentFieldData.aName;
+ rFieldData.nIndex = rCurrentFieldData.nIndex;
+ }
+ }
+}
+} // end anonymous namespace
+
+void FormatOutput::insertFieldMember(size_t nFieldIndex, ScDPOutLevelData const& rField,
+ tools::Long nMemberIndex, sheet::MemberResult const& rMember,
+ SCCOL nColPos, SCROW nRowPos,
+ sc::FormatResultDirection eResultDirection)
+{
+ if (!mpFormats)
+ return;
+
+ if (eResultDirection == sc::FormatResultDirection::ROW)
+ fillLineAndFieldData(maRowLines, nFieldIndex, rField, nMemberIndex, rMember, nRowPos,
+ nColPos);
+ else if (eResultDirection == sc::FormatResultDirection::COLUMN)
+ fillLineAndFieldData(maColumnLines, nFieldIndex, rField, nMemberIndex, rMember, nColPos,
+ nRowPos);
+}
+namespace
+{
+void checkForMatchingLines(std::vector<LineData> const& rLines,
+ std::vector<FormatOutputField> const& rFormatOutputField,
+ FormatType eType,
+ std::vector<std::reference_wrapper<const LineData>>& rMatches,
+ std::vector<std::reference_wrapper<const LineData>>& rMaybeMatches)
+{
+ for (LineData const& rLineData : rLines)
+ {
+ size_t nMatch = 0;
+ size_t nMaybeMatch = 0;
+ size_t nNoOfFields = rLineData.maFields.size();
+
+ for (size_t nIndex = 0; nIndex < nNoOfFields; nIndex++)
+ {
+ FieldData const& rFieldData = rLineData.maFields[nIndex];
+ FormatOutputField const& rFormatEntry = rFormatOutputField[nIndex];
+ bool bFieldMatch = false;
+ bool bFieldMaybeMatch = false;
+
+ tools::Long nDimension = rFieldData.mnDimension;
+ if (nDimension == rFormatEntry.nDimension)
+ {
+ if (rFormatEntry.bSet)
+ {
+ if (rFormatEntry.bMatchesAll && !rFieldData.bSubtotal)
+ bFieldMatch = true;
+ else if (nDimension == -2 && rFieldData.nIndex == rFormatEntry.nIndex)
+ bFieldMatch = true;
+ else if (nDimension != -2 && rFieldData.aName == rFormatEntry.aName)
+ bFieldMatch = true;
+ }
+ else if (!rFormatEntry.bSet && eType == FormatType::Data && !rFieldData.bIsMember
+ && !rFieldData.bContinue)
+ {
+ bFieldMatch = true;
+ }
+ else
+ {
+ bFieldMaybeMatch = true;
+ }
+ }
+
+ if (!bFieldMatch && !bFieldMaybeMatch)
+ break;
+
+ if (bFieldMatch)
+ nMatch++;
+
+ if (bFieldMaybeMatch)
+ nMaybeMatch++;
+ }
+
+ if (nMatch == nNoOfFields)
+ {
+ rMatches.push_back(std::cref(rLineData));
+ }
+ else if (nMatch + nMaybeMatch == nNoOfFields)
+ {
+ rMaybeMatches.push_back(std::cref(rLineData));
+ }
+ }
+}
+
+/** Check the lines in matches and maybe matches and output */
+void evaluateMatches(ScDocument& rDocument,
+ std::vector<std::reference_wrapper<const LineData>> const& rMatches,
+ std::vector<std::reference_wrapper<const LineData>> const& rMaybeMatches,
+ std::vector<SCCOLROW>& aRows, std::vector<SCCOLROW>& aColumns,
+ FormatOutputEntry const& rOutputEntry, FormatResultDirection eResultDirection)
+{
+ // We expect that tab and pattern to be set or this method shouldn't be called at all
+ assert(rOutputEntry.onTab);
+ assert(rOutputEntry.pPattern);
+
+ if (rMatches.empty() && rMaybeMatches.empty())
+ return;
+
+ bool bMaybeExists = rMatches.empty();
+
+ auto const& rLineDataVector = bMaybeExists ? rMaybeMatches : rMatches;
+
+ for (LineData const& rLineData : rLineDataVector)
+ {
+ // Can't continue if we don't have complete row/column data
+ if (!rLineData.oLine || !rLineData.oPosition)
+ continue;
+
+ if (rOutputEntry.eType == FormatType::Label && !bMaybeExists)
+ {
+ // Primary axis is set to column (line) then row (position)
+ SCCOLROW nColumn = *rLineData.oLine;
+ SCCOLROW nRow = *rLineData.oPosition;
+
+ // In row orientation, the primary axis is row, then column, so we need to swap
+ if (eResultDirection == FormatResultDirection::ROW)
+ std::swap(nRow, nColumn);
+
+ // Set the pattern to the sheet
+ rDocument.ApplyPattern(nColumn, nRow, *rOutputEntry.onTab, *rOutputEntry.pPattern);
+ }
+ else if (rOutputEntry.eType == FormatType::Data)
+ {
+ if (eResultDirection == FormatResultDirection::ROW)
+ aRows.push_back(*rLineData.oLine);
+ else if (eResultDirection == FormatResultDirection::COLUMN)
+ aColumns.push_back(*rLineData.oLine);
+ }
+ }
+}
+
+} // end anonymous namespace
+
+void FormatOutput::apply(ScDocument& rDocument)
+{
+ if (!mpFormats)
+ return;
+
+ for (auto const& rOutputEntry : maFormatOutputEntries)
+ {
+ if (!rOutputEntry.onTab || !rOutputEntry.pPattern)
+ continue;
+
+ std::vector<SCCOLROW> aRows;
+ std::vector<SCCOLROW> aColumns;
+ {
+ std::vector<std::reference_wrapper<const LineData>> rMatches;
+ std::vector<std::reference_wrapper<const LineData>> rMaybeMatches;
+
+ checkForMatchingLines(maRowLines, rOutputEntry.aRowOutputFields, rOutputEntry.eType,
+ rMatches, rMaybeMatches);
+
+ evaluateMatches(rDocument, rMatches, rMaybeMatches, aRows, aColumns, rOutputEntry,
+ FormatResultDirection::ROW);
+ }
+
+ {
+ std::vector<std::reference_wrapper<const LineData>> rMatches;
+ std::vector<std::reference_wrapper<const LineData>> rMaybeMatches;
+
+ checkForMatchingLines(maColumnLines, rOutputEntry.aColumnOutputFields,
+ rOutputEntry.eType, rMatches, rMaybeMatches);
+
+ evaluateMatches(rDocument, rMatches, rMaybeMatches, aRows, aColumns, rOutputEntry,
+ FormatResultDirection::COLUMN);
+ }
+
+ if (!aColumns.empty() && !aRows.empty() && rOutputEntry.eType == FormatType::Data)
+ {
+ for (SCCOLROW nRow : aRows)
+ for (SCCOLROW nColumn : aColumns)
+ rDocument.ApplyPattern(nColumn, nRow, *rOutputEntry.onTab,
+ *rOutputEntry.pPattern);
+ }
+ }
+}
+
+} // end sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/SolverSettings.cxx b/sc/source/core/data/SolverSettings.cxx
new file mode 100644
index 000000000000..1320d470efcf
--- /dev/null
+++ b/sc/source/core/data/SolverSettings.cxx
@@ -0,0 +1,804 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * 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/.
+ *
+ */
+
+#include <global.hxx>
+#include <compiler.hxx>
+#include <table.hxx>
+#include <docsh.hxx>
+#include <rtl/math.hxx>
+#include <o3tl/string_view.hxx>
+#include <solverutil.hxx>
+#include <unotools/charclass.hxx>
+#include <SolverSettings.hxx>
+
+namespace sc
+{
+SolverSettings::SolverSettings(ScTable& rTable)
+ : m_rTable(rTable)
+ , m_rDoc(m_rTable.GetDoc())
+ , m_pDocShell(m_rDoc.GetDocumentShell())
+{
+ // Get the named range manager for this tab
+ std::map<OUString, ScRangeName*> rRangeMap;
+ m_rDoc.GetRangeNameMap(rRangeMap);
+ m_pRangeName = rRangeMap.find(m_rTable.GetName())->second;
+
+ Initialize();
+}
+
+void SolverSettings::Initialize()
+{
+ // Assign default values for the solver parameters
+ ResetToDefaults();
+
+ // Read the parameter values in the sheet
+ ReadParamValue(SP_OBJ_CELL, m_sObjCell);
+ ReadParamValue(SP_OBJ_VAL, m_sObjVal);
+ ReadParamValue(SP_VAR_CELLS, m_sVariableCells);
+
+ // Read the objective type
+ OUString sObjType;
+ if (ReadParamValue(SP_OBJ_TYPE, sObjType))
+ {
+ switch (sObjType.toInt32())
+ {
+ case 1:
+ m_eObjType = ObjectiveType::OT_MAXIMIZE;
+ break;
+ case 2:
+ m_eObjType = ObjectiveType::OT_MINIMIZE;
+ break;
+ case 3:
+ m_eObjType = ObjectiveType::OT_VALUE;
+ break;
+ default:
+ m_eObjType = ObjectiveType::OT_MAXIMIZE;
+ }
+ }
+
+ // Read all constraints in the tab
+ ReadConstraints();
+
+ // Read the solver engine being used
+ ReadEngine();
+
+ // Read engine options
+ ReadParamValue(SP_INTEGER, m_sInteger);
+ ReadParamValue(SP_NON_NEGATIVE, m_sNonNegative);
+ ReadParamValue(SP_EPSILON_LEVEL, m_sEpsilonLevel);
+ ReadParamValue(SP_LIMIT_BBDEPTH, m_sLimitBBDepth);
+ ReadParamValue(SP_TIMEOUT, m_sTimeout);
+ ReadParamValue(SP_ALGORITHM, m_sAlgorithm);
+ // Engine options common for DEPS and SCO
+ ReadParamValue(SP_SWARM_SIZE, m_sSwarmSize);
+ ReadParamValue(SP_LEARNING_CYCLES, m_sLearningCycles);
+ ReadParamValue(SP_GUESS_VARIABLE_RANGE, m_sGuessVariableRange);
+ ReadDoubleParamValue(SP_VARIABLE_RANGE_THRESHOLD, m_sVariableRangeThreshold);
+ ReadParamValue(SP_ACR_COMPARATOR, m_sUseACRComparator);
+ ReadParamValue(SP_RND_STARTING_POINT, m_sUseRandomStartingPoint);
+ ReadParamValue(SP_STRONGER_PRNG, m_sUseStrongerPRNG);
+ ReadParamValue(SP_STAGNATION_LIMIT, m_sStagnationLimit);
+ ReadDoubleParamValue(SP_STAGNATION_TOLERANCE, m_sTolerance);
+ ReadParamValue(SP_ENHANCED_STATUS, m_sEnhancedSolverStatus);
+ // DEPS Options
+ ReadDoubleParamValue(SP_AGENT_SWITCH_RATE, m_sAgentSwitchRate);
+ ReadDoubleParamValue(SP_SCALING_MIN, m_sScalingFactorMin);
+ ReadDoubleParamValue(SP_SCALING_MAX, m_sScalingFactorMax);
+ ReadDoubleParamValue(SP_CROSSOVER_PROB, m_sCrossoverProbability);
+ ReadDoubleParamValue(SP_COGNITIVE_CONST, m_sCognitiveConstant);
+ ReadDoubleParamValue(SP_SOCIAL_CONST, m_sSocialConstant);
+ ReadDoubleParamValue(SP_CONSTRICTION_COEFF, m_sConstrictionCoeff);
+ ReadDoubleParamValue(SP_MUTATION_PROB, m_sMutationProbability);
+ // SCO Options
+ ReadParamValue(SP_LIBRARY_SIZE, m_sLibrarySize);
+}
+
+// Returns the current value of the parameter in the object as a string
+OUString SolverSettings::GetParameter(SolverParameter eParam)
+{
+ switch (eParam)
+ {
+ case SP_OBJ_CELL:
+ return m_sObjCell;
+ break;
+ case SP_OBJ_TYPE:
+ return OUString::number(m_eObjType);
+ break;
+ case SP_OBJ_VAL:
+ return m_sObjVal;
+ break;
+ case SP_VAR_CELLS:
+ return m_sVariableCells;
+ break;
+ case SP_CONSTR_COUNT:
+ return OUString::number(m_aConstraints.size());
+ break;
+ case SP_LO_ENGINE:
+ return m_sLOEngineName;
+ break;
+ case SP_MS_ENGINE:
+ return m_sMSEngineId;
+ break;
+ case SP_INTEGER:
+ return m_sInteger;
+ break;
+ case SP_NON_NEGATIVE:
+ return m_sNonNegative;
+ break;
+ case SP_EPSILON_LEVEL:
+ return m_sEpsilonLevel;
+ break;
+ case SP_LIMIT_BBDEPTH:
+ return m_sLimitBBDepth;
+ break;
+ case SP_TIMEOUT:
+ return m_sTimeout;
+ break;
+ case SP_ALGORITHM:
+ return m_sAlgorithm;
+ break;
+ case SP_SWARM_SIZE:
+ return m_sSwarmSize;
+ break;
+ case SP_LEARNING_CYCLES:
+ return m_sLearningCycles;
+ break;
+ case SP_GUESS_VARIABLE_RANGE:
+ return m_sGuessVariableRange;
+ break;
+ case SP_VARIABLE_RANGE_THRESHOLD:
+ return m_sVariableRangeThreshold;
+ break;
+ case SP_ACR_COMPARATOR:
+ return m_sUseACRComparator;
+ break;
+ case SP_RND_STARTING_POINT:
+ return m_sUseRandomStartingPoint;
+ break;
+ case SP_STRONGER_PRNG:
+ return m_sUseStrongerPRNG;
+ break;
+ case SP_STAGNATION_LIMIT:
+ return m_sStagnationLimit;
+ break;
+ case SP_STAGNATION_TOLERANCE:
+ return m_sTolerance;
+ break;
+ case SP_ENHANCED_STATUS:
+ return m_sEnhancedSolverStatus;
+ break;
+ case SP_AGENT_SWITCH_RATE:
+ return m_sAgentSwitchRate;
+ break;
+ case SP_SCALING_MIN:
+ return m_sScalingFactorMin;
+ break;
+ case SP_SCALING_MAX:
+ return m_sScalingFactorMax;
+ break;
+ case SP_CROSSOVER_PROB:
+ return m_sCrossoverProbability;
+ break;
+ case SP_COGNITIVE_CONST:
+ return m_sCognitiveConstant;
+ break;
+ case SP_SOCIAL_CONST:
+ return m_sSocialConstant;
+ break;
+ case SP_CONSTRICTION_COEFF:
+ return m_sConstrictionCoeff;
+ break;
+ case SP_MUTATION_PROB:
+ return m_sMutationProbability;
+ break;
+ case SP_LIBRARY_SIZE:
+ return m_sLibrarySize;
+ break;
+ default:
+ return "";
+ }
+}
+
+// Sets the value of a single solver parameter in the object
+void SolverSettings::SetParameter(SolverParameter eParam, OUString sValue)
+{
+ switch (eParam)
+ {
+ case SP_OBJ_CELL:
+ m_sObjCell = sValue;
+ break;
+ case SP_OBJ_TYPE:
+ {
+ sal_Int32 nObjType = sValue.toInt32();
+ switch (nObjType)
+ {
+ case OT_MAXIMIZE:
+ m_eObjType = ObjectiveType::OT_MAXIMIZE;
+ break;
+ case OT_MINIMIZE:
+ m_eObjType = ObjectiveType::OT_MINIMIZE;
+ break;
+ case OT_VALUE:
+ m_eObjType = ObjectiveType::OT_VALUE;
+ break;
+ default:
+ m_eObjType = ObjectiveType::OT_MAXIMIZE;
+ break;
+ }
+ break;
+ }
+ case SP_OBJ_VAL:
+ m_sObjVal = sValue;
+ break;
+ case SP_VAR_CELLS:
+ m_sVariableCells = sValue;
+ break;
+ case SP_LO_ENGINE:
+ m_sLOEngineName = sValue;
+ break;
+ case SP_INTEGER:
+ {
+ if (sValue == "0" || sValue == "1")
+ m_sInteger = sValue;
+ }
+ break;
+ case SP_NON_NEGATIVE:
+ {
+ if (sValue == "1" || sValue == "2")
+ m_sNonNegative = sValue;
+ }
+ break;
+ case SP_EPSILON_LEVEL:
+ m_sEpsilonLevel = sValue;
+ break;
+ case SP_LIMIT_BBDEPTH:
+ m_sLimitBBDepth = sValue;
+ break;
+ case SP_TIMEOUT:
+ m_sTimeout = sValue;
+ break;
+ case SP_ALGORITHM:
+ {
+ if (sValue == "1" || sValue == "2" || sValue == "3")
+ m_sAlgorithm = sValue;
+ }
+ break;
+ case SP_SWARM_SIZE:
+ m_sSwarmSize = sValue;
+ break;
+ case SP_LEARNING_CYCLES:
+ m_sLearningCycles = sValue;
+ break;
+ case SP_GUESS_VARIABLE_RANGE:
+ m_sGuessVariableRange = sValue;
+ break;
+ case SP_VARIABLE_RANGE_THRESHOLD:
+ m_sVariableRangeThreshold = sValue;
+ break;
+ case SP_ACR_COMPARATOR:
+ {
+ if (sValue == "0" || sValue == "1")
+ m_sUseACRComparator = sValue;
+ }
+ break;
+ case SP_RND_STARTING_POINT:
+ {
+ if (sValue == "0" || sValue == "1")
+ m_sUseRandomStartingPoint = sValue;
+ }
+ break;
+ case SP_STRONGER_PRNG:
+ {
+ if (sValue == "0" || sValue == "1")
+ m_sUseStrongerPRNG = sValue;
+ }
+ break;
+ case SP_STAGNATION_LIMIT:
+ m_sStagnationLimit = sValue;
+ break;
+ case SP_STAGNATION_TOLERANCE:
+ m_sTolerance = sValue;
+ break;
+ case SP_ENHANCED_STATUS:
+ {
+ if (sValue == "0" || sValue == "1")
+ m_sEnhancedSolverStatus = sValue;
+ }
+ break;
+ case SP_AGENT_SWITCH_RATE:
+ m_sAgentSwitchRate = sValue;
+ break;
+ case SP_SCALING_MIN:
+ m_sScalingFactorMin = sValue;
+ break;
+ case SP_SCALING_MAX:
+ m_sScalingFactorMax = sValue;
+ break;
+ case SP_CROSSOVER_PROB:
+ m_sCrossoverProbability = sValue;
+ break;
+ case SP_COGNITIVE_CONST:
+ m_sCognitiveConstant = sValue;
+ break;
+ case SP_SOCIAL_CONST:
+ m_sSocialConstant = sValue;
+ break;
+ case SP_CONSTRICTION_COEFF:
+ m_sConstrictionCoeff = sValue;
+ break;
+ case SP_MUTATION_PROB:
+ m_sMutationProbability = sValue;
+ break;
+ case SP_LIBRARY_SIZE:
+ m_sLibrarySize = sValue;
+ break;
+ default:
+ break;
+ }
+}
+
+void SolverSettings::SetObjectiveType(ObjectiveType eType) { m_eObjType = eType; }
+
+// Loads all constraints in the tab
+void SolverSettings::ReadConstraints()
+{
+ // Condition indices start at 1 for MS compatibility
+ // The number of "lhs", "rel" and "rhs" entries will always be the same
+ tools::Long nConstraint = 1;
+ m_aConstraints.clear();
+ OUString sValue;
+
+ while (ReadConstraintPart(CP_LEFT_HAND_SIDE, nConstraint, sValue))
+ {
+ // Left hand side
+ ModelConstraint aNewCondition;
+ aNewCondition.aLeftStr = sValue;
+
+ // Right hand side
+ if (ReadConstraintPart(CP_RIGHT_HAND_SIDE, nConstraint, sValue))
+ aNewCondition.aRightStr = sValue;
+
+ // Relation (operator)
+ if (ReadConstraintPart(CP_OPERATOR, nConstraint, sValue))
+ aNewCondition.nOperator = static_cast<sc::ConstraintOperator>(sValue.toInt32());
+
+ m_aConstraints.push_back(aNewCondition);
+ nConstraint++;
+ }
+}
+
+// Writes all constraints to the file
+void SolverSettings::WriteConstraints()
+{
+ // Condition indices start at 1 for MS compatibility
+ tools::Long nConstraint = 1;
+
+ for (auto& aConstraint : m_aConstraints)
+ {
+ // Left hand side
+ WriteConstraintPart(CP_LEFT_HAND_SIDE, nConstraint, aConstraint.aLeftStr);
+ // Relation (operator)
+ WriteConstraintPart(CP_OPERATOR, nConstraint, OUString::number(aConstraint.nOperator));
+ // Right hand side
+ WriteConstraintPart(CP_RIGHT_HAND_SIDE, nConstraint, aConstraint.aRightStr);
+ nConstraint++;
+ }
+}
+
+// Write a single constraint part to the file
+void SolverSettings::WriteConstraintPart(ConstraintPart ePart, tools::Long nIndex, OUString sValue)
+{
+ // Empty named ranges cannot be written to the file (this corrupts MS files)
+ if (sValue.isEmpty())
+ return;
+
+ OUString sRange = m_aConstraintParts[ePart] + OUString::number(nIndex);
+ ScRangeData* pNewEntry = new ScRangeData(m_rDoc, sRange, sValue);
+ pNewEntry->AddType(ScRangeData::Type::Hidden);
+ m_pRangeName->insert(pNewEntry);
+}
+
+// Reads a single constraint part from its associated named range; returns false if the named
+// range does not exist in the file
+bool SolverSettings::ReadConstraintPart(ConstraintPart ePart, tools::Long nIndex, OUString& rValue)
+{
+ OUString sRange = m_aConstraintParts[ePart] + OUString::number(nIndex);
+ ScRangeData* pRangeData
+ = m_pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(sRange));
+ if (pRangeData)
+ {
+ rValue = pRangeData->GetSymbol();
+ // tdf#156814 Remove sheet name if it is a range that refers to the same sheet
+ ScRange aRange;
+ ScRefFlags nFlags = aRange.ParseAny(rValue, m_rDoc);
+ bool bIsValidRange = (nFlags & ScRefFlags::VALID) == ScRefFlags::VALID;
+ if (bIsValidRange && m_rTable.GetTab() == aRange.aStart.Tab())
+ rValue = aRange.Format(m_rDoc, ScRefFlags::RANGE_ABS);
+ return true;
+ }
+ return false;
+}
+
+/* Reads the engine name parameter as informed in the file in the format used in LO.
+ * If only a MS engine is informed, then it is converted to a LO-equivalent engine
+ */
+void SolverSettings::ReadEngine()
+{
+ if (!ReadParamValue(SP_LO_ENGINE, m_sLOEngineName, true))
+ {
+ // If no engine is defined, use CoinMP solver as default
+ m_sLOEngineName = "com.sun.star.comp.Calc.CoinMPSolver";
+ }
+
+ if (SolverNamesToExcelEngines.count(m_sLOEngineName))
+ {
+ // Find equivalent MS engine code
+ m_sMSEngineId = SolverNamesToExcelEngines.find(m_sLOEngineName)->second;
+ }
+}
+
+// Write solver LO and MS-equivalent engine names
+void SolverSettings::WriteEngine()
+{
+ WriteParamValue(SP_LO_ENGINE, m_sLOEngineName, true);
+ // Find equivalent MS engine code
+ if (SolverNamesToExcelEngines.count(m_sLOEngineName))
+ {
+ m_sMSEngineId = SolverNamesToExcelEngines.find(m_sLOEngineName)->second;
+ WriteParamValue(SP_MS_ENGINE, m_sMSEngineId);
+ }
+}
+
+// Assigns a new constraints vector
+void SolverSettings::SetConstraints(std::vector<ModelConstraint> aConstraints)
+{
+ m_aConstraints = std::move(aConstraints);
+}
+
+// Saves all solver settings into the file
+void SolverSettings::SaveSolverSettings()
+{
+ // Before saving, remove all existing named ranges related to the solver
+ DeleteAllNamedRanges();
+
+ WriteParamValue(SP_OBJ_CELL, m_sObjCell);
+ WriteParamValue(SP_OBJ_TYPE, OUString::number(m_eObjType));
+ WriteParamValue(SP_OBJ_VAL, m_sObjVal);
+ WriteParamValue(SP_VAR_CELLS, m_sVariableCells);
+
+ WriteConstraints();
+ WriteEngine();
+
+ sal_Int32 nConstrCount = m_aConstraints.size();
+ WriteParamValue(SP_CONSTR_COUNT, OUString::number(nConstrCount));
+
+ // Solver engine options
+ WriteParamValue(SP_INTEGER, m_sInteger);
+ WriteParamValue(SP_NON_NEGATIVE, m_sNonNegative);
+ WriteParamValue(SP_EPSILON_LEVEL, m_sEpsilonLevel);
+ WriteParamValue(SP_LIMIT_BBDEPTH, m_sLimitBBDepth);
+ WriteParamValue(SP_TIMEOUT, m_sTimeout);
+ WriteParamValue(SP_ALGORITHM, m_sAlgorithm);
+ // Engine options common for DEPS and SCO
+ WriteParamValue(SP_SWARM_SIZE, m_sSwarmSize);
+ WriteParamValue(SP_LEARNING_CYCLES, m_sLearningCycles);
+ WriteParamValue(SP_GUESS_VARIABLE_RANGE, m_sGuessVariableRange);
+ WriteDoubleParamValue(SP_VARIABLE_RANGE_THRESHOLD, m_sVariableRangeThreshold);
+ WriteParamValue(SP_ACR_COMPARATOR, m_sUseACRComparator);
+ WriteParamValue(SP_RND_STARTING_POINT, m_sUseRandomStartingPoint);
+ WriteParamValue(SP_STRONGER_PRNG, m_sUseStrongerPRNG);
+ WriteParamValue(SP_STAGNATION_LIMIT, m_sStagnationLimit);
+ WriteDoubleParamValue(SP_STAGNATION_TOLERANCE, m_sTolerance);
+ WriteParamValue(SP_ENHANCED_STATUS, m_sEnhancedSolverStatus);
+ // DEPS Options
+ WriteDoubleParamValue(SP_AGENT_SWITCH_RATE, m_sAgentSwitchRate);
+ WriteDoubleParamValue(SP_SCALING_MIN, m_sScalingFactorMin);
+ WriteDoubleParamValue(SP_SCALING_MAX, m_sScalingFactorMax);
+ WriteDoubleParamValue(SP_CROSSOVER_PROB, m_sCrossoverProbability);
+ WriteDoubleParamValue(SP_COGNITIVE_CONST, m_sCognitiveConstant);
+ WriteDoubleParamValue(SP_SOCIAL_CONST, m_sSocialConstant);
+ WriteDoubleParamValue(SP_CONSTRICTION_COEFF, m_sConstrictionCoeff);
+ WriteDoubleParamValue(SP_MUTATION_PROB, m_sMutationProbability);
+ // SCO Options
+ WriteParamValue(SP_LIBRARY_SIZE, m_sLibrarySize);
+
+ if (m_pDocShell)
+ m_pDocShell->SetDocumentModified();
+}
+
+/* Reads the current value of the parameter in the named range into rValue
+ * If the value does not exist, the rValue is left unchanged
+ * This is private because it is only used during initialization
+ * Returns true if the value exits; returns false otherwise
+ */
+bool SolverSettings::ReadParamValue(SolverParameter eParam, OUString& rValue, bool bRemoveQuotes)
+{
+ const auto iter = m_mNamedRanges.find(eParam);
+ assert(iter != m_mNamedRanges.end());
+ OUString sRange = iter->second;
+ ScRangeData* pRangeData
+ = m_pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(sRange));
+ if (pRangeData)
+ {
+ rValue = pRangeData->GetSymbol();
+ if (bRemoveQuotes)
+ ScGlobal::EraseQuotes(rValue, '"');
+
+ // tdf#156814 Remove sheet name from the objective cell and value if they refer to the same sheet
+ if (eParam == SP_OBJ_CELL || eParam == SP_OBJ_VAL)
+ {
+ ScRange aRange;
+ ScRefFlags nFlags = aRange.ParseAny(rValue, m_rDoc);
+ bool bIsValidRange = ((nFlags & ScRefFlags::VALID) == ScRefFlags::VALID);
+
+ if (bIsValidRange && m_rTable.GetTab() == aRange.aStart.Tab())
+ rValue = aRange.Format(m_rDoc, ScRefFlags::RANGE_ABS);
+ }
+ else if (eParam == SP_VAR_CELLS)
+ {
+ // Variable cells may contain multiple ranges separated by ';'
+ sal_Int32 nIdx = 0;
+ OUString sNewValue;
+ bool bFirst = true;
+ // Delimiter character to separate ranges
+ sal_Unicode cDelimiter = ScCompiler::GetNativeSymbolChar(OpCode::ocSep);
+
+ do
+ {
+ OUString aRangeStr(o3tl::getToken(rValue, 0, cDelimiter, nIdx));
+ ScRange aRange;
+ ScRefFlags nFlags = aRange.ParseAny(aRangeStr, m_rDoc);
+ bool bIsValidRange = (nFlags & ScRefFlags::VALID) == ScRefFlags::VALID;
+
+ if (bIsValidRange && m_rTable.GetTab() == aRange.aStart.Tab())
+ aRangeStr = aRange.Format(m_rDoc, ScRefFlags::RANGE_ABS);
+
+ if (bFirst)
+ {
+ sNewValue = aRangeStr;
+ bFirst = false;
+ }
+ else
+ {
+ sNewValue += OUStringChar(cDelimiter) + aRangeStr;
+ }
+ } while (nIdx > 0);
+
+ rValue = sNewValue;
+ }
+ return true;
+ }
+ return false;
+}
+
+// Reads a parameter value of type 'double' from the named range and into rValue
+bool SolverSettings::ReadDoubleParamValue(SolverParameter eParam, OUString& rValue)
+{
+ const auto iter = m_mNamedRanges.find(eParam);
+ assert(iter != m_mNamedRanges.end());
+ OUString sRange = iter->second;
+ ScRangeData* pRangeData
+ = m_pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(sRange));
+ if (pRangeData)
+ {
+ OUString sLocalizedValue = pRangeData->GetSymbol();
+ double fValue = rtl::math::stringToDouble(sLocalizedValue,
+ ScGlobal::getLocaleData().getNumDecimalSep()[0],
+ ScGlobal::getLocaleData().getNumThousandSep()[0]);
+ rValue = OUString::number(fValue);
+ return true;
+ }
+ return false;
+}
+
+/* Writes a parameter value to the file as a named range.
+ * Argument bQuoted indicates whether the value should be enclosed with quotes or not (used
+ * for string expressions that must be enclosed with quotes)
+ */
+void SolverSettings::WriteParamValue(SolverParameter eParam, OUString sValue, bool bQuoted)
+{
+ // Empty parameters cannot be written to the file (this corrupts MS files)
+ // There's no problem if the parameter is missing both for LO and MS
+ if (sValue.isEmpty())
+ return;
+
+ if (bQuoted)
+ ScGlobal::AddQuotes(sValue, '"');
+
+ const auto iter = m_mNamedRanges.find(eParam);
+ assert(iter != m_mNamedRanges.end());
+ OUString sRange = iter->second;
+ ScRangeData* pNewEntry = new ScRangeData(m_rDoc, sRange, sValue);
+ pNewEntry->AddType(ScRangeData::Type::Hidden);
+ m_pRangeName->insert(pNewEntry);
+}
+
+// Writes a parameter value of type 'double' to the file as a named range
+// The argument 'sValue' uses dot as decimal separator and needs to be localized before
+// being written to the file
+void SolverSettings::WriteDoubleParamValue(SolverParameter eParam, std::u16string_view sValue)
+{
+ const auto iter = m_mNamedRanges.find(eParam);
+ assert(iter != m_mNamedRanges.end());
+ OUString sRange = iter->second;
+ double fValue = rtl::math::stringToDouble(sValue, '.', ',');
+ OUString sLocalizedValue = rtl::math::doubleToUString(
+ fValue, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
+ ScGlobal::getLocaleData().getNumDecimalSep()[0], true);
+ ScRangeData* pNewEntry = new ScRangeData(m_rDoc, sRange, sLocalizedValue);
+ pNewEntry->AddType(ScRangeData::Type::Hidden);
+ m_pRangeName->insert(pNewEntry);
+}
+
+void SolverSettings::GetEngineOptions(css::uno::Sequence<css::beans::PropertyValue>& aOptions)
+{
+ sal_Int32 nOptionsSize = aOptions.getLength();
+ auto pParamValues = aOptions.getArray();
+
+ for (auto i = 0; i < nOptionsSize; i++)
+ {
+ css::beans::PropertyValue aProp = aOptions[i];
+ OUString sLOParamName = aProp.Name;
+ // Only try to get the parameter value if it is an expected parameter name
+ if (SolverParamNames.count(sLOParamName))
+ {
+ TParamInfo aParamInfo;
+ aParamInfo = SolverParamNames.find(sLOParamName)->second;
+ SolverParameter eParamId = std::get<SolverParameter>(aParamInfo[0]);
+ OUString sParamType = std::get<OUString>(aParamInfo[2]);
+ OUString sParamValue = GetParameter(eParamId);
+ if (sParamType == "int")
+ {
+ css::uno::Any nValue(sParamValue.toInt32());
+ pParamValues[i] = css::beans::PropertyValue(sLOParamName, -1, nValue,
+ css::beans::PropertyState_DIRECT_VALUE);
+ }
+ if (sParamType == "double")
+ {
+ css::uno::Any fValue(sParamValue.toDouble());
+ pParamValues[i] = css::beans::PropertyValue(sLOParamName, -1, fValue,
+ css::beans::PropertyState_DIRECT_VALUE);
+ }
+ if (sParamType == "bool")
+ {
+ // The parameter NonNegative is a special case for MS compatibility
+ // It uses "1" for "true" and "2" for "false"
+ bool bTmpValue;
+ if (sLOParamName == "NonNegative")
+ bTmpValue = sParamValue == "1" ? true : false;
+ else
+ bTmpValue = sParamValue.toBoolean();
+
+ css::uno::Any bValue(bTmpValue);
+ pParamValues[i] = css::beans::PropertyValue(sLOParamName, -1, bValue,
+ css::beans::PropertyState_DIRECT_VALUE);
+ }
+ }
+ }
+}
+
+// Updates the object members related to solver engine options using aOptions info
+void SolverSettings::SetEngineOptions(css::uno::Sequence<css::beans::PropertyValue>& aOptions)
+{
+ sal_Int32 nOptionsSize = aOptions.getLength();
+
+ for (auto i = 0; i < nOptionsSize; i++)
+ {
+ css::beans::PropertyValue aProp = aOptions[i];
+ OUString sLOParamName = aProp.Name;
+ // Only try to set the parameter value if it is an expected parameter name
+ if (SolverParamNames.count(sLOParamName))
+ {
+ TParamInfo aParamInfo;
+ aParamInfo = SolverParamNames.find(sLOParamName)->second;
+ SolverParameter eParamId = std::get<SolverParameter>(aParamInfo[0]);
+ OUString sParamType = std::get<OUString>(aParamInfo[2]);
+ if (sParamType == "int")
+ {
+ sal_Int32 nValue = 0;
+ aProp.Value >>= nValue;
+ SetParameter(eParamId, OUString::number(nValue));
+ }
+ if (sParamType == "double")
+ {
+ double fValue = 0;
+ aProp.Value >>= fValue;
+ SetParameter(eParamId, OUString::number(fValue));
+ }
+ if (sParamType == "bool")
+ {
+ bool bValue = false;
+ aProp.Value >>= bValue;
+ if (sLOParamName == "NonNegative")
+ {
+ // The parameter NonNegative is a special case for MS compatibility
+ // It uses "1" for "true" and "2" for "false"
+ if (bValue)
+ SetParameter(eParamId, OUString::number(1));
+ else
+ SetParameter(eParamId, OUString::number(2));
+ }
+ else
+ {
+ SetParameter(eParamId, OUString::number(sal_Int32(bValue)));
+ }
+ }
+ }
+ }
+}
+
+// Deletes all named ranges in the current tab that are related to the solver (i.e. start with "solver_")
+void SolverSettings::DeleteAllNamedRanges()
+{
+ std::vector<ScRangeData*> aItemsToErase;
+
+ // Indices in m_pRangeName start at 1
+ for (size_t i = 1; i <= m_pRangeName->size(); ++i)
+ {
+ ScRangeData* pData = m_pRangeName->findByIndex(i);
+ if (pData && pData->GetName().startsWith("solver_"))
+ aItemsToErase.push_back(pData);
+ }
+
+ for (auto pItem : aItemsToErase)
+ m_pRangeName->erase(*pItem);
+}
+
+/* Sets all solver parameters to their default values and clear all constraints.
+ * This method only resets the object properties, but does not save changes to the
+ * document. To save changes, call SaveSolverSettings().
+ */
+void SolverSettings::ResetToDefaults()
+{
+ m_sObjCell = "";
+ m_eObjType = ObjectiveType::OT_MAXIMIZE;
+ m_sObjVal = "";
+ m_sVariableCells = "";
+ m_sMSEngineId = "1";
+
+ // The default solver engine is the first implementation available
+ css::uno::Sequence<OUString> aEngineNames;
+ css::uno::Sequence<OUString> aDescriptions;
+ ScSolverUtil::GetImplementations(aEngineNames, aDescriptions);
+ m_sLOEngineName = aEngineNames[0];
+
+ // Default engine options
+ m_aEngineOptions = ScSolverUtil::GetDefaults(m_sLOEngineName);
+
+ // Default solver engine options
+ SetEngineOptions(m_aEngineOptions);
+
+ // Clear all constraints
+ m_aConstraints.clear();
+}
+
+/* Returns true if the current sheet already has a solver model.
+ This is determined by checking if the current tab has the SP_OBJ_CELL named range
+ which is associated with solver models.
+ Note that the named ranges are only created after SaveSolverSettings is called,
+ so before it is called, no solver-related named ranges exist.
+*/
+bool SolverSettings::TabHasSolverModel()
+{
+ // Check if the named range for the objective value exists in the sheet
+ const auto iter = m_mNamedRanges.find(SP_OBJ_CELL);
+ if (iter == m_mNamedRanges.end())
+ return false;
+ OUString sRange = iter->second;
+ ScRangeData* pRangeData
+ = m_pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(sRange));
+ if (pRangeData)
+ return true;
+ return false;
+}
+
+} // namespace sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/sc/source/core/data/attarray.cxx b/sc/source/core/data/attarray.cxx
index 41fb51471c43..9f1e37913514 100644
--- a/sc/source/core/data/attarray.cxx
+++ b/sc/source/core/data/attarray.cxx
@@ -26,12 +26,12 @@
#include <editeng/editobj.hxx>
#include <editeng/justifyitem.hxx>
#include <osl/diagnose.h>
-#include <svl/poolcach.hxx>
-#include <sfx2/objsh.hxx>
+#include <poolcach.hxx>
#include <global.hxx>
#include <document.hxx>
#include <docpool.hxx>
+#include <docsh.hxx>
#include <patattr.hxx>
#include <stlsheet.hxx>
#include <stlpool.hxx>
@@ -61,11 +61,11 @@ ScAttrArray::ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument& rDoc, ScAttr
for ( size_t nIdx = 0; nIdx < pDefaultColAttrArray->mvData.size(); ++nIdx )
{
mvData[nIdx].nEndRow = pDefaultColAttrArray->mvData[nIdx].nEndRow;
- ScPatternAttr aNewPattern( *(pDefaultColAttrArray->mvData[nIdx].pPattern) );
- mvData[nIdx].pPattern = &rDocument.GetPool()->Put( aNewPattern );
+ mvData[nIdx].setScPatternAttr(pDefaultColAttrArray->mvData[nIdx].getScPatternAttr());
bool bNumFormatChanged = false;
if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
- mvData[nIdx].pPattern->GetItemSet(), rDocument.GetDefPattern()->GetItemSet() ) )
+ mvData[nIdx].getScPatternAttr()->GetItemSet(),
+ rDocument.getCellAttributeHelper().getDefaultCellAttribute().GetItemSet() ) )
{
aAdrStart.SetRow( nIdx ? mvData[nIdx-1].nEndRow+1 : 0 );
aAdrEnd.SetRow( mvData[nIdx].nEndRow );
@@ -79,10 +79,6 @@ ScAttrArray::~ScAttrArray()
#if DEBUG_SC_TESTATTRARRAY
TestData();
#endif
-
- ScDocumentPool* pDocPool = rDocument.GetPool();
- for (auto const & rEntry : mvData)
- pDocPool->Remove(*rEntry.pPattern);
}
#if DEBUG_SC_TESTATTRARRAY
@@ -96,8 +92,6 @@ void ScAttrArray::TestData() const
if (nPos > 0)
if (mvData[nPos].pPattern == mvData[nPos-1].pPattern || mvData[nPos].nRow <= mvData[nPos-1].nRow)
++nErr;
- if (mvData[nPos].pPattern->Which() != ATTR_PATTERN)
- ++nErr;
}
if ( nPos && mvData[nPos-1].nRow != rDocument.MaxRow() )
++nErr;
@@ -115,19 +109,22 @@ void ScAttrArray::SetDefaultIfNotInit( SCSIZE nNeeded )
mvData.reserve( nNewLimit );
mvData.emplace_back();
mvData[0].nEndRow = rDocument.MaxRow();
- mvData[0].pPattern = rDocument.GetDefPattern(); // no put
+ mvData[0].setScPatternAttr(&rDocument.getCellAttributeHelper().getDefaultCellAttribute()); // no put
}
-void ScAttrArray::Reset( const ScPatternAttr* pPattern )
+void ScAttrArray::Reset(const CellAttributeHolder& rPattern)
{
- ScDocumentPool* pDocPool = rDocument.GetPool();
+ const ScPatternAttr* pPattern(rPattern.getScPatternAttr());
+ if (nullptr == pPattern)
+ return;
+
ScAddress aAdrStart( nCol, 0, nTab );
ScAddress aAdrEnd ( nCol, 0, nTab );
for (SCSIZE i=0; i<mvData.size(); i++)
{
// ensure that attributing changes text width of cell
- const ScPatternAttr* pOldPattern = mvData[i].pPattern;
+ const ScPatternAttr* pOldPattern(mvData[i].getScPatternAttr());
if ( nCol != -1 )
{
bool bNumFormatChanged;
@@ -139,16 +136,14 @@ void ScAttrArray::Reset( const ScPatternAttr* pPattern )
rDocument.InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
}
}
- pDocPool->Remove(*pOldPattern);
}
mvData.resize(0);
rDocument.SetStreamValid(nTab, false);
mvData.resize(1);
- const ScPatternAttr* pNewPattern = &pDocPool->Put(*pPattern);
mvData[0].nEndRow = rDocument.MaxRow();
- mvData[0].pPattern = pNewPattern;
+ mvData[0].setScPatternAttr(pPattern);
}
bool ScAttrArray::Concat(SCSIZE nPos)
@@ -158,10 +153,9 @@ bool ScAttrArray::Concat(SCSIZE nPos)
{
if (nPos > 0)
{
- if (mvData[nPos - 1].pPattern == mvData[nPos].pPattern)
+ if (ScPatternAttr::areSame(mvData[nPos - 1].getScPatternAttr(), mvData[nPos].getScPatternAttr()))
{
mvData[nPos - 1].nEndRow = mvData[nPos].nEndRow;
- rDocument.GetPool()->Remove(*mvData[nPos].pPattern);
mvData.erase(mvData.begin() + nPos);
nPos--;
bRet = true;
@@ -169,10 +163,9 @@ bool ScAttrArray::Concat(SCSIZE nPos)
}
if (nPos + 1 < mvData.size())
{
- if (mvData[nPos + 1].pPattern == mvData[nPos].pPattern)
+ if (ScPatternAttr::areSame(mvData[nPos + 1].getScPatternAttr(), mvData[nPos].getScPatternAttr()))
{
mvData[nPos].nEndRow = mvData[nPos + 1].nEndRow;
- rDocument.GetPool()->Remove(*mvData[nPos].pPattern);
mvData.erase(mvData.begin() + nPos + 1);
bRet = true;
}
@@ -189,9 +182,11 @@ bool ScAttrArray::Concat(SCSIZE nPos)
*
* Iterative implementation of Binary Search
* The same implementation was used inside ScMarkArray::Search().
+ *
+ * @param oIndexHint, hint for the start of the search, useful when searching twice for successive values
*/
-bool ScAttrArray::Search( SCROW nRow, SCSIZE& nIndex ) const
+bool ScAttrArray::Search( SCROW nRow, SCSIZE& nIndex, std::optional<SCROW> oIndexHint ) const
{
/* auto it = std::lower_bound(mvData.begin(), mvData.end(), nRow,
[] (const ScAttrEntry &r1, SCROW nRow)
@@ -208,7 +203,8 @@ bool ScAttrArray::Search( SCROW nRow, SCSIZE& nIndex ) const
tools::Long nHi = static_cast<tools::Long>(mvData.size()) - 1;
tools::Long i = 0;
- tools::Long nLo = 0;
+ assert((!oIndexHint || *oIndexHint <= nHi) && "bad index hint");
+ tools::Long nLo = oIndexHint ? *oIndexHint : 0;
while ( nLo <= nHi )
{
@@ -242,11 +238,11 @@ const ScPatternAttr* ScAttrArray::GetPattern( SCROW nRow ) const
{
if ( !rDocument.ValidRow(nRow) )
return nullptr;
- return rDocument.GetDefPattern();
+ return &rDocument.getCellAttributeHelper().getDefaultCellAttribute();
}
SCSIZE i;
if (Search( nRow, i ))
- return mvData[i].pPattern;
+ return mvData[i].getScPatternAttr();
else
return nullptr;
}
@@ -260,7 +256,7 @@ const ScPatternAttr* ScAttrArray::GetPatternRange( SCROW& rStartRow,
return nullptr;
rStartRow = 0;
rEndRow = rDocument.MaxRow();
- return rDocument.GetDefPattern();
+ return &rDocument.getCellAttributeHelper().getDefaultCellAttribute();
}
SCSIZE nIndex;
if ( Search( nRow, nIndex ) )
@@ -270,7 +266,7 @@ const ScPatternAttr* ScAttrArray::GetPatternRange( SCROW& rStartRow,
else
rStartRow = 0;
rEndRow = mvData[nIndex].nEndRow;
- return mvData[nIndex].pPattern;
+ return mvData[nIndex].getScPatternAttr();
}
return nullptr;
}
@@ -290,20 +286,21 @@ void ScAttrArray::AddCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nInd
{
const ScPatternAttr* pPattern = GetPattern(nTempStartRow);
+ // changed to create pNewPattern only if needed, else use already
+ // existing pPattern. This shows by example how to avoid that special
+ // handling of ScPatternAttr in SC and massive
+ // incarnations/destructions of that Item (which contains an ItemSet)
std::unique_ptr<ScPatternAttr> pNewPattern;
if(pPattern)
{
- pNewPattern.reset( new ScPatternAttr(*pPattern) );
SCROW nPatternStartRow;
SCROW nPatternEndRow;
GetPatternRange( nPatternStartRow, nPatternEndRow, nTempStartRow );
nTempEndRow = std::min<SCROW>( nPatternEndRow, nEndRow );
- const SfxPoolItem* pItem = nullptr;
- pPattern->GetItemSet().GetItemState( ATTR_CONDITIONAL, true, &pItem );
- if(pItem)
+ if (const ScCondFormatItem* pItem = pPattern->GetItemSet().GetItemIfSet( ATTR_CONDITIONAL ))
{
- ScCondFormatIndexes const & rCondFormatData = static_cast<const ScCondFormatItem*>(pItem)->GetCondFormatData();
+ ScCondFormatIndexes const & rCondFormatData = pItem->GetCondFormatData();
if (rCondFormatData.find(nIndex) == rCondFormatData.end())
{
ScCondFormatIndexes aNewCondFormatData;
@@ -311,24 +308,30 @@ void ScAttrArray::AddCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nInd
aNewCondFormatData = rCondFormatData;
aNewCondFormatData.insert(nIndex);
ScCondFormatItem aItem( std::move(aNewCondFormatData) );
+ pNewPattern.reset( new ScPatternAttr(*pPattern) );
pNewPattern->GetItemSet().Put( aItem );
}
}
else
{
ScCondFormatItem aItem(nIndex);
+ pNewPattern.reset( new ScPatternAttr(*pPattern) );
pNewPattern->GetItemSet().Put( aItem );
}
}
else
{
- pNewPattern.reset( new ScPatternAttr( rDocument.GetPool() ) );
+ pNewPattern.reset( new ScPatternAttr( rDocument.getCellAttributeHelper() ) );
ScCondFormatItem aItem(nIndex);
pNewPattern->GetItemSet().Put( aItem );
nTempEndRow = nEndRow;
}
- SetPatternArea( nTempStartRow, nTempEndRow, std::move(pNewPattern), true );
+ if (pNewPattern)
+ SetPatternArea( nTempStartRow, nTempEndRow, CellAttributeHolder(pNewPattern.release(), true) );
+ else
+ SetPatternArea( nTempStartRow, nTempEndRow, CellAttributeHolder(pPattern) );
+
nTempStartRow = nTempEndRow + 1;
}
while(nTempEndRow < nEndRow);
@@ -357,28 +360,27 @@ void ScAttrArray::RemoveCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 n
GetPatternRange( nPatternStartRow, nPatternEndRow, nTempStartRow );
nTempEndRow = std::min<SCROW>( nPatternEndRow, nEndRow );
- const SfxPoolItem* pItem = nullptr;
- pPattern->GetItemSet().GetItemState( ATTR_CONDITIONAL, true, &pItem );
- if(pItem)
+ if (const ScCondFormatItem* pItem = pPattern->GetItemSet().GetItemIfSet( ATTR_CONDITIONAL ))
{
- auto pPatternAttr = std::make_unique<ScPatternAttr>( *pPattern );
if (nIndex == 0)
{
ScCondFormatItem aItem;
- pPatternAttr->GetItemSet().Put( aItem );
- SetPatternArea( nTempStartRow, nTempEndRow, std::move(pPatternAttr), true );
+ ScPatternAttr* pTemp(new ScPatternAttr(*pPattern));
+ pTemp->GetItemSet().Put( aItem );
+ SetPatternArea( nTempStartRow, nTempEndRow, CellAttributeHolder(pTemp, true) );
}
else
{
- ScCondFormatIndexes const & rCondFormatData = static_cast<const ScCondFormatItem*>(pItem)->GetCondFormatData();
+ ScCondFormatIndexes const & rCondFormatData = pItem->GetCondFormatData();
auto itr = rCondFormatData.find(nIndex);
if(itr != rCondFormatData.end())
{
ScCondFormatIndexes aNewCondFormatData(rCondFormatData);
aNewCondFormatData.erase_at(std::distance(rCondFormatData.begin(), itr));
ScCondFormatItem aItem( std::move(aNewCondFormatData) );
- pPatternAttr->GetItemSet().Put( aItem );
- SetPatternArea( nTempStartRow, nTempEndRow, std::move(pPatternAttr), true );
+ ScPatternAttr* pTemp(new ScPatternAttr(*pPattern));
+ pTemp->GetItemSet().Put( aItem );
+ SetPatternArea( nTempStartRow, nTempEndRow, CellAttributeHolder(pTemp, true) );
}
}
}
@@ -401,24 +403,25 @@ void ScAttrArray::RemoveCellCharAttribs( SCROW nStartRow, SCROW nEndRow,
// cache mdds position, this doesn't modify the mdds container, just EditTextObject's
sc::ColumnBlockPosition blockPos;
rDocument.InitColumnBlockPosition( blockPos, nTab, nCol );
+ nEndRow = rDocument.GetLastDataRow(nTab, nCol, nCol, nEndRow);
for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
{
ScAddress aPos(nCol, nRow, nTab);
ScRefCellValue aCell(rDocument, aPos, blockPos);
- if (aCell.meType != CELLTYPE_EDIT || !aCell.mpEditText)
+ if (aCell.getType() != CELLTYPE_EDIT || !aCell.getEditText())
continue;
std::unique_ptr<EditTextObject> pOldData;
if (pDataArray)
- pOldData = aCell.mpEditText->Clone();
+ pOldData = aCell.getEditText()->Clone();
// Direct modification of cell content - something to watch out for if
// we decide to share edit text instances in the future.
- ScEditUtil::RemoveCharAttribs(const_cast<EditTextObject&>(*aCell.mpEditText), *pPattern);
+ ScEditUtil::RemoveCharAttribs(const_cast<EditTextObject&>(*aCell.getEditText()), *pPattern);
if (pDataArray)
{
- std::unique_ptr<EditTextObject> pNewData = aCell.mpEditText->Clone();
+ std::unique_ptr<EditTextObject> pNewData = aCell.getEditText()->Clone();
pDataArray->AddItem(nTab, nCol, nRow, std::move(pOldData), std::move(pNewData));
}
}
@@ -432,7 +435,7 @@ bool ScAttrArray::Reserve( SCSIZE nReserve )
mvData.reserve(nReserve);
mvData.emplace_back();
mvData[0].nEndRow = rDocument.MaxRow();
- mvData[0].pPattern = rDocument.GetDefPattern(); // no put
+ mvData[0].setScPatternAttr(&rDocument.getCellAttributeHelper().getDefaultCellAttribute()); // no put
return true;
} catch (std::bad_alloc const &) {
return false;
@@ -451,20 +454,17 @@ bool ScAttrArray::Reserve( SCSIZE nReserve )
return false;
}
-const ScPatternAttr* ScAttrArray::SetPatternAreaImpl(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr* pPattern,
- bool bPutToPool, ScEditDataArray* pDataArray, bool bPassingOwnership )
+const ScPatternAttr* ScAttrArray::SetPatternAreaImpl(
+ SCROW nStartRow, SCROW nEndRow, const CellAttributeHolder& rPattern, ScEditDataArray* pDataArray)
{
+ const ScPatternAttr* pPattern(rPattern.getScPatternAttr());
+ if (nullptr == pPattern)
+ return nullptr;
+
if (rDocument.ValidRow(nStartRow) && rDocument.ValidRow(nEndRow))
{
- if (bPutToPool)
- {
- if (bPassingOwnership)
- pPattern = &rDocument.GetPool()->Put(std::unique_ptr<ScPatternAttr>(const_cast<ScPatternAttr*>(pPattern)));
- else
- pPattern = &rDocument.GetPool()->Put(*pPattern);
- }
if ((nStartRow == 0) && (nEndRow == rDocument.MaxRow()))
- Reset(pPattern);
+ Reset(rPattern);
else
{
SCSIZE nNeeded = mvData.size() + 2;
@@ -498,7 +498,7 @@ const ScPatternAttr* ScAttrArray::SetPatternAreaImpl(SCROW nStartRow, SCROW nEnd
if ( nCol != -1 && !bIsLoading )
{
const SfxItemSet& rNewSet = pPattern->GetItemSet();
- const SfxItemSet& rOldSet = mvData[nx].pPattern->GetItemSet();
+ const SfxItemSet& rOldSet = mvData[nx].getScPatternAttr()->GetItemSet();
bool bNumFormatChanged;
if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
rNewSet, rOldSet ) )
@@ -520,7 +520,7 @@ const ScPatternAttr* ScAttrArray::SetPatternAreaImpl(SCROW nStartRow, SCROW nEnd
if ( nStartRow > 0 )
{
nInsert = rDocument.MaxRow() + 1;
- if ( mvData[ni].pPattern != pPattern )
+ if ( !ScPatternAttr::areSame(mvData[ni].getScPatternAttr(), pPattern ) )
{
if ( ni == 0 || (mvData[ni-1].nEndRow < nStartRow - 1) )
{ // may be a split or a simple insert or just a shrink,
@@ -533,7 +533,7 @@ const ScPatternAttr* ScAttrArray::SetPatternAreaImpl(SCROW nStartRow, SCROW nEnd
else if (mvData[ni - 1].nEndRow == nStartRow - 1)
nInsert = ni;
}
- if ( ni > 0 && mvData[ni-1].pPattern == pPattern )
+ if ( ni > 0 && ScPatternAttr::areSame(mvData[ni-1].getScPatternAttr(), pPattern) )
{ // combine
mvData[ni-1].nEndRow = nEndRow;
nInsert = rDocument.MaxRow() + 1;
@@ -548,11 +548,11 @@ const ScPatternAttr* ScAttrArray::SetPatternAreaImpl(SCROW nStartRow, SCROW nEnd
nj++;
if ( !bSplit )
{
- if ( nj < mvData.size() && mvData[nj].pPattern == pPattern )
+ if ( nj < mvData.size() && ScPatternAttr::areSame(mvData[nj].getScPatternAttr(), pPattern ) )
{ // combine
if ( ni > 0 )
{
- if ( mvData[ni-1].pPattern == pPattern )
+ if ( ScPatternAttr::areSame(mvData[ni-1].getScPatternAttr(), pPattern ) )
{ // adjacent entries
mvData[ni-1].nEndRow = mvData[nj].nEndRow;
nj++;
@@ -566,21 +566,12 @@ const ScPatternAttr* ScAttrArray::SetPatternAreaImpl(SCROW nStartRow, SCROW nEnd
else if ( ni > 0 && ni == nInsert )
mvData[ni-1].nEndRow = nStartRow - 1; // shrink
}
- ScDocumentPool* pDocPool = rDocument.GetPool();
- if ( bSplit )
- { // duplicate split entry in pool
- pDocPool->Put( *mvData[ni-1].pPattern );
- }
if ( ni < nj )
{ // remove middle entries
- for ( SCSIZE nk=ni; nk<nj; nk++)
- { // remove entries from pool
- pDocPool->Remove( *mvData[nk].pPattern );
- }
if ( !bCombined )
{ // replace one entry
mvData[ni].nEndRow = nEndRow;
- mvData[ni].pPattern = pPattern;
+ mvData[ni].setScPatternAttr(pPattern);
ni++;
nInsert = rDocument.MaxRow() + 1;
}
@@ -605,7 +596,7 @@ const ScPatternAttr* ScAttrArray::SetPatternAreaImpl(SCROW nStartRow, SCROW nEnd
if ( nInsert )
mvData[nInsert-1].nEndRow = nStartRow - 1;
mvData[nInsert].nEndRow = nEndRow;
- mvData[nInsert].pPattern = pPattern;
+ mvData[nInsert].setScPatternAttr(pPattern);
// Remove character attributes from these cells if the pattern
// is applied during normal session.
@@ -642,7 +633,7 @@ void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleS
do
{
- const ScPatternAttr* pOldPattern = mvData[nPos].pPattern;
+ const ScPatternAttr* pOldPattern = mvData[nPos].getScPatternAttr();
std::unique_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr(*pOldPattern));
pNewPattern->SetStyleSheet(const_cast<ScStyleSheet*>(&rStyle));
SCROW nY1 = nStart;
@@ -659,7 +650,7 @@ void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleS
{
if (nY1 < nStartRow) nY1=nStartRow;
if (nY2 > nEndRow) nY2=nEndRow;
- SetPatternArea( nY1, nY2, std::move(pNewPattern), true );
+ SetPatternArea( nY1, nY2, CellAttributeHolder(pNewPattern.release(), true) );
Search( nStart, nPos );
}
else
@@ -681,8 +672,7 @@ void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleS
}
}
- rDocument.GetPool()->Remove(*mvData[nPos].pPattern);
- mvData[nPos].pPattern = &rDocument.GetPool()->Put(*pNewPattern);
+ mvData[nPos].setScPatternAttr(pNewPattern.release(), true);
if (Concat(nPos))
Search(nStart, nPos);
else
@@ -737,25 +727,22 @@ void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow,
do
{
- const ScPatternAttr* pOldPattern = mvData[nPos].pPattern;
+ const ScPatternAttr* pOldPattern = mvData[nPos].getScPatternAttr();
const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
- const SfxPoolItem* pBoxItem = nullptr;
- SfxItemState eState = rOldSet.GetItemState( ATTR_BORDER, true, &pBoxItem );
- const SfxPoolItem* pTLBRItem = nullptr;
- SfxItemState eTLBRState = rOldSet.GetItemState( ATTR_BORDER_TLBR, true, &pTLBRItem );
- const SfxPoolItem* pBLTRItem = nullptr;
- SfxItemState eBLTRState = rOldSet.GetItemState( ATTR_BORDER_BLTR, true, &pBLTRItem );
+ const SvxBoxItem* pBoxItem = rOldSet.GetItemIfSet( ATTR_BORDER );
+ const SvxLineItem* pTLBRItem = rOldSet.GetItemIfSet( ATTR_BORDER_TLBR );
+ const SvxLineItem* pBLTRItem = rOldSet.GetItemIfSet( ATTR_BORDER_BLTR );
- if ( (SfxItemState::SET == eState) || (SfxItemState::SET == eTLBRState) || (SfxItemState::SET == eBLTRState) )
+ if ( pBoxItem || pTLBRItem || pBLTRItem )
{
std::unique_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr(*pOldPattern));
SfxItemSet& rNewSet = pNewPattern->GetItemSet();
SCROW nY1 = nStart;
SCROW nY2 = mvData[nPos].nEndRow;
- std::unique_ptr<SvxBoxItem> pNewBoxItem( pBoxItem ? static_cast<SvxBoxItem*>(pBoxItem->Clone()) : nullptr);
- std::unique_ptr<SvxLineItem> pNewTLBRItem( pTLBRItem ? static_cast<SvxLineItem*>(pTLBRItem->Clone()) : nullptr);
- std::unique_ptr<SvxLineItem> pNewBLTRItem(pBLTRItem ? static_cast<SvxLineItem*>(pBLTRItem->Clone()) : nullptr);
+ std::unique_ptr<SvxBoxItem> pNewBoxItem( pBoxItem ? pBoxItem->Clone() : nullptr);
+ std::unique_ptr<SvxLineItem> pNewTLBRItem( pTLBRItem ? pTLBRItem->Clone() : nullptr);
+ std::unique_ptr<SvxLineItem> pNewBLTRItem(pBLTRItem ? pBLTRItem->Clone() : nullptr);
// fetch line and update attributes with parameters
@@ -805,9 +792,9 @@ void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow,
SetLine( pNewBLTRItem->GetLine(), pLine );
}
}
- if( pNewBoxItem ) rNewSet.Put( *pNewBoxItem );
- if( pNewTLBRItem ) rNewSet.Put( *pNewTLBRItem );
- if( pNewBLTRItem ) rNewSet.Put( *pNewBLTRItem );
+ if( pNewBoxItem ) rNewSet.Put( std::move(pNewBoxItem) );
+ if( pNewTLBRItem ) rNewSet.Put( std::move(pNewTLBRItem) );
+ if( pNewBLTRItem ) rNewSet.Put( std::move(pNewBLTRItem) );
nStart = mvData[nPos].nEndRow + 1;
@@ -815,15 +802,13 @@ void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow,
{
if (nY1 < nStartRow) nY1=nStartRow;
if (nY2 > nEndRow) nY2=nEndRow;
- SetPatternArea( nY1, nY2, std::move(pNewPattern), true );
+ SetPatternArea( nY1, nY2, CellAttributeHolder(pNewPattern.release(), true) );
Search( nStart, nPos );
}
else
{
// remove from pool ?
- rDocument.GetPool()->Remove(*mvData[nPos].pPattern);
- mvData[nPos].pPattern =
- &rDocument.GetPool()->Put(std::move(pNewPattern));
+ mvData[nPos].setScPatternAttr(pNewPattern.release(), true);
if (Concat(nPos))
Search(nStart, nPos);
@@ -840,7 +825,7 @@ void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow,
while ((nStart <= nEndRow) && (nPos < mvData.size()));
}
-void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCache* pCache, ScEditDataArray* pDataArray, bool* const pIsChanged )
+void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, ScItemPoolCache& rCache, ScEditDataArray* pDataArray, bool* const pIsChanged )
{
#if DEBUG_SC_TESTATTRARRAY
TestData();
@@ -863,9 +848,10 @@ void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCac
do
{
- const ScPatternAttr* pOldPattern = mvData[nPos].pPattern;
- const ScPatternAttr* pNewPattern = static_cast<const ScPatternAttr*>( &pCache->ApplyTo( *pOldPattern ) );
- if (pNewPattern != pOldPattern)
+ const CellAttributeHolder& rOldPattern(mvData[nPos].getCellAttributeHolder());
+ const CellAttributeHolder& rNewPattern(rCache.ApplyTo( rOldPattern ));
+
+ if (!CellAttributeHolder::areSame(&rNewPattern, &rOldPattern))
{
SCROW nY1 = nStart;
SCROW nY2 = mvData[nPos].nEndRow;
@@ -878,7 +864,7 @@ void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCac
{
if (nY1 < nStartRow) nY1=nStartRow;
if (nY2 > nEndRow) nY2=nEndRow;
- SetPatternArea( nY1, nY2, pNewPattern, false, pDataArray );
+ SetPatternArea( nY1, nY2, rNewPattern, pDataArray );
Search( nStart, nPos );
}
else
@@ -887,8 +873,8 @@ void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCac
{
// ensure attributing changes text-width of cell
- const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
- const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
+ const SfxItemSet& rNewSet = rNewPattern.getScPatternAttr()->GetItemSet();
+ const SfxItemSet& rOldSet = rOldPattern.getScPatternAttr()->GetItemSet();
bool bNumFormatChanged;
if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
@@ -900,8 +886,7 @@ void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCac
}
}
- rDocument.GetPool()->Remove(*mvData[nPos].pPattern);
- mvData[nPos].pPattern = pNewPattern;
+ mvData[nPos].setCellAttributeHolder(rNewPattern);
if (Concat(nPos))
Search(nStart, nPos);
else
@@ -925,11 +910,16 @@ void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCac
void ScAttrArray::SetAttrEntries(std::vector<ScAttrEntry> && vNewData)
{
- ScDocumentPool* pDocPool = rDocument.GetPool();
- for (auto const & rEntry : mvData)
- pDocPool->Remove(*rEntry.pPattern);
-
mvData = std::move(vNewData);
+
+#ifdef DBG_UTIL
+ SCROW lastEndRow = -1;
+ for(const auto& entry : mvData)
+ { // Verify that the data is not corrupted.
+ assert(entry.nEndRow > lastEndRow);
+ lastEndRow = entry.nEndRow;
+ }
+#endif
}
static void lcl_MergeDeep( SfxItemSet& rMergeSet, const SfxItemSet& rSource )
@@ -946,7 +936,7 @@ static void lcl_MergeDeep( SfxItemSet& rMergeSet, const SfxItemSet& rSource )
SfxItemState eNewState = rSource.GetItemState( nId, true, &pNewItem );
if ( eNewState == SfxItemState::SET )
{
- if ( *pNewItem != rMergeSet.GetPool()->GetDefaultItem(nId) )
+ if ( *pNewItem != rMergeSet.GetPool()->GetUserOrPoolDefaultItem(nId) )
rMergeSet.InvalidateItem( nId );
}
}
@@ -955,12 +945,12 @@ static void lcl_MergeDeep( SfxItemSet& rMergeSet, const SfxItemSet& rSource )
SfxItemState eNewState = rSource.GetItemState( nId, true, &pNewItem );
if ( eNewState == SfxItemState::SET )
{
- if ( pNewItem != pOldItem ) // Both pulled
+ if ( !SfxPoolItem::areSame(pNewItem, pOldItem) ) // Both pulled
rMergeSet.InvalidateItem( nId );
}
else // Default
{
- if ( *pOldItem != rSource.GetPool()->GetDefaultItem(nId) )
+ if ( *pOldItem != rSource.GetPool()->GetUserOrPoolDefaultItem(nId) )
rMergeSet.InvalidateItem( nId );
}
}
@@ -985,12 +975,12 @@ void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow,
do
{
// similar patterns must not be repeated
- const ScPatternAttr* pPattern = nullptr;
+ const ScPatternAttr* pPattern(&rDocument.getCellAttributeHelper().getDefaultCellAttribute());
if ( !mvData.empty() )
- pPattern = mvData[nPos].pPattern;
- else
- pPattern = rDocument.GetDefPattern();
- if ( pPattern != rState.pOld1 && pPattern != rState.pOld2 )
+ pPattern = mvData[nPos].getScPatternAttr();
+
+ if ( !ScPatternAttr::areSame(pPattern, rState.aOld1.getScPatternAttr())
+ && !ScPatternAttr::areSame(pPattern, rState.aOld2.getScPatternAttr()) )
{
const SfxItemSet& rThisSet = pPattern->GetItemSet();
if (rState.pItemSet)
@@ -1004,13 +994,13 @@ void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow,
else
{
// first pattern - copied from parent
- rState.pItemSet = std::make_unique<SfxItemSet>( *rThisSet.GetPool(), rThisSet.GetRanges() );
+ rState.pItemSet.emplace( *rThisSet.GetPool(), rThisSet.GetRanges() );
rState.pItemSet->Set( rThisSet, bDeep );
- rState.mnPatternId = pPattern->GetKey();
+ rState.mnPatternId = pPattern->GetPAKey();
}
- rState.pOld2 = rState.pOld1;
- rState.pOld1 = pPattern;
+ rState.aOld2 = rState.aOld1;
+ rState.aOld1 = pPattern;
}
if ( !mvData.empty() )
@@ -1066,7 +1056,7 @@ static void lcl_MergeToFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner
if ( rMerge.GetRowMerge() == nDistBottom + 1 )
nDistBottom = 0;
- const SvxBoxItem* pCellFrame = &pPattern->GetItemSet().Get( ATTR_BORDER );
+ const SvxBoxItem* pCellFrame = &pPattern->GetItem( ATTR_BORDER );
const SvxBorderLine* pLeftAttr = pCellFrame->GetLeft();
const SvxBorderLine* pRightAttr = pCellFrame->GetRight();
const SvxBorderLine* pTopAttr = pCellFrame->GetTop();
@@ -1141,7 +1131,7 @@ void ScAttrArray::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLine
Search( nEndRow-1, nEndIndex );
for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
{
- pPattern = mvData[i].pPattern;
+ pPattern = mvData[i].getScPatternAttr();
lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, false,
nEndRow - std::min( mvData[i].nEndRow, static_cast<SCROW>(nEndRow-1) ) );
// nDistBottom here always > 0
@@ -1152,7 +1142,7 @@ void ScAttrArray::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLine
}
else
{
- lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, rDocument.GetDefPattern(), bLeft, nDistRight, true, 0 );
+ lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, &rDocument.getCellAttributeHelper().getDefaultCellAttribute(), bLeft, nDistRight, true, 0 );
}
}
@@ -1160,15 +1150,15 @@ void ScAttrArray::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLine
// ApplyFrame - on an entry into the array
-bool ScAttrArray::ApplyFrame( const SvxBoxItem* pBoxItem,
+bool ScAttrArray::ApplyFrame( const SvxBoxItem& rBoxItem,
const SvxBoxInfoItem* pBoxInfoItem,
SCROW nStartRow, SCROW nEndRow,
bool bLeft, SCCOL nDistRight, bool bTop, SCROW nDistBottom )
{
- OSL_ENSURE( pBoxItem && pBoxInfoItem, "Missing line attributes!" );
+ OSL_ENSURE( pBoxInfoItem, "Missing line attributes!" );
const ScPatternAttr* pPattern = GetPattern( nStartRow );
- const SvxBoxItem* pOldFrame = &pPattern->GetItemSet().Get( ATTR_BORDER );
+ const SvxBoxItem* pOldFrame = &pPattern->GetItem( ATTR_BORDER );
// right/bottom border set when connected together
const ScMergeAttr& rMerge = pPattern->GetItem(ATTR_MERGE);
@@ -1185,34 +1175,34 @@ bool ScAttrArray::ApplyFrame( const SvxBoxItem* pBoxItem,
if( bLeft && nDistRight==0)
{
if ( pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::LEFT) )
- aNewFrame.SetLine( pBoxItem->GetLeft(), SvxBoxItemLine::RIGHT );
+ aNewFrame.SetLine( rBoxItem.GetLeft(), SvxBoxItemLine::RIGHT );
if ( pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::RIGHT) )
- aNewFrame.SetLine( pBoxItem->GetRight(), SvxBoxItemLine::LEFT );
+ aNewFrame.SetLine( rBoxItem.GetRight(), SvxBoxItemLine::LEFT );
}
else
{
if ( (nDistRight==0) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::LEFT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) )
- aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(),
+ aNewFrame.SetLine( (nDistRight==0) ? rBoxItem.GetLeft() : pBoxInfoItem->GetVert(),
SvxBoxItemLine::RIGHT );
if ( bLeft ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::RIGHT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) )
- aNewFrame.SetLine( bLeft ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(),
+ aNewFrame.SetLine( bLeft ? rBoxItem.GetRight() : pBoxInfoItem->GetVert(),
SvxBoxItemLine::LEFT );
}
}
else
{
if ( bLeft ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::LEFT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) )
- aNewFrame.SetLine( bLeft ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(),
+ aNewFrame.SetLine( bLeft ? rBoxItem.GetLeft() : pBoxInfoItem->GetVert(),
SvxBoxItemLine::LEFT );
if ( (nDistRight==0) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::RIGHT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) )
- aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(),
+ aNewFrame.SetLine( (nDistRight==0) ? rBoxItem.GetRight() : pBoxInfoItem->GetVert(),
SvxBoxItemLine::RIGHT );
}
if ( bTop ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::TOP) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::HORI) )
- aNewFrame.SetLine( bTop ? pBoxItem->GetTop() : pBoxInfoItem->GetHori(),
+ aNewFrame.SetLine( bTop ? rBoxItem.GetTop() : pBoxInfoItem->GetHori(),
SvxBoxItemLine::TOP );
if ( (nDistBottom==0) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::BOTTOM) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::HORI) )
- aNewFrame.SetLine( (nDistBottom==0) ? pBoxItem->GetBottom() : pBoxInfoItem->GetHori(),
+ aNewFrame.SetLine( (nDistBottom==0) ? rBoxItem.GetBottom() : pBoxInfoItem->GetHori(),
SvxBoxItemLine::BOTTOM );
if (aNewFrame == *pOldFrame)
@@ -1222,8 +1212,8 @@ bool ScAttrArray::ApplyFrame( const SvxBoxItem* pBoxItem,
}
else
{
- SfxItemPoolCache aCache( rDocument.GetPool(), &aNewFrame );
- ApplyCacheArea( nStartRow, nEndRow, &aCache );
+ ScItemPoolCache aCache( rDocument.getCellAttributeHelper(), aNewFrame );
+ ApplyCacheArea( nStartRow, nEndRow, aCache );
return true;
}
@@ -1232,11 +1222,12 @@ bool ScAttrArray::ApplyFrame( const SvxBoxItem* pBoxItem,
void ScAttrArray::ApplyBlockFrame(const SvxBoxItem& rLineOuter, const SvxBoxInfoItem* pLineInner,
SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight)
{
+ SetDefaultIfNotInit();
if (nStartRow == nEndRow)
- ApplyFrame(&rLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, true, 0);
- else if ( !mvData.empty() )
+ ApplyFrame(rLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, true, 0);
+ else
{
- ApplyFrame(&rLineOuter, pLineInner, nStartRow, nStartRow, bLeft, nDistRight,
+ ApplyFrame(rLineOuter, pLineInner, nStartRow, nStartRow, bLeft, nDistRight,
true, nEndRow-nStartRow);
if ( nEndRow > nStartRow+1 ) // inner part available?
@@ -1250,7 +1241,7 @@ void ScAttrArray::ApplyBlockFrame(const SvxBoxItem& rLineOuter, const SvxBoxInfo
for (SCSIZE i=nStartIndex; i<=nEndIndex;)
{
nTmpEnd = std::min( static_cast<SCROW>(nEndRow-1), mvData[i].nEndRow );
- bool bChanged = ApplyFrame(&rLineOuter, pLineInner, nTmpStart, nTmpEnd,
+ bool bChanged = ApplyFrame(rLineOuter, pLineInner, nTmpStart, nTmpEnd,
bLeft, nDistRight, false, nEndRow - nTmpEnd);
nTmpStart = nTmpEnd+1;
if (bChanged)
@@ -1263,11 +1254,7 @@ void ScAttrArray::ApplyBlockFrame(const SvxBoxItem& rLineOuter, const SvxBoxInfo
}
}
- ApplyFrame(&rLineOuter, pLineInner, nEndRow, nEndRow, bLeft, nDistRight, false, 0);
- }
- else
- {
- ApplyFrame(&rLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, true, 0);
+ ApplyFrame(rLineOuter, pLineInner, nEndRow, nEndRow, bLeft, nDistRight, false, 0);
}
}
@@ -1304,8 +1291,7 @@ bool ScAttrArray::HasAttrib_Impl(const ScPatternAttr* pPattern, HasAttrFlags nMa
}
if ( nMask & HasAttrFlags::Conditional )
{
- bool bContainsCondFormat = pPattern->GetItem( ATTR_CONDITIONAL ).GetCondFormatData().empty();
- if ( bContainsCondFormat )
+ if ( !pPattern->GetItem( ATTR_CONDITIONAL ).GetCondFormatData().empty())
bFound = true;
}
if ( nMask & HasAttrFlags::Protected )
@@ -1326,10 +1312,9 @@ bool ScAttrArray::HasAttrib_Impl(const ScPatternAttr* pPattern, HasAttrFlags nMa
{
const SfxItemSet* pSet = rDocument.GetCondResult( nCol, nRowCond, nTab );
- const SfxPoolItem* pItem;
- if( pSet && pSet->GetItemState( ATTR_PROTECTION, true, &pItem ) == SfxItemState::SET )
+ const ScProtectionAttr* pCondProtect;
+ if( pSet && (pCondProtect = pSet->GetItemIfSet( ATTR_PROTECTION )) )
{
- const ScProtectionAttr* pCondProtect = static_cast<const ScProtectionAttr*>(pItem);
if( pCondProtect->GetProtection() || pCondProtect->GetHideCell() )
bFoundCond = true;
else
@@ -1400,39 +1385,60 @@ bool ScAttrArray::HasAttrib( SCROW nRow1, SCROW nRow2, HasAttrFlags nMask ) cons
{
if (mvData.empty())
{
- return HasAttrib_Impl(rDocument.GetDefPattern(), nMask, 0, rDocument.MaxRow(), 0);
+ return HasAttrib_Impl(&rDocument.getCellAttributeHelper().getDefaultCellAttribute(), nMask, 0, rDocument.MaxRow(), 0);
}
SCSIZE nStartIndex;
SCSIZE nEndIndex;
Search( nRow1, nStartIndex );
if (nRow1 != nRow2)
- Search( nRow2, nEndIndex );
+ Search( nRow2, nEndIndex, /*hint*/nStartIndex );
else
nEndIndex = nStartIndex;
bool bFound = false;
for (SCSIZE i=nStartIndex; i<=nEndIndex && !bFound; i++)
{
- const ScPatternAttr* pPattern = mvData[i].pPattern;
+ const ScPatternAttr* pPattern = mvData[i].getScPatternAttr();
bFound = HasAttrib_Impl(pPattern, nMask, nRow1, nRow2, i);
}
return bFound;
}
+bool ScAttrArray::HasAttrib( SCROW nRow, HasAttrFlags nMask, SCROW* nStartRow, SCROW* nEndRow ) const
+{
+ if (mvData.empty())
+ {
+ if( nStartRow )
+ *nStartRow = 0;
+ if( nEndRow )
+ *nEndRow = rDocument.MaxRow();
+ return HasAttrib_Impl(&rDocument.getCellAttributeHelper().getDefaultCellAttribute(), nMask, 0, rDocument.MaxRow(), 0);
+ }
+
+ SCSIZE nIndex;
+ Search( nRow, nIndex );
+ if( nStartRow )
+ *nStartRow = nIndex > 0 ? mvData[nIndex-1].nEndRow+1 : 0;
+ if( nEndRow )
+ *nEndRow = mvData[nIndex].nEndRow;
+ const ScPatternAttr* pPattern = mvData[nIndex].getScPatternAttr();
+ return HasAttrib_Impl(pPattern, nMask, nRow, nRow, nIndex);
+}
+
bool ScAttrArray::IsMerged( SCROW nRow ) const
{
if ( !mvData.empty() )
{
SCSIZE nIndex;
Search(nRow, nIndex);
- const ScMergeAttr& rItem = mvData[nIndex].pPattern->GetItem(ATTR_MERGE);
+ const ScMergeAttr& rItem = mvData[nIndex].getScPatternAttr()->GetItem(ATTR_MERGE);
return rItem.IsMerged();
}
- return rDocument.GetDefPattern()->GetItem(ATTR_MERGE).IsMerged();
+ return rDocument.getCellAttributeHelper().getDefaultCellAttribute().GetItem(ATTR_MERGE).IsMerged();
}
/**
@@ -1454,7 +1460,7 @@ bool ScAttrArray::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
{
- pPattern = mvData[i].pPattern;
+ pPattern = mvData[i].getScPatternAttr();
pItem = &pPattern->GetItem( ATTR_MERGE );
SCCOL nCountX = pItem->GetColMerge();
SCROW nCountY = pItem->GetRowMerge();
@@ -1510,14 +1516,14 @@ void ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow)
if (nThisEnd > nEndRow)
nThisEnd = nEndRow;
- pPattern = mvData[nIndex].pPattern;
+ pPattern = mvData[nIndex].getScPatternAttr();
pItem = &pPattern->GetItem( ATTR_MERGE );
SCCOL nCountX = pItem->GetColMerge();
SCROW nCountY = pItem->GetRowMerge();
if (nCountX>1 || nCountY>1)
{
- const ScMergeAttr* pAttr = &rDocument.GetPool()->GetDefaultItem( ATTR_MERGE );
- const ScMergeFlagAttr* pFlagAttr = &rDocument.GetPool()->GetDefaultItem( ATTR_MERGE_FLAG );
+ const ScMergeAttr* pAttr = &rDocument.GetPool()->GetUserOrPoolDefaultItem( ATTR_MERGE );
+ const ScMergeFlagAttr* pFlagAttr = &rDocument.GetPool()->GetUserOrPoolDefaultItem( ATTR_MERGE_FLAG );
OSL_ENSURE( nCountY==1 || nThisStart==nThisEnd, "What's up?" );
@@ -1529,7 +1535,7 @@ void ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow)
for (SCROW nThisRow = nThisStart; nThisRow <= nThisEnd; nThisRow++)
rDocument.ApplyAttr( nThisCol, nThisRow, nTab, *pAttr );
- ScPatternAttr aNewPattern( rDocument.GetPool() );
+ ScPatternAttr aNewPattern( rDocument.getCellAttributeHelper() );
SfxItemSet* pSet = &aNewPattern.GetItemSet();
pSet->Put( *pFlagAttr );
rDocument.ApplyPatternAreaTab( nThisCol, nThisStart, nMergeEndCol, nMergeEndRow,
@@ -1546,51 +1552,40 @@ void ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow)
}
}
-void ScAttrArray::SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow,
- const ScPatternAttr* pWantedPattern, bool bDefault )
+void ScAttrArray::SetPatternAreaSafe(SCROW nStartRow, SCROW nEndRow, const CellAttributeHolder& rWantedPattern)
{
SetDefaultIfNotInit();
- const ScPatternAttr* pOldPattern;
- const ScMergeFlagAttr* pItem;
+ const ScMergeFlagAttr* pItem;
SCSIZE nIndex;
SCROW nRow;
SCROW nThisRow;
- bool bFirstUse = true;
Search( nStartRow, nIndex );
nThisRow = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0;
while ( nThisRow <= nEndRow )
{
- pOldPattern = mvData[nIndex].pPattern;
- if (pOldPattern != pWantedPattern) // FIXME: else-branch?
+ const CellAttributeHolder& rOldPattern(mvData[nIndex].getCellAttributeHolder());
+ if (!CellAttributeHolder::areSame(&rOldPattern, &rWantedPattern)) // FIXME: else-branch?
{
if (nThisRow < nStartRow) nThisRow = nStartRow;
nRow = mvData[nIndex].nEndRow;
SCROW nAttrRow = std::min( nRow, nEndRow );
- pItem = &pOldPattern->GetItem( ATTR_MERGE_FLAG );
+ pItem = &rOldPattern.getScPatternAttr()->GetItem( ATTR_MERGE_FLAG );
if (pItem->IsOverlapped() || pItem->HasAutoFilter())
{
// default-constructing a ScPatternAttr for DeleteArea doesn't work
// because it would have no cell style information.
- // Instead, the document's GetDefPattern is copied. Since it is passed as
+ // Instead, the document's getCellAttributeHelper().getDefaultCellAttribute() is copied. Since it is passed as
// pWantedPattern, no special treatment of default is needed here anymore.
- std::unique_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr( *pWantedPattern ));
+ ScPatternAttr* pNewPattern(new ScPatternAttr(*rWantedPattern.getScPatternAttr()));
pNewPattern->GetItemSet().Put( *pItem );
- SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true );
+ SetPatternArea( nThisRow, nAttrRow, CellAttributeHolder(pNewPattern, true) );
}
else
{
- if ( !bDefault )
- {
- if (bFirstUse)
- bFirstUse = false;
- else
- // it's in the pool
- rDocument.GetPool()->Put( *pWantedPattern );
- }
- SetPatternArea( nThisRow, nAttrRow, pWantedPattern );
+ SetPatternArea(nThisRow, nAttrRow, rWantedPattern);
}
Search( nThisRow, nIndex ); // data changed
@@ -1618,15 +1613,15 @@ bool ScAttrArray::ApplyFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags )
while ( nThisRow <= nEndRow )
{
- pOldPattern = mvData[nIndex].pPattern;
+ pOldPattern = mvData[nIndex].getScPatternAttr();
nOldValue = pOldPattern->GetItem( ATTR_MERGE_FLAG ).GetValue();
if ( (nOldValue | nFlags) != nOldValue )
{
nRow = mvData[nIndex].nEndRow;
SCROW nAttrRow = std::min( nRow, nEndRow );
- auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern);
+ ScPatternAttr* pNewPattern(new ScPatternAttr(*pOldPattern));
pNewPattern->GetItemSet().Put( ScMergeFlagAttr( nOldValue | nFlags ) );
- SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true );
+ SetPatternArea( nThisRow, nAttrRow, CellAttributeHolder(pNewPattern, true) );
Search( nThisRow, nIndex ); // data changed
bChanged = true;
}
@@ -1655,15 +1650,15 @@ bool ScAttrArray::RemoveFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags )
while ( nThisRow <= nEndRow )
{
- pOldPattern = mvData[nIndex].pPattern;
+ pOldPattern = mvData[nIndex].getScPatternAttr();
nOldValue = pOldPattern->GetItem( ATTR_MERGE_FLAG ).GetValue();
if ( (nOldValue & ~nFlags) != nOldValue )
{
nRow = mvData[nIndex].nEndRow;
SCROW nAttrRow = std::min( nRow, nEndRow );
- auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern);
+ ScPatternAttr* pNewPattern(new ScPatternAttr(*pOldPattern));
pNewPattern->GetItemSet().Put( ScMergeFlagAttr( nOldValue & ~nFlags ) );
- SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true );
+ SetPatternArea( nThisRow, nAttrRow, CellAttributeHolder(pNewPattern, true) );
Search( nThisRow, nIndex ); // data changed
bChanged = true;
}
@@ -1688,15 +1683,15 @@ void ScAttrArray::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16*
while ( nThisRow <= nEndRow )
{
- const ScPatternAttr* pOldPattern = mvData[nIndex].pPattern;
+ const ScPatternAttr* pOldPattern = mvData[nIndex].getScPatternAttr();
if ( pOldPattern->HasItemsSet( pWhich ) )
{
- auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern);
+ ScPatternAttr* pNewPattern(new ScPatternAttr(*pOldPattern));
pNewPattern->ClearItems( pWhich );
nRow = mvData[nIndex].nEndRow;
SCROW nAttrRow = std::min( nRow, nEndRow );
- SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true );
+ SetPatternArea( nThisRow, nAttrRow, CellAttributeHolder(pNewPattern, true) );
Search( nThisRow, nIndex ); // data changed
}
@@ -1715,23 +1710,25 @@ void ScAttrArray::ChangeIndent( SCROW nStartRow, SCROW nEndRow, bool bIncrement
while ( nThisStart <= nEndRow )
{
- const ScPatternAttr* pOldPattern = mvData[nIndex].pPattern;
+ const ScPatternAttr* pOldPattern = mvData[nIndex].getScPatternAttr();
const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
- const SfxPoolItem* pItem;
+ const SvxHorJustifyItem* pItem;
- bool bNeedJust = ( rOldSet.GetItemState( ATTR_HOR_JUSTIFY, false, &pItem ) != SfxItemState::SET
- || (static_cast<const SvxHorJustifyItem*>(pItem)->GetValue() != SvxCellHorJustify::Left &&
- static_cast<const SvxHorJustifyItem*>(pItem)->GetValue() != SvxCellHorJustify::Right ));
+ bool bNeedJust = !( pItem = rOldSet.GetItemIfSet( ATTR_HOR_JUSTIFY, false ) )
+ || (pItem->GetValue() != SvxCellHorJustify::Left &&
+ pItem->GetValue() != SvxCellHorJustify::Right );
sal_uInt16 nOldValue = rOldSet.Get( ATTR_INDENT ).GetValue();
sal_uInt16 nNewValue = nOldValue;
// To keep Increment indent from running outside the cell1659
- tools::Long nColWidth = static_cast<tools::Long>(rDocument.GetColWidth(nCol,nTab));
+ tools::Long nColWidth = static_cast<tools::Long>(
+ rDocument.GetColWidth(nCol == -1 ? rDocument.MaxCol() : nCol,nTab));
if ( bIncrement )
{
if ( nNewValue < nColWidth-SC_INDENT_STEP )
{
nNewValue += SC_INDENT_STEP;
- if ( nNewValue > nColWidth-SC_INDENT_STEP ) nNewValue = nColWidth-SC_INDENT_STEP;
+ if ( nNewValue > nColWidth-SC_INDENT_STEP )
+ nNewValue = nColWidth-SC_INDENT_STEP;
}
}
else
@@ -1749,12 +1746,12 @@ void ScAttrArray::ChangeIndent( SCROW nStartRow, SCROW nEndRow, bool bIncrement
{
SCROW nThisEnd = mvData[nIndex].nEndRow;
SCROW nAttrRow = std::min( nThisEnd, nEndRow );
- auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern);
+ ScPatternAttr* pNewPattern(new ScPatternAttr(*pOldPattern));
pNewPattern->GetItemSet().Put( ScIndentItem( nNewValue ) );
if ( bNeedJust )
pNewPattern->GetItemSet().Put(
SvxHorJustifyItem( SvxCellHorJustify::Left, ATTR_HOR_JUSTIFY ) );
- SetPatternArea( nThisStart, nAttrRow, std::move(pNewPattern), true );
+ SetPatternArea( nThisStart, nAttrRow, CellAttributeHolder(pNewPattern, true) );
nThisStart = nThisEnd + 1;
Search( nThisStart, nIndex ); // data changed
@@ -1782,8 +1779,7 @@ SCROW ScAttrArray::GetNextUnprotected( SCROW nRow, bool bUp ) const
SCSIZE nIndex;
Search(nRow, nIndex);
- while (mvData[nIndex].pPattern->
- GetItem(ATTR_PROTECTION).GetProtection())
+ while (mvData[nIndex].getScPatternAttr()->GetItem(ATTR_PROTECTION).GetProtection())
{
if (bUp)
{
@@ -1812,20 +1808,19 @@ void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBo
while (nPos < mvData.size())
{
SCROW nEnd = mvData[nPos].nEndRow;
- if (mvData[nPos].pPattern->GetStyleSheet() == pStyleSheet)
+ if (mvData[nPos].getScPatternAttr()->GetStyleSheet() == pStyleSheet)
{
rUsedRows.setTrue(nStart, nEnd);
if (bReset)
{
- ScPatternAttr aNewPattern(*mvData[nPos].pPattern);
- rDocument.GetPool()->Remove(*mvData[nPos].pPattern);
- aNewPattern.SetStyleSheet( static_cast<ScStyleSheet*>(
+ ScPatternAttr* pNewPattern(new ScPatternAttr(*mvData[nPos].getScPatternAttr()));
+ pNewPattern->SetStyleSheet( static_cast<ScStyleSheet*>(
rDocument.GetStyleSheetPool()->
Find( ScResId(STR_STYLENAME_STANDARD),
SfxStyleFamily::Para,
SfxStyleSearchBits::Auto | SfxStyleSearchBits::ScStandard ) ) );
- mvData[nPos].pPattern = &rDocument.GetPool()->Put(aNewPattern);
+ mvData[nPos].setScPatternAttr(pNewPattern, true);
if (Concat(nPos))
{
@@ -1843,7 +1838,7 @@ bool ScAttrArray::IsStyleSheetUsed( const ScStyleSheet& rStyle ) const
{
if ( mvData.empty() )
{
- const ScStyleSheet* pStyle = rDocument.GetDefPattern()->GetStyleSheet();
+ const ScStyleSheet* pStyle = rDocument.getCellAttributeHelper().getDefaultCellAttribute().GetStyleSheet();
if ( pStyle )
{
pStyle->SetUsage( ScStyleSheet::Usage::USED );
@@ -1858,7 +1853,7 @@ bool ScAttrArray::IsStyleSheetUsed( const ScStyleSheet& rStyle ) const
while ( nPos < mvData.size() )
{
- const ScStyleSheet* pStyle = mvData[nPos].pPattern->GetStyleSheet();
+ const ScStyleSheet* pStyle = mvData[nPos].getScPatternAttr()->GetStyleSheet();
if ( pStyle )
{
pStyle->SetUsage( ScStyleSheet::Usage::USED );
@@ -1880,7 +1875,7 @@ bool ScAttrArray::IsEmpty() const
if (mvData.size() == 1)
{
- return mvData[0].pPattern == rDocument.GetDefPattern();
+ return mvData[0].getScPatternAttr()->isDefault();
}
else
return false;
@@ -1898,14 +1893,14 @@ bool ScAttrArray::GetFirstVisibleAttr( SCROW& rFirstRow ) const
// Entries at the end are not skipped, GetFirstVisibleAttr may be larger than GetLastVisibleAttr.
SCSIZE nVisStart = 1;
- while ( nVisStart < mvData.size() && mvData[nVisStart].pPattern->IsVisibleEqual(*mvData[nVisStart-1].pPattern) )
+ while ( nVisStart < mvData.size() && mvData[nVisStart].getScPatternAttr()->IsVisibleEqual(*mvData[nVisStart-1].getScPatternAttr()) )
++nVisStart;
if ( nVisStart >= mvData.size() || mvData[nVisStart-1].nEndRow > 0 ) // more than 1 row?
nStart = nVisStart;
while ( nStart < mvData.size() && !bFound )
{
- if ( mvData[nStart].pPattern->IsVisible() )
+ if ( mvData[nStart].getScPatternAttr()->IsVisible() )
{
rFirstRow = nStart ? ( mvData[nStart-1].nEndRow + 1 ) : 0;
bFound = true;
@@ -1922,7 +1917,7 @@ bool ScAttrArray::GetFirstVisibleAttr( SCROW& rFirstRow ) const
const SCROW SC_VISATTR_STOP = 84;
-bool ScAttrArray::GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData ) const
+bool ScAttrArray::GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData, bool bSkipEmpty ) const
{
if ( mvData.empty() )
{
@@ -1951,42 +1946,50 @@ bool ScAttrArray::GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData ) const
rLastRow = nLastData;
return false;
}
-
- // Find a run below last data row.
+ // tdf#93315: If "Suppress output of empty pages" in Calc Options is not checked, show empty
+ // (containing only empty data cells) page in the document
bool bFound = false;
- Search( nLastData, nPos );
- while ( nPos < mvData.size() )
- {
- SCROW nAttrStartRow = ( nPos > 0 ) ? ( mvData[nPos-1].nEndRow + 1 ) : 0;
- if ( nAttrStartRow <= nLastData )
- nAttrStartRow = nLastData + 1;
- // find range of visually equal formats
- SCSIZE nEndPos = nPos;
- while ( nEndPos < mvData.size()-1 &&
- mvData[nEndPos].pPattern->IsVisibleEqual( *mvData[nEndPos+1].pPattern))
- {
- if ( (mvData[nEndPos].nEndRow + 1 - nAttrStartRow) >= SC_VISATTR_STOP )
- return false; // ignore this range and below
- ++nEndPos;
+ if (bSkipEmpty)
+ {
+ Search( nLastData, nPos );
+ while ( nPos < mvData.size() )
+ {
+ // find range of visually equal formats
+ SCSIZE nEndPos = nPos;
+ while ( nEndPos < mvData.size()-1 &&
+ mvData[nEndPos].getScPatternAttr()->IsVisibleEqual(*mvData[nEndPos+1].getScPatternAttr()))
+ ++nEndPos;
+ SCROW nAttrStartRow = ( nPos > 0 ) ? ( mvData[nPos-1].nEndRow + 1) : 0;
+ if ( nAttrStartRow <= nLastData )
+ nAttrStartRow = nLastData + 1;
+ SCROW nAttrSize = mvData[nEndPos].nEndRow + 1 - nAttrStartRow;
+ if ( nAttrSize >= SC_VISATTR_STOP )
+ break; // while, ignore this range and below
+ else if ( mvData[nEndPos].getScPatternAttr()->IsVisible() )
+ {
+ rLastRow = mvData[nEndPos].nEndRow;
+ bFound = true;
+ }
+ nPos = nEndPos + 1;
}
- SCROW nAttrSize = mvData[nEndPos].nEndRow + 1 - nAttrStartRow;
- if ( nAttrSize >= SC_VISATTR_STOP )
- return false; // ignore this range and below
- else if ( mvData[nEndPos].pPattern->IsVisible() )
+ }
+ else
+ {
+ if ((nPos > 0 && mvData[nPos-1].getScPatternAttr()->IsVisible())
+ || (nPos > 1 && !mvData[nPos-1].getScPatternAttr()->IsVisibleEqual(*mvData[nPos-2].getScPatternAttr())))
{
- rLastRow = mvData[nEndPos].nEndRow;
- bFound = true;
+ rLastRow = mvData[nPos-1].nEndRow;
+ return true;
}
- nPos = nEndPos + 1;
+ rLastRow = nLastData;
}
-
return bFound;
}
bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
{
if ( mvData.empty() )
- return rDocument.GetDefPattern()->IsVisible();
+ return rDocument.getCellAttributeHelper().getDefaultCellAttribute().IsVisible();
SCSIZE nIndex;
Search( nStartRow, nIndex );
@@ -1994,7 +1997,7 @@ bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
bool bFound = false;
while ( nIndex < mvData.size() && nThisStart <= nEndRow && !bFound )
{
- if ( mvData[nIndex].pPattern->IsVisible() )
+ if ( mvData[nIndex].getScPatternAttr()->IsVisible() )
bFound = true;
nThisStart = mvData[nIndex].nEndRow + 1;
@@ -2009,9 +2012,9 @@ bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
{
if ( mvData.empty() && rOther.mvData.empty() )
{
- const ScPatternAttr* pDefPattern1 = rDocument.GetDefPattern();
- const ScPatternAttr* pDefPattern2 = rOther.rDocument.GetDefPattern();
- return ( pDefPattern1 == pDefPattern2 || pDefPattern1->IsVisibleEqual( *pDefPattern2 ) );
+ const ScPatternAttr* pDefPattern1(&rDocument.getCellAttributeHelper().getDefaultCellAttribute());
+ const ScPatternAttr* pDefPattern2(&rOther.rDocument.getCellAttributeHelper().getDefaultCellAttribute());
+ return ( ScPatternAttr::areSame(pDefPattern1, pDefPattern2) || pDefPattern1->IsVisibleEqual( *pDefPattern2 ) );
}
{
@@ -2021,13 +2024,13 @@ bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
if ( mvData.empty() && !rOther.mvData.empty() )
{
pNonDefault = &rOther;
- pDefPattern = rDocument.GetDefPattern();
+ pDefPattern = &rDocument.getCellAttributeHelper().getDefaultCellAttribute();
bDefNonDefCase = true;
}
else if ( !mvData.empty() && rOther.mvData.empty() )
{
pNonDefault = this;
- pDefPattern = rOther.rDocument.GetDefPattern();
+ pDefPattern = &rOther.rDocument.getCellAttributeHelper().getDefaultCellAttribute();
bDefNonDefCase = true;
}
@@ -2040,9 +2043,8 @@ bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
while ( nPos < pNonDefault->Count() && bEqual )
{
- const ScPatternAttr* pNonDefPattern = pNonDefault->mvData[nPos].pPattern;
- bEqual = ( pNonDefPattern == pDefPattern ||
- pNonDefPattern->IsVisibleEqual( *pDefPattern ) );
+ const ScPatternAttr* pNonDefPattern = pNonDefault->mvData[nPos].getScPatternAttr();
+ bEqual = ScPatternAttr::areSame(pNonDefPattern, pDefPattern) || pNonDefPattern->IsVisibleEqual( *pDefPattern );
if ( pNonDefault->mvData[nPos].nEndRow >= nEndRow ) break;
++nPos;
@@ -2064,10 +2066,9 @@ bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
{
SCROW nThisRow = mvData[nThisPos].nEndRow;
SCROW nOtherRow = rOther.mvData[nOtherPos].nEndRow;
- const ScPatternAttr* pThisPattern = mvData[nThisPos].pPattern;
- const ScPatternAttr* pOtherPattern = rOther.mvData[nOtherPos].pPattern;
- bEqual = ( pThisPattern == pOtherPattern ||
- pThisPattern->IsVisibleEqual(*pOtherPattern) );
+ const ScPatternAttr* pThisPattern = mvData[nThisPos].getScPatternAttr();
+ const ScPatternAttr* pOtherPattern = rOther.mvData[nOtherPos].getScPatternAttr();
+ bEqual = ( ScPatternAttr::areSame(pThisPattern, pOtherPattern) || pThisPattern->IsVisibleEqual(*pOtherPattern) );
if ( nThisRow >= nOtherRow )
{
@@ -2089,9 +2090,9 @@ bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW
// summarised with IsVisibleEqual
if ( mvData.empty() && rOther.mvData.empty() )
{
- const ScPatternAttr* pDefPattern1 = rDocument.GetDefPattern();
- const ScPatternAttr* pDefPattern2 = rOther.rDocument.GetDefPattern();
- return ( pDefPattern1 == pDefPattern2 );
+ const ScPatternAttr* pDefPattern1(&rDocument.getCellAttributeHelper().getDefaultCellAttribute());
+ const ScPatternAttr* pDefPattern2(&rOther.rDocument.getCellAttributeHelper().getDefaultCellAttribute());
+ return ScPatternAttr::areSame(pDefPattern1, pDefPattern2);
}
{
@@ -2101,13 +2102,13 @@ bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW
if ( mvData.empty() && !rOther.mvData.empty() )
{
pNonDefault = &rOther;
- pDefPattern = rDocument.GetDefPattern();
+ pDefPattern = &rDocument.getCellAttributeHelper().getDefaultCellAttribute();
bDefNonDefCase = true;
}
else if ( !mvData.empty() && rOther.mvData.empty() )
{
pNonDefault = this;
- pDefPattern = rOther.rDocument.GetDefPattern();
+ pDefPattern = &rOther.rDocument.getCellAttributeHelper().getDefaultCellAttribute();
bDefNonDefCase = true;
}
@@ -2120,8 +2121,8 @@ bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW
while ( nPos < pNonDefault->Count() && bEqual )
{
- const ScPatternAttr* pNonDefPattern = pNonDefault->mvData[nPos].pPattern;
- bEqual = ( pNonDefPattern == pDefPattern );
+ const ScPatternAttr* pNonDefPattern = pNonDefault->mvData[nPos].getScPatternAttr();
+ bEqual = ScPatternAttr::areSame( pNonDefPattern, pDefPattern );
if ( pNonDefault->mvData[nPos].nEndRow >= nEndRow ) break;
++nPos;
@@ -2143,9 +2144,9 @@ bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW
{
SCROW nThisRow = mvData[nThisPos].nEndRow;
SCROW nOtherRow = rOther.mvData[nOtherPos].nEndRow;
- const ScPatternAttr* pThisPattern = mvData[nThisPos].pPattern;
- const ScPatternAttr* pOtherPattern = rOther.mvData[nOtherPos].pPattern;
- bEqual = ( pThisPattern == pOtherPattern );
+ const ScPatternAttr* pThisPattern = mvData[nThisPos].getScPatternAttr();
+ const ScPatternAttr* pOtherPattern = rOther.mvData[nOtherPos].getScPatternAttr();
+ bEqual = ScPatternAttr::areSame( pThisPattern, pOtherPattern );
if ( nThisRow >= nOtherRow )
{
@@ -2176,8 +2177,7 @@ bool ScAttrArray::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
for ( ; nIndex < mvData.size(); nIndex++ )
{
- if ( mvData[nIndex].pPattern->
- GetItem(ATTR_MERGE_FLAG).IsHorOverlapped() )
+ if ( mvData[nIndex].getScPatternAttr()->GetItem(ATTR_MERGE_FLAG).IsHorOverlapped() )
{
bTest = false; // may not be pushed out
break;
@@ -2196,15 +2196,13 @@ bool ScAttrArray::TestInsertRow( SCSIZE nSize ) const
// rDocument.MaxRow() + 1 - nSize = 1st row pushed out
if ( mvData.empty() )
- return !rDocument.GetDefPattern()->
- GetItem(ATTR_MERGE_FLAG).IsVerOverlapped();
+ return !rDocument.getCellAttributeHelper().getDefaultCellAttribute().GetItem(ATTR_MERGE_FLAG).IsVerOverlapped();
SCSIZE nFirstLost = mvData.size()-1;
while ( nFirstLost && mvData[nFirstLost-1].nEndRow >= sal::static_int_cast<SCROW>(rDocument.MaxRow() + 1 - nSize) )
--nFirstLost;
- return !mvData[nFirstLost].pPattern->
- GetItem(ATTR_MERGE_FLAG).IsVerOverlapped();
+ return !mvData[nFirstLost].getScPatternAttr()->GetItem(ATTR_MERGE_FLAG).IsVerOverlapped();
}
void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
@@ -2217,7 +2215,7 @@ void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
// set ScMergeAttr may not be extended (so behind delete again)
- bool bDoMerge = mvData[nIndex].pPattern->GetItem(ATTR_MERGE).IsMerged();
+ bool bDoMerge = mvData[nIndex].getScPatternAttr()->GetItem(ATTR_MERGE).IsMerged();
assert( !bDoMerge || nCol != -1 );
@@ -2244,7 +2242,7 @@ void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
{
// ApplyAttr for areas
- const SfxPoolItem& rDef = rDocument.GetPool()->GetDefaultItem( ATTR_MERGE );
+ const SfxPoolItem& rDef = rDocument.GetPool()->GetUserOrPoolDefaultItem( ATTR_MERGE );
for (SCSIZE nAdd=0; nAdd<nSize; nAdd++)
rDocument.ApplyAttr( nCol, nStartRow+nAdd, nTab, rDef );
@@ -2291,7 +2289,7 @@ void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize )
{
DeleteRange( nStartIndex, nEndIndex );
if (nStartIndex > 0)
- if ( mvData[nStartIndex-1].pPattern == mvData[nStartIndex].pPattern )
+ if ( ScPatternAttr::areSame( mvData[nStartIndex-1].getScPatternAttr(), mvData[nStartIndex].getScPatternAttr() ) )
DeleteRange( nStartIndex-1, nStartIndex-1 );
}
}
@@ -2307,10 +2305,6 @@ void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize )
void ScAttrArray::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex )
{
SetDefaultIfNotInit();
- ScDocumentPool* pDocPool = rDocument.GetPool();
- for (SCSIZE i = nStartIndex; i <= nEndIndex; i++)
- pDocPool->Remove(*mvData[i].pPattern);
-
mvData.erase(mvData.begin() + nStartIndex, mvData.begin() + nEndIndex + 1);
}
@@ -2320,16 +2314,18 @@ void ScAttrArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
if ( nCol != -1 )
RemoveAreaMerge( nStartRow, nEndRow ); // remove from combined flags
+ const CellAttributeHolder aDefHolder(&rDocument.getCellAttributeHelper().getDefaultCellAttribute());
+
if ( !HasAttrib( nStartRow, nEndRow, HasAttrFlags::Overlapped | HasAttrFlags::AutoFilter) )
- SetPatternArea( nStartRow, nEndRow, rDocument.GetDefPattern() );
+ SetPatternArea( nStartRow, nEndRow, aDefHolder );
else
- SetPatternAreaSafe( nStartRow, nEndRow, rDocument.GetDefPattern(), true ); // leave merge flags
+ SetPatternAreaSafe( nStartRow, nEndRow, aDefHolder ); // leave merge flags
}
void ScAttrArray::DeleteHardAttr(SCROW nStartRow, SCROW nEndRow)
{
SetDefaultIfNotInit();
- const ScPatternAttr* pDefPattern = rDocument.GetDefPattern();
+ const CellAttributeHolder aDefHolder(&rDocument.getCellAttributeHelper().getDefaultCellAttribute());
SCSIZE nIndex;
SCROW nRow;
@@ -2341,23 +2337,28 @@ void ScAttrArray::DeleteHardAttr(SCROW nStartRow, SCROW nEndRow)
while ( nThisRow <= nEndRow )
{
- const ScPatternAttr* pOldPattern = mvData[nIndex].pPattern;
+ const ScPatternAttr* pOldPattern = mvData[nIndex].getScPatternAttr();
if ( pOldPattern->GetItemSet().Count() ) // hard attributes ?
{
nRow = mvData[nIndex].nEndRow;
SCROW nAttrRow = std::min( nRow, nEndRow );
- auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern);
+ ScPatternAttr* pNewPattern(new ScPatternAttr(*pOldPattern));
SfxItemSet& rSet = pNewPattern->GetItemSet();
for (sal_uInt16 nId = ATTR_PATTERN_START; nId <= ATTR_PATTERN_END; nId++)
if (nId != ATTR_MERGE && nId != ATTR_MERGE_FLAG)
rSet.ClearItem(nId);
- if ( *pNewPattern == *pDefPattern )
- SetPatternArea( nThisRow, nAttrRow, pDefPattern );
+ if ( *pNewPattern == *aDefHolder.getScPatternAttr() )
+ {
+ delete pNewPattern;
+ SetPatternArea( nThisRow, nAttrRow, aDefHolder );
+ }
else
- SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true );
+ {
+ SetPatternArea( nThisRow, nAttrRow, CellAttributeHolder(pNewPattern, true) );
+ }
Search( nThisRow, nIndex ); // data changed
}
@@ -2379,8 +2380,7 @@ void ScAttrArray::MoveTo(SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray
if ((mvData[i].nEndRow >= nStartRow) && (i == 0 || mvData[i-1].nEndRow < nEndRow))
{
// copy (bPutToPool=TRUE)
- rAttrArray.SetPatternArea( nStart, std::min( mvData[i].nEndRow, nEndRow ),
- mvData[i].pPattern, true );
+ rAttrArray.SetPatternArea( nStart, std::min( mvData[i].nEndRow, nEndRow ), mvData[i].getCellAttributeHolder() );
}
nStart = std::max( nStart, mvData[i].nEndRow + 1 );
}
@@ -2398,14 +2398,11 @@ void ScAttrArray::CopyArea(
SCROW nDestStart = std::max(static_cast<tools::Long>(static_cast<tools::Long>(nStartRow) + nDy), tools::Long(0));
SCROW nDestEnd = std::min(static_cast<tools::Long>(static_cast<tools::Long>(nEndRow) + nDy), tools::Long(rDocument.MaxRow()));
-
- ScDocumentPool* pSourceDocPool = rDocument.GetPool();
- ScDocumentPool* pDestDocPool = rAttrArray.rDocument.GetPool();
- bool bSamePool = (pSourceDocPool==pDestDocPool);
+ const bool bSameCellAttributeHelper(&rDocument.getCellAttributeHelper() == &rAttrArray.rDocument.getCellAttributeHelper());
if ( mvData.empty() )
{
- const ScPatternAttr* pNewPattern = &pDestDocPool->GetDefaultItem( ATTR_PATTERN );
+ const ScPatternAttr* pNewPattern = &rAttrArray.rDocument.getCellAttributeHelper().getDefaultCellAttribute();
rAttrArray.SetPatternArea(nDestStart, nDestEnd, pNewPattern);
return;
}
@@ -2414,42 +2411,44 @@ void ScAttrArray::CopyArea(
{
if (mvData[i].nEndRow >= nStartRow)
{
- const ScPatternAttr* pOldPattern = mvData[i].pPattern;
- const ScPatternAttr* pNewPattern;
+ const ScPatternAttr* pOldPattern = mvData[i].getScPatternAttr();
+ CellAttributeHolder aNewPattern;
- if (IsDefaultItem( pOldPattern ))
+ if (ScPatternAttr::areSame(&rDocument.getCellAttributeHelper().getDefaultCellAttribute(), pOldPattern ))
{
// default: nothing changed
-
- pNewPattern = &pDestDocPool->GetDefaultItem( ATTR_PATTERN );
+ aNewPattern.setScPatternAttr(&rAttrArray.rDocument.getCellAttributeHelper().getDefaultCellAttribute());
}
else if ( nStripFlags != ScMF::NONE )
{
- ScPatternAttr aTmpPattern( *pOldPattern );
+ ScPatternAttr* pTmpPattern(new ScPatternAttr(*pOldPattern ));
ScMF nNewFlags = ScMF::NONE;
if ( nStripFlags != ScMF::All )
- nNewFlags = aTmpPattern.GetItem(ATTR_MERGE_FLAG).GetValue() & ~nStripFlags;
+ nNewFlags = pTmpPattern->GetItem(ATTR_MERGE_FLAG).GetValue() & ~nStripFlags;
if ( nNewFlags != ScMF::NONE )
- aTmpPattern.GetItemSet().Put( ScMergeFlagAttr( nNewFlags ) );
+ pTmpPattern->GetItemSet().Put( ScMergeFlagAttr( nNewFlags ) );
else
- aTmpPattern.GetItemSet().ClearItem( ATTR_MERGE_FLAG );
+ pTmpPattern->GetItemSet().ClearItem( ATTR_MERGE_FLAG );
- if (bSamePool)
- pNewPattern = &pDestDocPool->Put(aTmpPattern);
+ if (bSameCellAttributeHelper)
+ aNewPattern.setScPatternAttr(pTmpPattern, true);
else
- pNewPattern = aTmpPattern.PutInPool( &rAttrArray.rDocument, &rDocument );
+ {
+ aNewPattern = pTmpPattern->MigrateToDocument( &rAttrArray.rDocument, &rDocument );
+ delete pTmpPattern;
+ }
}
else
{
- if (bSamePool)
- pNewPattern = &pDestDocPool->Put(*pOldPattern);
+ if (bSameCellAttributeHelper)
+ aNewPattern.setScPatternAttr(pOldPattern);
else
- pNewPattern = pOldPattern->PutInPool( &rAttrArray.rDocument, &rDocument );
+ aNewPattern = pOldPattern->MigrateToDocument( &rAttrArray.rDocument, &rDocument );
}
rAttrArray.SetPatternArea(nDestStart,
- std::min(static_cast<SCROW>(mvData[i].nEndRow + nDy), nDestEnd), pNewPattern);
+ std::min(static_cast<SCROW>(mvData[i].nEndRow + nDy), nDestEnd), aNewPattern.getScPatternAttr());
}
// when pasting from clipboard and skipping filtered rows, the adjusted
@@ -2476,19 +2475,17 @@ void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, tools::Long nDy,
return;
}
- ScDocumentPool* pSourceDocPool = rDocument.GetPool();
- ScDocumentPool* pDestDocPool = rAttrArray.rDocument.GetPool();
- bool bSamePool = (pSourceDocPool==pDestDocPool);
+ const bool bSameCellAttributeHelper(&rDocument.getCellAttributeHelper() == &rAttrArray.rDocument.getCellAttributeHelper());
if ( mvData.empty() )
{
- const ScPatternAttr* pNewPattern;
- if (bSamePool)
- pNewPattern = &pDestDocPool->Put(*rDocument.GetDefPattern());
+ CellAttributeHolder aNewPattern;
+ if (bSameCellAttributeHelper)
+ aNewPattern.setScPatternAttr(&rDocument.getCellAttributeHelper().getDefaultCellAttribute());
else
- pNewPattern = rDocument.GetDefPattern()->PutInPool( &rAttrArray.rDocument, &rDocument );
+ aNewPattern = rDocument.getCellAttributeHelper().getDefaultCellAttribute().MigrateToDocument( &rAttrArray.rDocument, &rDocument );
- rAttrArray.SetPatternAreaSafe(nDestStart, nDestEnd, pNewPattern, false);
+ rAttrArray.SetPatternAreaSafe(nDestStart, nDestEnd, aNewPattern);
return;
}
@@ -2497,16 +2494,16 @@ void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, tools::Long nDy,
{
if (mvData[i].nEndRow >= nStartRow)
{
- const ScPatternAttr* pOldPattern = mvData[i].pPattern;
- const ScPatternAttr* pNewPattern;
+ const ScPatternAttr* pOldPattern = mvData[i].getScPatternAttr();
+ CellAttributeHolder aNewPattern;
- if (bSamePool)
- pNewPattern = &pDestDocPool->Put(*pOldPattern);
+ if (bSameCellAttributeHelper)
+ aNewPattern.setScPatternAttr(pOldPattern);
else
- pNewPattern = pOldPattern->PutInPool( &rAttrArray.rDocument, &rDocument );
+ aNewPattern = pOldPattern->MigrateToDocument( &rAttrArray.rDocument, &rDocument );
rAttrArray.SetPatternAreaSafe(nDestStart,
- std::min(static_cast<SCROW>(mvData[i].nEndRow + nDy), nDestEnd), pNewPattern, false);
+ std::min(static_cast<SCROW>(mvData[i].nEndRow + nDy), nDestEnd), aNewPattern);
}
// when pasting from clipboard and skipping filtered rows, the adjusted
@@ -2530,7 +2527,7 @@ SCROW ScAttrArray::SearchStyle(
if ( mvData.empty() )
{
- if (rDocument.GetDefPattern()->GetStyleSheet() == pSearchStyle)
+ if (rDocument.getCellAttributeHelper().getDefaultCellAttribute().GetStyleSheet() == pSearchStyle)
return nRow;
nRow = bUp ? -1 : rDocument.MaxRow() + 1;
@@ -2539,7 +2536,7 @@ SCROW ScAttrArray::SearchStyle(
SCSIZE nIndex;
Search(nRow, nIndex);
- const ScPatternAttr* pPattern = mvData[nIndex].pPattern;
+ const ScPatternAttr* pPattern = mvData[nIndex].getScPatternAttr();
while (nIndex < mvData.size() && !bFound)
{
@@ -2569,7 +2566,7 @@ SCROW ScAttrArray::SearchStyle(
{
--nIndex;
nRow = mvData[nIndex].nEndRow;
- pPattern = mvData[nIndex].pPattern;
+ pPattern = mvData[nIndex].getScPatternAttr();
}
}
else
@@ -2577,7 +2574,7 @@ SCROW ScAttrArray::SearchStyle(
nRow = mvData[nIndex].nEndRow+1;
++nIndex;
if (nIndex<mvData.size())
- pPattern = mvData[nIndex].pPattern;
+ pPattern = mvData[nIndex].getScPatternAttr();
}
}
}
diff --git a/sc/source/core/data/attrib.cxx b/sc/source/core/data/attrib.cxx
index fc83491845bb..1a587d2b6572 100644
--- a/sc/source/core/data/attrib.cxx
+++ b/sc/source/core/data/attrib.cxx
@@ -26,6 +26,7 @@
#include <editeng/eerdll.hxx>
#include <editeng/borderline.hxx>
#include <editeng/itemtype.hxx>
+#include <svl/itempool.hxx>
#include <libxml/xmlwriter.h>
@@ -154,6 +155,17 @@ bool ScMergeFlagAttr::HasPivotPopupButton() const
return bool(GetValue() & ScMF::ButtonPopup);
}
+bool ScMergeFlagAttr::HasPivotToggle() const
+{
+ auto nFlags = GetValue();
+ return (nFlags & ScMF::DpCollapse) || (nFlags & ScMF::DpExpand);
+}
+
+bool ScMergeFlagAttr::HasPivotMultiFieldPopupButton() const
+{
+ return bool(GetValue() & ScMF::ButtonPopup2);
+}
+
void ScMergeFlagAttr::dumpAsXml(xmlTextWriterPtr pWriter) const
{
(void)xmlTextWriterStartElement(pWriter, BAD_CAST("ScMergeFlagAttr"));
@@ -366,6 +378,16 @@ void ScProtectionAttr::SetHidePrint( bool bHPrint)
bHidePrint = bHPrint;
}
+void ScProtectionAttr::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("ScProtectionAttr"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("protection"), BAD_CAST(OString::boolean(GetProtection()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("hide-formula"), BAD_CAST(OString::boolean(GetHideFormula()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("hide-cell"), BAD_CAST(OString::boolean(GetHideCell()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("hide-print"), BAD_CAST(OString::boolean(GetHidePrint()).getStr()));
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
/**
* ScPageHFItem - Dates from the Head and Foot lines
*/
@@ -483,6 +505,14 @@ void ScPageHFItem::SetRightArea( const EditTextObject& rNew )
{
pRightArea = rNew.Clone();
}
+void ScPageHFItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("ScPageHFItem"));
+ GetLeftArea()->dumpAsXml(pWriter);
+ GetCenterArea()->dumpAsXml(pWriter);
+ GetRightArea()->dumpAsXml(pWriter);
+ (void)xmlTextWriterEndElement(pWriter);
+}
/**
* ScViewObjectModeItem - Display Mode of View Objects
@@ -656,6 +686,13 @@ bool ScPageScaleToItem::PutValue( const uno::Any& rAny, sal_uInt8 nMemberId )
}
return bRet;
}
+void ScPageScaleToItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("ScPageScaleToItem"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("width"), BAD_CAST(OString::number(GetWidth()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("height"), BAD_CAST(OString::number(GetHeight()).getStr()));
+ (void)xmlTextWriterEndElement(pWriter);
+}
ScCondFormatItem::ScCondFormatItem():
SfxPoolItem( ATTR_CONDITIONAL )
@@ -691,24 +728,11 @@ bool ScCondFormatItem::operator==( const SfxPoolItem& rCmp ) const
auto const & other = static_cast<const ScCondFormatItem&>(rCmp);
if (maIndex.empty() && other.maIndex.empty())
return true;
- // memcmp is faster than operator< on std::vector
+ // memcmp is faster than operator== on std::vector
return maIndex.size() == other.maIndex.size()
&& memcmp(&maIndex.front(), &other.maIndex.front(), maIndex.size() * sizeof(sal_uInt32)) == 0;
}
-bool ScCondFormatItem::operator<( const SfxPoolItem& rCmp ) const
-{
- auto const & other = static_cast<const ScCondFormatItem&>(rCmp);
- if ( maIndex.size() < other.maIndex.size() )
- return true;
- if ( maIndex.size() > other.maIndex.size() )
- return false;
- if (maIndex.empty() && other.maIndex.empty())
- return false;
- // memcmp is faster than operator< on std::vector
- return memcmp(&maIndex.front(), &other.maIndex.front(), maIndex.size() * sizeof(sal_uInt32)) < 0;
-}
-
ScCondFormatItem* ScCondFormatItem::Clone(SfxItemPool*) const
{
return new ScCondFormatItem(maIndex);
@@ -762,7 +786,7 @@ bool ScShrinkToFitCell::GetPresentation(SfxItemPresentation,
OUString& rText,
const IntlWrapper&) const
{
- const char* pId = GetValue() ? STR_SHRINKTOFITCELL_ON : STR_SHRINKTOFITCELL_OFF;
+ TranslateId pId = GetValue() ? STR_SHRINKTOFITCELL_ON : STR_SHRINKTOFITCELL_OFF;
rText = ScResId(pId);
return true;
}
@@ -782,7 +806,7 @@ bool ScVerticalStackCell::GetPresentation(SfxItemPresentation,
OUString& rText,
const IntlWrapper&) const
{
- const char* pId = GetValue() ? STR_VERTICALSTACKCELL_ON : STR_VERTICALSTACKCELL_OFF;
+ TranslateId pId = GetValue() ? STR_VERTICALSTACKCELL_ON : STR_VERTICALSTACKCELL_OFF;
rText = ScResId(pId);
return true;
}
@@ -802,7 +826,7 @@ bool ScLineBreakCell::GetPresentation(SfxItemPresentation,
OUString& rText,
const IntlWrapper&) const
{
- const char* pId = GetValue() ? STR_LINEBREAKCELL_ON : STR_LINEBREAKCELL_OFF;
+ TranslateId pId = GetValue() ? STR_LINEBREAKCELL_ON : STR_LINEBREAKCELL_OFF;
rText = ScResId(pId);
return true;
}
@@ -822,7 +846,7 @@ bool ScHyphenateCell::GetPresentation(SfxItemPresentation,
OUString& rText,
const IntlWrapper&) const
{
- const char* pId = GetValue() ? STR_HYPHENATECELL_ON : STR_HYPHENATECELL_OFF;
+ TranslateId pId = GetValue() ? STR_HYPHENATECELL_ON : STR_HYPHENATECELL_OFF;
rText = ScResId(pId);
return true;
}
diff --git a/sc/source/core/data/autonamecache.cxx b/sc/source/core/data/autonamecache.cxx
index a2be03c25796..f74219baf706 100644
--- a/sc/source/core/data/autonamecache.cxx
+++ b/sc/source/core/data/autonamecache.cxx
@@ -77,7 +77,7 @@ const ScAutoNameAddresses& ScAutoNameCache::GetNameOccurrences( const OUString&
; // nothing, prevent compiler warning
break;
}
- if ( ScGlobal::GetpTransliteration()->isEqual( aStr, rName ) )
+ if ( ScGlobal::GetTransliteration().isEqual( aStr, rName ) )
{
rAddresses.push_back(aIter.GetPos());
}
diff --git a/sc/source/core/data/bcaslot.cxx b/sc/source/core/data/bcaslot.cxx
index bbca9dda93ae..209eb9f2a9ba 100644
--- a/sc/source/core/data/bcaslot.cxx
+++ b/sc/source/core/data/bcaslot.cxx
@@ -17,46 +17,21 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
-#include <sfx2/objsh.hxx>
#include <svl/listener.hxx>
#include <sal/log.hxx>
#include <osl/diagnose.h>
#include <document.hxx>
+#include <docsh.hxx>
#include <brdcst.hxx>
#include <bcaslot.hxx>
#include <scerrors.hxx>
#include <refupdat.hxx>
#include <bulkdatahint.hxx>
#include <columnspanset.hxx>
-
-#if DEBUG_AREA_BROADCASTER
#include <formulacell.hxx>
#include <grouparealistener.hxx>
-#endif
-
-// Number of slots per dimension
-// must be integer divisors of MAXCOLCOUNT respectively MAXROWCOUNT
-constexpr SCCOL BCA_SLOTS_COL = MAXCOLCOUNT / 16;
-constexpr SCCOL BCA_SLOT_COLS = MAXCOLCOUNT / BCA_SLOTS_COL;
-#if !defined NDEBUG
-constexpr SCROW BCA_SLICE = 128;
-static SCROW BCA_SLOTS_ROW(const ScSheetLimits& rLimits) { return rLimits.GetMaxRowCount() / BCA_SLICE; }
-static SCROW BCA_SLOT_ROWS(const ScSheetLimits& rLimits)
-{
- auto nMaxRowCount = rLimits.GetMaxRowCount();
- auto nSlotsRow = BCA_SLOTS_ROW(rLimits);
- assert((nMaxRowCount / nSlotsRow * nSlotsRow) == nMaxRowCount && "bad BCA_SLOTS_ROW value");
- return nMaxRowCount / nSlotsRow;
-}
-#endif
-// multiple?
-static_assert((BCA_SLOT_COLS * BCA_SLOTS_COL) == MAXCOLCOUNT, "bad BCA_SLOTS_COL value");
-
-// size of slot array if linear
-#if !defined NDEBUG
-static int BCA_SLOTS(const ScSheetLimits& rLimits) { return BCA_SLOTS_COL * BCA_SLOTS_ROW(rLimits); }
-#endif
+#include <broadcast.hxx>
ScBroadcastArea::ScBroadcastArea( const ScRange& rRange ) :
pUpdateChainNext(nullptr),
@@ -85,7 +60,7 @@ ScBroadcastAreaSlot::~ScBroadcastAreaSlot()
ScBroadcastArea* pArea = (*aIter).mpArea;
// Erase all so no hash will be accessed upon destruction of the
// unordered_map.
- aBroadcastAreaTbl.erase( aIter++);
+ aIter = aBroadcastAreaTbl.erase(aIter);
if (!pArea->DecRef())
delete pArea;
}
@@ -98,7 +73,7 @@ ScDocument::HardRecalcState ScBroadcastAreaSlot::CheckHardRecalcStateCondition()
{
if (aBroadcastAreaTbl.size() >= aBroadcastAreaTbl.max_size())
{ // this is more hypothetical now, check existed for old SV_PTRARR_SORT
- SfxObjectShell* pShell = pDoc->GetDocumentShell();
+ ScDocShell* pShell = pDoc->GetDocumentShell();
OSL_ENSURE( pShell, "Missing DocShell :-/" );
if ( pShell )
@@ -213,16 +188,15 @@ namespace {
void broadcastRangeByCell( SvtBroadcaster& rBC, const ScRange& rRange, SfxHintId nHint )
{
ScHint aHint(nHint, ScAddress());
- ScAddress& rPos = aHint.GetAddress();
for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab)
{
- rPos.SetTab(nTab);
+ aHint.SetAddressTab(nTab);
for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
{
- rPos.SetCol(nCol);
+ aHint.SetAddressCol(nCol);
for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
{
- rPos.SetRow(nRow);
+ aHint.SetAddressRow(nRow);
rBC.Broadcast(aHint);
}
}
@@ -296,7 +270,7 @@ bool ScBroadcastAreaSlot::AreaBroadcast( const ScHint& rHint)
mbHasErasedArea = false;
- const ScAddress& rAddress = rHint.GetAddress();
+ const ScRange& rRange = rHint.GetRange();
for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin()),
aIterEnd( aBroadcastAreaTbl.end()); aIter != aIterEnd; ++aIter )
{
@@ -305,13 +279,13 @@ bool ScBroadcastAreaSlot::AreaBroadcast( const ScHint& rHint)
ScBroadcastArea* pArea = (*aIter).mpArea;
const ScRange& rAreaRange = pArea->GetRange();
- if (rAreaRange.In( rAddress))
+ if (rAreaRange.Intersects( rRange))
{
if (pArea->IsGroupListening())
{
if (pBASM->IsInBulkBroadcast())
{
- pBASM->InsertBulkGroupArea(pArea, rAddress);
+ pBASM->InsertBulkGroupArea(pArea, rRange);
}
else
{
@@ -345,10 +319,10 @@ void ScBroadcastAreaSlot::DelBroadcastAreasInRange( const ScRange& rRange )
aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
{
const ScRange& rAreaRange = (*aIter).mpArea->GetRange();
- if (rRange.In( rAreaRange))
+ if (rRange.Contains( rAreaRange))
{
ScBroadcastArea* pArea = (*aIter).mpArea;
- aBroadcastAreaTbl.erase( aIter++); // erase before modifying
+ aIter = aBroadcastAreaTbl.erase(aIter); // erase before modifying
if (!pArea->DecRef())
{
if (pBASM->IsInBulkBroadcast())
@@ -377,7 +351,7 @@ void ScBroadcastAreaSlot::UpdateRemove( UpdateRefMode eUpdateRefMode,
ScBroadcastArea* pArea = (*aIter).mpArea;
if ( pArea->IsInUpdateChain() )
{
- aBroadcastAreaTbl.erase( aIter++);
+ aIter = aBroadcastAreaTbl.erase(aIter);
pArea->DecRef();
}
else
@@ -387,7 +361,7 @@ void ScBroadcastAreaSlot::UpdateRemove( UpdateRefMode eUpdateRefMode,
nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ))
{
- aBroadcastAreaTbl.erase( aIter++);
+ aIter = aBroadcastAreaTbl.erase(aIter);
pArea->DecRef();
if (pBASM->IsInBulkBroadcast())
pBASM->RemoveBulkArea( pArea);
@@ -489,7 +463,7 @@ void ScBroadcastAreaSlot::GetAllListeners(
switch (eType)
{
case sc::AreaOverlapType::Inside:
- if (!rRange.In(rAreaRange))
+ if (!rRange.Contains(rAreaRange))
// The range needs to be fully inside specified range.
continue;
break;
@@ -499,13 +473,13 @@ void ScBroadcastAreaSlot::GetAllListeners(
continue;
break;
case sc::AreaOverlapType::OneRowInside:
- if (rAreaRange.aStart.Row() != rAreaRange.aEnd.Row() || !rRange.In(rAreaRange))
+ if (rAreaRange.aStart.Row() != rAreaRange.aEnd.Row() || !rRange.Contains(rAreaRange))
// The range needs to be one single row and fully inside
// specified range.
continue;
break;
case sc::AreaOverlapType::OneColumnInside:
- if (rAreaRange.aStart.Col() != rAreaRange.aEnd.Col() || !rRange.In(rAreaRange))
+ if (rAreaRange.aStart.Col() != rAreaRange.aEnd.Col() || !rRange.Contains(rAreaRange))
// The range needs to be one single column and fully inside
// specified range.
continue;
@@ -524,46 +498,32 @@ void ScBroadcastAreaSlot::GetAllListeners(
}
}
-#if DEBUG_AREA_BROADCASTER
-void ScBroadcastAreaSlot::Dump() const
+void ScBroadcastAreaSlot::CollectBroadcasterState(sc::BroadcasterState& rState) const
{
for (const ScBroadcastAreaEntry& rEntry : aBroadcastAreaTbl)
{
- const ScBroadcastArea* pArea = rEntry.mpArea;
- const SvtBroadcaster& rBC = pArea->GetBroadcaster();
- const SvtBroadcaster::ListenersType& rListeners = rBC.GetAllListeners();
- size_t n = rListeners.size();
-
- cout << " * range: " << OUStringToOString(pArea->GetRange().Format(ScRefFlags::VALID|ScRefFlags::TAB_3D, pDoc), RTL_TEXTENCODING_UTF8).getStr()
- << ", group: " << pArea->IsGroupListening()
- << ", listener count: " << n << endl;
+ const ScRange& rRange = rEntry.mpArea->GetRange();
+ auto aRes = rState.aAreaListenerStore.try_emplace(rRange);
+ auto& rLisStore = aRes.first->second;
- for (size_t i = 0; i < n; ++i)
+ for (const SvtListener* pLis : rEntry.mpArea->GetBroadcaster().GetAllListeners())
{
- const ScFormulaCell* pFC = dynamic_cast<const ScFormulaCell*>(rListeners[i]);
- if (pFC)
+ if (auto pFC = dynamic_cast<const ScFormulaCell*>(pLis); pFC)
{
- cout << " * listener: formula cell: "
- << OUStringToOString(pFC->aPos.Format(ScRefFlags::VALID|ScRefFlags::TAB_3D, pDoc), RTL_TEXTENCODING_UTF8).getStr()
- << endl;
+ rLisStore.emplace_back(pFC);
continue;
}
- const sc::FormulaGroupAreaListener* pFGListener = dynamic_cast<const sc::FormulaGroupAreaListener*>(rListeners[i]);
- if (pFGListener)
+ if (auto pFGL = dynamic_cast<const sc::FormulaGroupAreaListener*>(pLis); pFGL)
{
- cout << " * listener: formula group: (pos: "
- << OUStringToOString(pFGListener->getTopCellPos().Format(ScRefFlags::VALID | ScRefFlags::TAB_3D, pDoc), RTL_TEXTENCODING_UTF8).getStr()
- << ", length: " << pFGListener->getGroupLength()
- << ")" << endl;
+ rLisStore.emplace_back(pFGL);
continue;
}
- cout << " * listener: unknown" << endl;
+ rLisStore.emplace_back(pLis);
}
}
}
-#endif
void ScBroadcastAreaSlot::FinallyEraseAreas()
{
@@ -579,10 +539,17 @@ ScBroadcastAreaSlotMachine::TableSlots::TableSlots(SCSIZE nBcaSlots)
memset( ppSlots.get(), 0 , sizeof( ScBroadcastAreaSlot* ) * nBcaSlots );
}
+ScBroadcastAreaSlotMachine::TableSlots::TableSlots(TableSlots&& rOther) noexcept
+ : mnBcaSlots(rOther.mnBcaSlots)
+ , ppSlots( std::move(rOther.ppSlots) )
+{
+}
+
ScBroadcastAreaSlotMachine::TableSlots::~TableSlots()
{
- for ( ScBroadcastAreaSlot** pp = ppSlots.get() + mnBcaSlots; --pp >= ppSlots.get(); /* nothing */ )
- delete *pp;
+ if (ppSlots)
+ for ( ScBroadcastAreaSlot** pp = ppSlots.get() + mnBcaSlots; --pp >= ppSlots.get(); /* nothing */ )
+ delete *pp;
}
ScBroadcastAreaSlotMachine::ScBroadcastAreaSlotMachine(
@@ -592,35 +559,52 @@ ScBroadcastAreaSlotMachine::ScBroadcastAreaSlotMachine(
pEOUpdateChain( nullptr ),
nInBulkBroadcast( 0 )
{
- const ScSheetLimits& rSheetLimits = pDoc->GetSheetLimits();
-
- assert((BCA_SLOT_ROWS(rSheetLimits) * BCA_SLOTS_ROW(rSheetLimits)) == pDoc->GetSheetLimits().GetMaxRowCount() && "bad BCA_SLOTS_ROW value");
- // Arbitrary 2**31/8, assuming size_t can hold at least 2^31 values and
- // sizeof_ptr is at most 8 bytes. You'd probably doom your machine's memory
- // anyway, once you reached these values...
- assert(BCA_SLOTS(rSheetLimits) <= 268435456 && "DOOMed");
-
// initSlotDistribution ---------
// Logarithmic or any other distribution.
- // Upper sheet part usually is more populated and referenced and gets fine
+ // Upper and leftmost sheet part usually is more populated and referenced and gets fine
// grained resolution, larger data in larger hunks.
- // Could be further enhanced by also applying a different distribution of
- // column slots.
+ // Just like with cells, slots are organized in columns. Slot 0 is for first nSliceRow x nSliceCol
+ // cells, slot 1 is for next nSliceRow x nSliceCel cells below, etc. After a while the size of row
+ // slice doubles (making more cells share the same slot), this distribution data is stored
+ // in ScSlotData including ranges of cells. This is repeated for another column of nSliceCol cells,
+ // again with the column slice doubling after some time.
+ // Functions ComputeSlotOffset(), ComputeArePoints() and ComputeNextSlot() do the necessary
+ // calculations.
SCSIZE nSlots = 0;
- SCROW nRow1 = 0;
- SCROW nRow2 = 32*1024;
- SCSIZE nSlice = 128;
- // Must be sorted by row1,row2!
- while (nRow2 <= rSheetLimits.GetMaxRowCount())
+ // This should be SCCOL, but that's only 16bit and would overflow when doubling 16k columns.
+ sal_Int32 nCol1 = 0;
+ sal_Int32 nCol2 = 1024;
+ SCSIZE nSliceCol = 16;
+ while (nCol2 <= pDoc->GetMaxColCount())
{
- maSlotDistribution.emplace_back( nRow1, nRow2, nSlice, nSlots);
- nSlots += (nRow2 - nRow1) / nSlice;
- nRow1 = nRow2;
- nRow2 *= 2;
- nSlice *= 2;
+ SCROW nRow1 = 0;
+ SCROW nRow2 = 32*1024;
+ SCSIZE nSliceRow = 128;
+ SCSIZE nSlotsCol = 0;
+ SCSIZE nSlotsStartCol = nSlots;
+ // Must be sorted by row1,row2!
+ while (nRow2 <= pDoc->GetMaxRowCount())
+ {
+ maSlotDistribution.emplace_back(nRow1, nRow2, nSliceRow, nSlotsCol, nCol1, nCol2, nSliceCol, nSlotsStartCol);
+ nSlotsCol += (nRow2 - nRow1) / nSliceRow;
+ nRow1 = nRow2;
+ nRow2 *= 2;
+ nSliceRow *= 2;
+ }
+ // Store the number of slots in a column in mnBcaSlotsCol, so that finding a slot
+ // to the right can be computed quickly in ComputeNextSlot().
+ if(nCol1 == 0)
+ mnBcaSlotsCol = nSlotsCol;
+ assert(nSlotsCol == mnBcaSlotsCol);
+ nSlots += (nCol2 - nCol1) / nSliceCol * nSlotsCol;
+ nCol1 = nCol2;
+ nCol2 *= 2;
+ nSliceCol *= 2;
}
- mnBcaSlotsRow = nSlots;
- mnBcaSlots = mnBcaSlotsRow * BCA_SLOTS_COL;
+ mnBcaSlots = nSlots;
+#ifdef DBG_UTIL
+ DoChecks();
+#endif
}
ScBroadcastAreaSlotMachine::~ScBroadcastAreaSlotMachine()
@@ -642,14 +626,18 @@ inline SCSIZE ScBroadcastAreaSlotMachine::ComputeSlotOffset(
OSL_FAIL( "Row/Col invalid, using first slot!" );
return 0;
}
- for (const ScSlotData & i : maSlotDistribution)
+ for (const ScSlotData& rSD : maSlotDistribution)
{
- if (nRow < i.nStopRow)
+ if (nRow < rSD.nStopRow && nCol < rSD.nStopCol)
{
- const ScSlotData& rSD = i;
- return rSD.nCumulated +
- static_cast<SCSIZE>(nRow - rSD.nStartRow) / rSD.nSlice +
- static_cast<SCSIZE>(nCol) / BCA_SLOT_COLS * mnBcaSlotsRow;
+ assert(nRow >= rSD.nStartRow);
+ assert(nCol >= rSD.nStartCol);
+ SCSIZE slot = rSD.nCumulatedRow
+ + static_cast<SCSIZE>(nRow - rSD.nStartRow) / rSD.nSliceRow
+ + rSD.nCumulatedCol
+ + static_cast<SCSIZE>(nCol - rSD.nStartCol) / rSD.nSliceCol * mnBcaSlotsCol;
+ assert(slot < mnBcaSlots);
+ return slot;
}
}
OSL_FAIL( "No slot found, using last!" );
@@ -667,7 +655,7 @@ void ScBroadcastAreaSlotMachine::ComputeAreaPoints( const ScRange& rRange,
}
static void ComputeNextSlot( SCSIZE & nOff, SCSIZE & nBreak, ScBroadcastAreaSlot** & pp,
- SCSIZE & nStart, ScBroadcastAreaSlot** const & ppSlots, SCSIZE nRowBreak, SCSIZE nBcaSlotsRow )
+ SCSIZE & nStart, ScBroadcastAreaSlot** const & ppSlots, SCSIZE nRowBreak, SCSIZE nBcaSlotsCol )
{
if ( nOff < nBreak )
{
@@ -676,13 +664,100 @@ static void ComputeNextSlot( SCSIZE & nOff, SCSIZE & nBreak, ScBroadcastAreaSlot
}
else
{
- nStart += nBcaSlotsRow;
+ nStart += nBcaSlotsCol;
nOff = nStart;
pp = ppSlots + nOff;
nBreak = nOff + nRowBreak;
}
}
+#ifdef DBG_UTIL
+static void compare(SCSIZE value1, SCSIZE value2, int line)
+{
+ if(value1!=value2)
+ SAL_WARN("sc", "V1:" << value1 << " V2:" << value2 << " (" << line << ")");
+ assert(value1 == value2);
+}
+
+// Basic checks that the calculations work correctly.
+void ScBroadcastAreaSlotMachine::DoChecks()
+{
+ // Copy&paste from the ctor.
+ constexpr SCSIZE nSliceRow = 128;
+ constexpr SCSIZE nSliceCol = 16;
+ // First and second column are in the same slice and so get the same slot.
+ compare( ComputeSlotOffset( ScAddress( 0, 0, 0 )), ComputeSlotOffset( ScAddress( 1, 0, 0 )), __LINE__);
+ // Each nSliceRow rows are offset by one slot (at the start of the logarithmic distribution).
+ compare( ComputeSlotOffset( ScAddress( 0, 0, 0 )),
+ ComputeSlotOffset( ScAddress( 0, nSliceRow, 0 )) - 1, __LINE__ );
+ compare( ComputeSlotOffset( ScAddress( nSliceCol - 1, 0, 0 )),
+ ComputeSlotOffset( ScAddress( nSliceCol, 0, 0 )) - mnBcaSlotsCol, __LINE__ );
+ // Check that last cell is the last slot.
+ compare( ComputeSlotOffset( ScAddress( pDoc->GetMaxColCount() - 1, pDoc->GetMaxRowCount() - 1, 0 )),
+ mnBcaSlots - 1, __LINE__ );
+ // Check that adjacent rows in the same column but in different distribution areas differ by one slot.
+ for( size_t i = 0; i < maSlotDistribution.size() - 1; ++i )
+ {
+ const ScSlotData& s1 = maSlotDistribution[ i ];
+ const ScSlotData& s2 = maSlotDistribution[ i + 1 ];
+ if( s1.nStartCol == s2.nStartCol )
+ {
+ assert( s1.nStopRow == s2.nStartRow );
+ compare( ComputeSlotOffset( ScAddress( s1.nStartCol, s1.nStopRow - 1, 0 )),
+ ComputeSlotOffset( ScAddress( s1.nStartCol, s1.nStopRow, 0 )) - 1, __LINE__ );
+ }
+ }
+ // Check that adjacent columns in the same row but in different distribution areas differ by mnBcaSlotsCol.
+ for( size_t i = 0; i < maSlotDistribution.size() - 1; ++i )
+ {
+ const ScSlotData& s1 = maSlotDistribution[ i ];
+ for( size_t j = i + 1; j < maSlotDistribution.size(); ++j )
+ {
+ const ScSlotData& s2 = maSlotDistribution[ i + 1 ];
+ if( s1.nStartRow == s2.nStartRow && s1.nStopCol == s2.nStartCol )
+ {
+ assert( s1.nStopRow == s2.nStartRow );
+ compare( ComputeSlotOffset( ScAddress( s1.nStopCol - 1, s1.nStartRow, 0 )),
+ ComputeSlotOffset( ScAddress( s1.nStopCol, s1.nStartRow, 0 )) - mnBcaSlotsCol, __LINE__ );
+ }
+ }
+ }
+ // Iterate all slots.
+ ScRange range( ScAddress( 0, 0, 0 ), ScAddress( pDoc->MaxCol(), pDoc->MaxRow(), 0 ));
+ SCSIZE nStart, nEnd, nRowBreak;
+ ComputeAreaPoints( range, nStart, nEnd, nRowBreak );
+ assert( nStart == 0 );
+ assert( nEnd == mnBcaSlots - 1 );
+ SCSIZE nOff = nStart;
+ SCSIZE nBreak = nOff + nRowBreak;
+ std::unique_ptr<ScBroadcastAreaSlot*[]> slots( new ScBroadcastAreaSlot*[ mnBcaSlots ] ); // dummy, not accessed
+ ScBroadcastAreaSlot** ppSlots = slots.get();
+ ScBroadcastAreaSlot** pp = ppSlots;
+ while ( nOff <= nEnd )
+ {
+ SCSIZE previous = nOff;
+ ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
+ compare( nOff, previous + 1, __LINE__ );
+ }
+ // Iterate slots in the last row (each will differ by mnBcaSlotsCol).
+ range = ScRange( ScAddress( 0, pDoc->MaxRow(), 0 ),
+ ScAddress( pDoc->MaxCol(), pDoc->MaxRow() - 1, 0 ));
+ ComputeAreaPoints( range, nStart, nEnd, nRowBreak );
+ assert( nStart == mnBcaSlotsCol - 1 );
+ assert( nEnd == mnBcaSlots - 1 );
+ nOff = nStart;
+ nBreak = nOff + nRowBreak;
+ ppSlots = slots.get();
+ pp = ppSlots;
+ while ( nOff <= nEnd )
+ {
+ SCSIZE previous = nOff;
+ ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
+ compare( nOff, previous + mnBcaSlotsCol, __LINE__ );
+ }
+}
+#endif
+
void ScBroadcastAreaSlotMachine::StartListeningArea(
const ScRange& rRange, bool bGroupListening, SvtListener* pListener )
{
@@ -705,8 +780,9 @@ void ScBroadcastAreaSlotMachine::StartListeningArea(
{
TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
if (iTab == aTableSlotsMap.end())
- iTab = aTableSlotsMap.emplace(nTab, std::make_unique<TableSlots>(mnBcaSlots)).first;
- ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
+ iTab = aTableSlotsMap.emplace( std::piecewise_construct,
+ std::forward_as_tuple(nTab), std::forward_as_tuple(mnBcaSlots) ).first;
+ ScBroadcastAreaSlot** ppSlots = (*iTab).second.getSlots();
SCSIZE nStart, nEnd, nRowBreak;
ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
SCSIZE nOff = nStart;
@@ -727,7 +803,7 @@ void ScBroadcastAreaSlotMachine::StartListeningArea(
}
else
(*pp)->InsertListeningArea( pArea);
- ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsRow);
+ ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
}
}
}
@@ -753,7 +829,7 @@ void ScBroadcastAreaSlotMachine::EndListeningArea(
for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
{
- ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
+ ScBroadcastAreaSlot** ppSlots = (*iTab).second.getSlots();
SCSIZE nStart, nEnd, nRowBreak;
ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
SCSIZE nOff = nStart;
@@ -777,7 +853,7 @@ void ScBroadcastAreaSlotMachine::EndListeningArea(
{
if ( *pp )
(*pp)->EndListeningArea( rRange, bGroupListening, pListener, pArea);
- ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsRow);
+ ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
}
}
}
@@ -791,7 +867,7 @@ bool ScBroadcastAreaSlotMachine::AreaBroadcast( const ScRange& rRange, SfxHintId
for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
{
- ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
+ ScBroadcastAreaSlot** ppSlots = (*iTab).second.getSlots();
SCSIZE nStart, nEnd, nRowBreak;
ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
SCSIZE nOff = nStart;
@@ -801,7 +877,7 @@ bool ScBroadcastAreaSlotMachine::AreaBroadcast( const ScRange& rRange, SfxHintId
{
if ( *pp )
bBroadcasted |= (*pp)->AreaBroadcast( rRange, nHint );
- ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsRow);
+ ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
}
}
return bBroadcasted;
@@ -809,7 +885,7 @@ bool ScBroadcastAreaSlotMachine::AreaBroadcast( const ScRange& rRange, SfxHintId
bool ScBroadcastAreaSlotMachine::AreaBroadcast( const ScHint& rHint ) const
{
- const ScAddress& rAddress = rHint.GetAddress();
+ const ScAddress& rAddress = rHint.GetStartAddress();
if ( rAddress == BCA_BRDCST_ALWAYS )
{
if ( pBCAlways )
@@ -825,12 +901,23 @@ bool ScBroadcastAreaSlotMachine::AreaBroadcast( const ScHint& rHint ) const
TableSlotsMap::const_iterator iTab( aTableSlotsMap.find( rAddress.Tab()));
if (iTab == aTableSlotsMap.end())
return false;
- ScBroadcastAreaSlot* pSlot = (*iTab).second->getAreaSlot(
- ComputeSlotOffset( rAddress));
- if ( pSlot )
- return pSlot->AreaBroadcast( rHint );
- else
- return false;
+ // Process all slots for the given row range.
+ ScRange broadcastRange( rAddress,
+ ScAddress( rAddress.Col(), rAddress.Row() + rHint.GetRowCount() - 1, rAddress.Tab()));
+ bool bBroadcasted = false;
+ ScBroadcastAreaSlot** ppSlots = (*iTab).second.getSlots();
+ SCSIZE nStart, nEnd, nRowBreak;
+ ComputeAreaPoints( broadcastRange, nStart, nEnd, nRowBreak );
+ SCSIZE nOff = nStart;
+ SCSIZE nBreak = nOff + nRowBreak;
+ ScBroadcastAreaSlot** pp = ppSlots + nOff;
+ while ( nOff <= nEnd )
+ {
+ if ( *pp )
+ bBroadcasted |= (*pp)->AreaBroadcast( rHint );
+ ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
+ }
+ return bBroadcasted;
}
}
@@ -841,7 +928,7 @@ void ScBroadcastAreaSlotMachine::DelBroadcastAreasInRange(
for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
{
- ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
+ ScBroadcastAreaSlot** ppSlots = (*iTab).second.getSlots();
SCSIZE nStart, nEnd, nRowBreak;
ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
SCSIZE nOff = nStart;
@@ -864,7 +951,7 @@ void ScBroadcastAreaSlotMachine::DelBroadcastAreasInRange(
{
if ( *pp )
(*pp)->DelBroadcastAreasInRange( rRange );
- ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsRow);
+ ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
}
}
}
@@ -880,7 +967,7 @@ void ScBroadcastAreaSlotMachine::UpdateBroadcastAreas(
for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
{
- ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
+ ScBroadcastAreaSlot** ppSlots = (*iTab).second.getSlots();
SCSIZE nStart, nEnd, nRowBreak;
ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
SCSIZE nOff = nStart;
@@ -903,7 +990,7 @@ void ScBroadcastAreaSlotMachine::UpdateBroadcastAreas(
{
if ( *pp )
(*pp)->UpdateRemove( eUpdateRefMode, rRange, nDx, nDy, nDz );
- ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsRow);
+ ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
}
}
}
@@ -925,7 +1012,7 @@ void ScBroadcastAreaSlotMachine::UpdateBroadcastAreas(
OSL_FAIL( "UpdateBroadcastAreas: Where's the TableSlot?!?");
continue; // for
}
- ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
+ ScBroadcastAreaSlot** ppSlots = (*iTab).second.getSlots();
SCSIZE nStart, nEnd, nRowBreak;
ComputeAreaPoints( aRange, nStart, nEnd, nRowBreak );
SCSIZE nOff = nStart;
@@ -935,7 +1022,7 @@ void ScBroadcastAreaSlotMachine::UpdateBroadcastAreas(
{
if (*pp)
(*pp)->UpdateRemoveArea( pArea);
- ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsRow);
+ ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
}
}
@@ -951,14 +1038,14 @@ void ScBroadcastAreaSlotMachine::UpdateBroadcastAreas(
// Remove sheets, if any, iDel or/and iTab may as well point to end().
while (iDel != iTab)
{
- aTableSlotsMap.erase( iDel++);
+ iDel = aTableSlotsMap.erase(iDel);
}
// shift remaining down
while (iTab != aTableSlotsMap.end())
{
SCTAB nTab = (*iTab).first + nDz;
- aTableSlotsMap[nTab] = std::move((*iTab).second);
- aTableSlotsMap.erase( iTab++);
+ aTableSlotsMap.emplace(nTab, std::move((*iTab).second));
+ iTab = aTableSlotsMap.erase(iTab);
}
}
else
@@ -974,14 +1061,14 @@ void ScBroadcastAreaSlotMachine::UpdateBroadcastAreas(
while (iTab != iStop)
{
SCTAB nTab = (*iTab).first + nDz;
- aTableSlotsMap[nTab] = std::move((*iTab).second);
+ aTableSlotsMap.emplace(nTab, std::move((*iTab).second));
aTableSlotsMap.erase( iTab--);
}
// Shift the very first, iTab==iStop in this case.
if (bStopIsBegin)
{
SCTAB nTab = (*iTab).first + nDz;
- aTableSlotsMap[nTab] = std::move((*iTab).second);
+ aTableSlotsMap.emplace(nTab, std::move((*iTab).second));
aTableSlotsMap.erase( iStop);
}
}
@@ -1016,8 +1103,9 @@ void ScBroadcastAreaSlotMachine::UpdateBroadcastAreas(
{
TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
if (iTab == aTableSlotsMap.end())
- iTab = aTableSlotsMap.emplace(nTab, std::make_unique<TableSlots>(mnBcaSlots)).first;
- ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
+ iTab = aTableSlotsMap.emplace( std::piecewise_construct,
+ std::forward_as_tuple(nTab), std::forward_as_tuple(mnBcaSlots) ).first;
+ ScBroadcastAreaSlot** ppSlots = (*iTab).second.getSlots();
SCSIZE nStart, nEnd, nRowBreak;
ComputeAreaPoints( aRange, nStart, nEnd, nRowBreak );
SCSIZE nOff = nStart;
@@ -1028,7 +1116,7 @@ void ScBroadcastAreaSlotMachine::UpdateBroadcastAreas(
if (!*pp)
*pp = new ScBroadcastAreaSlot( pDoc, this );
(*pp)->UpdateInsert( pArea );
- ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsRow);
+ ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
}
}
@@ -1077,12 +1165,11 @@ void ScBroadcastAreaSlotMachine::InsertBulkGroupArea( ScBroadcastArea* pArea, co
if (it == m_BulkGroupAreas.end() || m_BulkGroupAreas.key_comp()(pArea, it->first))
{
// Insert a new one.
- it = m_BulkGroupAreas.insert(it, std::make_pair(pArea, std::make_unique<sc::ColumnSpanSet>()));
+ it = m_BulkGroupAreas.insert(it, std::make_pair(pArea, sc::ColumnSpanSet()));
}
- sc::ColumnSpanSet *const pSet = it->second.get();
- assert(pSet);
- pSet->set(*pDoc, rRange, true);
+ sc::ColumnSpanSet& rSet = it->second;
+ rSet.set(*pDoc, rRange, true);
}
bool ScBroadcastAreaSlotMachine::BulkBroadcastGroupAreas( SfxHintId nHintId )
@@ -1093,7 +1180,7 @@ bool ScBroadcastAreaSlotMachine::BulkBroadcastGroupAreas( SfxHintId nHintId )
sc::BulkDataHint aHint( *pDoc, nHintId);
bool bBroadcasted = false;
- for (const auto& [pArea, rxSpans] : m_BulkGroupAreas)
+ for (const auto& [pArea, rSpans] : m_BulkGroupAreas)
{
assert(pArea);
SvtBroadcaster& rBC = pArea->GetBroadcaster();
@@ -1105,9 +1192,7 @@ bool ScBroadcastAreaSlotMachine::BulkBroadcastGroupAreas( SfxHintId nHintId )
}
else
{
- const sc::ColumnSpanSet *const pSpans = rxSpans.get();
- assert(pSpans);
- aHint.setSpans(pSpans);
+ aHint.setSpans(&rSpans);
rBC.Broadcast(aHint);
bBroadcasted = true;
}
@@ -1164,7 +1249,7 @@ std::vector<sc::AreaListener> ScBroadcastAreaSlotMachine::GetAllListeners(
for (TableSlotsMap::const_iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
{
- ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
+ ScBroadcastAreaSlot** ppSlots = (*iTab).second.getSlots();
SCSIZE nStart, nEnd, nRowBreak;
ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
SCSIZE nOff = nStart;
@@ -1175,34 +1260,27 @@ std::vector<sc::AreaListener> ScBroadcastAreaSlotMachine::GetAllListeners(
ScBroadcastAreaSlot* p = *pp;
if (p)
p->GetAllListeners(rRange, aRet, eType, eGroup);
- ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsRow);
+ ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak, mnBcaSlotsCol);
}
}
return aRet;
}
-#if DEBUG_AREA_BROADCASTER
-void ScBroadcastAreaSlotMachine::Dump() const
+void ScBroadcastAreaSlotMachine::CollectBroadcasterState(sc::BroadcasterState& rState) const
{
- cout << "slot distribution count: " << nBcaSlots << endl;
- for (const auto& [rIndex, pTabSlots] : aTableSlotsMap)
+ for (const auto& [rTab, rTabSlots] : aTableSlotsMap)
{
- cout << "-- sheet (index: " << rIndex << ")" << endl;
+ (void)rTab;
- assert(pTabSlots);
- ScBroadcastAreaSlot** ppSlots = pTabSlots->getSlots();
- for (SCSIZE i = 0; i < nBcaSlots; ++i)
+ ScBroadcastAreaSlot** pp = rTabSlots.getSlots();
+ for (SCSIZE i = 0; i < mnBcaSlots; ++i)
{
- const ScBroadcastAreaSlot* pSlot = ppSlots[i];
+ const ScBroadcastAreaSlot* pSlot = pp[i];
if (pSlot)
- {
- cout << "* slot " << i << endl;
- pSlot->Dump();
- }
+ pSlot->CollectBroadcasterState(rState);
}
}
}
-#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/bigrange.cxx b/sc/source/core/data/bigrange.cxx
index 58a11eb03735..192765743958 100644
--- a/sc/source/core/data/bigrange.cxx
+++ b/sc/source/core/data/bigrange.cxx
@@ -14,11 +14,11 @@ bool ScBigAddress::IsValid( const ScDocument& rDoc ) const
{ // min/max interval bounds define whole col/row/tab
return
((0 <= nCol && nCol <= rDoc.MaxCol())
- || nCol == nInt32Min || nCol == nInt32Max) &&
+ || nCol == ScBigRange::nRangeMin || nCol == ScBigRange::nRangeMax) &&
((0 <= nRow && nRow <= rDoc.MaxRow())
- || nRow == nInt32Min || nRow == nInt32Max) &&
+ || nRow == ScBigRange::nRangeMin || nRow == ScBigRange::nRangeMax) &&
((0 <= nTab && nTab < rDoc.GetTableCount())
- || nTab == nInt32Min || nTab == nInt32Max)
+ || nTab == ScBigRange::nRangeMin || nTab == ScBigRange::nRangeMax)
;
}
diff --git a/sc/source/core/data/broadcast.cxx b/sc/source/core/data/broadcast.cxx
new file mode 100644
index 000000000000..d76591692f15
--- /dev/null
+++ b/sc/source/core/data/broadcast.cxx
@@ -0,0 +1,159 @@
+/* -*- 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/.
+ */
+
+#include <broadcast.hxx>
+#include <address.hxx>
+#include <formulacell.hxx>
+
+namespace sc
+{
+BroadcasterState::CellListener::CellListener(const ScFormulaCell* p)
+ : pData(p)
+{
+}
+
+BroadcasterState::CellListener::CellListener(const SvtListener* p)
+ : pData(p)
+{
+}
+
+BroadcasterState::AreaListener::AreaListener(const ScFormulaCell* p)
+ : pData(p)
+{
+}
+
+BroadcasterState::AreaListener::AreaListener(const sc::FormulaGroupAreaListener* p)
+ : pData(p)
+{
+}
+
+BroadcasterState::AreaListener::AreaListener(const SvtListener* p)
+ : pData(p)
+{
+}
+
+bool BroadcasterState::hasFormulaCellListener(const ScAddress& rBroadcasterPos,
+ const ScAddress& rFormulaPos) const
+{
+ auto it = aCellListenerStore.find(rBroadcasterPos);
+ if (it == aCellListenerStore.end())
+ return false;
+
+ for (const auto& rLis : it->second)
+ {
+ if (rLis.pData.index() == 0)
+ {
+ auto pFC = std::get<const ScFormulaCell*>(rLis.pData);
+ if (pFC->aPos == rFormulaPos)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool BroadcasterState::hasFormulaCellListener(const ScRange& rBroadcasterRange,
+ const ScAddress& rFormulaPos) const
+{
+ auto it = aAreaListenerStore.find(rBroadcasterRange);
+ if (it == aAreaListenerStore.end())
+ return false;
+
+ for (const auto& rLis : it->second)
+ {
+ if (rLis.pData.index() == 0)
+ {
+ auto pFC = std::get<const ScFormulaCell*>(rLis.pData);
+ if (pFC->aPos == rFormulaPos)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void BroadcasterState::dump(std::ostream& rStrm, const ScDocument* pDoc) const
+{
+ constexpr ScRefFlags nPosFlags = ScRefFlags::VALID | ScRefFlags::TAB_3D;
+
+ rStrm << "---" << std::endl;
+
+ for (const auto & [ rPos, rListeners ] : aCellListenerStore)
+ {
+ rStrm << "- type: cell-broadcaster\n";
+ rStrm << " position: " << rPos.Format(nPosFlags, pDoc) << std::endl;
+
+ if (!rListeners.empty())
+ rStrm << " listeners:\n";
+
+ for (const auto& rLis : rListeners)
+ {
+ switch (rLis.pData.index())
+ {
+ case 0:
+ {
+ auto* pFC = std::get<const ScFormulaCell*>(rLis.pData);
+ rStrm << " - type: formula-cell\n";
+ rStrm << " position: " << pFC->aPos.Format(nPosFlags, pDoc) << std::endl;
+ break;
+ }
+ case 1:
+ {
+ rStrm << " - type: unknown" << std::endl;
+ break;
+ }
+ }
+ }
+ }
+
+ for (const auto & [ rRange, rListeners ] : aAreaListenerStore)
+ {
+ rStrm << "- type: area-broadcaster\n";
+ rStrm << " range: " << rRange.Format(*pDoc, nPosFlags) << std::endl;
+
+ if (!rListeners.empty())
+ rStrm << " listeners:\n";
+
+ for (const auto& rLis : rListeners)
+ {
+ switch (rLis.pData.index())
+ {
+ case 0:
+ {
+ auto* pFC = std::get<const ScFormulaCell*>(rLis.pData);
+ rStrm << " - type: formula-cell\n";
+ rStrm << " position: " << pFC->aPos.Format(nPosFlags, pDoc) << std::endl;
+ break;
+ }
+ case 1:
+ {
+ auto* pFGL = std::get<const sc::FormulaGroupAreaListener*>(rLis.pData);
+
+ auto pTopCell = pFGL->getTopCell();
+ if (auto xFG = pTopCell->GetCellGroup(); xFG)
+ {
+ ScRange aGR(pTopCell->aPos);
+ aGR.aEnd.IncRow(xFG->mnLength - 1);
+ rStrm << " - type: formula-group\n";
+ rStrm << " range: " << aGR.Format(*pDoc, nPosFlags) << std::endl;
+ }
+ break;
+ }
+ case 2:
+ {
+ rStrm << " - type: unknown" << std::endl;
+ break;
+ }
+ }
+ }
+ }
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/cellvalue.cxx b/sc/source/core/data/cellvalue.cxx
index 419123ef7622..4330ea972992 100644
--- a/sc/source/core/data/cellvalue.cxx
+++ b/sc/source/core/data/cellvalue.cxx
@@ -37,23 +37,23 @@ CellType adjustCellType( CellType eOrig )
template<typename T>
OUString getString( const T& rVal )
{
- if (rVal.meType == CELLTYPE_STRING)
- return rVal.mpString->getString();
+ if (rVal.getType() == CELLTYPE_STRING)
+ return rVal.getSharedString()->getString();
- if (rVal.meType == CELLTYPE_EDIT)
+ if (rVal.getType() == CELLTYPE_EDIT)
{
OUStringBuffer aRet;
- sal_Int32 n = rVal.mpEditText->GetParagraphCount();
+ sal_Int32 n = rVal.getEditText()->GetParagraphCount();
for (sal_Int32 i = 0; i < n; ++i)
{
if (i > 0)
aRet.append('\n');
- aRet.append(rVal.mpEditText->GetText(i));
+ aRet.append(rVal.getEditText()->GetText(i));
}
return aRet.makeStringAndClear();
}
- return EMPTY_OUSTRING;
+ return OUString();
}
bool equalsFormulaCells( const ScFormulaCell* p1, const ScFormulaCell* p2 )
@@ -82,8 +82,8 @@ bool equalsFormulaCells( const ScFormulaCell* p1, const ScFormulaCell* p2 )
template<typename T>
bool equalsWithoutFormatImpl( const T& left, const T& right )
{
- CellType eType1 = adjustCellType(left.meType);
- CellType eType2 = adjustCellType(right.meType);
+ CellType eType1 = adjustCellType(left.getType());
+ CellType eType2 = adjustCellType(right.getType());
if (eType1 != eType2)
return false;
@@ -92,7 +92,7 @@ bool equalsWithoutFormatImpl( const T& left, const T& right )
case CELLTYPE_NONE:
return true;
case CELLTYPE_VALUE:
- return left.mfValue == right.mfValue;
+ return left.getDouble() == right.getDouble();
case CELLTYPE_STRING:
{
OUString aStr1 = getString(left);
@@ -100,7 +100,34 @@ bool equalsWithoutFormatImpl( const T& left, const T& right )
return aStr1 == aStr2;
}
case CELLTYPE_FORMULA:
- return equalsFormulaCells(left.mpFormula, right.mpFormula);
+ return equalsFormulaCells(left.getFormula(), right.getFormula());
+ default:
+ ;
+ }
+ return false;
+}
+
+bool equalsWithoutFormatImpl( const ScCellValue& left, const ScCellValue& right )
+{
+ CellType eType1 = adjustCellType(left.getType());
+ CellType eType2 = adjustCellType(right.getType());
+ if (eType1 != eType2)
+ return false;
+
+ switch (eType1)
+ {
+ case CELLTYPE_NONE:
+ return true;
+ case CELLTYPE_VALUE:
+ return left.getDouble() == right.getDouble();
+ case CELLTYPE_STRING:
+ {
+ OUString aStr1 = getString(left);
+ OUString aStr2 = getString(right);
+ return aStr1 == aStr2;
+ }
+ case CELLTYPE_FORMULA:
+ return equalsFormulaCells(left.getFormula(), right.getFormula());
default:
;
}
@@ -109,21 +136,21 @@ bool equalsWithoutFormatImpl( const T& left, const T& right )
void commitToColumn( const ScCellValue& rCell, ScColumn& rColumn, SCROW nRow )
{
- switch (rCell.meType)
+ switch (rCell.getType())
{
case CELLTYPE_STRING:
- rColumn.SetRawString(nRow, *rCell.mpString);
+ rColumn.SetRawString(nRow, *rCell.getSharedString());
break;
case CELLTYPE_EDIT:
- rColumn.SetEditText(nRow, ScEditUtil::Clone(*rCell.mpEditText, rColumn.GetDoc()));
+ rColumn.SetEditText(nRow, ScEditUtil::Clone(*rCell.getEditText(), rColumn.GetDoc()));
break;
case CELLTYPE_VALUE:
- rColumn.SetValue(nRow, rCell.mfValue);
+ rColumn.SetValue(nRow, rCell.getDouble());
break;
case CELLTYPE_FORMULA:
{
ScAddress aDestPos(rColumn.GetCol(), nRow, rColumn.GetTab());
- rColumn.SetFormulaCell(nRow, new ScFormulaCell(*rCell.mpFormula, rColumn.GetDoc(), aDestPos));
+ rColumn.SetFormulaCell(nRow, new ScFormulaCell(*rCell.getFormula(), rColumn.GetDoc(), aDestPos));
}
break;
default:
@@ -158,111 +185,107 @@ bool hasNumericImpl( CellType eType, ScFormulaCell* pFormula )
}
}
-template<typename CellT>
-OUString getStringImpl( const CellT& rCell, const ScDocument* pDoc )
+template <typename T>
+OUString getStringImpl( const T& rCell, const ScDocument* pDoc )
{
- switch (rCell.meType)
+ switch (rCell.getType())
{
case CELLTYPE_VALUE:
- return OUString::number(rCell.mfValue);
+ return OUString::number(rCell.getDouble());
case CELLTYPE_STRING:
- return rCell.mpString->getString();
+ return rCell.getSharedString()->getString();
case CELLTYPE_EDIT:
- if (rCell.mpEditText)
- return ScEditUtil::GetString(*rCell.mpEditText, pDoc);
+ if (rCell.getEditText())
+ return ScEditUtil::GetString(*rCell.getEditText(), pDoc);
break;
case CELLTYPE_FORMULA:
- return rCell.mpFormula->GetString().getString();
+ return rCell.getFormula()->GetString().getString();
default:
;
}
- return EMPTY_OUSTRING;
+ return OUString();
}
template<typename CellT>
OUString getRawStringImpl( const CellT& rCell, const ScDocument& rDoc )
{
- switch (rCell.meType)
+ switch (rCell.getType())
{
case CELLTYPE_VALUE:
- return OUString::number(rCell.mfValue);
+ return OUString::number(rCell.getDouble());
case CELLTYPE_STRING:
- return rCell.mpString->getString();
+ return rCell.getSharedString()->getString();
case CELLTYPE_EDIT:
- if (rCell.mpEditText)
- return ScEditUtil::GetString(*rCell.mpEditText, &rDoc);
+ if (rCell.getEditText())
+ return ScEditUtil::GetString(*rCell.getEditText(), &rDoc);
break;
case CELLTYPE_FORMULA:
- return rCell.mpFormula->GetRawString().getString();
+ return rCell.getFormula()->GetRawString().getString();
default:
;
}
- return EMPTY_OUSTRING;
+ return OUString();
}
}
-ScCellValue::ScCellValue() : meType(CELLTYPE_NONE), mfValue(0.0) {}
+ScCellValue::ScCellValue() {}
-ScCellValue::ScCellValue( const ScRefCellValue& rCell ) : meType(rCell.meType), mfValue(rCell.mfValue)
+ScCellValue::ScCellValue( const ScRefCellValue& rCell )
{
- switch (rCell.meType)
+ switch (rCell.getType())
{
case CELLTYPE_STRING:
- mpString = new svl::SharedString(*rCell.mpString);
+ maData = *rCell.getSharedString();
break;
case CELLTYPE_EDIT:
- mpEditText = rCell.mpEditText->Clone().release();
+ maData = rCell.getEditText()->Clone().release();
break;
case CELLTYPE_FORMULA:
- mpFormula = rCell.mpFormula->Clone();
+ maData = rCell.getFormula()->Clone();
break;
- default:
- ;
+ case CELLTYPE_VALUE:
+ maData = rCell.getDouble();
+ break;
+ default: ;
}
}
-ScCellValue::ScCellValue( double fValue ) : meType(CELLTYPE_VALUE), mfValue(fValue) {}
+ScCellValue::ScCellValue( double fValue ) : maData(fValue) {}
+
+ScCellValue::ScCellValue( const svl::SharedString& rString ) : maData(rString) {}
-ScCellValue::ScCellValue( const svl::SharedString& rString ) : meType(CELLTYPE_STRING), mpString(new svl::SharedString(rString)) {}
+ScCellValue::ScCellValue( std::unique_ptr<EditTextObject> xEdit ) : maData(xEdit.release()) {}
-ScCellValue::ScCellValue( const ScCellValue& r ) : meType(r.meType), mfValue(r.mfValue)
+ScCellValue::ScCellValue( const ScCellValue& r )
{
- switch (r.meType)
+ switch (r.getType())
{
case CELLTYPE_STRING:
- mpString = new svl::SharedString(*r.mpString);
+ maData = *r.getSharedString();
break;
case CELLTYPE_EDIT:
- mpEditText = r.mpEditText->Clone().release();
+ maData = r.getEditText()->Clone().release();
break;
case CELLTYPE_FORMULA:
- mpFormula = r.mpFormula->Clone();
+ maData = r.getFormula()->Clone();
break;
- default:
- ;
+ case CELLTYPE_VALUE:
+ maData = r.getDouble();
+ break;
+ default: ;
}
}
+void ScCellValue::reset_to_empty()
+{
+ suppress_fun_call_w_exception(maData = std::monostate()); // reset to empty;
+}
+
ScCellValue::ScCellValue(ScCellValue&& r) noexcept
- : meType(r.meType)
- , mfValue(r.mfValue)
+ : maData(std::move(r.maData))
{
- switch (r.meType)
- {
- case CELLTYPE_STRING:
- mpString = r.mpString;
- break;
- case CELLTYPE_EDIT:
- mpEditText = r.mpEditText;
- break;
- case CELLTYPE_FORMULA:
- mpFormula = r.mpFormula;
- break;
- default:
- ;
- }
- r.meType = CELLTYPE_NONE;
+ r.reset_to_empty();
}
ScCellValue::~ScCellValue()
@@ -270,61 +293,67 @@ ScCellValue::~ScCellValue()
clear();
}
+CellType ScCellValue::getType() const
+{
+ switch (maData.index())
+ {
+ case 0: return CELLTYPE_NONE;
+ case 1: return CELLTYPE_VALUE;
+ case 2: return CELLTYPE_STRING;
+ case 3: return CELLTYPE_EDIT;
+ case 4: return CELLTYPE_FORMULA;
+ default:
+ assert(false);
+ return CELLTYPE_NONE;
+ }
+}
+
void ScCellValue::clear() noexcept
{
- switch (meType)
+ switch (getType())
{
- case CELLTYPE_STRING:
- delete mpString;
- break;
case CELLTYPE_EDIT:
- delete mpEditText;
+ suppress_fun_call_w_exception(delete getEditText());
break;
case CELLTYPE_FORMULA:
- delete mpFormula;
+ suppress_fun_call_w_exception(delete getFormula());
break;
default:
;
}
// Reset to empty value.
- meType = CELLTYPE_NONE;
- mfValue = 0.0;
+ reset_to_empty();
}
void ScCellValue::set( double fValue )
{
clear();
- meType = CELLTYPE_VALUE;
- mfValue = fValue;
+ maData = fValue;
}
void ScCellValue::set( const svl::SharedString& rStr )
{
clear();
- meType = CELLTYPE_STRING;
- mpString = new svl::SharedString(rStr);
+ maData = rStr;
}
void ScCellValue::set( const EditTextObject& rEditText )
{
clear();
- meType = CELLTYPE_EDIT;
- mpEditText = rEditText.Clone().release();
+ maData = rEditText.Clone().release();
}
-void ScCellValue::set( EditTextObject* pEditText )
+void ScCellValue::set( std::unique_ptr<EditTextObject> xEditText )
{
clear();
- meType = CELLTYPE_EDIT;
- mpEditText = pEditText;
+ maData = xEditText.release();
}
void ScCellValue::set( ScFormulaCell* pFormula )
{
clear();
- meType = CELLTYPE_FORMULA;
- mpFormula = pFormula;
+ maData = pFormula;
}
void ScCellValue::assign( const ScDocument& rDoc, const ScAddress& rPos )
@@ -333,24 +362,21 @@ void ScCellValue::assign( const ScDocument& rDoc, const ScAddress& rPos )
ScRefCellValue aRefVal(const_cast<ScDocument&>(rDoc), rPos);
- meType = aRefVal.meType;
- switch (meType)
+ switch (aRefVal.getType())
{
case CELLTYPE_STRING:
- mpString = new svl::SharedString(*aRefVal.mpString);
+ maData = *aRefVal.getSharedString();
break;
case CELLTYPE_EDIT:
- if (aRefVal.mpEditText)
- mpEditText = aRefVal.mpEditText->Clone().release();
+ maData = aRefVal.getEditText() ? aRefVal.getEditText()->Clone().release() : static_cast<EditTextObject*>(nullptr);
break;
case CELLTYPE_VALUE:
- mfValue = aRefVal.mfValue;
+ maData = aRefVal.getDouble();
break;
case CELLTYPE_FORMULA:
- mpFormula = aRefVal.mpFormula->Clone();
+ maData = aRefVal.getFormula()->Clone();
break;
- default:
- meType = CELLTYPE_NONE; // reset to empty.
+ default: ; // leave empty
}
}
@@ -358,66 +384,64 @@ void ScCellValue::assign(const ScCellValue& rOther, ScDocument& rDestDoc, ScClon
{
clear();
- meType = rOther.meType;
- switch (meType)
+ switch (rOther.getType())
{
case CELLTYPE_STRING:
- mpString = new svl::SharedString(*rOther.mpString);
+ maData = rOther.maData;
break;
case CELLTYPE_EDIT:
{
// Switch to the pool of the destination document.
ScFieldEditEngine& rEngine = rDestDoc.GetEditEngine();
- if (rOther.mpEditText->HasOnlineSpellErrors())
+ if (rOther.getEditText()->HasOnlineSpellErrors())
{
EEControlBits nControl = rEngine.GetControlWord();
const EEControlBits nSpellControl = EEControlBits::ONLINESPELLING | EEControlBits::ALLOWBIGOBJS;
bool bNewControl = ((nControl & nSpellControl) != nSpellControl);
if (bNewControl)
rEngine.SetControlWord(nControl | nSpellControl);
- rEngine.SetTextCurrentDefaults(*rOther.mpEditText);
- mpEditText = rEngine.CreateTextObject().release();
+ rEngine.SetTextCurrentDefaults(*rOther.getEditText());
+ maData = rEngine.CreateTextObject().release();
if (bNewControl)
rEngine.SetControlWord(nControl);
}
else
{
- rEngine.SetTextCurrentDefaults(*rOther.mpEditText);
- mpEditText = rEngine.CreateTextObject().release();
+ rEngine.SetTextCurrentDefaults(*rOther.getEditText());
+ maData = rEngine.CreateTextObject().release();
}
}
break;
case CELLTYPE_VALUE:
- mfValue = rOther.mfValue;
+ maData = rOther.maData;
break;
case CELLTYPE_FORMULA:
// Switch to the destination document.
- mpFormula = new ScFormulaCell(*rOther.mpFormula, rDestDoc, rOther.mpFormula->aPos, nCloneFlags);
+ maData = new ScFormulaCell(*rOther.getFormula(), rDestDoc, rOther.getFormula()->aPos, nCloneFlags);
break;
- default:
- meType = CELLTYPE_NONE; // reset to empty.
+ default: ; // leave empty
}
}
void ScCellValue::commit( ScDocument& rDoc, const ScAddress& rPos ) const
{
- switch (meType)
+ switch (getType())
{
case CELLTYPE_STRING:
{
ScSetStringParam aParam;
aParam.setTextInput();
- rDoc.SetString(rPos, mpString->getString(), &aParam);
+ rDoc.SetString(rPos, getSharedString()->getString(), &aParam);
}
break;
case CELLTYPE_EDIT:
- rDoc.SetEditText(rPos, mpEditText->Clone());
+ rDoc.SetEditText(rPos, getEditText()->Clone());
break;
case CELLTYPE_VALUE:
- rDoc.SetValue(rPos, mfValue);
+ rDoc.SetValue(rPos, getDouble());
break;
case CELLTYPE_FORMULA:
- rDoc.SetFormulaCell(rPos, mpFormula->Clone());
+ rDoc.SetFormulaCell(rPos, getFormula()->Clone());
break;
default:
rDoc.SetEmptyCell(rPos);
@@ -431,64 +455,60 @@ void ScCellValue::commit( ScColumn& rColumn, SCROW nRow ) const
void ScCellValue::release( ScDocument& rDoc, const ScAddress& rPos )
{
- switch (meType)
+ switch (getType())
{
case CELLTYPE_STRING:
{
// Currently, string cannot be placed without copying.
ScSetStringParam aParam;
aParam.setTextInput();
- rDoc.SetString(rPos, mpString->getString(), &aParam);
- delete mpString;
+ rDoc.SetString(rPos, getSharedString()->getString(), &aParam);
}
break;
case CELLTYPE_EDIT:
// Cell takes the ownership of the text object.
- rDoc.SetEditText(rPos, std::unique_ptr<EditTextObject>(mpEditText));
+ rDoc.SetEditText(rPos, std::unique_ptr<EditTextObject>(getEditText()));
break;
case CELLTYPE_VALUE:
- rDoc.SetValue(rPos, mfValue);
+ rDoc.SetValue(rPos, getDouble());
break;
case CELLTYPE_FORMULA:
// This formula cell instance is directly placed in the document without copying.
- rDoc.SetFormulaCell(rPos, mpFormula);
+ rDoc.SetFormulaCell(rPos, getFormula());
break;
default:
rDoc.SetEmptyCell(rPos);
}
- meType = CELLTYPE_NONE;
- mfValue = 0.0;
+ reset_to_empty(); // reset to empty
}
void ScCellValue::release( ScColumn& rColumn, SCROW nRow, sc::StartListeningType eListenType )
{
- switch (meType)
+ switch (getType())
{
case CELLTYPE_STRING:
{
// Currently, string cannot be placed without copying.
- rColumn.SetRawString(nRow, *mpString);
- delete mpString;
+ rColumn.SetRawString(nRow, *getSharedString());
}
break;
case CELLTYPE_EDIT:
// Cell takes the ownership of the text object.
- rColumn.SetEditText(nRow, std::unique_ptr<EditTextObject>(mpEditText));
+ rColumn.SetEditText(nRow, std::unique_ptr<EditTextObject>(getEditText()));
break;
case CELLTYPE_VALUE:
- rColumn.SetValue(nRow, mfValue);
+ rColumn.SetValue(nRow, getDouble());
break;
case CELLTYPE_FORMULA:
// This formula cell instance is directly placed in the document without copying.
- rColumn.SetFormulaCell(nRow, mpFormula, eListenType);
+ rColumn.SetFormulaCell(nRow, getFormula(), eListenType);
break;
default:
rColumn.DeleteContent(nRow);
}
- meType = CELLTYPE_NONE;
- mfValue = 0.0;
+ reset_to_empty(); // reset to empty
}
OUString ScCellValue::getString( const ScDocument& rDoc ) const
@@ -498,7 +518,7 @@ OUString ScCellValue::getString( const ScDocument& rDoc ) const
bool ScCellValue::isEmpty() const
{
- return meType == CELLTYPE_NONE;
+ return getType() == CELLTYPE_NONE;
}
bool ScCellValue::equalsWithoutFormat( const ScCellValue& r ) const
@@ -516,27 +536,8 @@ ScCellValue& ScCellValue::operator= ( const ScCellValue& r )
ScCellValue& ScCellValue::operator=(ScCellValue&& rCell) noexcept
{
clear();
-
- meType = rCell.meType;
- mfValue = rCell.mfValue;
- switch (rCell.meType)
- {
- case CELLTYPE_STRING:
- mpString = rCell.mpString;
- break;
- case CELLTYPE_EDIT:
- mpEditText = rCell.mpEditText;
- break;
- case CELLTYPE_FORMULA:
- mpFormula = rCell.mpFormula;
- break;
- default:
- ;
- }
- //we don't need to reset mpString/mpEditText/mpFormula if we
- //set meType to NONE as the ScCellValue dtor keys off the meType
- rCell.meType = CELLTYPE_NONE;
-
+ maData = std::move(rCell.maData);
+ rCell.reset_to_empty(); // reset to empty;
return *this;
}
@@ -549,11 +550,7 @@ ScCellValue& ScCellValue::operator= ( const ScRefCellValue& r )
void ScCellValue::swap( ScCellValue& r )
{
- std::swap(meType, r.meType);
-
- // double is 8 bytes, whereas a pointer may be 4 or 8 bytes depending on
- // the platform. Swap by double values.
- std::swap(mfValue, r.mfValue);
+ std::swap(maData, r.maData);
}
ScRefCellValue::ScRefCellValue() : meType(CELLTYPE_NONE), mfValue(0.0) {}
diff --git a/sc/source/core/data/cellvalues.cxx b/sc/source/core/data/cellvalues.cxx
index 290dc0d091a9..d23d7a9eccca 100644
--- a/sc/source/core/data/cellvalues.cxx
+++ b/sc/source/core/data/cellvalues.cxx
@@ -11,6 +11,7 @@
#include <cellvalues.hxx>
#include <column.hxx>
#include <formulacell.hxx>
+#include <editeng/editobj.hxx>
#include <cassert>
@@ -147,6 +148,12 @@ void CellValues::setValue( size_t nRow, const svl::SharedString& rStr )
mpImpl->miAttrPos = mpImpl->maCellTextAttrs.set(mpImpl->miAttrPos, nRow, sc::CellTextAttr());
}
+void CellValues::setValue( size_t nRow, std::unique_ptr<EditTextObject> pEditText )
+{
+ mpImpl->miCellPos = mpImpl->maCells.set(mpImpl->miCellPos, nRow, pEditText.release());
+ mpImpl->miAttrPos = mpImpl->maCellTextAttrs.set(mpImpl->miAttrPos, nRow, sc::CellTextAttr());
+}
+
void CellValues::swap( CellValues& r )
{
std::swap(mpImpl, r.mpImpl);
diff --git a/sc/source/core/data/clipcontext.cxx b/sc/source/core/data/clipcontext.cxx
index f0e5db210fbd..bccbdf0a086e 100644
--- a/sc/source/core/data/clipcontext.cxx
+++ b/sc/source/core/data/clipcontext.cxx
@@ -14,12 +14,13 @@
#include <column.hxx>
#include <scitems.hxx>
#include <tokenarray.hxx>
-#include <editutil.hxx>
#include <clipparam.hxx>
#include <svl/intitem.hxx>
+#include <svl/numformat.hxx>
#include <formula/errorcodes.hxx>
#include <refdata.hxx>
+#include <listenercontext.hxx>
namespace sc {
@@ -35,7 +36,7 @@ ColumnBlockPosition* ClipContextBase::getBlockPosition(SCTAB nTab, SCCOL nCol)
CopyFromClipContext::CopyFromClipContext(ScDocument& rDoc,
ScDocument* pRefUndoDoc, ScDocument* pClipDoc, InsertDeleteFlags nInsertFlag,
- bool bAsLink, bool bSkipAttrForEmptyCells) :
+ bool bAsLink, bool bSkipEmptyCells) :
ClipContextBase(rDoc),
mnDestCol1(-1), mnDestCol2(-1),
mnDestRow1(-1), mnDestRow2(-1),
@@ -44,8 +45,7 @@ CopyFromClipContext::CopyFromClipContext(ScDocument& rDoc,
mpRefUndoDoc(pRefUndoDoc), mpClipDoc(pClipDoc),
mnInsertFlag(nInsertFlag), mnDeleteFlag(InsertDeleteFlags::NONE),
mpCondFormatList(nullptr),
- mbAsLink(bAsLink), mbSkipAttrForEmptyCells(bSkipAttrForEmptyCells),
- mbCloneNotes (mnInsertFlag & (InsertDeleteFlags::NOTE|InsertDeleteFlags::ADDNOTES)),
+ mbAsLink(bAsLink), mbSkipEmptyCells(bSkipEmptyCells),
mbTableProtected(false)
{
}
@@ -113,12 +113,59 @@ InsertDeleteFlags CopyFromClipContext::getDeleteFlag() const
return mnDeleteFlag;
}
+void CopyFromClipContext::setListeningFormulaSpans(
+ SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
+{
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+ maListeningFormulaSpans.set(mrDestDoc, nTab, nCol, nRow1, nRow2, true);
+}
+
+namespace {
+
+class StartListeningAction : public sc::ColumnSpanSet::Action
+{
+ ScDocument& mrDestDoc;
+ sc::StartListeningContext& mrStartCxt;
+ sc::EndListeningContext& mrEndCxt;
+
+public:
+ StartListeningAction( ScDocument& rDestDoc, sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt ) :
+ mrDestDoc(rDestDoc), mrStartCxt(rStartCxt), mrEndCxt(rEndCxt)
+ {
+ }
+
+ virtual void execute( const ScAddress& rPos, SCROW nLength, bool bVal ) override
+ {
+ if (!bVal)
+ return;
+
+ SCROW nRow1 = rPos.Row();
+ SCROW nRow2 = nRow1 + nLength - 1;
+
+ mrDestDoc.StartListeningFromClip(
+ mrStartCxt, mrEndCxt, rPos.Tab(), rPos.Col(), nRow1, rPos.Col(), nRow2);
+ }
+};
+
+}
+
+void CopyFromClipContext::startListeningFormulas()
+{
+ auto pSet = std::make_shared<sc::ColumnBlockPositionSet>(mrDestDoc);
+ sc::StartListeningContext aStartCxt(mrDestDoc, pSet);
+ sc::EndListeningContext aEndCxt(mrDestDoc, pSet, nullptr);
+
+ StartListeningAction aAction(mrDestDoc, aStartCxt, aEndCxt);
+ maListeningFormulaSpans.executeAction(mrDestDoc, aAction);
+}
+
void CopyFromClipContext::setSingleCellColumnSize( size_t nSize )
{
maSingleCells.resize(nSize);
maSingleCellAttrs.resize(nSize);
maSinglePatterns.resize(nSize, nullptr);
maSingleNotes.resize(nSize, nullptr);
+ maSingleSparkline.resize(nSize);
}
ScCellValue& CopyFromClipContext::getSingleCell( size_t nColOffset )
@@ -169,7 +216,7 @@ void CopyFromClipContext::setSingleCell( const ScAddress& rSrcPos, const ScColum
bool bBoolean = (nFlags & InsertDeleteFlags::SPECIAL_BOOLEAN) != InsertDeleteFlags::NONE;
bool bFormula = (nFlags & InsertDeleteFlags::FORMULA) != InsertDeleteFlags::NONE;
- switch (rSrcCell.meType)
+ switch (rSrcCell.getType())
{
case CELLTYPE_VALUE:
{
@@ -192,7 +239,7 @@ void CopyFromClipContext::setSingleCell( const ScAddress& rSrcPos, const ScColum
if (bBoolean)
{
// Check if this formula cell is a boolean cell, and if so, go ahead and paste it.
- const ScTokenArray* pCode = rSrcCell.mpFormula->GetCode();
+ const ScTokenArray* pCode = rSrcCell.getFormula()->GetCode();
if (pCode && pCode->GetLen() == 1)
{
const formula::FormulaToken* p = pCode->FirstToken();
@@ -206,7 +253,7 @@ void CopyFromClipContext::setSingleCell( const ScAddress& rSrcPos, const ScColum
// Good.
break;
- FormulaError nErr = rSrcCell.mpFormula->GetErrCode();
+ FormulaError nErr = rSrcCell.getFormula()->GetErrCode();
if (nErr != FormulaError::NONE)
{
// error codes are cloned with values
@@ -221,12 +268,12 @@ void CopyFromClipContext::setSingleCell( const ScAddress& rSrcPos, const ScColum
rSrcCell.set(pErrCell);
}
}
- else if (rSrcCell.mpFormula->IsEmptyDisplayedAsString())
+ else if (rSrcCell.getFormula()->IsEmptyDisplayedAsString())
{
// Empty stays empty and doesn't become 0.
rSrcCell.clear();
}
- else if (rSrcCell.mpFormula->IsValue())
+ else if (rSrcCell.getFormula()->IsValue())
{
bool bPaste = isDateCell(rSrcCol, rSrcPos.Row()) ? bDateTime : bNumeric;
if (!bPaste)
@@ -237,11 +284,11 @@ void CopyFromClipContext::setSingleCell( const ScAddress& rSrcPos, const ScColum
}
// Turn this into a numeric cell.
- rSrcCell.set(rSrcCell.mpFormula->GetValue());
+ rSrcCell.set(rSrcCell.getFormula()->GetValue());
}
else if (bString)
{
- svl::SharedString aStr = rSrcCell.mpFormula->GetString();
+ svl::SharedString aStr = rSrcCell.getFormula()->GetString();
if (aStr.isEmpty())
{
// do not clone empty string
@@ -250,18 +297,14 @@ void CopyFromClipContext::setSingleCell( const ScAddress& rSrcPos, const ScColum
}
// Turn this into a string or edit cell.
- if (rSrcCell.mpFormula->IsMultilineResult())
+ if (rSrcCell.getFormula()->IsMultilineResult())
{
- // TODO : Add shared string support to the edit engine to
- // make this process simpler.
- ScFieldEditEngine& rEngine = mrDestDoc.GetEditEngine();
- rEngine.SetTextCurrentDefaults(rSrcCell.mpFormula->GetString().getString());
- std::unique_ptr<EditTextObject> pObj(rEngine.CreateTextObject());
- pObj->NormalizeString(mrDestDoc.GetSharedStringPool());
+ std::unique_ptr<EditTextObject> pObj(mrDestDoc.CreateSharedStringTextObject(
+ rSrcCell.getFormula()->GetString()));
rSrcCell.set(*pObj);
}
else
- rSrcCell.set(rSrcCell.mpFormula->GetString());
+ rSrcCell.set(rSrcCell.getFormula()->GetString());
}
else
// We don't want to paste this.
@@ -299,6 +342,18 @@ void CopyFromClipContext::setSingleCellNote( size_t nColOffset, const ScPostIt*
maSingleNotes[nColOffset] = pNote;
}
+std::shared_ptr<sc::Sparkline> const& CopyFromClipContext::getSingleSparkline(size_t nColOffset) const
+{
+ assert(nColOffset < maSingleSparkline.size());
+ return maSingleSparkline[nColOffset];
+}
+
+void CopyFromClipContext::setSingleSparkline(size_t nColOffset, std::shared_ptr<sc::Sparkline> const& pSparkline)
+{
+ assert(nColOffset < maSingleSparkline.size());
+ maSingleSparkline[nColOffset] = pSparkline;
+}
+
void CopyFromClipContext::setCondFormatList( ScConditionalFormatList* pCondFormatList )
{
mpCondFormatList = pCondFormatList;
@@ -324,26 +379,31 @@ bool CopyFromClipContext::isAsLink() const
return mbAsLink;
}
-bool CopyFromClipContext::isSkipAttrForEmptyCells() const
+bool CopyFromClipContext::isSkipEmptyCells() const
{
- return mbSkipAttrForEmptyCells;
+ return mbSkipEmptyCells;
}
bool CopyFromClipContext::isCloneNotes() const
{
- return mbCloneNotes;
+ return bool(mnInsertFlag & (InsertDeleteFlags::NOTE | InsertDeleteFlags::ADDNOTES));
+}
+
+bool CopyFromClipContext::isCloneSparklines() const
+{
+ return bool(mnInsertFlag & InsertDeleteFlags::SPARKLINES);
}
bool CopyFromClipContext::isDateCell( const ScColumn& rCol, SCROW nRow ) const
{
- sal_uLong nNumIndex = rCol.GetAttr(nRow, ATTR_VALUE_FORMAT).GetValue();
+ sal_uInt32 nNumIndex = rCol.GetAttr(nRow, ATTR_VALUE_FORMAT).GetValue();
SvNumFormatType nType = mpClipDoc->GetFormatTable()->GetType(nNumIndex);
return (nType == SvNumFormatType::DATE) || (nType == SvNumFormatType::TIME) || (nType == SvNumFormatType::DATETIME);
}
CopyToClipContext::CopyToClipContext(
- ScDocument& rDoc, bool bKeepScenarioFlags) :
- ClipContextBase(rDoc), mbKeepScenarioFlags(bKeepScenarioFlags) {}
+ ScDocument& rDoc, bool bKeepScenarioFlags, bool bCopyChartRanges) :
+ ClipContextBase(rDoc), mbKeepScenarioFlags(bKeepScenarioFlags), mbCopyChartRanges(bCopyChartRanges) {}
CopyToClipContext::~CopyToClipContext() {}
diff --git a/sc/source/core/data/colorscale.cxx b/sc/source/core/data/colorscale.cxx
index 52496653ab1b..963ee78c05d3 100644
--- a/sc/source/core/data/colorscale.cxx
+++ b/sc/source/core/data/colorscale.cxx
@@ -16,13 +16,14 @@
#include <tokenarray.hxx>
#include <refupdatecontext.hxx>
#include <refdata.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <scitems.hxx>
#include <formula/token.hxx>
#include <vcl/bitmapex.hxx>
#include <algorithm>
#include <cassert>
-#include <string_view>
ScFormulaListener::ScFormulaListener(ScFormulaCell* pCell):
mbDirty(false),
@@ -153,15 +154,17 @@ bool ScFormulaListener::NeedsRepaint() const
ScColorScaleEntry::ScColorScaleEntry():
mnVal(0),
mpFormat(nullptr),
- meType(COLORSCALE_VALUE)
+ meType(COLORSCALE_VALUE),
+ meMode(ScConditionMode::Equal)
{
}
-ScColorScaleEntry::ScColorScaleEntry(double nVal, const Color& rCol, ScColorScaleEntryType eType):
+ScColorScaleEntry::ScColorScaleEntry(double nVal, const Color& rCol, ScColorScaleEntryType eType, ScConditionMode eMode):
mnVal(nVal),
mpFormat(nullptr),
maColor(rCol),
- meType(eType)
+ meType(eType),
+ meMode(eMode)
{
}
@@ -169,7 +172,8 @@ ScColorScaleEntry::ScColorScaleEntry(const ScColorScaleEntry& rEntry):
mnVal(rEntry.mnVal),
mpFormat(rEntry.mpFormat),
maColor(rEntry.maColor),
- meType(rEntry.meType)
+ meType(rEntry.meType),
+ meMode(rEntry.meMode)
{
setListener();
if(rEntry.mpCell)
@@ -182,15 +186,15 @@ ScColorScaleEntry::ScColorScaleEntry(const ScColorScaleEntry& rEntry):
ScColorScaleEntry::ScColorScaleEntry(ScDocument* pDoc, const ScColorScaleEntry& rEntry):
mnVal(rEntry.mnVal),
- mpCell(),
mpFormat(rEntry.mpFormat),
maColor(rEntry.maColor),
- meType(rEntry.meType)
+ meType(rEntry.meType),
+ meMode(rEntry.meMode)
{
setListener();
if(rEntry.mpCell)
{
- mpCell.reset(new ScFormulaCell(*rEntry.mpCell, rEntry.mpCell->GetDocument(), rEntry.mpCell->aPos, ScCloneFlags::NoMakeAbsExternal));
+ mpCell.reset(new ScFormulaCell(*rEntry.mpCell, *pDoc, rEntry.mpCell->aPos, ScCloneFlags::NoMakeAbsExternal));
mpCell->StartListeningTo( *pDoc );
mpListener.reset(new ScFormulaListener(mpCell.get()));
if (mpFormat)
@@ -225,13 +229,12 @@ const ScTokenArray* ScColorScaleEntry::GetFormula() const
OUString ScColorScaleEntry::GetFormula( formula::FormulaGrammar::Grammar eGrammar ) const
{
- OUString aFormula;
if(mpCell)
{
- mpCell->GetFormula(aFormula, eGrammar);
+ return mpCell->GetFormula(eGrammar);
}
- return aFormula;
+ return OUString();
}
double ScColorScaleEntry::GetValue() const
@@ -379,6 +382,9 @@ ScColorScaleFormat::ScColorScaleFormat(ScDocument* pDoc, const ScColorScaleForma
{
maColorScales.emplace_back(new ScColorScaleEntry(pDoc, *rxEntry));
}
+
+ auto aCache = rFormat.GetCache();
+ SetCache(aCache);
}
ScColorFormat* ScColorScaleFormat::Clone(ScDocument* pDoc) const
@@ -405,6 +411,24 @@ void ScColorScaleFormat::AddEntry( ScColorScaleEntry* pEntry )
maColorScales.back()->SetRepaintCallback(mpParent);
}
+bool ScColorScaleFormat::IsEqual(const ScFormatEntry& rOther, bool /*bIgnoreSrcPos*/) const
+{
+ if (GetType() != rOther.GetType())
+ return false;
+
+ const ScColorScaleFormat& r = static_cast<const ScColorScaleFormat&>(rOther);
+
+ for (size_t i = 0; i < maColorScales.size(); ++i)
+ {
+ if (!maColorScales[i]->GetColor().IsRGBEqual(r.maColorScales[i]->GetColor().GetRGBColor())
+ || maColorScales[i]->GetType() != r.maColorScales[i]->GetType()
+ || maColorScales[i]->GetValue() != r.maColorScales[i]->GetValue())
+ return false;
+ }
+
+ return true;
+}
+
double ScColorScaleFormat::GetMinValue() const
{
ScColorScaleEntries::const_iterator itr = maColorScales.begin();
@@ -440,12 +464,41 @@ const ScRangeList& ScColorFormat::GetRange() const
return mpParent->GetRange();
}
+std::vector<double> ScColorFormat::GetCache() const
+{
+ if (!mpParent)
+ return {};
+
+ std::vector<double>* pRes = mpParent->GetCache();
+ if (pRes)
+ return *pRes;
+
+ return {};
+}
+
+void ScColorFormat::SetCache(const std::vector<double>& aValues) const
+{
+ if (!mpParent)
+ return;
+
+ mpParent->SetCache(aValues);
+}
+
std::vector<double>& ScColorFormat::getValues() const
{
- if(!mpCache)
+ assert(mpParent);
+
+ std::vector<double>* pCache = mpParent->GetCache();
+ if (!pCache || pCache->empty())
{
- mpCache.reset(new ScColorFormatCache);
- std::vector<double>& rValues = mpCache->maValues;
+ if (!pCache)
+ {
+ SetCache({});
+ pCache = mpParent->GetCache();
+ assert(pCache);
+ }
+
+ std::vector<double>& rValues = *pCache;
size_t n = GetRange().size();
const ScRangeList& aRanges = GetRange();
@@ -459,7 +512,7 @@ std::vector<double>& ScColorFormat::getValues() const
SCCOL nColEnd = rRange.aEnd.Col();
SCROW nRowEnd = rRange.aEnd.Row();
- if(nRowEnd == MAXROW)
+ if(nRowEnd == mpDoc->MaxRow())
{
bool bShrunk = false;
mpDoc->ShrinkToUsedDataArea(bShrunk, nTab, nColStart, nRowStart,
@@ -483,7 +536,7 @@ std::vector<double>& ScColorFormat::getValues() const
std::sort(rValues.begin(), rValues.end());
}
- return mpCache->maValues;
+ return *pCache;
}
double ScColorFormat::getMinValue() const
@@ -504,12 +557,16 @@ double ScColorFormat::getMaxValue() const
void ScColorFormat::startRendering()
{
- mpCache.reset();
}
void ScColorFormat::endRendering()
{
- mpCache.reset();
+}
+
+void ScColorFormat::updateValues()
+{
+ getMinValue();
+ getMaxValue();
}
namespace {
@@ -541,9 +598,15 @@ Color CalcColor( double nVal, double nVal1, const Color& rCol1, double nVal2, co
*/
double GetPercentile( const std::vector<double>& rArray, double fPercentile )
{
+ assert(!rArray.empty());
+ SAL_WARN_IF(fPercentile < 0, "sc", "negative percentile");
+ if (fPercentile < 0)
+ return rArray.front();
+ assert(fPercentile <= 1);
size_t nSize = rArray.size();
- size_t nIndex = static_cast<size_t>(::rtl::math::approxFloor( fPercentile * (nSize-1)));
- double fDiff = fPercentile * (nSize-1) - ::rtl::math::approxFloor( fPercentile * (nSize-1));
+ double fFloor = ::rtl::math::approxFloor(fPercentile * (nSize-1));
+ size_t nIndex = static_cast<size_t>(fFloor);
+ double fDiff = fPercentile * (nSize-1) - fFloor;
std::vector<double>::const_iterator iter = rArray.begin() + nIndex;
if (fDiff == 0.0)
return *iter;
@@ -603,7 +666,7 @@ std::optional<Color> ScColorScaleFormat::GetColor( const ScAddress& rAddr ) cons
calcMinMax(nMin, nMax);
// this check is for safety
- if(nMin >= nMax)
+ if(nMin > nMax)
return std::optional<Color>();
ScColorScaleEntries::const_iterator itr = begin();
@@ -613,11 +676,15 @@ std::optional<Color> ScColorScaleFormat::GetColor( const ScAddress& rAddr ) cons
double nValMax = CalcValue(nMin, nMax, itr);
Color rColMax = (*itr)->GetColor();
+ // tdf#155321 for the last percentile value, use always the end of the color scale,
+ // i.e. not the first possible color in the case of repeating values
+ bool bEqual = COLORSCALE_PERCENTILE == (*itr)->GetType() && nVal == nMax && nVal == nValMax;
+
++itr;
- while(itr != end() && nVal > nValMax)
+ while(itr != end() && (nVal > nValMax || bEqual))
{
rColMin = rColMax;
- nValMin = nValMax;
+ nValMin = !bEqual ? nValMax : nValMax - 1;
rColMax = (*itr)->GetColor();
nValMax = CalcValue(nMin, nMax, itr);
++itr;
@@ -758,6 +825,41 @@ ScFormatEntry::Type ScDataBarFormat::GetType() const
return Type::Databar;
}
+bool ScDataBarFormat::IsEqual(const ScFormatEntry& rOther, bool /*bIgnoreSrcPos*/) const
+{
+ if (GetType() != rOther.GetType())
+ return false;
+
+ const ScDataBarFormat& r = static_cast<const ScDataBarFormat&>(rOther);
+
+ bool bEq = (mpFormatData->maAxisColor.IsRGBEqual(r.mpFormatData->maAxisColor)
+ && mpFormatData->maPositiveColor.IsRGBEqual(r.mpFormatData->maPositiveColor)
+ && mpFormatData->mxNegativeColor == r.mpFormatData->mxNegativeColor
+ && mpFormatData->meAxisPosition == r.mpFormatData->meAxisPosition
+ && mpFormatData->mbGradient == r.mpFormatData->mbGradient
+ && mpFormatData->mbOnlyBar == r.mpFormatData->mbOnlyBar);
+
+ if (mpFormatData->mpUpperLimit->GetType() == r.mpFormatData->mpUpperLimit->GetType()
+ && bEq)
+ {
+ bEq = (mpFormatData->mpUpperLimit->GetColor().IsRGBEqual(
+ r.mpFormatData->mpUpperLimit->GetColor())
+ && mpFormatData->mpUpperLimit->GetValue()
+ == r.mpFormatData->mpUpperLimit->GetValue());
+ }
+
+ if (mpFormatData->mpLowerLimit->GetType() == r.mpFormatData->mpLowerLimit->GetType()
+ && bEq)
+ {
+ bEq = (mpFormatData->mpLowerLimit->GetColor().IsRGBEqual(
+ r.mpFormatData->mpLowerLimit->GetColor())
+ && mpFormatData->mpLowerLimit->GetValue()
+ == r.mpFormatData->mpLowerLimit->GetValue());
+ }
+
+ return bEq;
+}
+
void ScDataBarFormat::UpdateReference( sc::RefUpdateContext& rCxt )
{
mpFormatData->mpUpperLimit->UpdateReference(rCxt);
@@ -968,6 +1070,30 @@ void ScDataBarFormat::EnsureSize()
}
}
+static bool Compare(double nVal1, double nVal2, const ScIconSetFormat::const_iterator& itr)
+{
+ switch ((*itr)->GetMode())
+ {
+ case ScConditionMode::Equal:
+ return nVal1 == nVal2;
+ case ScConditionMode::Less:
+ return nVal1 < nVal2;
+ case ScConditionMode::Greater:
+ return nVal1 > nVal2;
+ case ScConditionMode::EqLess:
+ return nVal1 <= nVal2;
+ case ScConditionMode::EqGreater:
+ return nVal1 >= nVal2;
+ case ScConditionMode::NotEqual:
+ return nVal1 != nVal2;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
ScIconSetFormatData::ScIconSetFormatData(ScIconSetFormatData const& rOther)
: eIconSetType(rOther.eIconSetType)
, mbShowValue(rOther.mbShowValue)
@@ -1033,30 +1159,39 @@ std::unique_ptr<ScIconSetInfo> ScIconSetFormat::GetIconSetInfo(const ScAddress&
// now we have for sure a value
double nVal = rCell.getValue();
- if (mpFormatData->m_Entries.size() < 2)
+ if (mpFormatData->m_Entries.size() < 1)
return nullptr;
double nMin = GetMinValue();
double nMax = GetMaxValue();
- sal_Int32 nIndex = 0;
+ sal_Int32 nIndex = -1;
+ ScConditionMode eMode = ScConditionMode::EqGreater;
const_iterator itr = begin();
- ++itr;
- double nValMax = CalcValue(nMin, nMax, itr);
+ double nValRef = 0;
- ++itr;
- while(itr != end() && nVal >= nValMax)
+ int i = 0;
+ while(itr != end())
{
- ++nIndex;
- nValMax = CalcValue(nMin, nMax, itr);
- ++itr;
+ nValRef = CalcValue(nMin, nMax, itr);
+ if (Compare(nVal, nValRef, itr))
+ {
+ nIndex = i;
+ eMode = (*itr)->GetMode();
+ }
+ itr++;
+ i++;
}
- if(nVal >= nValMax)
- ++nIndex;
+ if (nIndex == -1)
+ return nullptr;
std::unique_ptr<ScIconSetInfo> pInfo(new ScIconSetInfo);
+ const SfxPoolItem& rPoolItem = mpDoc->GetPattern(rAddr)->GetItem(ATTR_FONT_HEIGHT);
+ tools::Long aFontHeight = static_cast<const SvxFontHeightItem&>(rPoolItem).GetHeight();
+ pInfo->mnHeight = aFontHeight;
+
if(mpFormatData->mbReverse)
{
sal_Int32 nMaxIndex = mpFormatData->m_Entries.size() - 1;
@@ -1082,6 +1217,7 @@ std::unique_ptr<ScIconSetInfo> ScIconSetFormat::GetIconSetInfo(const ScAddress&
}
pInfo->mbShowValue = mpFormatData->mbShowValue;
+ pInfo->eConditionMode = eMode;
return pInfo;
}
@@ -1229,102 +1365,102 @@ size_t ScIconSetFormat::size() const
namespace {
-const std::u16string_view a3TrafficLights1[] = {
- u"" BMP_ICON_SET_CIRCLES1_RED, u"" BMP_ICON_SET_CIRCLES1_YELLOW, u"" BMP_ICON_SET_CIRCLES1_GREEN
+constexpr OUString a3TrafficLights1[] = {
+ BMP_ICON_SET_CIRCLES1_RED, BMP_ICON_SET_CIRCLES1_YELLOW, BMP_ICON_SET_CIRCLES1_GREEN
};
-const std::u16string_view a3TrafficLights2[] = {
- u"" BMP_ICON_SET_TRAFFICLIGHTS_RED, u"" BMP_ICON_SET_TRAFFICLIGHTS_YELLOW, u"" BMP_ICON_SET_TRAFFICLIGHTS_GREEN
+constexpr OUString a3TrafficLights2[] = {
+ BMP_ICON_SET_TRAFFICLIGHTS_RED, BMP_ICON_SET_TRAFFICLIGHTS_YELLOW, BMP_ICON_SET_TRAFFICLIGHTS_GREEN
};
-const std::u16string_view a3Arrows[] = {
- u"" BMP_ICON_SET_COLORARROWS_DOWN, u"" BMP_ICON_SET_COLORARROWS_SAME, u"" BMP_ICON_SET_COLORARROWS_UP
+constexpr OUString a3Arrows[] = {
+ BMP_ICON_SET_COLORARROWS_DOWN, BMP_ICON_SET_COLORARROWS_SAME, BMP_ICON_SET_COLORARROWS_UP
};
-const std::u16string_view a3ArrowsGray[] = {
- u"" BMP_ICON_SET_GRAYARROWS_DOWN, u"" BMP_ICON_SET_GRAYARROWS_SAME, u"" BMP_ICON_SET_GRAYARROWS_UP
+constexpr OUString a3ArrowsGray[] = {
+ BMP_ICON_SET_GRAYARROWS_DOWN, BMP_ICON_SET_GRAYARROWS_SAME, BMP_ICON_SET_GRAYARROWS_UP
};
-const std::u16string_view a3Flags[] = {
- u"" BMP_ICON_SET_FLAGS_RED, u"" BMP_ICON_SET_FLAGS_YELLOW, u"" BMP_ICON_SET_FLAGS_GREEN
+constexpr OUString a3Flags[] = {
+ BMP_ICON_SET_FLAGS_RED, BMP_ICON_SET_FLAGS_YELLOW, BMP_ICON_SET_FLAGS_GREEN
};
-const std::u16string_view a3Smilies[] = {
- u"" BMP_ICON_SET_POSITIVE_YELLOW_SMILIE, u"" BMP_ICON_SET_NEUTRAL_YELLOW_SMILIE, u"" BMP_ICON_SET_NEGATIVE_YELLOW_SMILIE
+constexpr OUString a3Smilies[] = {
+ BMP_ICON_SET_NEGATIVE_YELLOW_SMILIE, BMP_ICON_SET_NEUTRAL_YELLOW_SMILIE, BMP_ICON_SET_POSITIVE_YELLOW_SMILIE
};
-const std::u16string_view a3ColorSmilies[] = {
- u"" BMP_ICON_SET_POSITIVE_GREEN_SMILIE, u"" BMP_ICON_SET_NEUTRAL_YELLOW_SMILIE, u"" BMP_ICON_SET_NEGATIVE_RED_SMILIE
+constexpr OUString a3ColorSmilies[] = {
+ BMP_ICON_SET_NEGATIVE_RED_SMILIE, BMP_ICON_SET_NEUTRAL_YELLOW_SMILIE, BMP_ICON_SET_POSITIVE_GREEN_SMILIE
};
-const std::u16string_view a3Stars[] = {
- u"" BMP_ICON_SET_STARS_EMPTY, u"" BMP_ICON_SET_STARS_HALF, u"" BMP_ICON_SET_STARS_FULL
+constexpr OUString a3Stars[] = {
+ BMP_ICON_SET_STARS_EMPTY, BMP_ICON_SET_STARS_HALF, BMP_ICON_SET_STARS_FULL
};
-const std::u16string_view a3Triangles[] = {
- u"" BMP_ICON_SET_TRIANGLES_DOWN, u"" BMP_ICON_SET_TRIANGLES_SAME, u"" BMP_ICON_SET_TRIANGLES_UP
+constexpr OUString a3Triangles[] = {
+ BMP_ICON_SET_TRIANGLES_DOWN, BMP_ICON_SET_TRIANGLES_SAME, BMP_ICON_SET_TRIANGLES_UP
};
-const std::u16string_view a4Arrows[] = {
- u"" BMP_ICON_SET_COLORARROWS_DOWN, u"" BMP_ICON_SET_COLORARROWS_SLIGHTLY_DOWN, u"" BMP_ICON_SET_COLORARROWS_SLIGHTLY_UP, u"" BMP_ICON_SET_COLORARROWS_UP
+constexpr OUString a4Arrows[] = {
+ BMP_ICON_SET_COLORARROWS_DOWN, BMP_ICON_SET_COLORARROWS_SLIGHTLY_DOWN, BMP_ICON_SET_COLORARROWS_SLIGHTLY_UP, BMP_ICON_SET_COLORARROWS_UP
};
-const std::u16string_view a4ArrowsGray[] = {
- u"" BMP_ICON_SET_GRAYARROWS_DOWN, u"" BMP_ICON_SET_GRAYARROWS_SLIGHTLY_DOWN, u"" BMP_ICON_SET_GRAYARROWS_SLIGHTLY_UP, u"" BMP_ICON_SET_GRAYARROWS_UP
+constexpr OUString a4ArrowsGray[] = {
+ BMP_ICON_SET_GRAYARROWS_DOWN, BMP_ICON_SET_GRAYARROWS_SLIGHTLY_DOWN, BMP_ICON_SET_GRAYARROWS_SLIGHTLY_UP, BMP_ICON_SET_GRAYARROWS_UP
};
-const std::u16string_view a5Arrows[] = {
- u"" BMP_ICON_SET_COLORARROWS_DOWN, u"" BMP_ICON_SET_COLORARROWS_SLIGHTLY_DOWN,
- u"" BMP_ICON_SET_COLORARROWS_SAME, u"" BMP_ICON_SET_COLORARROWS_SLIGHTLY_UP, u"" BMP_ICON_SET_COLORARROWS_UP
+constexpr OUString a5Arrows[] = {
+ BMP_ICON_SET_COLORARROWS_DOWN, BMP_ICON_SET_COLORARROWS_SLIGHTLY_DOWN,
+ BMP_ICON_SET_COLORARROWS_SAME, BMP_ICON_SET_COLORARROWS_SLIGHTLY_UP, BMP_ICON_SET_COLORARROWS_UP
};
-const std::u16string_view a5ArrowsGray[] = {
- u"" BMP_ICON_SET_GRAYARROWS_DOWN, u"" BMP_ICON_SET_GRAYARROWS_SLIGHTLY_DOWN,
- u"" BMP_ICON_SET_GRAYARROWS_SAME, u"" BMP_ICON_SET_GRAYARROWS_SLIGHTLY_UP, u"" BMP_ICON_SET_GRAYARROWS_UP
+constexpr OUString a5ArrowsGray[] = {
+ BMP_ICON_SET_GRAYARROWS_DOWN, BMP_ICON_SET_GRAYARROWS_SLIGHTLY_DOWN,
+ BMP_ICON_SET_GRAYARROWS_SAME, BMP_ICON_SET_GRAYARROWS_SLIGHTLY_UP, BMP_ICON_SET_GRAYARROWS_UP
};
-const std::u16string_view a4TrafficLights[] = {
- u"" BMP_ICON_SET_CIRCLES1_GRAY, u"" BMP_ICON_SET_CIRCLES1_RED,
- u"" BMP_ICON_SET_CIRCLES1_YELLOW, u"" BMP_ICON_SET_CIRCLES1_GREEN
+constexpr OUString a4TrafficLights[] = {
+ BMP_ICON_SET_CIRCLES1_GRAY, BMP_ICON_SET_CIRCLES1_RED,
+ BMP_ICON_SET_CIRCLES1_YELLOW, BMP_ICON_SET_CIRCLES1_GREEN
};
-const std::u16string_view a5Quarters[] = {
- u"" BMP_ICON_SET_PIES_EMPTY, u"" BMP_ICON_SET_PIES_ONE_QUARTER, u"" BMP_ICON_SET_PIES_HALF,
- u"" BMP_ICON_SET_PIES_THREE_QUARTER, u"" BMP_ICON_SET_PIES_FULL,
+constexpr OUString a5Quarters[] = {
+ BMP_ICON_SET_PIES_EMPTY, BMP_ICON_SET_PIES_ONE_QUARTER, BMP_ICON_SET_PIES_HALF,
+ BMP_ICON_SET_PIES_THREE_QUARTER, BMP_ICON_SET_PIES_FULL,
};
-const std::u16string_view a5Boxes[] = {
- u"" BMP_ICON_SET_SQUARES_EMPTY, u"" BMP_ICON_SET_SQUARES_ONE_QUARTER,
- u"" BMP_ICON_SET_SQUARES_HALF, u"" BMP_ICON_SET_SQUARES_THREE_QUARTER,
- u"" BMP_ICON_SET_SQUARES_FULL
+constexpr OUString a5Boxes[] = {
+ BMP_ICON_SET_SQUARES_EMPTY, BMP_ICON_SET_SQUARES_ONE_QUARTER,
+ BMP_ICON_SET_SQUARES_HALF, BMP_ICON_SET_SQUARES_THREE_QUARTER,
+ BMP_ICON_SET_SQUARES_FULL
};
-const std::u16string_view a3Symbols1[] = {
- u"" BMP_ICON_SET_SYMBOLS1_CROSS, u"" BMP_ICON_SET_SYMBOLS1_EXCLAMATION_MARK, u"" BMP_ICON_SET_SYMBOLS1_CHECK
+constexpr OUString a3Symbols1[] = {
+ BMP_ICON_SET_SYMBOLS1_CROSS, BMP_ICON_SET_SYMBOLS1_EXCLAMATION_MARK, BMP_ICON_SET_SYMBOLS1_CHECK
};
-const std::u16string_view a3Signs[] = {
- u"" BMP_ICON_SET_SHAPES_DIAMOND, u"" BMP_ICON_SET_SHAPES_TRIANGLE, u"" BMP_ICON_SET_SHAPES_CIRCLE
+constexpr OUString a3Signs[] = {
+ BMP_ICON_SET_SHAPES_DIAMOND, BMP_ICON_SET_SHAPES_TRIANGLE, BMP_ICON_SET_SHAPES_CIRCLE
};
-const std::u16string_view a4RedToBlack[] = {
- u"" BMP_ICON_SET_CIRCLES2_DARK_GRAY, u"" BMP_ICON_SET_CIRCLES2_LIGHT_GRAY,
- u"" BMP_ICON_SET_CIRCLES2_LIGHT_RED, u"" BMP_ICON_SET_CIRCLES2_DARK_RED
+constexpr OUString a4RedToBlack[] = {
+ BMP_ICON_SET_CIRCLES2_DARK_GRAY, BMP_ICON_SET_CIRCLES2_LIGHT_GRAY,
+ BMP_ICON_SET_CIRCLES2_LIGHT_RED, BMP_ICON_SET_CIRCLES2_DARK_RED
};
-const std::u16string_view a4Ratings[] = {
- u"" BMP_ICON_SET_BARS_ONE_QUARTER, u"" BMP_ICON_SET_BARS_HALF,
- u"" BMP_ICON_SET_BARS_THREE_QUARTER, u"" BMP_ICON_SET_BARS_FULL
+constexpr OUString a4Ratings[] = {
+ BMP_ICON_SET_BARS_ONE_QUARTER, BMP_ICON_SET_BARS_HALF,
+ BMP_ICON_SET_BARS_THREE_QUARTER, BMP_ICON_SET_BARS_FULL
};
-const std::u16string_view a5Ratings[] = {
- u"" BMP_ICON_SET_BARS_EMPTY, u"" BMP_ICON_SET_BARS_ONE_QUARTER, u"" BMP_ICON_SET_BARS_HALF,
- u"" BMP_ICON_SET_BARS_THREE_QUARTER, u"" BMP_ICON_SET_BARS_FULL
+constexpr OUString a5Ratings[] = {
+ BMP_ICON_SET_BARS_EMPTY, BMP_ICON_SET_BARS_ONE_QUARTER, BMP_ICON_SET_BARS_HALF,
+ BMP_ICON_SET_BARS_THREE_QUARTER, BMP_ICON_SET_BARS_FULL
};
struct ScIconSetBitmapMap {
ScIconSetType eType;
- const std::u16string_view* pBitmaps;
+ const OUString* pBitmaps;
};
const ScIconSetBitmapMap aBitmapMap[] = {
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 8cdbf7e9386c..f744f741f1b5 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -20,9 +20,9 @@
#include <column.hxx>
#include <scitems.hxx>
#include <formulacell.hxx>
+#include <docsh.hxx>
#include <document.hxx>
#include <table.hxx>
-#include <docpool.hxx>
#include <attarray.hxx>
#include <patattr.hxx>
#include <compiler.hxx>
@@ -43,8 +43,10 @@
#include <formulagroup.hxx>
#include <drwlayer.hxx>
#include <mtvelements.hxx>
+#include <bcaslot.hxx>
-#include <svl/poolcach.hxx>
+#include <svl/numformat.hxx>
+#include <poolcach.hxx>
#include <svl/zforlist.hxx>
#include <svl/sharedstringpool.hxx>
#include <editeng/fieldupdater.hxx>
@@ -73,21 +75,23 @@ bool IsAmbiguousScriptNonZero( SvtScriptType nScript )
}
ScNeededSizeOptions::ScNeededSizeOptions() :
- pPattern(nullptr), bFormula(false), bSkipMerged(true), bGetFont(true), bTotalSize(false)
+ aPattern(), bFormula(false), bSkipMerged(true), bGetFont(true), bTotalSize(false)
{
}
ScColumn::ScColumn(ScSheetLimits const & rSheetLimits) :
maCellTextAttrs(rSheetLimits.GetMaxRowCount()),
- maCellNotes(rSheetLimits.GetMaxRowCount()),
+ maCellNotes(sc::CellStoreEvent(this)),
maBroadcasters(rSheetLimits.GetMaxRowCount()),
- maCellsEvent(this),
- maCells(maCellsEvent),
+ maCells(sc::CellStoreEvent(this)),
+ maSparklines(rSheetLimits.GetMaxRowCount()),
mnBlkCountFormula(0),
+ mnBlkCountCellNotes(0),
nCol( 0 ),
nTab( 0 ),
- mbFiltering( false )
+ mbEmptyBroadcastersPending( false )
{
+ maCellNotes.resize(rSheetLimits.GetMaxRowCount());
maCells.resize(rSheetLimits.GetMaxRowCount());
}
@@ -101,14 +105,9 @@ void ScColumn::Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument& rDoc, bool bEmptyA
nCol = nNewCol;
nTab = nNewTab;
if ( bEmptyAttrArray )
- pAttrArray.reset(new ScAttrArray( nCol, nTab, rDoc, nullptr ));
+ InitAttrArray(new ScAttrArray( nCol, nTab, rDoc, nullptr ));
else
- pAttrArray.reset(new ScAttrArray( nCol, nTab, rDoc, &rDoc.maTabs[nTab]->aDefaultColAttrArray ));
-}
-
-SCROW ScColumn::GetNextUnprotected( SCROW nRow, bool bUp ) const
-{
- return pAttrArray->GetNextUnprotected(nRow, bUp);
+ InitAttrArray(new ScAttrArray( nCol, nTab, rDoc, &rDoc.maTabs[nTab]->aDefaultColData.AttrArray()));
}
sc::MatrixEdge ScColumn::GetBlockMatrixEdges( SCROW nRow1, SCROW nRow2, sc::MatrixEdge nMask,
@@ -192,7 +191,7 @@ sc::MatrixEdge ScColumn::GetBlockMatrixEdges( SCROW nRow1, SCROW nRow2, sc::Matr
return nEdges;
}
-bool ScColumn::HasSelectionMatrixFragment(const ScMarkData& rMark) const
+bool ScColumn::HasSelectionMatrixFragment(const ScMarkData& rMark, const ScRangeList& rRangeList) const
{
using namespace sc;
@@ -203,7 +202,7 @@ bool ScColumn::HasSelectionMatrixFragment(const ScMarkData& rMark) const
ScAddress aCurOrigin = aOrigin;
bool bOpen = false;
- ScRangeList aRanges = rMark.GetMarkedRanges();
+ ScRangeList aRanges = rRangeList; // cached rMark.GetMarkedRanges(), for performance reasons (tdf#148147)
for (size_t i = 0, n = aRanges.size(); i < n; ++i)
{
const ScRange& r = aRanges[i];
@@ -300,11 +299,6 @@ bool ScColumn::HasSelectionMatrixFragment(const ScMarkData& rMark) const
return bOpen;
}
-bool ScColumn::HasAttrib( SCROW nRow1, SCROW nRow2, HasAttrFlags nMask ) const
-{
- return pAttrArray->HasAttrib( nRow1, nRow2, nMask );
-}
-
bool ScColumn::HasAttribSelection( const ScMarkData& rMark, HasAttrFlags nMask ) const
{
bool bFound = false;
@@ -325,13 +319,6 @@ bool ScColumn::HasAttribSelection( const ScMarkData& rMark, HasAttrFlags nMask )
return bFound;
}
-bool ScColumn::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
- SCCOL& rPaintCol, SCROW& rPaintRow,
- bool bRefresh )
-{
- return pAttrArray->ExtendMerge( nThisCol, nStartRow, nEndRow, rPaintCol, rPaintRow, bRefresh );
-}
-
void ScColumn::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, bool bDeep ) const
{
SCROW nTop;
@@ -349,41 +336,13 @@ void ScColumn::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkD
}
}
-void ScColumn::MergePatternArea( ScMergePatternState& rState, SCROW nRow1, SCROW nRow2, bool bDeep ) const
-{
- pAttrArray->MergePatternArea( nRow1, nRow2, rState, bDeep );
-}
-
-void ScColumn::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
- ScLineFlags& rFlags,
- SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight ) const
-{
- pAttrArray->MergeBlockFrame( pLineOuter, pLineInner, rFlags, nStartRow, nEndRow, bLeft, nDistRight );
-}
-
-void ScColumn::ApplyBlockFrame(const SvxBoxItem& rLineOuter, const SvxBoxInfoItem* pLineInner,
- SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight)
-{
- pAttrArray->ApplyBlockFrame(rLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight);
-}
-
-const ScPatternAttr* ScColumn::GetPattern( SCROW nRow ) const
-{
- return pAttrArray->GetPattern( nRow );
-}
-
-const SfxPoolItem& ScColumn::GetAttr( SCROW nRow, sal_uInt16 nWhich ) const
-{
- return pAttrArray->GetPattern( nRow )->GetItemSet().Get(nWhich);
-}
-
-const ScPatternAttr* ScColumn::GetMostUsedPattern( SCROW nStartRow, SCROW nEndRow ) const
+const ScPatternAttr* ScColumnData::GetMostUsedPattern( SCROW nStartRow, SCROW nEndRow ) const
{
::std::map< const ScPatternAttr*, size_t > aAttrMap;
const ScPatternAttr* pMaxPattern = nullptr;
size_t nMaxCount = 0;
- ScAttrIterator aAttrIter( pAttrArray.get(), nStartRow, nEndRow, GetDoc().GetDefPattern() );
+ ScAttrIterator aAttrIter( pAttrArray.get(), nStartRow, nEndRow, &GetDoc().getCellAttributeHelper().getDefaultCellAttribute() );
const ScPatternAttr* pPattern;
SCROW nAttrRow1 = 0, nAttrRow2 = 0;
@@ -401,88 +360,39 @@ const ScPatternAttr* ScColumn::GetMostUsedPattern( SCROW nStartRow, SCROW nEndRo
return pMaxPattern;
}
-sal_uInt32 ScColumn::GetNumberFormat( SCROW nStartRow, SCROW nEndRow ) const
+sal_uInt32 ScColumnData::GetNumberFormat( SCROW nStartRow, SCROW nEndRow ) const
{
- ScDocument& rDocument = GetDoc();
SCROW nPatStartRow, nPatEndRow;
const ScPatternAttr* pPattern = pAttrArray->GetPatternRange(nPatStartRow, nPatEndRow, nStartRow);
- sal_uInt32 nFormat = pPattern->GetNumberFormat(rDocument.GetFormatTable());
+ sal_uInt32 nFormat = pPattern->GetNumberFormat(GetDoc().GetFormatTable());
while (nEndRow > nPatEndRow)
{
nStartRow = nPatEndRow + 1;
pPattern = pAttrArray->GetPatternRange(nPatStartRow, nPatEndRow, nStartRow);
- sal_uInt32 nTmpFormat = pPattern->GetNumberFormat(rDocument.GetFormatTable());
+ sal_uInt32 nTmpFormat = pPattern->GetNumberFormat(GetDoc().GetFormatTable());
if (nFormat != nTmpFormat)
return 0;
}
return nFormat;
}
-sal_uInt32 ScColumn::GetNumberFormat( const ScInterpreterContext& rContext, SCROW nRow ) const
+void ScColumnData::ApplySelectionCache(ScItemPoolCache& rCache, SCROW nStartRow, SCROW nEndRow,
+ ScEditDataArray* pDataArray, bool* pIsChanged)
{
- return pAttrArray->GetPattern( nRow )->GetNumberFormat( rContext.GetFormatTable() );
+ pAttrArray->ApplyCacheArea(nStartRow, nEndRow, rCache, pDataArray, pIsChanged);
}
-SCROW ScColumn::ApplySelectionCache( SfxItemPoolCache* pCache, const ScMarkData& rMark, ScEditDataArray* pDataArray, bool* const pIsChanged )
+void ScColumnData::ChangeSelectionIndent(bool bIncrement, SCROW nStartRow, SCROW nEndRow)
{
- SCROW nTop = 0;
- SCROW nBottom = 0;
- bool bFound = false;
-
- if ( rMark.IsMultiMarked() )
- {
- ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
- while (aMultiIter.Next( nTop, nBottom ))
- {
- pAttrArray->ApplyCacheArea( nTop, nBottom, pCache, pDataArray, pIsChanged );
- bFound = true;
- }
- }
-
- if (!bFound)
- return -1;
- else if (nTop==0 && nBottom==GetDoc().MaxRow())
- return 0;
- else
- return nBottom;
-}
-
-void ScColumn::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark )
-{
- SCROW nTop;
- SCROW nBottom;
-
- if ( pAttrArray && rMark.IsMultiMarked() )
- {
- ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
- while (aMultiIter.Next( nTop, nBottom ))
- pAttrArray->ChangeIndent(nTop, nBottom, bIncrement);
- }
+ pAttrArray->ChangeIndent(nStartRow, nEndRow, bIncrement);
}
-void ScColumn::ClearSelectionItems( const sal_uInt16* pWhich,const ScMarkData& rMark )
+void ScColumnData::ClearSelectionItems(const sal_uInt16* pWhich, SCROW nStartRow, SCROW nEndRow)
{
- SCROW nTop;
- SCROW nBottom;
-
if (!pAttrArray)
return;
- if (rMark.IsMultiMarked() )
- {
- ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
- while (aMultiIter.Next( nTop, nBottom ))
- pAttrArray->ClearItems(nTop, nBottom, pWhich);
- }
- else if (rMark.IsMarked())
- {
- ScRange aRange;
- rMark.GetMarkArea(aRange);
- if (aRange.aStart.Col() <= nCol && nCol <= aRange.aEnd.Col())
- {
- pAttrArray->ClearItems(aRange.aStart.Row(), aRange.aEnd.Row(), pWhich);
- }
- }
+ pAttrArray->ClearItems(nStartRow, nEndRow, pWhich);
}
void ScColumn::DeleteSelection( InsertDeleteFlags nDelFlag, const ScMarkData& rMark, bool bBroadcast )
@@ -501,31 +411,31 @@ void ScColumn::DeleteSelection( InsertDeleteFlags nDelFlag, const ScMarkData& rM
void ScColumn::ApplyPattern( SCROW nRow, const ScPatternAttr& rPatAttr )
{
const SfxItemSet* pSet = &rPatAttr.GetItemSet();
- SfxItemPoolCache aCache( GetDoc().GetPool(), pSet );
+ ScItemPoolCache aCache( GetDoc().getCellAttributeHelper(), *pSet );
- const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
+ const CellAttributeHolder aPattern(pAttrArray->GetPattern( nRow ));
// true = keep old content
- const ScPatternAttr* pNewPattern = static_cast<const ScPatternAttr*>( &aCache.ApplyTo( *pPattern ) );
+ const CellAttributeHolder& rNewPattern = aCache.ApplyTo( aPattern );
- if (pNewPattern != pPattern)
- pAttrArray->SetPattern( nRow, pNewPattern );
+ if (!CellAttributeHolder::areSame(&rNewPattern, &aPattern))
+ pAttrArray->SetPattern( nRow, rNewPattern );
}
-void ScColumn::ApplyPatternArea( SCROW nStartRow, SCROW nEndRow, const ScPatternAttr& rPatAttr,
+void ScColumnData::ApplyPatternArea( SCROW nStartRow, SCROW nEndRow, const ScPatternAttr& rPatAttr,
ScEditDataArray* pDataArray, bool* const pIsChanged )
{
const SfxItemSet* pSet = &rPatAttr.GetItemSet();
- SfxItemPoolCache aCache( GetDoc().GetPool(), pSet );
- pAttrArray->ApplyCacheArea( nStartRow, nEndRow, &aCache, pDataArray, pIsChanged );
+ ScItemPoolCache aCache( GetDoc().getCellAttributeHelper(), *pSet );
+ pAttrArray->ApplyCacheArea( nStartRow, nEndRow, aCache, pDataArray, pIsChanged );
}
void ScColumn::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
const ScPatternAttr& rPattern, SvNumFormatType nNewType )
{
const SfxItemSet* pSet = &rPattern.GetItemSet();
- SfxItemPoolCache aCache( GetDoc().GetPool(), pSet );
+ ScItemPoolCache aCache( GetDoc().getCellAttributeHelper(), *pSet );
SvNumberFormatter* pFormatter = GetDoc().GetFormatTable();
SCROW nEndRow = rRange.aEnd.Row();
for ( SCROW nRow = rRange.aStart.Row(); nRow <= nEndRow; nRow++ )
@@ -541,46 +451,23 @@ void ScColumn::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
{
SCROW nNewRow1 = std::max( nRow1, nRow );
SCROW nNewRow2 = std::min( nRow2, nEndRow );
- pAttrArray->ApplyCacheArea( nNewRow1, nNewRow2, &aCache );
+ pAttrArray->ApplyCacheArea( nNewRow1, nNewRow2, aCache );
nRow = nNewRow2;
}
}
}
-void ScColumn::AddCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
-{
- pAttrArray->AddCondFormat( nStartRow, nEndRow, nIndex );
-}
-
-void ScColumn::RemoveCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
-{
- pAttrArray->RemoveCondFormat( nStartRow, nEndRow, nIndex );
-}
-
void ScColumn::ApplyStyle( SCROW nRow, const ScStyleSheet* rStyle )
{
const ScPatternAttr* pPattern = pAttrArray->GetPattern(nRow);
- std::unique_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr(*pPattern));
+ ScPatternAttr* pNewPattern(new ScPatternAttr(*pPattern));
pNewPattern->SetStyleSheet(const_cast<ScStyleSheet*>(rStyle));
- pAttrArray->SetPattern(nRow, std::move(pNewPattern), true);
+ pAttrArray->SetPattern(nRow, CellAttributeHolder(pNewPattern, true));
}
-void ScColumn::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleSheet& rStyle )
+void ScColumnData::ApplySelectionStyle(const ScStyleSheet& rStyle, SCROW nTop, SCROW nBottom)
{
- pAttrArray->ApplyStyleArea(nStartRow, nEndRow, rStyle);
-}
-
-void ScColumn::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
-{
- SCROW nTop;
- SCROW nBottom;
-
- if ( rMark.IsMultiMarked() )
- {
- ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
- while (aMultiIter.Next( nTop, nBottom ))
- pAttrArray->ApplyStyleArea(nTop, nBottom, rStyle);
- }
+ pAttrArray->ApplyStyleArea(nTop, nBottom, rStyle);
}
void ScColumn::ApplySelectionLineStyle( const ScMarkData& rMark,
@@ -600,11 +487,6 @@ void ScColumn::ApplySelectionLineStyle( const ScMarkData& rMark,
}
}
-const ScStyleSheet* ScColumn::GetStyle( SCROW nRow ) const
-{
- return pAttrArray->GetPattern( nRow )->GetStyleSheet();
-}
-
const ScStyleSheet* ScColumn::GetSelectionStyle( const ScMarkData& rMark, bool& rFound ) const
{
rFound = false;
@@ -625,7 +507,7 @@ const ScStyleSheet* ScColumn::GetSelectionStyle( const ScMarkData& rMark, bool&
SCROW nBottom;
while (bEqual && aMultiIter.Next( nTop, nBottom ))
{
- ScAttrIterator aAttrIter( pAttrArray.get(), nTop, nBottom, rDocument.GetDefPattern() );
+ ScAttrIterator aAttrIter( pAttrArray.get(), nTop, nBottom, &rDocument.getCellAttributeHelper().getDefaultCellAttribute() );
SCROW nRow;
SCROW nDummy;
while (bEqual)
@@ -653,7 +535,7 @@ const ScStyleSheet* ScColumn::GetAreaStyle( bool& rFound, SCROW nRow1, SCROW nRo
const ScStyleSheet* pStyle = nullptr;
const ScStyleSheet* pNewStyle;
- ScAttrIterator aAttrIter( pAttrArray.get(), nRow1, nRow2, GetDoc().GetDefPattern() );
+ ScAttrIterator aAttrIter( pAttrArray.get(), nRow1, nRow2, &GetDoc().getCellAttributeHelper().getDefaultCellAttribute() );
SCROW nRow;
SCROW nDummy;
while (bEqual)
@@ -671,63 +553,19 @@ const ScStyleSheet* ScColumn::GetAreaStyle( bool& rFound, SCROW nRow1, SCROW nRo
return bEqual ? pStyle : nullptr;
}
-void ScColumn::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
-{
- pAttrArray->FindStyleSheet( pStyleSheet, rUsedRows, bReset );
-}
-
-bool ScColumn::IsStyleSheetUsed( const ScStyleSheet& rStyle ) const
-{
- return pAttrArray->IsStyleSheetUsed( rStyle );
-}
-
-bool ScColumn::ApplyFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags )
-{
- return pAttrArray->ApplyFlags( nStartRow, nEndRow, nFlags );
-}
-
-bool ScColumn::RemoveFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags )
-{
- return pAttrArray->RemoveFlags( nStartRow, nEndRow, nFlags );
-}
-
-void ScColumn::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
-{
- pAttrArray->ClearItems( nStartRow, nEndRow, pWhich );
-}
-
-const ScPatternAttr* ScColumn::SetPattern( SCROW nRow, std::unique_ptr<ScPatternAttr> pPatAttr )
-{
- return pAttrArray->SetPattern( nRow, std::move(pPatAttr), true/*bPutToPool*/ );
-}
-
-void ScColumn::SetPattern( SCROW nRow, const ScPatternAttr& rPatAttr )
-{
- pAttrArray->SetPattern( nRow, &rPatAttr, true/*bPutToPool*/ );
-}
-
-void ScColumn::SetPatternArea( SCROW nStartRow, SCROW nEndRow,
- const ScPatternAttr& rPatAttr )
-{
- pAttrArray->SetPatternArea( nStartRow, nEndRow, &rPatAttr, true/*bPutToPool*/ );
-}
-
void ScColumn::ApplyAttr( SCROW nRow, const SfxPoolItem& rAttr )
{
// in order to only create a new SetItem, we don't need SfxItemPoolCache.
- //TODO: Warning: SfxItemPoolCache seems to create too many Refs for the new SetItem ??
+ //TODO: Warning: ScItemPoolCache seems to create too many Refs for the new SetItem ??
- ScDocumentPool* pDocPool = GetDoc().GetPool();
+ const ScPatternAttr* pOldPattern(pAttrArray->GetPattern(nRow));
+ ScPatternAttr* pNewPattern(new ScPatternAttr(*pOldPattern));
+ pNewPattern->GetItemSet().Put(rAttr);
- const ScPatternAttr* pOldPattern = pAttrArray->GetPattern( nRow );
- ScPatternAttr aTemp(*pOldPattern);
- aTemp.GetItemSet().Put(rAttr);
- const ScPatternAttr* pNewPattern = &pDocPool->Put( aTemp );
-
- if ( pNewPattern != pOldPattern )
- pAttrArray->SetPattern( nRow, pNewPattern );
+ if (!ScPatternAttr::areSame( pNewPattern, pOldPattern ))
+ pAttrArray->SetPattern( nRow, CellAttributeHolder(pNewPattern, true) );
else
- pDocPool->Remove( *pNewPattern ); // free up resources
+ delete pNewPattern;
}
ScRefCellValue ScColumn::GetCellValue( SCROW nRow ) const
@@ -761,34 +599,23 @@ ScRefCellValue ScColumn::GetCellValue( sc::ColumnBlockConstPosition& rBlockPos,
ScRefCellValue ScColumn::GetCellValue( const sc::CellStoreType::const_iterator& itPos, size_t nOffset )
{
- ScRefCellValue aVal; // Defaults to empty cell.
switch (itPos->type)
{
case sc::element_type_numeric:
// Numeric cell
- aVal.mfValue = sc::numeric_block::at(*itPos->data, nOffset);
- aVal.meType = CELLTYPE_VALUE;
- break;
+ return ScRefCellValue(sc::numeric_block::at(*itPos->data, nOffset));
case sc::element_type_string:
// String cell
- aVal.mpString = &sc::string_block::at(*itPos->data, nOffset);
- aVal.meType = CELLTYPE_STRING;
- break;
+ return ScRefCellValue(&sc::string_block::at(*itPos->data, nOffset));
case sc::element_type_edittext:
// Edit cell
- aVal.mpEditText = sc::edittext_block::at(*itPos->data, nOffset);
- aVal.meType = CELLTYPE_EDIT;
- break;
+ return ScRefCellValue(sc::edittext_block::at(*itPos->data, nOffset));
case sc::element_type_formula:
// Formula cell
- aVal.mpFormula = sc::formula_block::at(*itPos->data, nOffset);
- aVal.meType = CELLTYPE_FORMULA;
- break;
+ return ScRefCellValue(sc::formula_block::at(*itPos->data, nOffset));
default:
- ;
+ return ScRefCellValue(); // empty cell
}
-
- return aVal;
}
const sc::CellTextAttr* ScColumn::GetCellTextAttr( SCROW nRow ) const
@@ -869,16 +696,19 @@ void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
pAttrArray->InsertRow( nStartRow, nSize );
maCellNotes.insert_empty(nStartRow, nSize);
- maCellNotes.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
+ maCellNotes.resize(GetDoc().GetMaxRowCount());
+
+ maSparklines.insert_empty(nStartRow, nSize);
+ maSparklines.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
maBroadcasters.insert_empty(nStartRow, nSize);
- maBroadcasters.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
+ maBroadcasters.resize(GetDoc().GetMaxRowCount());
maCellTextAttrs.insert_empty(nStartRow, nSize);
- maCellTextAttrs.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
+ maCellTextAttrs.resize(GetDoc().GetMaxRowCount());
maCells.insert_empty(nStartRow, nSize);
- maCells.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
+ maCells.resize(GetDoc().GetMaxRowCount());
CellStorageModified();
@@ -1010,6 +840,7 @@ public:
setDefaultAttrsToDest(nTopRow, nDataSize);
mrSrcCol.DuplicateNotes(nTopRow, nDataSize, mrDestCol, maDestPos, false);
+ mrSrcCol.DuplicateSparklines(nTopRow, nDataSize, mrDestCol, maDestPos);
}
};
@@ -1043,14 +874,16 @@ public:
void ScColumn::CopyToClip(
sc::CopyToClipContext& rCxt, SCROW nRow1, SCROW nRow2, ScColumn& rColumn ) const
{
- pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray,
- rCxt.isKeepScenarioFlags() ? (ScMF::All & ~ScMF::Scenario) : ScMF::All );
+ if (!rCxt.isCopyChartRanges()) // No need to copy attributes for chart ranges
+ pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray,
+ rCxt.isKeepScenarioFlags() ? (ScMF::All & ~ScMF::Scenario) : ScMF::All );
{
CopyToClipHandler aFunc(GetDoc(), *this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol));
sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
}
+ if (!rCxt.isCopyChartRanges()) // No need to copy attributes for chart ranges
{
CopyTextAttrToClipHandler aFunc(rColumn.maCellTextAttrs);
sc::ParseBlock(maCellTextAttrs.begin(), maCellTextAttrs, aFunc, nRow1, nRow2);
@@ -1720,12 +1553,10 @@ void ScColumn::CopyToColumn(
// e.g. DIF and RTF Clipboard-Import
for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ )
{
- const ScStyleSheet* pStyle =
- rColumn.pAttrArray->GetPattern( nRow )->GetStyleSheet();
- const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
- std::unique_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr( *pPattern ));
- pNewPattern->SetStyleSheet( const_cast<ScStyleSheet*>(pStyle) );
- rColumn.pAttrArray->SetPattern( nRow, std::move(pNewPattern), true );
+ const ScStyleSheet* pStyle(rColumn.pAttrArray->GetPattern( nRow )->GetStyleSheet());
+ ScPatternAttr* pNewPattern(new ScPatternAttr(*pAttrArray->GetPattern(nRow)));
+ pNewPattern->SetStyleSheet(const_cast<ScStyleSheet*>(pStyle));
+ rColumn.pAttrArray->SetPattern(nRow, CellAttributeHolder(pNewPattern, true));
}
}
else
@@ -1770,14 +1601,15 @@ void ScColumn::UndoToColumn(
CopyToColumn(rCxt, nRow2+1, GetDoc().MaxRow(), InsertDeleteFlags::FORMULA, false, rColumn);
}
-void ScColumn::CopyUpdated( const ScColumn& rPosCol, ScColumn& rDestCol ) const
+void ScColumn::CopyUpdated( const ScColumn* pPosCol, ScColumn& rDestCol ) const
{
// Copy cells from this column to the destination column only for those
- // rows that are present in the position column (rPosCol).
+ // rows that are present in the position column (pPosCol).
// First, mark all the non-empty cell ranges from the position column.
sc::SingleColumnSpanSet aRangeSet(GetDoc().GetSheetLimits());
- aRangeSet.scan(rPosCol);
+ if(pPosCol)
+ aRangeSet.scan(*pPosCol);
// Now, copy cells from this column to the destination column for those
// marked row ranges.
@@ -1796,7 +1628,7 @@ void ScColumn::CopyScenarioFrom( const ScColumn& rSrcCol )
{
// This is the scenario table, the data is copied into it
ScDocument& rDocument = GetDoc();
- ScAttrIterator aAttrIter( pAttrArray.get(), 0, GetDoc().MaxRow(), rDocument.GetDefPattern() );
+ ScAttrIterator aAttrIter( pAttrArray.get(), 0, GetDoc().MaxRow(), &rDocument.getCellAttributeHelper().getDefaultCellAttribute() );
SCROW nStart = -1, nEnd = -1;
const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
while (pPattern)
@@ -1825,7 +1657,7 @@ void ScColumn::CopyScenarioTo( ScColumn& rDestCol ) const
{
// This is the scenario table, the data is copied to the other
ScDocument& rDocument = GetDoc();
- ScAttrIterator aAttrIter( pAttrArray.get(), 0, GetDoc().MaxRow(), rDocument.GetDefPattern() );
+ ScAttrIterator aAttrIter( pAttrArray.get(), 0, GetDoc().MaxRow(), &rDocument.getCellAttributeHelper().getDefaultCellAttribute() );
SCROW nStart = -1, nEnd = -1;
const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
while (pPattern)
@@ -1850,7 +1682,7 @@ void ScColumn::CopyScenarioTo( ScColumn& rDestCol ) const
bool ScColumn::TestCopyScenarioTo( const ScColumn& rDestCol ) const
{
bool bOk = true;
- ScAttrIterator aAttrIter( pAttrArray.get(), 0, GetDoc().MaxRow(), GetDoc().GetDefPattern() );
+ ScAttrIterator aAttrIter( pAttrArray.get(), 0, GetDoc().MaxRow(), &GetDoc().getCellAttributeHelper().getDefaultCellAttribute() );
SCROW nStart = 0, nEnd = 0;
const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
while (pPattern && bOk)
@@ -1868,7 +1700,7 @@ void ScColumn::MarkScenarioIn( ScMarkData& rDestMark ) const
{
ScRange aRange( nCol, 0, nTab );
- ScAttrIterator aAttrIter( pAttrArray.get(), 0, GetDoc().MaxRow(), GetDoc().GetDefPattern() );
+ ScAttrIterator aAttrIter( pAttrArray.get(), 0, GetDoc().MaxRow(), &GetDoc().getCellAttributeHelper().getDefaultCellAttribute() );
SCROW nStart = -1, nEnd = -1;
const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
while (pPattern)
@@ -1905,22 +1737,47 @@ void resetColumnPosition(sc::CellStoreType& rCells, SCCOL nCol)
class NoteCaptionUpdater
{
- SCCOL mnCol;
- SCTAB mnTab;
+ const ScDocument& m_rDocument;
+ const ScAddress m_aAddress; // 'incomplete' address consisting of tab, column
+ bool m_bUpdateCaptionPos; // false if we want to skip updating the caption pos, only useful in kit mode
+ bool m_bAddressChanged; // false if the cell anchor address is unchanged
public:
- NoteCaptionUpdater( SCCOL nCol, SCTAB nTab ) : mnCol(nCol), mnTab(nTab) {}
+ NoteCaptionUpdater(const ScDocument& rDocument, const ScAddress& rPos, bool bUpdateCaptionPos, bool bAddressChanged)
+ : m_rDocument(rDocument)
+ , m_aAddress(rPos)
+ , m_bUpdateCaptionPos(bUpdateCaptionPos)
+ , m_bAddressChanged(bAddressChanged)
+ {
+ }
void operator() ( size_t nRow, ScPostIt* p )
{
- p->UpdateCaptionPos(ScAddress(mnCol,nRow,mnTab));
+ // Create a 'complete' address object
+ ScAddress aAddr(m_aAddress);
+ aAddr.SetRow(nRow);
+
+ if (m_bUpdateCaptionPos)
+ p->UpdateCaptionPos(aAddr);
+
+ // Notify our LOK clients
+ if (m_bAddressChanged)
+ ScDocShell::LOKCommentNotify(LOKCommentNotificationType::Modify, m_rDocument, aAddr, p);
}
};
}
-void ScColumn::UpdateNoteCaptions( SCROW nRow1, SCROW nRow2 )
+void ScColumn::UpdateNoteCaptions( SCROW nRow1, SCROW nRow2, bool bAddressChanged )
+{
+ ScAddress aAddr(nCol, 0, nTab);
+ NoteCaptionUpdater aFunc(GetDoc(), aAddr, true, bAddressChanged);
+ sc::ProcessNote(maCellNotes.begin(), maCellNotes, nRow1, nRow2, aFunc);
+}
+
+void ScColumn::CommentNotifyAddressChange( SCROW nRow1, SCROW nRow2 )
{
- NoteCaptionUpdater aFunc(nCol, nTab);
+ ScAddress aAddr(nCol, 0, nTab);
+ NoteCaptionUpdater aFunc(GetDoc(), aAddr, false, true);
sc::ProcessNote(maCellNotes.begin(), maCellNotes, nRow1, nRow2, aFunc);
}
@@ -1967,9 +1824,13 @@ void ScColumn::SwapCol(ScColumn& rCol)
maCells.swap(rCol.maCells);
maCellTextAttrs.swap(rCol.maCellTextAttrs);
maCellNotes.swap(rCol.maCellNotes);
+ maSparklines.swap(rCol.maSparklines);
// Swap all CellStoreEvent mdds event_func related.
+ maCells.event_handler().swap(rCol.maCells.event_handler());
+ maCellNotes.event_handler().swap(rCol.maCellNotes.event_handler());
std::swap( mnBlkCountFormula, rCol.mnBlkCountFormula);
+ std::swap(mnBlkCountCellNotes, rCol.mnBlkCountCellNotes);
// notes update caption
UpdateNoteCaptions(0, GetDoc().MaxRow());
@@ -2041,12 +1902,11 @@ void ScColumn::MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol)
// Broadcast on moved ranges. Area-broadcast only.
ScDocument& rDocument = GetDoc();
ScHint aHint(SfxHintId::ScDataChanged, ScAddress(nCol, 0, nTab));
- ScAddress& rPos = aHint.GetAddress();
for (const auto& rRange : aRanges)
{
for (SCROW nRow = rRange.mnRow1; nRow <= rRange.mnRow2; ++nRow)
{
- rPos.SetRow(nRow);
+ aHint.SetAddressRow(nRow);
rDocument.AreaBroadcast(aHint);
}
}
@@ -2167,7 +2027,7 @@ class UpdateRefOnNonCopy
ScFormulaCell** ppEnd = pp + rGroup.mnLength;
ScFormulaCell* pTop = *pp;
ScTokenArray* pCode = pTop->GetCode();
- std::unique_ptr<ScTokenArray> pOldCode(pCode->Clone());
+ ScTokenArray aOldCode(pCode->CloneValue());
ScAddress aOldPos = pTop->aPos;
// Run this before the position gets updated.
@@ -2181,7 +2041,8 @@ class UpdateRefOnNonCopy
for (++pp; pp != ppEnd; ++pp) // skip the top cell.
{
ScFormulaCell* pFC = *pp;
- if (!pFC->aPos.Move(mpCxt->mnColDelta, mpCxt->mnRowDelta, mpCxt->mnTabDelta, aErrorPos))
+ if (!pFC->aPos.Move(mpCxt->mnColDelta, mpCxt->mnRowDelta, mpCxt->mnTabDelta,
+ aErrorPos, mpCxt->mrDoc))
{
assert(!"can't move formula cell");
}
@@ -2211,7 +2072,7 @@ class UpdateRefOnNonCopy
if (aRes.mbReferenceModified || aRes.mbNameModified || bGroupShifted)
{
- sc::EndListeningContext aEndCxt(mpCxt->mrDoc, pOldCode.get());
+ sc::EndListeningContext aEndCxt(mpCxt->mrDoc, &aOldCode);
aEndCxt.setPositionDelta(
ScAddress(-mpCxt->mnColDelta, -mpCxt->mnRowDelta, -mpCxt->mnTabDelta));
@@ -2224,7 +2085,7 @@ class UpdateRefOnNonCopy
mbUpdated = true;
- fillUndoDoc(aOldPos, rGroup.mnLength, *pOldCode);
+ fillUndoDoc(aOldPos, rGroup.mnLength, aOldCode);
}
if (aRes.mbValueChanged)
@@ -2251,13 +2112,13 @@ class UpdateRefOnNonCopy
ScFormulaCell** ppEnd = pp + rGroup.mnLength;
ScFormulaCell* pTop = *pp;
ScTokenArray* pCode = pTop->GetCode();
- std::unique_ptr<ScTokenArray> pOldCode(pCode->Clone());
+ ScTokenArray aOldCode(pCode->CloneValue());
ScAddress aPos = pTop->aPos;
ScAddress aOldPos = aPos;
bool bCellMoved;
- if (mpCxt->maRange.In(aPos))
+ if (mpCxt->maRange.Contains(aPos))
{
bCellMoved = true;
@@ -2298,7 +2159,7 @@ class UpdateRefOnNonCopy
auto pPosSet = std::make_shared<sc::ColumnBlockPositionSet>(mpCxt->mrDoc);
sc::StartListeningContext aStartCxt(mpCxt->mrDoc, pPosSet);
- sc::EndListeningContext aEndCxt(mpCxt->mrDoc, pPosSet, pOldCode.get());
+ sc::EndListeningContext aEndCxt(mpCxt->mrDoc, pPosSet, &aOldCode);
aEndCxt.setPositionDelta(
ScAddress(-mpCxt->mnColDelta, -mpCxt->mnRowDelta, -mpCxt->mnTabDelta));
@@ -2316,7 +2177,7 @@ class UpdateRefOnNonCopy
// Move from clipboard is Cut&Paste, then do not copy the original
// positions' formula cells to the Undo document.
if (!mbClipboardSource || !bCellMoved)
- fillUndoDoc(aOldPos, rGroup.mnLength, *pOldCode);
+ fillUndoDoc(aOldPos, rGroup.mnLength, aOldCode);
}
void fillUndoDoc( const ScAddress& rOldPos, SCROW nLength, const ScTokenArray& rOldCode )
@@ -2478,13 +2339,13 @@ bool ScColumn::UpdateReferenceOnCopy( sc::RefUpdateContext& rCxt, ScDocument* pU
bool ScColumn::UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc )
{
- if (rCxt.meMode == URM_COPY)
- return UpdateReferenceOnCopy(rCxt, pUndoDoc);
-
if (IsEmptyData() || GetDoc().IsClipOrUndo())
// Cells in this column are all empty, or clip or undo doc. No update needed.
return false;
+ if (rCxt.meMode == URM_COPY)
+ return UpdateReferenceOnCopy(rCxt, pUndoDoc);
+
std::vector<SCROW> aBounds;
bool bThisColShifted = (rCxt.maRange.aStart.Tab() <= nTab && nTab <= rCxt.maRange.aEnd.Tab() &&
@@ -2514,15 +2375,17 @@ bool ScColumn::UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc
// Check the row positions at which the group must be split per relative
// references.
- UpdateRefGroupBoundChecker aBoundChecker(rCxt, aBounds);
- std::for_each(maCells.begin(), maCells.end(), aBoundChecker);
+ {
+ UpdateRefGroupBoundChecker aBoundChecker(rCxt, aBounds);
+ std::for_each(maCells.begin(), maCells.end(), std::move(aBoundChecker));
+ }
// If expand reference edges is on, splitting groups may happen anywhere
// where a reference points to an adjacent row of the insertion.
if (rCxt.mnRowDelta > 0 && rCxt.mrDoc.IsExpandRefs())
{
UpdateRefExpandGroupBoundChecker aExpandChecker(rCxt, aBounds);
- std::for_each(maCells.begin(), maCells.end(), aExpandChecker);
+ std::for_each(maCells.begin(), maCells.end(), std::move(aExpandChecker));
}
// Do the actual splitting.
@@ -2617,7 +2480,7 @@ public:
mbModified = true;
}
- void operator() (size_t nRow, const EditTextObject* pCell)
+ void operator() (size_t nRow, EditTextObject* pCell)
{
editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
aUpdater.updateTableFields(mnTab);
@@ -2649,7 +2512,7 @@ public:
mbModified = true;
}
- void operator() (size_t nRow, const EditTextObject* pCell)
+ void operator() (size_t nRow, EditTextObject* pCell)
{
editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
aUpdater.updateTableFields(mnTab);
@@ -2681,7 +2544,7 @@ public:
mbModified = true;
}
- void operator() (size_t nRow, const EditTextObject* pCell)
+ void operator() (size_t nRow, EditTextObject* pCell)
{
editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
aUpdater.updateTableFields(mnTab);
@@ -2713,7 +2576,7 @@ public:
mbModified = true;
}
- void operator() (size_t nRow, const EditTextObject* pCell)
+ void operator() (size_t nRow, EditTextObject* pCell)
{
editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
aUpdater.updateTableFields(mnTab);
@@ -3262,22 +3125,20 @@ namespace {
class BroadcastBroadcastersHandler
{
- ScHint& mrHint;
- ScAddress& mrAddress;
+ ScHint maHint;
bool mbBroadcasted;
public:
- explicit BroadcastBroadcastersHandler( ScHint& rHint )
- : mrHint(rHint)
- , mrAddress(mrHint.GetAddress())
+ explicit BroadcastBroadcastersHandler( SfxHintId nHint, SCTAB nTab, SCCOL nCol )
+ : maHint(nHint, ScAddress(nCol, 0, nTab))
, mbBroadcasted(false)
{
}
void operator() ( size_t nRow, SvtBroadcaster* pBroadcaster )
{
- mrAddress.SetRow(nRow);
- pBroadcaster->Broadcast(mrHint);
+ maHint.SetAddressRow(nRow);
+ pBroadcaster->Broadcast(maHint);
mbBroadcasted = true;
}
@@ -3286,10 +3147,9 @@ public:
}
-bool ScColumn::BroadcastBroadcasters( SCROW nRow1, SCROW nRow2, ScHint& rHint )
+bool ScColumn::BroadcastBroadcasters( SCROW nRow1, SCROW nRow2, SfxHintId nHint )
{
- rHint.GetAddress().SetCol(nCol);
- BroadcastBroadcastersHandler aBroadcasterHdl( rHint);
+ BroadcastBroadcastersHandler aBroadcasterHdl(nHint, nTab, nCol);
sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aBroadcasterHdl);
return aBroadcasterHdl.wasBroadcasted();
}
@@ -3322,8 +3182,7 @@ void ScColumn::SetDirty( SCROW nRow1, SCROW nRow2, BroadcastMode eMode )
SetDirtyOnRangeHandler aHdl(*this);
sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl);
// Broadcast all broadcasters in range.
- ScHint aHint( SfxHintId::ScDataChanged, ScAddress( nCol, nRow1, nTab));
- if (BroadcastBroadcasters( nRow1, nRow2, aHint))
+ if (BroadcastBroadcasters( nRow1, nRow2, SfxHintId::ScDataChanged))
{
// SetDirtyOnRangeHandler implicitly tracks notified
// formulas via ScDocument::Broadcast(), which
@@ -3377,6 +3236,7 @@ void ScColumn::SetDirtyIfPostponed()
{
sc::AutoCalcSwitch aSwitch(GetDoc(), false);
SetDirtyIfPostponedHandler aFunc;
+ ScBulkBroadcast aBulkBroadcast( GetDoc().GetBASM(), SfxHintId::ScDataChanged);
sc::ProcessFormula(maCells, aFunc);
}
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 21217e9cbbe1..c4ac17ffe358 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -41,6 +41,9 @@
#include <scmatrix.hxx>
#include <rowheightcontext.hxx>
#include <tokenstringcontext.hxx>
+#include <sortparam.hxx>
+#include <SparklineGroup.hxx>
+#include <SparklineList.hxx>
#include <editeng/eeitem.hxx>
#include <o3tl/safeint.hxx>
@@ -53,8 +56,10 @@
#include <svx/rotmodit.hxx>
#include <editeng/unolingu.hxx>
#include <editeng/justifyitem.hxx>
+#include <svl/numformat.hxx>
#include <svl/zforlist.hxx>
#include <svl/broadcast.hxx>
+#include <utility>
#include <vcl/outdev.hxx>
#include <formula/errorcodes.hxx>
#include <formula/vectortoken.hxx>
@@ -64,8 +69,6 @@
#include <memory>
#include <numeric>
-#include <math.h>
-
// factor from font size to optimal cell height (text width)
#define SC_ROT_BREAK_FACTOR 6
@@ -106,7 +109,7 @@ tools::Long ScColumn::GetNeededSize(
return bInPrintTwips ? nMeasure : static_cast<tools::Long>(nMeasure * fScale);
};
- const ScPatternAttr* pPattern = rOptions.pPattern;
+ const ScPatternAttr* pPattern = rOptions.aPattern.getScPatternAttr();
if (!pPattern)
pPattern = pAttrArray->GetPattern( nRow );
@@ -136,7 +139,7 @@ tools::Long ScColumn::GetNeededSize(
const SfxItemSet* pCondSet = rDocument.GetCondResult( nCol, nRow, nTab );
//The pPattern may change in GetCondResult
- if (aCell.meType == CELLTYPE_FORMULA)
+ if (aCell.getType() == CELLTYPE_FORMULA)
{
pPattern = pAttrArray->GetPattern( nRow );
if (ppPatternChange)
@@ -144,43 +147,53 @@ tools::Long ScColumn::GetNeededSize(
}
// line break?
- const SfxPoolItem* pCondItem;
+ const SvxHorJustifyItem* pCondItem;
SvxCellHorJustify eHorJust;
- if (pCondSet &&
- pCondSet->GetItemState(ATTR_HOR_JUSTIFY, true, &pCondItem) == SfxItemState::SET)
- eHorJust = static_cast<const SvxHorJustifyItem*>(pCondItem)->GetValue();
+ if (pCondSet && (pCondItem = pCondSet->GetItemIfSet(ATTR_HOR_JUSTIFY)) )
+ eHorJust = pCondItem->GetValue();
else
eHorJust = pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue();
bool bBreak;
+ const ScLineBreakCell* pLineBreakCell;
if ( eHorJust == SvxCellHorJustify::Block )
bBreak = true;
- else if ( pCondSet &&
- pCondSet->GetItemState(ATTR_LINEBREAK, true, &pCondItem) == SfxItemState::SET)
- bBreak = static_cast<const ScLineBreakCell*>(pCondItem)->GetValue();
+ else if ( pCondSet && (pLineBreakCell = pCondSet->GetItemIfSet(ATTR_LINEBREAK)) )
+ bBreak = pLineBreakCell->GetValue();
else
bBreak = pPattern->GetItem(ATTR_LINEBREAK).GetValue();
- SvNumberFormatter* pFormatter = rDocument.GetFormatTable();
- sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
+ ScInterpreterContext& rContext = rDocument.GetNonThreadedContext();
+ sal_uInt32 nFormat = pPattern->GetNumberFormat( rContext, pCondSet );
// get "cell is value" flag
// Must be synchronized with ScOutputData::LayoutStrings()
- bool bCellIsValue = (aCell.meType == CELLTYPE_VALUE);
- if (aCell.meType == CELLTYPE_FORMULA)
+ bool bCellIsValue = (aCell.getType() == CELLTYPE_VALUE);
+ if (aCell.getType() == CELLTYPE_FORMULA)
{
- ScFormulaCell* pFCell = aCell.mpFormula;
- bCellIsValue = pFCell->IsRunning() || pFCell->IsValue();
+ ScFormulaCell* pFCell = aCell.getFormula();
+ bCellIsValue = pFCell->IsRunning();
+ if (!bCellIsValue)
+ {
+ bCellIsValue = pFCell->IsValue();
+ if (bCellIsValue)
+ {
+ // the pattern may change in IsValue()
+ pPattern = pAttrArray->GetPattern( nRow );
+ if (ppPatternChange)
+ *ppPatternChange = pPattern;
+ }
+ }
}
// #i111387#, tdf#121040: disable automatic line breaks for all number formats
- if (bBreak && bCellIsValue && (pFormatter->GetType(nFormat) == SvNumFormatType::NUMBER))
+ if (bBreak && bCellIsValue && (rContext.NFGetType(nFormat) == SvNumFormatType::NUMBER))
{
// If a formula cell needs to be interpreted during aCell.hasNumeric()
// to determine the type, the pattern may get invalidated because the
// result may set a number format. In which case there's also the
// General format not set anymore...
- bool bMayInvalidatePattern = (aCell.meType == CELLTYPE_FORMULA);
- const ScPatternAttr* pOldPattern = pPattern;
+ bool bMayInvalidatePattern = (aCell.getType() == CELLTYPE_FORMULA);
+ const CellAttributeHolder aOldPattern(pPattern);
bool bNumeric = aCell.hasNumeric();
if (bMayInvalidatePattern)
{
@@ -190,12 +203,12 @@ tools::Long ScColumn::GetNeededSize(
}
if (bNumeric)
{
- if (!bMayInvalidatePattern || pPattern == pOldPattern)
+ if (!bMayInvalidatePattern || ScPatternAttr::areSame(pPattern, aOldPattern.getScPatternAttr()))
bBreak = false;
else
{
- nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
- if (pFormatter->GetType(nFormat) == SvNumFormatType::NUMBER)
+ nFormat = pPattern->GetNumberFormat( rContext, pCondSet );
+ if (rContext.NFGetType(nFormat) == SvNumFormatType::NUMBER)
bBreak = false;
}
}
@@ -216,16 +229,18 @@ tools::Long ScColumn::GetNeededSize(
SvxRotateMode eRotMode = SVX_ROTATE_MODE_STANDARD;
if ( eOrient == SvxCellOrientation::Standard )
{
+ const ScRotateValueItem* pRotateValueItem;
if (pCondSet &&
- pCondSet->GetItemState(ATTR_ROTATE_VALUE, true, &pCondItem) == SfxItemState::SET)
- nRotate = static_cast<const ScRotateValueItem*>(pCondItem)->GetValue();
+ (pRotateValueItem = pCondSet->GetItemIfSet(ATTR_ROTATE_VALUE)) )
+ nRotate = pRotateValueItem->GetValue();
else
nRotate = pPattern->GetItem(ATTR_ROTATE_VALUE).GetValue();
if ( nRotate )
{
+ const SvxRotateModeItem* pRotateModeItem;
if (pCondSet &&
- pCondSet->GetItemState(ATTR_ROTATE_MODE, true, &pCondItem) == SfxItemState::SET)
- eRotMode = static_cast<const SvxRotateModeItem*>(pCondItem)->GetValue();
+ (pRotateModeItem = pCondSet->GetItemIfSet(ATTR_ROTATE_MODE)) )
+ eRotMode = pRotateModeItem->GetValue();
else
eRotMode = pPattern->GetItem(ATTR_ROTATE_MODE).GetValue();
@@ -244,16 +259,17 @@ tools::Long ScColumn::GetNeededSize(
const SvxMarginItem* pMargin;
if (pCondSet &&
- pCondSet->GetItemState(ATTR_MARGIN, true, &pCondItem) == SfxItemState::SET)
- pMargin = static_cast<const SvxMarginItem*>(pCondItem);
+ (pMargin = pCondSet->GetItemIfSet(ATTR_MARGIN)) )
+ ;
else
pMargin = &pPattern->GetItem(ATTR_MARGIN);
sal_uInt16 nIndent = 0;
if ( eHorJust == SvxCellHorJustify::Left )
{
+ const ScIndentItem* pIndentItem;
if (pCondSet &&
- pCondSet->GetItemState(ATTR_INDENT, true, &pCondItem) == SfxItemState::SET)
- nIndent = static_cast<const ScIndentItem*>(pCondItem)->GetValue();
+ (pIndentItem = pCondSet->GetItemIfSet(ATTR_INDENT)) )
+ nIndent = pIndentItem->GetValue();
else
nIndent = pPattern->GetItem(ATTR_INDENT).GetValue();
}
@@ -267,25 +283,25 @@ tools::Long ScColumn::GetNeededSize(
{
Fraction aFontZoom = ( eOrient == SvxCellOrientation::Standard ) ? rZoomX : rZoomY;
vcl::Font aFont;
+ aFont.SetKerning(FontKerning::NONE); // like ScDrawStringsVars::SetPattern
// font color doesn't matter here
- pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &aFontZoom, pCondSet, nScript );
+ pPattern->fillFontOnly(aFont, pDev, &aFontZoom, pCondSet, nScript);
pDev->SetFont(aFont);
}
bool bAddMargin = true;
- CellType eCellType = aCell.meType;
+ CellType eCellType = aCell.getType();
bool bEditEngine = (eCellType == CELLTYPE_EDIT ||
eOrient == SvxCellOrientation::Stacked ||
IsAmbiguousScript(nScript) ||
- ((eCellType == CELLTYPE_FORMULA) && aCell.mpFormula->IsMultilineResult()));
+ ((eCellType == CELLTYPE_FORMULA) && aCell.getFormula()->IsMultilineResult()));
if (!bEditEngine) // direct output
{
const Color* pColor;
- OUString aValStr;
- ScCellFormat::GetString(
- aCell, nFormat, aValStr, &pColor, *pFormatter, rDocument, true, rOptions.bFormula);
+ OUString aValStr = ScCellFormat::GetString(
+ aCell, nFormat, &pColor, &rContext, rDocument, true, rOptions.bFormula);
if (!aValStr.isEmpty())
{
@@ -302,7 +318,7 @@ tools::Long ScColumn::GetNeededSize(
{
//TODO: take different X/Y scaling into consideration
- double nRealOrient = nRotate.get() * F_PI18000; // nRotate is in 1/100 Grad
+ double nRealOrient = toRadians(nRotate);
double nCosAbs = fabs( cos( nRealOrient ) );
double nSinAbs = fabs( sin( nRealOrient ) );
tools::Long nHeight = static_cast<tools::Long>( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
@@ -371,39 +387,32 @@ tools::Long ScColumn::GetNeededSize(
vcl::Font aOldFont = pDev->GetFont();
MapMode aHMMMode( MapUnit::Map100thMM, Point(), rZoomX, rZoomY );
- MapMode aTwipMode(MapUnit::MapTwip, Point(), rZoomX, rZoomY);
// save in document ?
std::unique_ptr<ScFieldEditEngine> pEngine = rDocument.CreateFieldEditEngine();
- pEngine->SetUpdateMode( false );
+ const bool bPrevUpdateLayout = pEngine->SetUpdateLayout( false );
bool bTextWysiwyg = ( pDev->GetOutDevType() == OUTDEV_PRINTER );
- EEControlBits nCtrl = pEngine->GetControlWord();
- if ( bTextWysiwyg )
- nCtrl |= EEControlBits::FORMAT100;
- else
- nCtrl &= ~EEControlBits::FORMAT100;
- pEngine->SetControlWord( nCtrl );
MapMode aOld = pDev->GetMapMode();
pDev->SetMapMode( aHMMMode );
pEngine->SetRefDevice( pDev );
rDocument.ApplyAsianEditSettings( *pEngine );
- std::unique_ptr<SfxItemSet> pSet(new SfxItemSet( pEngine->GetEmptyItemSet() ));
+ SfxItemSet aSet( pEngine->GetEmptyItemSet() );
if ( ScStyleSheet* pPreviewStyle = rDocument.GetPreviewCellStyle( nCol, nRow, nTab ) )
{
ScPatternAttr aPreviewPattern( *pPattern );
aPreviewPattern.SetStyleSheet(pPreviewStyle);
- aPreviewPattern.FillEditItemSet( pSet.get(), pCondSet );
+ aPreviewPattern.FillEditItemSet( &aSet, pCondSet );
}
else
{
SfxItemSet* pFontSet = rDocument.GetPreviewFont( nCol, nRow, nTab );
- pPattern->FillEditItemSet( pSet.get(), pFontSet ? pFontSet : pCondSet );
+ pPattern->FillEditItemSet( &aSet, pFontSet ? pFontSet : pCondSet );
}
// no longer needed, are set with the text (is faster)
// pEngine->SetDefaults( pSet );
- if ( pSet->Get(EE_PARA_HYPHENATE).GetValue() ) {
+ if ( aSet.Get(EE_PARA_HYPHENATE).GetValue() ) {
css::uno::Reference<css::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
pEngine->SetHyphenator( xXHyphenator );
@@ -448,33 +457,32 @@ tools::Long ScColumn::GetNeededSize(
if ( !bTextWysiwyg )
{
aPaper = bInPrintTwips ?
- OutputDevice::LogicToLogic(aPaper, aTwipMode, aHMMMode) :
+ o3tl::convert(aPaper, o3tl::Length::twip, o3tl::Length::mm100) :
pDev->PixelToLogic(aPaper, aHMMMode);
}
}
pEngine->SetPaperSize(aPaper);
- if (aCell.meType == CELLTYPE_EDIT)
+ if (aCell.getType() == CELLTYPE_EDIT)
{
- pEngine->SetTextNewDefaults(*aCell.mpEditText, std::move(pSet));
+ pEngine->SetTextNewDefaults(*aCell.getEditText(), std::move(aSet));
}
else
{
const Color* pColor;
- OUString aString;
- ScCellFormat::GetString(
- aCell, nFormat, aString, &pColor, *pFormatter, rDocument, true,
+ OUString aString = ScCellFormat::GetString(
+ aCell, nFormat, &pColor, &rContext, rDocument, true,
rOptions.bFormula);
if (!aString.isEmpty())
- pEngine->SetTextNewDefaults(aString, std::move(pSet));
+ pEngine->SetTextNewDefaults(aString, std::move(aSet));
else
- pEngine->SetDefaults(std::move(pSet));
+ pEngine->SetDefaults(std::move(aSet));
}
- bool bEngineVertical = pEngine->IsVertical();
+ bool bEngineVertical = pEngine->IsEffectivelyVertical();
pEngine->SetVertical( bAsianVertical );
- pEngine->SetUpdateMode( true );
+ pEngine->SetUpdateLayout( bPrevUpdateLayout );
bool bEdWidth = bWidth;
if ( eOrient != SvxCellOrientation::Standard && eOrient != SvxCellOrientation::Stacked )
@@ -484,7 +492,7 @@ tools::Long ScColumn::GetNeededSize(
//TODO: take different X/Y scaling into consideration
Size aSize( pEngine->CalcTextWidth(), pEngine->GetTextHeight() );
- double nRealOrient = nRotate.get() * F_PI18000; // nRotate is in 1/100 Grad
+ double nRealOrient = toRadians(nRotate);
double nCosAbs = fabs( cos( nRealOrient ) );
double nSinAbs = fabs( sin( nRealOrient ) );
tools::Long nHeight = static_cast<tools::Long>( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
@@ -504,7 +512,7 @@ tools::Long ScColumn::GetNeededSize(
aSize = Size( nWidth, nHeight );
Size aTextSize = bInPrintTwips ?
- OutputDevice::LogicToLogic(aSize, aHMMMode, aTwipMode) :
+ o3tl::toTwips(aSize, o3tl::Length::mm100) :
pDev->LogicToPixel(aSize, aHMMMode);
if ( bEdWidth )
@@ -528,32 +536,18 @@ tools::Long ScColumn::GetNeededSize(
nValue = 0;
else
{
- Size aTextSize(pEngine->CalcTextWidth(), 0);
+ sal_uInt32 aTextSize(pEngine->CalcTextWidth());
nValue = bInPrintTwips ?
- OutputDevice::LogicToLogic(aTextSize, aHMMMode, aTwipMode).Width() :
- pDev->LogicToPixel(aTextSize, aHMMMode).Width();
+ o3tl::toTwips(aTextSize, o3tl::Length::mm100) :
+ pDev->LogicToPixel(Size(aTextSize, 0), aHMMMode).Width();
}
}
else // height
{
- Size aTextSize(0, pEngine->GetTextHeight());
+ sal_uInt32 aTextSize(pEngine->GetTextHeight());
nValue = bInPrintTwips ?
- OutputDevice::LogicToLogic(aTextSize, aHMMMode, aTwipMode).Height() :
- pDev->LogicToPixel(aTextSize, aHMMMode).Height();
-
- // With non-100% zoom and several lines or paragraphs, don't shrink below the result with FORMAT100 set
- if ( !bTextWysiwyg && ( rZoomY.GetNumerator() != 1 || rZoomY.GetDenominator() != 1 ) &&
- ( pEngine->GetParagraphCount() > 1 || ( bBreak && pEngine->GetLineCount(0) > 1 ) ) )
- {
- pEngine->SetControlWord( nCtrl | EEControlBits::FORMAT100 );
- pEngine->QuickFormatDoc( true );
- aTextSize = Size(0, pEngine->GetTextHeight());
- tools::Long nSecondValue = bInPrintTwips ?
- OutputDevice::LogicToLogic(aTextSize, aHMMMode, aTwipMode).Height() :
- pDev->LogicToPixel(aTextSize, aHMMMode).Height();
- if ( nSecondValue > nValue )
- nValue = nSecondValue;
- }
+ o3tl::toTwips(aTextSize, o3tl::Length::mm100) :
+ pDev->LogicToPixel(Size(0, aTextSize), aHMMMode).Height();
}
if ( nValue && bAddMargin )
@@ -615,17 +609,66 @@ class MaxStrLenFinder
OUString maMaxLenStr;
sal_Int32 mnMaxLen;
+ // tdf#59820 - search for the longest substring in a multiline string
+ void checkLineBreak(const OUString& aStrVal)
+ {
+ sal_Int32 nFromIndex = 0;
+ sal_Int32 nToIndex = aStrVal.indexOf('\n', nFromIndex);
+ // if there is no line break, just take the length of the entire string
+ if (nToIndex == -1)
+ {
+ mnMaxLen = aStrVal.getLength();
+ maMaxLenStr = aStrVal;
+ }
+ else
+ {
+ sal_Int32 nMaxLen = 0;
+ // search for the longest substring in the multiline string
+ while (nToIndex != -1)
+ {
+ if (nMaxLen < nToIndex - nFromIndex)
+ {
+ nMaxLen = nToIndex - nFromIndex;
+ }
+ nFromIndex = nToIndex + 1;
+ nToIndex = aStrVal.indexOf('\n', nFromIndex);
+ }
+ // take into consideration the last part of multiline string
+ nToIndex = aStrVal.getLength() - nFromIndex;
+ if (nMaxLen < nToIndex)
+ {
+ nMaxLen = nToIndex;
+ }
+ // assign new maximum including its substring
+ if (mnMaxLen < nMaxLen)
+ {
+ mnMaxLen = nMaxLen;
+ maMaxLenStr = aStrVal.subView(nFromIndex);
+ }
+ }
+ }
+
void checkLength(const ScRefCellValue& rCell)
{
const Color* pColor;
- OUString aValStr;
- ScCellFormat::GetString(
- rCell, mnFormat, aValStr, &pColor, *mrDoc.GetFormatTable(), mrDoc);
+ OUString aValStr = ScCellFormat::GetString(
+ rCell, mnFormat, &pColor, nullptr, mrDoc);
- if (aValStr.getLength() > mnMaxLen)
+ if (aValStr.getLength() <= mnMaxLen)
+ return;
+
+ switch (rCell.getType())
{
- mnMaxLen = aValStr.getLength();
- maMaxLenStr = aValStr;
+ case CELLTYPE_NONE:
+ case CELLTYPE_VALUE:
+ mnMaxLen = aValStr.getLength();
+ maMaxLenStr = aValStr;
+ break;
+ case CELLTYPE_EDIT:
+ case CELLTYPE_STRING:
+ case CELLTYPE_FORMULA:
+ default:
+ checkLineBreak(aValStr);
}
}
@@ -643,8 +686,7 @@ public:
{
if (rSS.getLength() > mnMaxLen)
{
- mnMaxLen = rSS.getLength();
- maMaxLenStr = rSS.getString();
+ checkLineBreak(rSS.getString());
}
}
@@ -673,10 +715,10 @@ sal_uInt16 ScColumn::GetOptimalColWidth(
// All cells are empty.
return nOldWidth;
- sc::SingleColumnSpanSet aSpanSet(GetDoc().GetSheetLimits());
sc::SingleColumnSpanSet::SpansType aMarkedSpans;
if (pMarkData && (pMarkData->IsMarked() || pMarkData->IsMultiMarked()))
{
+ sc::SingleColumnSpanSet aSpanSet(GetDoc().GetSheetLimits());
aSpanSet.scan(*pMarkData, nTab, nCol);
aSpanSet.getSpans(aMarkedSpans);
}
@@ -690,25 +732,38 @@ sal_uInt16 ScColumn::GetOptimalColWidth(
if ( pParam && pParam->mbSimpleText )
{ // all the same except for number format
- const ScPatternAttr* pPattern = GetPattern( 0 );
+ SCROW nRow = 0;
+ const ScPatternAttr* pPattern = GetPattern( nRow );
vcl::Font aFont;
+ aFont.SetKerning(FontKerning::NONE); // like ScDrawStringsVars::SetPattern
// font color doesn't matter here
- pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &rZoomX );
- pDev->SetFont( aFont );
+ pPattern->fillFontOnly(aFont, pDev, &rZoomX);
+ pDev->SetFont(aFont);
const SvxMarginItem* pMargin = &pPattern->GetItem(ATTR_MARGIN);
tools::Long nMargin = static_cast<tools::Long>( pMargin->GetLeftMargin() * nPPTX ) +
static_cast<tools::Long>( pMargin->GetRightMargin() * nPPTX );
// Try to find the row that has the longest string, and measure the width of that string.
- SvNumberFormatter* pFormatter = rDocument.GetFormatTable();
- sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
+ ScInterpreterContext& rContext = rDocument.GetNonThreadedContext();
+ sal_uInt32 nFormat = pPattern->GetNumberFormat(rContext);
+ while ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && nRow <= 2)
+ {
+ // This is often used with CSV import or other data having a header
+ // row; if there is no specific format set try next row for actual
+ // data format.
+ // Or again in case there was a leading sep=";" row or two header
+ // rows..
+ const ScPatternAttr* pNextPattern = GetPattern( ++nRow );
+ if (!ScPatternAttr::areSame(pNextPattern, pPattern))
+ nFormat = pNextPattern->GetNumberFormat(rContext);
+ }
OUString aLongStr;
const Color* pColor;
if (pParam->mnMaxTextRow >= 0)
{
ScRefCellValue aCell = GetCellValue(pParam->mnMaxTextRow);
- ScCellFormat::GetString(
- aCell, nFormat, aLongStr, &pColor, *pFormatter, rDocument);
+ aLongStr = ScCellFormat::GetString(
+ aCell, nFormat, &pColor, &rContext, rDocument);
}
else
{
@@ -735,31 +790,30 @@ sal_uInt16 ScColumn::GetOptimalColWidth(
// Go though all non-empty cells within selection.
sc::CellStoreType::const_iterator itPos = maCells.begin();
- for (const auto& rMarkedSpan : aMarkedSpans)
+ // coverity[auto_causes_copy] This trivial copy is intentional
+ for (auto [ nRow, nRow2 ] : aMarkedSpans)
{
- SCROW nRow1 = rMarkedSpan.mnRow1, nRow2 = rMarkedSpan.mnRow2;
- SCROW nRow = nRow1;
while (nRow <= nRow2)
{
- std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
- itPos = aPos.first;
+ size_t nOffset;
+ std::tie(itPos, nOffset) = maCells.position(itPos, nRow);
if (itPos->type == sc::element_type_empty)
{
// Skip empty cells.
- nRow += itPos->size - aPos.second;
+ nRow += itPos->size - nOffset;
continue;
}
- for (size_t nOffset = aPos.second; nOffset < itPos->size; ++nOffset, ++nRow)
+ for (; nOffset < itPos->size && nRow <= nRow2; ++nOffset, ++nRow)
{
SvtScriptType nScript = rDocument.GetScriptType(nCol, nRow, nTab);
if (nScript == SvtScriptType::NONE)
nScript = ScGlobal::GetDefaultScriptType();
const ScPatternAttr* pPattern = GetPattern(nRow);
- aOptions.pPattern = pPattern;
- aOptions.bGetFont = (pPattern != pOldPattern || nScript != SvtScriptType::NONE);
- pOldPattern = pPattern;
+ aOptions.bGetFont = (!ScPatternAttr::areSame(pPattern, pOldPattern) || nScript != SvtScriptType::NONE);
+ aOptions.aPattern.setScPatternAttr(pPattern);
+ pOldPattern = aOptions.aPattern.getScPatternAttr();
sal_uInt16 nThis = static_cast<sal_uInt16>(GetNeededSize(
nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, true, aOptions, &pOldPattern));
if (nThis && (nThis > nWidth || !bFound))
@@ -776,14 +830,15 @@ sal_uInt16 ScColumn::GetOptimalColWidth(
{
nWidth += 2;
sal_uInt16 nTwips = static_cast<sal_uInt16>(
- std::min(nWidth / nPPTX, double(std::numeric_limits<sal_uInt16>::max())));
+ std::min(nWidth / nPPTX, std::numeric_limits<sal_uInt16>::max() / 2.0));
return nTwips;
}
else
return nOldWidth;
}
-static sal_uInt16 lcl_GetAttribHeight( const ScPatternAttr& rPattern, sal_uInt16 nFontHeightId )
+static sal_uInt16 lcl_GetAttribHeight(const ScPatternAttr& rPattern, sal_uInt16 nFontHeightId,
+ sal_uInt16 nMinHeight)
{
const SvxFontHeightItem& rFontHeight =
static_cast<const SvxFontHeightItem&>(rPattern.GetItem(nFontHeightId));
@@ -805,8 +860,8 @@ static sal_uInt16 lcl_GetAttribHeight( const ScPatternAttr& rPattern, sal_uInt16
if (nHeight > STD_ROWHEIGHT_DIFF)
nHeight -= STD_ROWHEIGHT_DIFF;
- if (nHeight < ScGlobal::nStdRowHeight)
- nHeight = ScGlobal::nStdRowHeight;
+ if (nHeight < nMinHeight)
+ nHeight = nMinHeight;
return nHeight;
}
@@ -820,7 +875,7 @@ void ScColumn::GetOptimalHeight(
{
ScDocument& rDocument = GetDoc();
RowHeightsArray& rHeights = rCxt.getHeightArray();
- ScAttrIterator aIter( pAttrArray.get(), nStartRow, nEndRow, rDocument.GetDefPattern() );
+ ScAttrIterator aIter( pAttrArray.get(), nStartRow, nEndRow, &rDocument.getCellAttributeHelper().getDefaultCellAttribute() );
SCROW nStart = -1;
SCROW nEnd = -1;
@@ -830,6 +885,7 @@ void ScColumn::GetOptimalHeight(
// with conditional formatting, always consider the individual cells
const ScPatternAttr* pPattern = aIter.Next(nStart,nEnd);
+ const sal_uInt16 nOptimalMinRowHeight = GetDoc().GetSheetOptimalMinRowHeight(nTab);
while ( pPattern )
{
const ScMergeAttr* pMerge = &pPattern->GetItem(ATTR_MERGE);
@@ -906,11 +962,14 @@ void ScColumn::GetOptimalHeight(
sal_uInt16 nDefHeight;
SvtScriptType nDefScript = ScGlobal::GetDefaultScriptType();
if ( nDefScript == SvtScriptType::ASIAN )
- nDefHeight = nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
+ nDefHeight = nCjkHeight = lcl_GetAttribHeight(*pPattern, ATTR_CJK_FONT_HEIGHT,
+ nOptimalMinRowHeight);
else if ( nDefScript == SvtScriptType::COMPLEX )
- nDefHeight = nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
+ nDefHeight = nCtlHeight = lcl_GetAttribHeight(*pPattern, ATTR_CTL_FONT_HEIGHT,
+ nOptimalMinRowHeight);
else
- nDefHeight = nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
+ nDefHeight = nLatHeight = lcl_GetAttribHeight(*pPattern, ATTR_FONT_HEIGHT,
+ nOptimalMinRowHeight);
// if everything below is already larger, the loop doesn't have to
// be run again
@@ -951,21 +1010,26 @@ void ScColumn::GetOptimalHeight(
if ( nScript == SvtScriptType::ASIAN )
{
if ( nCjkHeight == 0 )
- nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
+ nCjkHeight = lcl_GetAttribHeight(*pPattern,
+ ATTR_CJK_FONT_HEIGHT,
+ nOptimalMinRowHeight);
if (nCjkHeight > rHeights.GetValue(nRow))
rHeights.SetValue(nRow, nRow, nCjkHeight);
}
else if ( nScript == SvtScriptType::COMPLEX )
{
if ( nCtlHeight == 0 )
- nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
+ nCtlHeight = lcl_GetAttribHeight(*pPattern,
+ ATTR_CTL_FONT_HEIGHT,
+ nOptimalMinRowHeight);
if (nCtlHeight > rHeights.GetValue(nRow))
rHeights.SetValue(nRow, nRow, nCtlHeight);
}
else
{
if ( nLatHeight == 0 )
- nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
+ nLatHeight = lcl_GetAttribHeight(*pPattern, ATTR_FONT_HEIGHT,
+ nOptimalMinRowHeight);
if (nLatHeight > rHeights.GetValue(nRow))
rHeights.SetValue(nRow, nRow, nLatHeight);
}
@@ -977,6 +1041,7 @@ void ScColumn::GetOptimalHeight(
if (!bStdOnly) // search covered cells
{
ScNeededSizeOptions aOptions;
+ CellAttributeHolder aOldPattern;
for (const auto& rSpan : aSpans)
{
@@ -986,8 +1051,8 @@ void ScColumn::GetOptimalHeight(
if (rCxt.isForceAutoSize() || !(rDocument.GetRowFlags(nRow, nTab) & CRFlags::ManualSize) )
{
- aOptions.pPattern = pPattern;
- const ScPatternAttr* pOldPattern = pPattern;
+ aOptions.aPattern.setScPatternAttr(pPattern);
+ aOldPattern.setScPatternAttr(aOptions.aPattern.getScPatternAttr());
sal_uInt16 nHeight = static_cast<sal_uInt16>(
std::min(
GetNeededSize( nRow, rCxt.getOutputDevice(), rCxt.getPPTX(), rCxt.getPPTY(),
@@ -996,8 +1061,9 @@ void ScColumn::GetOptimalHeight(
double(std::numeric_limits<sal_uInt16>::max())));
if (nHeight > rHeights.GetValue(nRow))
rHeights.SetValue(nRow, nRow, nHeight);
+
// Pattern changed due to calculation? => sync.
- if (pPattern != pOldPattern)
+ if (!ScPatternAttr::areSame(pPattern, aOldPattern.getScPatternAttr()))
{
pPattern = aIter.Resync( nRow, nStart, nEnd);
nNextEnd = 0;
@@ -1022,7 +1088,6 @@ void ScColumn::GetOptimalHeight(
bool ScColumn::GetNextSpellingCell(SCROW& nRow, bool bInSel, const ScMarkData& rData) const
{
ScDocument& rDocument = GetDoc();
- bool bStop = false;
sc::CellStoreType::const_iterator it = maCells.position(nRow).first;
mdds::mtv::element_t eType = it->type;
if (!bInSel && it != maCells.end() && eType != sc::element_type_empty)
@@ -1032,15 +1097,16 @@ bool ScColumn::GetNextSpellingCell(SCROW& nRow, bool bInSel, const ScMarkData& r
rDocument.IsTabProtected(nTab)) )
return true;
}
- while (!bStop)
+ if (bInSel)
{
- if (bInSel)
+ SCROW lastDataPos = GetLastDataPos();
+ for (;;)
{
nRow = rData.GetNextMarked(nCol, nRow, false);
- if (!rDocument.ValidRow(nRow))
+ if (!rDocument.ValidRow(nRow) || nRow > lastDataPos )
{
nRow = GetDoc().MaxRow()+1;
- bStop = true;
+ return false;
}
else
{
@@ -1054,7 +1120,10 @@ bool ScColumn::GetNextSpellingCell(SCROW& nRow, bool bInSel, const ScMarkData& r
nRow++;
}
}
- else if (GetNextDataPos(nRow))
+ }
+ else
+ {
+ while (GetNextDataPos(nRow))
{
it = maCells.position(it, nRow).first;
eType = it->type;
@@ -1065,13 +1134,9 @@ bool ScColumn::GetNextSpellingCell(SCROW& nRow, bool bInSel, const ScMarkData& r
else
nRow++;
}
- else
- {
- nRow = GetDoc().MaxRow()+1;
- bStop = true;
- }
+ nRow = GetDoc().MaxRow()+1;
+ return false;
}
- return false;
}
namespace {
@@ -1086,7 +1151,7 @@ protected:
SCROW mnRow;
OUString maStr;
- StrEntry(SCROW nRow, const OUString& rStr) : mnRow(nRow), maStr(rStr) {}
+ StrEntry(SCROW nRow, OUString aStr) : mnRow(nRow), maStr(std::move(aStr)) {}
};
std::vector<StrEntry> maStrEntries;
@@ -1183,10 +1248,13 @@ public:
}
-void ScColumn::RemoveEditAttribs( SCROW nStartRow, SCROW nEndRow )
+void ScColumn::RemoveEditAttribs( sc::ColumnBlockPosition& rBlockPos, SCROW nStartRow, SCROW nEndRow )
{
RemoveEditAttribsHandler aFunc(maCells, &GetDoc());
- sc::ProcessEditText(maCells.begin(), maCells, nStartRow, nEndRow, aFunc);
+
+ rBlockPos.miCellPos = sc::ProcessEditText(
+ rBlockPos.miCellPos, maCells, nStartRow, nEndRow, aFunc);
+
aFunc.commitStrings();
}
@@ -1242,16 +1310,12 @@ bool ScColumn::HasVisibleDataAt(SCROW nRow) const
return it->type != sc::element_type_empty;
}
-bool ScColumn::IsEmptyAttr() const
+bool ScColumn::IsEmptyData(SCROW nStartRow, SCROW nEndRow) const
{
- if (pAttrArray)
- return pAttrArray->IsEmpty();
- else
+ // simple case
+ if (maCells.block_size() == 1 && maCells.begin()->type == sc::element_type_empty)
return true;
-}
-bool ScColumn::IsEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
-{
std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
sc::CellStoreType::const_iterator it = aPos.first;
if (it == maCells.end())
@@ -1286,13 +1350,13 @@ bool ScColumn::IsNotesEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
SCSIZE ScColumn::GetEmptyLinesInBlock( SCROW nStartRow, SCROW nEndRow, ScDirection eDir ) const
{
- // Given a range of rows, find a top or bottom empty segment. Skip the start row.
+ // Given a range of rows, find a top or bottom empty segment.
switch (eDir)
{
case DIR_TOP:
{
// Determine the length of empty head segment.
- size_t nLength = nEndRow - nStartRow;
+ size_t nLength = nEndRow - nStartRow + 1;
std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
sc::CellStoreType::const_iterator it = aPos.first;
if (it->type != sc::element_type_empty)
@@ -1307,7 +1371,7 @@ SCSIZE ScColumn::GetEmptyLinesInBlock( SCROW nStartRow, SCROW nEndRow, ScDirecti
case DIR_BOTTOM:
{
// Determine the length of empty tail segment.
- size_t nLength = nEndRow - nStartRow;
+ size_t nLength = nEndRow - nStartRow + 1;
std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nEndRow);
sc::CellStoreType::const_iterator it = aPos.first;
if (it->type != sc::element_type_empty)
@@ -1350,19 +1414,20 @@ SCROW ScColumn::GetLastDataPos() const
return GetDoc().MaxRow() - static_cast<SCROW>(it->size);
}
-SCROW ScColumn::GetLastDataPos( SCROW nLastRow, bool bConsiderCellNotes,
- bool bConsiderCellDrawObjects, bool bConsiderCellFormats ) const
+SCROW ScColumn::GetLastDataPos( SCROW nLastRow, ScDataAreaExtras* pDataAreaExtras ) const
{
- sc::CellStoreType::const_position_type aPos = maCells.position(std::min(nLastRow,GetDoc().MaxRow()));
-
- if (bConsiderCellNotes && !IsNotesEmptyBlock(nLastRow, nLastRow))
- return nLastRow;
+ nLastRow = std::min( nLastRow, GetDoc().MaxRow());
- if (bConsiderCellDrawObjects && !IsDrawObjectsEmptyBlock(nLastRow, nLastRow))
- return nLastRow;
+ if (pDataAreaExtras && pDataAreaExtras->mnEndRow < nLastRow)
+ {
+ // Check in order of likeliness.
+ if ( (pDataAreaExtras->mbCellFormats && HasVisibleAttrIn(nLastRow, nLastRow)) ||
+ (pDataAreaExtras->mbCellNotes && !IsNotesEmptyBlock(nLastRow, nLastRow)) ||
+ (pDataAreaExtras->mbCellDrawObjects && !IsDrawObjectsEmptyBlock(nLastRow, nLastRow)))
+ pDataAreaExtras->mnEndRow = nLastRow;
+ }
- if (bConsiderCellFormats && HasVisibleAttrIn(nLastRow, nLastRow))
- return nLastRow;
+ sc::CellStoreType::const_position_type aPos = maCells.position(nLastRow);
if (aPos.first->type != sc::element_type_empty)
return nLastRow;
@@ -1609,28 +1674,16 @@ void ScColumn::CellStorageModified()
// TODO: Update column's "last updated" timestamp here.
-#if DEBUG_COLUMN_STORAGE
- if (maCells.size() != MAXROWCOUNT1)
- {
- cout << "ScColumn::CellStorageModified: Size of the cell array is incorrect." << endl;
- cout.flush();
- abort();
- }
+ assert(sal::static_int_cast<SCROW>(maCells.size()) == GetDoc().GetMaxRowCount()
+ && "Size of the cell array is incorrect." );
- if (maCellTextAttrs.size() != MAXROWCOUNT1)
- {
- cout << "ScColumn::CellStorageModified: Size of the cell text attribute array is incorrect." << endl;
- cout.flush();
- abort();
- }
+ assert(sal::static_int_cast<SCROW>(maCellTextAttrs.size()) == GetDoc().GetMaxRowCount()
+ && "Size of the cell text attribute array is incorrect.");
- if (maBroadcasters.size() != MAXROWCOUNT1)
- {
- cout << "ScColumn::CellStorageModified: Size of the broadcaster array is incorrect." << endl;
- cout.flush();
- abort();
- }
+ assert(sal::static_int_cast<SCROW>(maBroadcasters.size()) == GetDoc().GetMaxRowCount()
+ && "Size of the broadcaster array is incorrect.");
+#if DEBUG_COLUMN_STORAGE
// Make sure that these two containers are synchronized wrt empty segments.
auto lIsEmptyType = [](const auto& rElement) { return rElement.type == sc::element_type_empty; };
// Move to the first empty blocks.
@@ -1873,9 +1926,10 @@ public:
SCROW nDestRow = nRow + mnDestOffset;
ScAddress aSrcPos(mnSrcCol, nRow, mnSrcTab);
ScAddress aDestPos(mnDestCol, nDestRow, mnDestTab);
- miPos = mrDestNotes.set(miPos, nDestRow, p->Clone(aSrcPos, mrDestCol.GetDoc(), aDestPos, mbCloneCaption).release());
+ ScPostIt* pNew = p->Clone(aSrcPos, mrDestCol.GetDoc(), aDestPos, mbCloneCaption).release();
+ miPos = mrDestNotes.set(miPos, nDestRow, pNew);
// Notify our LOK clients also
- ScDocShell::LOKCommentNotify(LOKCommentNotificationType::Add, &mrDestCol.GetDoc(), aDestPos, p);
+ ScDocShell::LOKCommentNotify(LOKCommentNotificationType::Add, mrDestCol.GetDoc(), aDestPos, pNew);
}
};
@@ -1940,6 +1994,191 @@ void ScColumn::PrepareBroadcastersForDestruction()
}
}
+namespace
+{
+struct BroadcasterNoListenersPredicate
+{
+ bool operator()( size_t, const SvtBroadcaster* broadcaster )
+ {
+ return !broadcaster->HasListeners();
+ }
+};
+
+}
+
+void ScColumn::DeleteEmptyBroadcasters()
+{
+ if(!mbEmptyBroadcastersPending)
+ return;
+ // Clean up after ScDocument::EnableDelayDeletingBroadcasters().
+ BroadcasterNoListenersPredicate predicate;
+ sc::SetElementsToEmpty1<sc::broadcaster_block>( maBroadcasters, predicate );
+ mbEmptyBroadcastersPending = false;
+}
+
+// Sparklines
+
+namespace
+{
+
+class DeletingSparklinesHandler
+{
+ ScDocument& m_rDocument;
+ SCTAB m_nTab;
+
+public:
+ DeletingSparklinesHandler(ScDocument& rDocument, SCTAB nTab)
+ : m_rDocument(rDocument)
+ , m_nTab(nTab)
+ {}
+
+ void operator() (size_t /*nRow*/, const sc::SparklineCell* pCell)
+ {
+ auto* pList = m_rDocument.GetSparklineList(m_nTab);
+ pList->removeSparkline(pCell->getSparkline());
+ }
+};
+
+} // end anonymous ns
+
+sc::SparklineCell* ScColumn::GetSparklineCell(SCROW nRow)
+{
+ return maSparklines.get<sc::SparklineCell*>(nRow);
+}
+
+void ScColumn::CreateSparklineCell(SCROW nRow, std::shared_ptr<sc::Sparkline> const& pSparkline)
+{
+ auto* pList = GetDoc().GetSparklineList(GetTab());
+ pList->addSparkline(pSparkline);
+ maSparklines.set(nRow, new sc::SparklineCell(pSparkline));
+}
+
+void ScColumn::DeleteSparklineCells(sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2)
+{
+ DeletingSparklinesHandler aFunction(GetDoc(), nTab);
+ sc::ParseSparkline(maSparklines.begin(), maSparklines, nRow1, nRow2, aFunction);
+
+ rBlockPos.miSparklinePos = maSparklines.set_empty(rBlockPos.miSparklinePos, nRow1, nRow2);
+}
+
+bool ScColumn::DeleteSparkline(SCROW nRow)
+{
+ if (!GetDoc().ValidRow(nRow))
+ return false;
+
+ DeletingSparklinesHandler aFunction(GetDoc(), nTab);
+ sc::ParseSparkline(maSparklines.begin(), maSparklines, nRow, nRow, aFunction);
+
+ maSparklines.set_empty(nRow, nRow);
+ return true;
+}
+
+bool ScColumn::IsSparklinesEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
+{
+ std::pair<sc::SparklineStoreType::const_iterator,size_t> aPos = maSparklines.position(nStartRow);
+ sc::SparklineStoreType::const_iterator it = aPos.first;
+ if (it == maSparklines.end())
+ return false;
+
+ if (it->type != sc::element_type_empty)
+ return false;
+
+ // start position of next block which is not empty.
+ SCROW nNextRow = nStartRow + it->size - aPos.second;
+ return nEndRow < nNextRow;
+}
+
+namespace
+{
+
+class CopySparklinesHandler
+{
+ ScColumn& mrDestColumn;
+ sc::SparklineStoreType& mrDestSparkline;
+ sc::SparklineStoreType::iterator miDestPosition;
+ SCROW mnDestOffset;
+
+public:
+ CopySparklinesHandler(ScColumn& rDestColumn, SCROW nDestOffset)
+ : mrDestColumn(rDestColumn)
+ , mrDestSparkline(mrDestColumn.GetSparklineStore())
+ , miDestPosition(mrDestSparkline.begin())
+ , mnDestOffset(nDestOffset)
+ {}
+
+ void operator() (size_t nRow, const sc::SparklineCell* pCell)
+ {
+ SCROW nDestRow = nRow + mnDestOffset;
+
+ auto const& pSparkline = pCell->getSparkline();
+ auto const& pGroup = pCell->getSparklineGroup();
+
+ auto& rDestDoc = mrDestColumn.GetDoc();
+ auto pDestinationGroup = rDestDoc.SearchSparklineGroup(pGroup->getID());
+ if (!pDestinationGroup)
+ pDestinationGroup = std::make_shared<sc::SparklineGroup>(*pGroup); // Copy the group
+ auto pNewSparkline = std::make_shared<sc::Sparkline>(mrDestColumn.GetCol(), nDestRow, pDestinationGroup);
+ pNewSparkline->setInputRange(pSparkline->getInputRange());
+
+ auto* pList = rDestDoc.GetSparklineList(mrDestColumn.GetTab());
+ pList->addSparkline(pNewSparkline);
+
+ miDestPosition = mrDestSparkline.set(miDestPosition, nDestRow, new sc::SparklineCell(pNewSparkline));
+ }
+};
+
+}
+
+void ScColumn::CopyCellSparklinesToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol, SCROW nRowOffsetDest) const
+{
+ if (IsSparklinesEmptyBlock(nRow1, nRow2))
+ // The column has no cell sparklines to copy between specified rows.
+ return;
+
+ CopySparklinesHandler aFunctor(rDestCol, nRowOffsetDest);
+ sc::ParseSparkline(maSparklines.begin(), maSparklines, nRow1, nRow2, aFunctor);
+}
+
+void ScColumn::DuplicateSparklines(SCROW nStartRow, size_t nDataSize, ScColumn& rDestCol,
+ sc::ColumnBlockPosition& rDestBlockPos, SCROW nRowOffsetDest) const
+{
+ CopyCellSparklinesToDocument(nStartRow, nStartRow + nDataSize - 1, rDestCol, nRowOffsetDest);
+ rDestBlockPos.miSparklinePos = rDestCol.maSparklines.begin();
+}
+
+bool ScColumn::HasSparklines() const
+{
+ if (maSparklines.block_size() == 1 && maSparklines.begin()->type == sc::element_type_empty)
+ return false; // all elements are empty
+ return true; // otherwise some must be sparklines
+}
+
+SCROW ScColumn::GetSparklinesMaxRow() const
+{
+ SCROW maxRow = 0;
+ for (const auto& rSparkline : maSparklines)
+ {
+ if (rSparkline.type == sc::element_type_sparkline)
+ maxRow = rSparkline.position + rSparkline.size - 1;
+ }
+ return maxRow;
+}
+
+SCROW ScColumn::GetSparklinesMinRow() const
+{
+ SCROW minRow = 0;
+ sc::SparklineStoreType::const_iterator it = std::find_if(maSparklines.begin(), maSparklines.end(),
+ [](const auto& rSparkline)
+ {
+ return rSparkline.type == sc::element_type_sparkline;
+ });
+ if (it != maSparklines.end())
+ minRow = it->position;
+ return minRow;
+}
+
+// Notes
+
ScPostIt* ScColumn::GetCellNote(SCROW nRow)
{
return maCellNotes.get<ScPostIt*>(nRow);
@@ -1975,13 +2214,13 @@ void ScColumn::SetCellNote(SCROW nRow, std::unique_ptr<ScPostIt> pNote)
namespace {
class CellNoteHandler
{
- const ScDocument* m_pDocument;
+ const ScDocument& m_rDocument;
const ScAddress m_aAddress; // 'incomplete' address consisting of tab, column
const bool m_bForgetCaptionOwnership;
public:
- CellNoteHandler(const ScDocument* pDocument, const ScAddress& rPos, bool bForgetCaptionOwnership) :
- m_pDocument(pDocument),
+ CellNoteHandler(const ScDocument& rDocument, const ScAddress& rPos, bool bForgetCaptionOwnership) :
+ m_rDocument(rDocument),
m_aAddress(rPos),
m_bForgetCaptionOwnership(bForgetCaptionOwnership) {}
@@ -1994,7 +2233,7 @@ namespace {
ScAddress aAddr(m_aAddress);
aAddr.SetRow(nRow);
// Notify our LOK clients
- ScDocShell::LOKCommentNotify(LOKCommentNotificationType::Remove, m_pDocument, aAddr, p);
+ ScDocShell::LOKCommentNotify(LOKCommentNotificationType::Remove, m_rDocument, aAddr, p);
}
};
} // anonymous namespace
@@ -2002,7 +2241,7 @@ namespace {
void ScColumn::CellNotesDeleting(SCROW nRow1, SCROW nRow2, bool bForgetCaptionOwnership)
{
ScAddress aAddr(nCol, 0, nTab);
- CellNoteHandler aFunc(&GetDoc(), aAddr, bForgetCaptionOwnership);
+ CellNoteHandler aFunc(GetDoc(), aAddr, bForgetCaptionOwnership);
sc::ParseNote(maCellNotes.begin(), maCellNotes, nRow1, nRow2, aFunc);
}
@@ -2016,10 +2255,7 @@ void ScColumn::DeleteCellNotes( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1,
bool ScColumn::HasCellNotes() const
{
- return std::any_of(maCellNotes.begin(), maCellNotes.end(),
- [](const auto& rCellNote) {
- // Having a cellnote block automatically means there is at least one cell note.
- return rCellNote.type == sc::element_type_cellnote; });
+ return mnBlkCountCellNotes != 0;
}
SCROW ScColumn::GetCellNotesMaxRow() const
@@ -2186,7 +2422,7 @@ formula::FormulaTokenRef ScColumn::ResolveStaticReference( SCROW nRow )
const EditTextObject* pText = sc::edittext_block::at(*it->data, aPos.second);
OUString aStr = ScEditUtil::GetString(*pText, &GetDoc());
svl::SharedString aSS( GetDoc().GetSharedStringPool().intern(aStr));
- return formula::FormulaTokenRef(new formula::FormulaStringToken(aSS));
+ return formula::FormulaTokenRef(new formula::FormulaStringToken(std::move(aSS)));
}
case sc::element_type_empty:
default:
@@ -2472,8 +2708,6 @@ bool appendToBlock(
{
svl::SharedStringPool& rPool = pDoc->GetSharedStringPool();
size_t nLenRemain = nArrayLen - nPos;
- double fNan;
- rtl::math::setNan(&fNan);
for (sc::CellStoreType::iterator it = _it; it != itEnd; ++it)
{
@@ -2627,9 +2861,6 @@ copyFirstFormulaBlock(
sc::FormulaGroupContext& rCxt, const sc::CellStoreType::iterator& itBlk, size_t nArrayLen,
SCTAB nTab, SCCOL nCol )
{
- double fNan;
- rtl::math::setNan(&fNan);
-
size_t nLen = std::min(itBlk->size, nArrayLen);
sc::formula_block::iterator it = sc::formula_block::begin(*itBlk->data);
@@ -2661,7 +2892,8 @@ copyFirstFormulaBlock(
if (!pNumArray)
{
rCxt.m_NumArrays.push_back(
- std::make_unique<sc::FormulaGroupContext::NumArrayType>(nArrayLen, fNan));
+ std::make_unique<sc::FormulaGroupContext::NumArrayType>(nArrayLen,
+ std::numeric_limits<double>::quiet_NaN()));
pNumArray = rCxt.m_NumArrays.back().get();
}
@@ -2741,9 +2973,6 @@ formula::VectorRefArray ScColumn::FetchVectorRefArray( SCROW nRow1, SCROW nRow2
// So temporarily block the discarding.
ProtectFormulaGroupContext protectContext(&GetDoc());
- double fNan;
- rtl::math::setNan(&fNan);
-
// We need to fetch all cell values from row 0 to nRow2 for caching purposes.
sc::CellStoreType::iterator itBlk = maCells.begin();
switch (itBlk->type)
@@ -2763,7 +2992,8 @@ formula::VectorRefArray ScColumn::FetchVectorRefArray( SCROW nRow1, SCROW nRow2
rCxt.m_NumArrays.push_back(
std::make_unique<sc::FormulaGroupContext::NumArrayType>(it, itEnd));
sc::FormulaGroupContext::NumArrayType& rArray = *rCxt.m_NumArrays.back();
- rArray.resize(nRow2+1, fNan); // allocate to the requested length.
+ // allocate to the requested length.
+ rArray.resize(nRow2+1, std::numeric_limits<double>::quiet_NaN());
pColArray = rCxt.setCachedColArray(nTab, nCol, &rArray, nullptr);
if (!pColArray)
@@ -2877,7 +3107,8 @@ formula::VectorRefArray ScColumn::FetchVectorRefArray( SCROW nRow1, SCROW nRow2
{
// Fill the whole length with NaN's.
rCxt.m_NumArrays.push_back(
- std::make_unique<sc::FormulaGroupContext::NumArrayType>(nRow2+1, fNan));
+ std::make_unique<sc::FormulaGroupContext::NumArrayType>(nRow2+1,
+ std::numeric_limits<double>::quiet_NaN()));
sc::FormulaGroupContext::NumArrayType& rArray = *rCxt.m_NumArrays.back();
pColArray = rCxt.setCachedColArray(nTab, nCol, &rArray, nullptr);
if (!pColArray)
@@ -2950,8 +3181,11 @@ void ScColumn::SetFormulaResults( SCROW nRow, const double* pResults, size_t nLe
size_t nBlockLen = it->size - aPos.second;
if (nBlockLen < nLen)
+ {
// Result array is longer than the length of formula cells. Not good.
+ assert( false );
return;
+ }
sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
std::advance(itCell, aPos.second);
@@ -2986,8 +3220,11 @@ void ScColumn::CalculateInThread( ScInterpreterContext& rContext, SCROW nRow, si
size_t nBlockLen = it->size - aPos.second;
if (nBlockLen < nLen)
+ {
// Length is longer than the length of formula cells. Not good.
+ assert( false );
return;
+ }
sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
std::advance(itCell, aPos.second);
@@ -3019,8 +3256,11 @@ void ScColumn::HandleStuffAfterParallelCalculation( SCROW nRow, size_t nLen, ScI
size_t nBlockLen = it->size - aPos.second;
if (nBlockLen < nLen)
+ {
// Length is longer than the length of formula cells. Not good.
+ assert( false );
return;
+ }
sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
std::advance(itCell, aPos.second);
@@ -3119,33 +3359,19 @@ void ScColumn::FindDataAreaPos(SCROW& rRow, bool bDown) const
rRow = nLastRow;
}
-bool ScColumn::HasDataAt(SCROW nRow, bool bConsiderCellNotes, bool bConsiderCellDrawObjects,
- bool bConsiderCellFormats) const
+bool ScColumn::HasDataAt(SCROW nRow, ScDataAreaExtras* pDataAreaExtras ) const
{
- if (bConsiderCellNotes && !IsNotesEmptyBlock(nRow, nRow))
- return true;
-
- if (bConsiderCellDrawObjects && !IsDrawObjectsEmptyBlock(nRow, nRow))
- return true;
-
- if (bConsiderCellFormats && HasVisibleAttrIn(nRow, nRow))
- return true;
+ if (pDataAreaExtras)
+ GetDataExtrasAt( nRow, *pDataAreaExtras);
return maCells.get_type(nRow) != sc::element_type_empty;
}
-bool ScColumn::HasDataAt(sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow,
- bool bConsiderCellNotes, bool bConsiderCellDrawObjects,
- bool bConsiderCellFormats) const
+bool ScColumn::HasDataAt( sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow,
+ ScDataAreaExtras* pDataAreaExtras ) const
{
- if (bConsiderCellNotes && !IsNotesEmptyBlock(nRow, nRow))
- return true;
-
- if (bConsiderCellDrawObjects && !IsDrawObjectsEmptyBlock(nRow, nRow))
- return true;
-
- if (bConsiderCellFormats && HasVisibleAttrIn(nRow, nRow))
- return true;
+ if (pDataAreaExtras)
+ GetDataExtrasAt( nRow, *pDataAreaExtras);
std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rBlockPos.miCellPos, nRow);
if (aPos.first == maCells.end())
@@ -3154,17 +3380,11 @@ bool ScColumn::HasDataAt(sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow,
return aPos.first->type != sc::element_type_empty;
}
-bool ScColumn::HasDataAt(sc::ColumnBlockPosition& rBlockPos, SCROW nRow,
- bool bConsiderCellNotes, bool bConsiderCellDrawObjects, bool bConsiderCellFormats)
+bool ScColumn::HasDataAt( sc::ColumnBlockPosition& rBlockPos, SCROW nRow,
+ ScDataAreaExtras* pDataAreaExtras )
{
- if (bConsiderCellNotes && !IsNotesEmptyBlock(nRow, nRow))
- return true;
-
- if (bConsiderCellDrawObjects && !IsDrawObjectsEmptyBlock(nRow, nRow))
- return true;
-
- if (bConsiderCellFormats && HasVisibleAttrIn(nRow, nRow))
- return true;
+ if (pDataAreaExtras)
+ GetDataExtrasAt( nRow, *pDataAreaExtras);
std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(rBlockPos.miCellPos, nRow);
if (aPos.first == maCells.end())
@@ -3173,49 +3393,21 @@ bool ScColumn::HasDataAt(sc::ColumnBlockPosition& rBlockPos, SCROW nRow,
return aPos.first->type != sc::element_type_empty;
}
-bool ScColumn::IsAllAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
+void ScColumn::GetDataExtrasAt( SCROW nRow, ScDataAreaExtras& rDataAreaExtras ) const
{
- if (pAttrArray && rCol.pAttrArray)
- return pAttrArray->IsAllEqual( *rCol.pAttrArray, nStartRow, nEndRow );
- else
- return !pAttrArray && !rCol.pAttrArray;
-}
-
-bool ScColumn::IsVisibleAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
-{
- if (pAttrArray && rCol.pAttrArray)
- return pAttrArray->IsVisibleEqual( *rCol.pAttrArray, nStartRow, nEndRow );
- else
- return !pAttrArray && !rCol.pAttrArray;
-}
-
-bool ScColumn::GetFirstVisibleAttr( SCROW& rFirstRow ) const
-{
- if (pAttrArray)
- return pAttrArray->GetFirstVisibleAttr( rFirstRow );
- else
- return false;
-}
+ if (rDataAreaExtras.mnStartRow <= nRow && nRow <= rDataAreaExtras.mnEndRow)
+ return;
-bool ScColumn::GetLastVisibleAttr( SCROW& rLastRow ) const
-{
- if (pAttrArray)
+ // Check in order of likeliness.
+ if ( (rDataAreaExtras.mbCellFormats && HasVisibleAttrIn(nRow, nRow)) ||
+ (rDataAreaExtras.mbCellNotes && !IsNotesEmptyBlock(nRow, nRow)) ||
+ (rDataAreaExtras.mbCellDrawObjects && !IsDrawObjectsEmptyBlock(nRow, nRow)))
{
- // row of last cell is needed
- SCROW nLastData = GetLastDataPos(); // always including notes, 0 if none
-
- return pAttrArray->GetLastVisibleAttr( rLastRow, nLastData );
+ if (rDataAreaExtras.mnStartRow > nRow)
+ rDataAreaExtras.mnStartRow = nRow;
+ if (rDataAreaExtras.mnEndRow < nRow)
+ rDataAreaExtras.mnEndRow = nRow;
}
- else
- return false;
-}
-
-bool ScColumn::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
-{
- if (pAttrArray)
- return pAttrArray->HasVisibleAttrIn( nStartRow, nEndRow );
- else
- return false;
}
namespace {
@@ -3271,13 +3463,7 @@ void startListening(
}
break;
default:
-#if DEBUG_COLUMN_STORAGE
- cout << "ScColumn::StartListening: wrong block type encountered in the broadcaster storage." << endl;
- cout.flush();
- abort();
-#else
- ;
-#endif
+ assert(false && "wrong block type encountered in the broadcaster storage.");
}
}
@@ -3297,8 +3483,12 @@ void ScColumn::EndListening( SvtListener& rLst, SCROW nRow )
rLst.EndListening(*pBC);
if (!pBC->HasListeners())
- // There is no more listeners for this cell. Remove the broadcaster.
- maBroadcasters.set_empty(nRow, nRow);
+ { // There is no more listeners for this cell. Remove the broadcaster.
+ if(GetDoc().IsDelayedDeletingBroadcasters())
+ mbEmptyBroadcastersPending = true;
+ else
+ maBroadcasters.set_empty(nRow, nRow);
+ }
}
void ScColumn::StartListening( sc::StartListeningContext& rCxt, const ScAddress& rAddress, SvtListener& rLst )
@@ -3514,7 +3704,7 @@ namespace {
class WeightedCounter
{
- sal_uLong mnCount;
+ size_t mnCount;
public:
WeightedCounter() : mnCount(0) {}
@@ -3523,7 +3713,7 @@ public:
mnCount += getWeight(node);
}
- static sal_uLong getWeight(const sc::CellStoreType::value_type& node)
+ static size_t getWeight(const sc::CellStoreType::value_type& node)
{
switch (node.type)
{
@@ -3544,14 +3734,14 @@ public:
}
}
- sal_uLong getCount() const { return mnCount; }
+ size_t getCount() const { return mnCount; }
};
class WeightedCounterWithRows
{
const SCROW mnStartRow;
const SCROW mnEndRow;
- sal_uLong mnCount;
+ size_t mnCount;
public:
WeightedCounterWithRows(SCROW nStartRow, SCROW nEndRow)
@@ -3572,19 +3762,19 @@ public:
}
}
- sal_uLong getCount() const { return mnCount; }
+ size_t getCount() const { return mnCount; }
};
}
-sal_uLong ScColumn::GetWeightedCount() const
+sal_uInt64 ScColumn::GetWeightedCount() const
{
const WeightedCounter aFunc = std::for_each(maCells.begin(), maCells.end(),
WeightedCounter());
return aFunc.getCount();
}
-sal_uLong ScColumn::GetWeightedCount(SCROW nStartRow, SCROW nEndRow) const
+sal_uInt64 ScColumn::GetWeightedCount(SCROW nStartRow, SCROW nEndRow) const
{
const WeightedCounterWithRows aFunc = std::for_each(maCells.begin(), maCells.end(),
WeightedCounterWithRows(nStartRow, nEndRow));
@@ -3595,7 +3785,7 @@ namespace {
class CodeCounter
{
- size_t mnCount;
+ sal_uInt64 mnCount;
public:
CodeCounter() : mnCount(0) {}
@@ -3604,31 +3794,16 @@ public:
mnCount += p->GetCode()->GetCodeLen();
}
- size_t getCount() const { return mnCount; }
+ sal_uInt64 getCount() const { return mnCount; }
};
}
-sal_uInt32 ScColumn::GetCodeCount() const
+sal_uInt64 ScColumn::GetCodeCount() const
{
CodeCounter aFunc;
sc::ParseFormula(maCells, aFunc);
return aFunc.getCount();
}
-SCSIZE ScColumn::GetPatternCount() const
-{
- return pAttrArray ? pAttrArray->Count() : 0;
-}
-
-SCSIZE ScColumn::GetPatternCount( SCROW nRow1, SCROW nRow2 ) const
-{
- return pAttrArray ? pAttrArray->Count( nRow1, nRow2 ) : 0;
-}
-
-bool ScColumn::ReservePatternCount( SCSIZE nReserve )
-{
- return pAttrArray && pAttrArray->Reserve( nReserve );
-}
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 73a2ed613548..26fcd36de0ba 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -33,7 +33,6 @@
#include <subtotal.hxx>
#include <markdata.hxx>
#include <stringutil.hxx>
-#include <docpool.hxx>
#include <cellvalue.hxx>
#include <tokenarray.hxx>
#include <clipcontext.hxx>
@@ -44,20 +43,24 @@
#include <sharedformula.hxx>
#include <listenercontext.hxx>
#include <filterentries.hxx>
+#include <conditio.hxx>
+#include <colorscale.hxx>
+#include <table.hxx>
#include <editeng/brushitem.hxx>
-#include <editeng/colritem.hxx>
#include <com/sun/star/i18n/LocaleDataItem2.hpp>
#include <com/sun/star/lang/IllegalArgumentException.hpp>
#include <memory>
+#include <o3tl/deleter.hxx>
+
#include <rtl/tencinfo.h>
+#include <svl/numformat.hxx>
#include <svl/zforlist.hxx>
#include <svl/zformat.hxx>
#include <svl/sharedstringpool.hxx>
-#include <osl/diagnose.h>
#include <cstdio>
#include <refdata.hxx>
@@ -82,13 +85,15 @@ void ScColumn::BroadcastCells( const std::vector<SCROW>& rRows, SfxHintId nHint
ScHint aHint(nHint, ScAddress(nCol, 0, nTab));
for (const auto& rRow : rRows)
{
- aHint.GetAddress().SetRow(rRow);
+ aHint.SetAddressRow(rRow);
rDocument.Broadcast(aHint);
}
}
void ScColumn::BroadcastRows( SCROW nStartRow, SCROW nEndRow, SfxHintId nHint )
{
+ if( nStartRow > GetLastDataPos())
+ return;
sc::SingleColumnSpanSet aSpanSet(GetDoc().GetSheetLimits());
aSpanSet.scan(*this, nStartRow, nEndRow);
std::vector<SCROW> aRows;
@@ -98,13 +103,79 @@ void ScColumn::BroadcastRows( SCROW nStartRow, SCROW nEndRow, SfxHintId nHint )
namespace {
-struct DirtyCellInterpreter
+class CellInterpreterBase
{
- void operator() (size_t, ScFormulaCell* p)
+protected:
+ void Interpret(ScFormulaCell* p)
{
- if (p->GetDirty())
+ // Interpret() takes a range in a formula group, so group those together.
+ if( !groupCells.empty() && p->GetCellGroup() == groupCells.back()->GetCellGroup()
+ && p->aPos.Row() == groupCells.back()->aPos.Row() + 1 )
+ {
+ assert( p->aPos.Tab() == groupCells.back()->aPos.Tab()
+ && p->aPos.Col() == groupCells.back()->aPos.Col());
+ groupCells.push_back(p); // Extend range.
+ return;
+ }
+ flushPending();
+ if( !p->GetCellGroup())
+ {
p->Interpret();
+ return;
+ }
+ groupCells.push_back(p);
+
+ }
+ ~CellInterpreterBase()
+ {
+ suppress_fun_call_w_exception(flushPending());
+ }
+private:
+ void flushPending()
+ {
+ if(groupCells.empty())
+ return;
+ SCROW firstRow = groupCells.front()->GetCellGroup()->mpTopCell->aPos.Row();
+ if(!groupCells.front()->Interpret(
+ groupCells.front()->aPos.Row() - firstRow, groupCells.back()->aPos.Row() - firstRow))
+ {
+ // Interpret() will try to group-interpret the given cell range if possible, but if that
+ // is not possible, it will interpret just the given cell. So if group-interpreting
+ // wasn't possible, interpret them one by one.
+ for(ScFormulaCell* cell : groupCells)
+ cell->Interpret();
+ }
+ groupCells.clear();
+ }
+ std::vector<ScFormulaCell*> groupCells;
+};
+
+class DirtyCellInterpreter : public CellInterpreterBase
+{
+public:
+ void operator() (size_t, ScFormulaCell* p)
+ {
+ if(p->GetDirty())
+ Interpret(p);
+ }
+};
+
+class NeedsInterpretCellInterpreter : public CellInterpreterBase
+{
+public:
+ void operator() (size_t, ScFormulaCell* p)
+ {
+ if(p->NeedsInterpret())
+ {
+ Interpret(p);
+ // In some cases such as circular dependencies Interpret()
+ // will not reset the dirty flag, check that in order to tell
+ // the caller that the cell range may trigger Interpret() again.
+ if(p->NeedsInterpret())
+ allInterpreted = false;
+ }
}
+ bool allInterpreted = true;
};
}
@@ -118,6 +189,16 @@ void ScColumn::InterpretDirtyCells( SCROW nRow1, SCROW nRow2 )
sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
}
+bool ScColumn::InterpretCellsIfNeeded( SCROW nRow1, SCROW nRow2 )
+{
+ if (!GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2) || nRow1 > nRow2)
+ return false;
+
+ NeedsInterpretCellInterpreter aFunc;
+ sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
+ return aFunc.allInterpreted;
+}
+
void ScColumn::DeleteContent( SCROW nRow, bool bBroadcast )
{
sc::CellStoreType::position_type aPos = maCells.position(nRow);
@@ -145,6 +226,7 @@ void ScColumn::Delete( SCROW nRow )
DeleteContent(nRow, false);
maCellTextAttrs.set_empty(nRow, nRow);
maCellNotes.set_empty(nRow, nRow);
+ maSparklines.set_empty(nRow, nRow);
Broadcast(nRow);
CellStorageModified();
@@ -152,7 +234,10 @@ void ScColumn::Delete( SCROW nRow )
void ScColumn::FreeAll()
{
- auto maxRowCount = GetDoc().GetSheetLimits().GetMaxRowCount();
+ maCells.event_handler().stop();
+ maCellNotes.event_handler().stop();
+
+ auto maxRowCount = GetDoc().GetMaxRowCount();
// Keep a logical empty range of 0-rDoc.MaxRow() at all times.
maCells.clear();
maCells.resize(maxRowCount);
@@ -160,13 +245,15 @@ void ScColumn::FreeAll()
maCellTextAttrs.resize(maxRowCount);
maCellNotes.clear();
maCellNotes.resize(maxRowCount);
+ maSparklines.clear();
+ maSparklines.resize(maxRowCount);
CellStorageModified();
}
void ScColumn::FreeNotes()
{
maCellNotes.clear();
- maCellNotes.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
+ maCellNotes.resize(GetDoc().GetMaxRowCount());
}
namespace {
@@ -190,11 +277,11 @@ void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize, std::vector<ScAddress>*
SCROW nEndRow = nStartRow + nSize - 1;
maBroadcasters.erase(nStartRow, nEndRow);
- maBroadcasters.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
+ maBroadcasters.resize(GetDoc().GetMaxRowCount());
CellNotesDeleting(nStartRow, nEndRow, false);
maCellNotes.erase(nStartRow, nEndRow);
- maCellNotes.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
+ maCellNotes.resize(GetDoc().GetMaxRowCount());
// See if we have any cells that would get deleted or shifted by deletion.
sc::CellStoreType::position_type aPos = maCells.position(nStartRow);
@@ -244,7 +331,7 @@ void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize, std::vector<ScAddress>*
// Remove the cells.
maCells.erase(nStartRow, nEndRow);
- maCells.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
+ maCells.resize(GetDoc().GetMaxRowCount());
// Get the position again after the container change.
aPos = maCells.position(nStartRow);
@@ -259,7 +346,7 @@ void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize, std::vector<ScAddress>*
// Shift the text attribute array too (before the broadcast).
maCellTextAttrs.erase(nStartRow, nEndRow);
- maCellTextAttrs.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
+ maCellTextAttrs.resize(GetDoc().GetMaxRowCount());
CellStorageModified();
}
@@ -481,63 +568,53 @@ void ScColumn::AttachFormulaCells( sc::StartListeningContext& rCxt, SCROW nRow1,
if (GetDoc().IsClipOrUndo())
return;
- AttachFormulaCellsHandler aFunc(rCxt);
- sc::ProcessFormula(it, maCells, nRow1, nRow2, aFunc);
-}
-
-void ScColumn::DetachFormulaCells( sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2,
- std::vector<SCROW>* pNewSharedRows )
-{
- sc::CellStoreType::position_type aPos = maCells.position(nRow1);
- sc::CellStoreType::iterator it = aPos.first;
-
- bool bLowerSplitOff = false;
- if (pNewSharedRows && !GetDoc().IsClipOrUndo())
+ // Need to process (start listening) entire shared formula groups, not just
+ // a slice thereof.
+ bool bEnlargedDown = false;
+ aPos = maCells.position(nRow1);
+ it = aPos.first;
+ if (it->type == sc::element_type_formula)
{
- const ScFormulaCell* pFC = sc::SharedFormulaUtil::getSharedTopFormulaCell(aPos);
- if (pFC)
+ ScFormulaCell& rCell = *sc::formula_block::at(*it->data, aPos.second);
+ if (rCell.IsShared())
{
- const SCROW nTopRow = pFC->GetSharedTopRow();
- const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1;
- // nTopRow <= nRow1 <= nBotRow, because otherwise pFC would not exist.
- if (nTopRow < nRow1)
+ nRow1 = std::min( nRow1, rCell.GetSharedTopRow());
+ if (nRow2 < rCell.GetSharedTopRow() + rCell.GetSharedLength())
{
- // Upper part will be split off.
- pNewSharedRows->push_back(nTopRow);
- pNewSharedRows->push_back(nRow1 - 1);
+ nRow2 = rCell.GetSharedTopRow() + rCell.GetSharedLength() - 1;
+ bEnlargedDown = true;
+ // Same end row is also enlarged, i.e. doesn't need to be
+ // checked for another group.
}
- if (nRow2 < nBotRow)
+ }
+ }
+ if (!bEnlargedDown)
+ {
+ aPos = maCells.position(it, nRow2);
+ it = aPos.first;
+ if (it->type == sc::element_type_formula)
+ {
+ ScFormulaCell& rCell = *sc::formula_block::at(*it->data, aPos.second);
+ if (rCell.IsShared())
{
- // Lower part will be split off.
- pNewSharedRows->push_back(nRow2 + 1);
- pNewSharedRows->push_back(nBotRow);
- bLowerSplitOff = true;
+ nRow2 = std::max( nRow2, rCell.GetSharedTopRow() + rCell.GetSharedLength() - 1);
}
}
}
+ AttachFormulaCellsHandler aFunc(rCxt);
+ sc::ProcessFormula(it, maCells, nRow1, nRow2, aFunc);
+}
+
+void ScColumn::DetachFormulaCells( sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2 )
+{
+ sc::CellStoreType::position_type aPos = maCells.position(nRow1);
+ sc::CellStoreType::iterator it = aPos.first;
+
// Split formula grouping at the top and bottom boundaries.
sc::SharedFormulaUtil::splitFormulaCellGroup(aPos, &rCxt);
if (GetDoc().ValidRow(nRow2+1))
{
- if (pNewSharedRows && !bLowerSplitOff && !GetDoc().IsClipOrUndo())
- {
- sc::CellStoreType::position_type aPos2 = maCells.position(aPos.first, nRow2);
- const ScFormulaCell* pFC = sc::SharedFormulaUtil::getSharedTopFormulaCell(aPos2);
- if (pFC)
- {
- const SCROW nTopRow = pFC->GetSharedTopRow();
- const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1;
- // nRow1 < nTopRow <= nRow2 < nBotRow
- if (nRow2 < nBotRow)
- {
- // Lower part will be split off.
- pNewSharedRows->push_back(nRow2 + 1);
- pNewSharedRows->push_back(nBotRow);
- }
- }
- }
-
aPos = maCells.position(it, nRow2+1);
sc::SharedFormulaUtil::splitFormulaCellGroup(aPos, &rCxt);
}
@@ -789,10 +866,11 @@ bool ScColumn::UpdateScriptType( sc::CellTextAttr& rAttr, SCROW nRow, sc::CellSt
SvNumberFormatter* pFormatter = rDocument.GetFormatTable();
- OUString aStr;
+ // fetch the pattern again, it might have changed under us
+ pPattern = GetPattern(nRow);
const Color* pColor;
sal_uInt32 nFormat = pPattern->GetNumberFormat(pFormatter, pCondSet);
- ScCellFormat::GetString(aCell, nFormat, aStr, &pColor, *pFormatter, rDocument);
+ OUString aStr = ScCellFormat::GetString(aCell, nFormat, &pColor, nullptr, rDocument);
// Store the real script type to the array.
rAttr.mnScriptType = rDocument.GetStringScriptType(aStr);
@@ -848,13 +926,9 @@ public:
if (!mbFormula)
return;
- sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
- std::advance(it, nOffset);
- sc::formula_block::iterator itEnd = it;
- std::advance(itEnd, nDataSize);
-
- for (; it != itEnd; ++it)
- maFormulaCells.push_back(*it);
+ sc::formula_block::iterator it = sc::formula_block::begin(*node.data) + nOffset;
+ sc::formula_block::iterator itEnd = it + nDataSize;
+ maFormulaCells.insert(maFormulaCells.end(), it, itEnd);
}
break;
case sc::element_type_empty:
@@ -917,6 +991,33 @@ public:
(nType == SvNumFormatType::DATETIME);
}
+ /**
+ * Query the formula ranges that may have stopped listening, accounting for
+ * the formula groups.
+ */
+ std::vector<std::pair<SCROW, SCROW>> getFormulaRanges()
+ {
+ std::vector<std::pair<SCROW, SCROW>> aRet;
+
+ for (const ScFormulaCell* pFC : maFormulaCells)
+ {
+ SCROW nTopRow = pFC->aPos.Row();
+ SCROW nBottomRow = pFC->aPos.Row();
+
+ auto xGroup = pFC->GetCellGroup();
+ if (xGroup)
+ {
+ pFC = xGroup->mpTopCell;
+ nTopRow = pFC->aPos.Row();
+ nBottomRow = nTopRow + xGroup->mnLength - 1;
+ }
+
+ aRet.emplace_back(nTopRow, nBottomRow);
+ }
+
+ return aRet;
+ }
+
void endFormulas()
{
mrDoc.EndListeningFormulaCells(maFormulaCells);
@@ -964,14 +1065,21 @@ public:
}
-void ScColumn::DeleteCells(
- sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2, InsertDeleteFlags nDelFlag,
- sc::SingleColumnSpanSet& rDeleted )
+ScColumn::DeleteCellsResult::DeleteCellsResult( const ScDocument& rDoc ) :
+ aDeletedRows( rDoc.GetSheetLimits() )
{
+}
+
+std::unique_ptr<ScColumn::DeleteCellsResult> ScColumn::DeleteCells(
+ sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2, InsertDeleteFlags nDelFlag )
+{
+ std::unique_ptr<DeleteCellsResult> xResult = std::make_unique<DeleteCellsResult>(GetDoc());
+
// Determine which cells to delete based on the deletion flags.
DeleteAreaHandler aFunc(GetDoc(), nDelFlag, *this);
sc::CellStoreType::iterator itPos = maCells.position(rBlockPos.miCellPos, nRow1).first;
sc::ProcessBlock(itPos, maCells, aFunc, nRow1, nRow2);
+ xResult->aFormulaRanges = aFunc.getFormulaRanges();
aFunc.endFormulas(); // Have the formula cells stop listening.
// Get the deletion spans.
@@ -983,7 +1091,9 @@ void ScColumn::DeleteCells(
std::for_each(aSpans.rbegin(), aSpans.rend(), EmptyCells(rBlockPos, *this));
CellStorageModified();
- aFunc.getSpans().swap(rDeleted);
+ aFunc.getSpans().swap(xResult->aDeletedRows);
+
+ return xResult;
}
void ScColumn::DeleteArea(
@@ -996,18 +1106,17 @@ void ScColumn::DeleteArea(
nContMask |= InsertDeleteFlags::NOCAPTIONS;
InsertDeleteFlags nContFlag = nDelFlag & nContMask;
- sc::SingleColumnSpanSet aDeletedRows(GetDoc().GetSheetLimits());
-
sc::ColumnBlockPosition aBlockPos;
InitBlockPosition(aBlockPos);
+ std::unique_ptr<DeleteCellsResult> xResult;
if (!IsEmptyData() && nContFlag != InsertDeleteFlags::NONE)
{
- DeleteCells(aBlockPos, nStartRow, nEndRow, nDelFlag, aDeletedRows);
+ xResult = DeleteCells(aBlockPos, nStartRow, nEndRow, nDelFlag);
if (pBroadcastSpans)
{
sc::SingleColumnSpanSet::SpansType aSpans;
- aDeletedRows.getSpans(aSpans);
+ xResult->aDeletedRows.getSpans(aSpans);
for (const auto& rSpan : aSpans)
pBroadcastSpans->set(GetDoc(), nTab, nCol, rSpan.mnRow1, rSpan.mnRow2, true);
}
@@ -1019,10 +1128,14 @@ void ScColumn::DeleteArea(
DeleteCellNotes(aBlockPos, nStartRow, nEndRow, bForgetCaptionOwnership);
}
+ if (nDelFlag & InsertDeleteFlags::SPARKLINES)
+ {
+ DeleteSparklineCells(aBlockPos, nStartRow, nEndRow);
+ }
+
if ( nDelFlag & InsertDeleteFlags::EDITATTR )
{
- OSL_ENSURE( nContFlag == InsertDeleteFlags::NONE, "DeleteArea: Wrong Flags" );
- RemoveEditAttribs( nStartRow, nEndRow );
+ RemoveEditAttribs(aBlockPos, nStartRow, nEndRow);
}
// Delete attributes just now
@@ -1031,12 +1144,12 @@ void ScColumn::DeleteArea(
else if ((nDelFlag & InsertDeleteFlags::HARDATTR) == InsertDeleteFlags::HARDATTR)
pAttrArray->DeleteHardAttr( nStartRow, nEndRow );
- if (bBroadcast)
+ if (xResult && bBroadcast)
{
// Broadcast on only cells that were deleted; no point broadcasting on
// cells that were already empty before the deletion.
std::vector<SCROW> aRows;
- aDeletedRows.getRows(aRows);
+ xResult->aDeletedRows.getRows(aRows);
BroadcastCells(aRows, SfxHintId::ScDataChanged);
}
}
@@ -1047,6 +1160,7 @@ void ScColumn::InitBlockPosition( sc::ColumnBlockPosition& rBlockPos )
rBlockPos.miCellNotePos = maCellNotes.begin();
rBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
rBlockPos.miCellPos = maCells.begin();
+ rBlockPos.miSparklinePos = maSparklines.begin();
}
void ScColumn::InitBlockPosition( sc::ColumnBlockConstPosition& rBlockPos ) const
@@ -1108,6 +1222,11 @@ class CopyCellsFromClipHandler
mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestBlockPos, bCloneCaption, mnRowOffset);
}
+ void duplicateSparklines(SCROW nStartRow, size_t nDataSize)
+ {
+ mrSrcCol.DuplicateSparklines(nStartRow, nDataSize, mrDestCol, maDestBlockPos, mnRowOffset);
+ }
+
public:
CopyCellsFromClipHandler(sc::CopyFromClipContext& rCxt, ScColumn& rSrcCol, ScColumn& rDestCol, SCTAB nDestTab, SCCOL nDestCol, tools::Long nRowOffset, svl::SharedStringPool* pSharedStringPool) :
mrCxt(rCxt),
@@ -1122,7 +1241,16 @@ public:
mpSharedStringPool(pSharedStringPool)
{
if (mpDestBlockPos)
+ {
+ {
+ // Re-initialize the broadcaster position hint, which may have
+ // become invalid by the time it gets here...
+ sc::ColumnBlockPosition aTempPos;
+ mrDestCol.InitBlockPosition(aTempPos);
+ mpDestBlockPos->miBroadcasterPos = aTempPos.miBroadcasterPos;
+ }
maDestBlockPos = *mpDestBlockPos;
+ }
else
mrDestCol.InitBlockPosition(maDestBlockPos);
}
@@ -1138,16 +1266,21 @@ public:
{
SCROW nSrcRow1 = node.position + nOffset;
bool bCopyCellNotes = mrCxt.isCloneNotes();
+ bool bCopySparklines = mrCxt.isCloneSparklines();
InsertDeleteFlags nFlags = mrCxt.getInsertFlag();
if (node.type == sc::element_type_empty)
{
- if (bCopyCellNotes && !mrCxt.isSkipAttrForEmptyCells())
+ if (bCopyCellNotes && !mrCxt.isSkipEmptyCells())
{
bool bCloneCaption = (nFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE;
duplicateNotes(nSrcRow1, nDataSize, bCloneCaption );
}
+ if (bCopySparklines) // If there is a sparkline is it empty?
+ {
+ duplicateSparklines(nSrcRow1, nDataSize);
+ }
return;
}
@@ -1338,6 +1471,10 @@ public:
bool bCloneCaption = (nFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE;
duplicateNotes(nSrcRow1, nDataSize, bCloneCaption );
}
+ if (bCopySparklines)
+ {
+ duplicateSparklines(nSrcRow1, nDataSize);
+ }
}
};
@@ -1356,7 +1493,7 @@ public:
mpDestBlockPos(rCxt.getBlockPosition(nDestTab, nDestCol))
{
if (mpDestBlockPos)
- maDestBlockPos = *mpDestBlockPos;
+ maDestBlockPos.miCellTextAttrPos = mpDestBlockPos->miCellTextAttrPos;
else
rDestCol.InitBlockPosition(maDestBlockPos);
}
@@ -1365,7 +1502,7 @@ public:
{
if (mpDestBlockPos)
// Don't forget to save this to the context!
- *mpDestBlockPos = maDestBlockPos;
+ mpDestBlockPos->miCellTextAttrPos = maDestBlockPos.miCellTextAttrPos;
}
void operator() ( const sc::CellTextAttrStoreType::value_type& aNode, size_t nOffset, size_t nDataSize )
@@ -1391,9 +1528,13 @@ public:
void ScColumn::CopyFromClip(
sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, tools::Long nDy, ScColumn& rColumn )
{
+ sc::ColumnBlockPosition* pBlockPos = rCxt.getBlockPosition(nTab, nCol);
+ if (!pBlockPos)
+ return;
+
if ((rCxt.getInsertFlag() & InsertDeleteFlags::ATTRIB) != InsertDeleteFlags::NONE)
{
- if (rCxt.isSkipAttrForEmptyCells())
+ if (rCxt.isSkipEmptyCells())
{
// copy only attributes for non-empty cells between nRow1-nDy and nRow2-nDy.
sc::SingleColumnSpanSet aSpanSet(GetDoc().GetSheetLimits());
@@ -1432,7 +1573,7 @@ void ScColumn::CopyFromClip(
ScTokenArray aArr(GetDoc());
aArr.AddSingleReference( aRef );
- SetFormulaCell(nDestRow, new ScFormulaCell(rDocument, aDestPos, aArr));
+ SetFormulaCell(*pBlockPos, nDestRow, new ScFormulaCell(rDocument, aDestPos, aArr));
}
// Don't forget to copy the cell text attributes.
@@ -1901,9 +2042,9 @@ void ScColumn::MixData(
CellStorageModified();
}
-std::unique_ptr<ScAttrIterator> ScColumn::CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) const
+ScAttrIterator ScColumnData::CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) const
{
- return std::make_unique<ScAttrIterator>( pAttrArray.get(), nStartRow, nEndRow, GetDoc().GetDefPattern() );
+ return ScAttrIterator( pAttrArray.get(), nStartRow, nEndRow, &GetDoc().getCellAttributeHelper().getDefaultCellAttribute() );
}
namespace {
@@ -1954,7 +2095,7 @@ namespace {
void applyTextNumFormat( ScColumn& rCol, SCROW nRow, SvNumberFormatter* pFormatter )
{
sal_uInt32 nFormat = pFormatter->GetStandardFormat(SvNumFormatType::TEXT);
- ScPatternAttr aNewAttrs(rCol.GetDoc().GetPool());
+ ScPatternAttr aNewAttrs(rCol.GetDoc().getCellAttributeHelper());
SfxItemSet& rSet = aNewAttrs.GetItemSet();
rSet.Put(SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat));
rCol.ApplyPattern(nRow, aNewAttrs);
@@ -2019,21 +2160,20 @@ bool ScColumn::ParseString(
}
else if ( cFirstChar == '\'') // 'Text
{
- bool bNumeric = false;
if (aParam.mbHandleApostrophe)
{
- // Cell format is not 'Text', and the first char
- // is an apostrophe. Check if the input is considered a number.
- OUString aTest = rString.copy(1);
- double fTest;
- bNumeric = aParam.mpNumFormatter->IsNumberFormat(aTest, nIndex, fTest);
- if (bNumeric)
- // This is a number. Strip out the first char.
- rCell.set(rPool.intern(aTest));
+ // Cell format is not 'Text', and the first char is an apostrophe.
+ // Strip it and set text content.
+ // NOTE: this corresponds with sc/source/ui/view/tabvwsha.cxx
+ // ScTabViewShell::UpdateInputHandler() prepending an apostrophe if
+ // necessary.
+ rCell.set(rPool.intern(rString.copy(1)));
}
- if (!bNumeric)
+ else
+ {
// This is normal text. Take it as-is.
rCell.set(rPool.intern(rString));
+ }
}
else
{
@@ -2059,7 +2199,7 @@ bool ScColumn::ParseString(
if (bForceFormatDate)
{
ScRefCellValue aCell = GetCellValue(nRow);
- if (aCell.meType == CELLTYPE_VALUE)
+ if (aCell.getType() == CELLTYPE_VALUE)
{
// Only for an actual date (serial number), not an
// arbitrary string or formula or empty cell.
@@ -2070,8 +2210,8 @@ bool ScColumn::ParseString(
bForceFormatDate = false;
else
{
- nIndex = aParam.mpNumFormatter->GetEditFormat( aCell.getValue(), nOldIndex, eNumFormatType,
- pOldFormat->GetLanguage(), pOldFormat);
+ nIndex = aParam.mpNumFormatter->GetEditFormat(
+ aCell.getValue(), nOldIndex, eNumFormatType, pOldFormat);
eEvalDateFormat = aParam.mpNumFormatter->GetEvalDateFormat();
aParam.mpNumFormatter->SetEvalDateFormat( NF_EVALDATEFORMAT_FORMAT_INTL);
}
@@ -2161,7 +2301,7 @@ bool ScColumn::ParseString(
sal_Unicode gsep = rGroupSep[0];
sal_Unicode dsepa = rDecSepAlt.toChar();
- if (!ScStringUtil::parseSimpleNumber(rString, dsep, gsep, dsepa, nVal))
+ if (!ScStringUtil::parseSimpleNumber(rString, dsep, gsep, dsepa, nVal, aParam.mbDetectScientificNumberFormat))
break;
rCell.set(nVal);
@@ -2169,7 +2309,7 @@ bool ScColumn::ParseString(
}
while (false);
- if (rCell.meType == CELLTYPE_NONE)
+ if (rCell.getType() == CELLTYPE_NONE)
{
// If we reach here with ScSetStringParam::SpecialNumberOnly it
// means a simple number was not detected above, so test for
@@ -2216,6 +2356,11 @@ bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const OUString& rString,
void ScColumn::SetEditText( SCROW nRow, std::unique_ptr<EditTextObject> pEditText )
{
+ if (!pEditText)
+ {
+ return;
+ }
+
pEditText->NormalizeString(GetDoc().GetSharedStringPool());
std::vector<SCROW> aNewSharedRows;
sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, false);
@@ -2421,43 +2566,61 @@ class FilterEntriesHandler
{
ScColumn& mrColumn;
ScFilterEntries& mrFilterEntries;
+ bool mbFiltering;
+ bool mbFilteredRow;
- void processCell(ScColumn& rColumn, SCROW nRow, ScRefCellValue& rCell)
+ void processCell(const ScColumn& rColumn, SCROW nRow, ScRefCellValue& rCell, bool bIsEmptyCell=false)
{
- SvNumberFormatter* pFormatter = mrColumn.GetDoc().GetFormatTable();
- OUString aStr;
- sal_uLong nFormat = mrColumn.GetNumberFormat(mrColumn.GetDoc().GetNonThreadedContext(), nRow);
- ScCellFormat::GetInputString(rCell, nFormat, aStr, *pFormatter, mrColumn.GetDoc(), mrColumn.HasFiltering());
+ ScInterpreterContext& rContext = mrColumn.GetDoc().GetNonThreadedContext();
+ sal_uInt32 nFormat = mrColumn.GetNumberFormat(rContext, nRow);
+ OUString aStr = ScCellFormat::GetInputString(rCell, nFormat, &rContext, mrColumn.GetDoc(), mbFiltering);
// Colors
ScAddress aPos(rColumn.GetCol(), nRow, rColumn.GetTab());
- const SvxColorItem* pColor = rColumn.GetDoc().GetAttr(aPos, ATTR_FONT_COLOR);
- Color textColor = pColor->GetValue();
- if (textColor != COL_AUTO)
- mrFilterEntries.addTextColor(textColor);
+ if (ScTable* pTable = rColumn.GetDoc().FetchTable(rColumn.GetTab()))
+ {
+ mrFilterEntries.addTextColor(pTable->GetCellTextColor(aPos));
+ mrFilterEntries.addBackgroundColor(pTable->GetCellBackgroundColor(aPos));
+ }
- const SvxBrushItem* pBrush = rColumn.GetDoc().GetAttr(aPos, ATTR_BACKGROUND);
- Color backgroundColor = pBrush->GetColor();
- if (backgroundColor != COL_AUTO)
- mrFilterEntries.addBackgroundColor(backgroundColor);
+ if (bIsEmptyCell)
+ {
+ if (mbFilteredRow)
+ {
+ if (!mrFilterEntries.mbHasHiddenEmpties)
+ {
+ mrFilterEntries.push_back(ScTypedStrData(OUString(), 0.0, 0.0, ScTypedStrData::Standard, false, true));
+ mrFilterEntries.mbHasHiddenEmpties = true;
+ }
+ }
+ else
+ {
+ if (!mrFilterEntries.mbHasUnHiddenEmpties)
+ {
+ mrFilterEntries.push_back(ScTypedStrData(OUString(), 0.0, 0.0, ScTypedStrData::Standard, false, false));
+ mrFilterEntries.mbHasUnHiddenEmpties = true;
+ }
+ }
+ return;
+ }
if (rCell.hasString())
{
- mrFilterEntries.push_back(ScTypedStrData(aStr));
+ mrFilterEntries.push_back(ScTypedStrData(std::move(aStr), 0.0, 0.0, ScTypedStrData::Standard, false, mbFilteredRow));
return;
}
double fVal = 0.0;
- switch (rCell.meType)
+ switch (rCell.getType())
{
case CELLTYPE_VALUE:
- fVal = rCell.mfValue;
+ fVal = rCell.getDouble();
break;
case CELLTYPE_FORMULA:
{
- ScFormulaCell* pFC = rCell.mpFormula;
+ ScFormulaCell* pFC = rCell.getFormula();
FormulaError nErr = pFC->GetErrCode();
if (nErr != FormulaError::NONE)
{
@@ -2465,7 +2628,7 @@ class FilterEntriesHandler
OUString aErr = ScGlobal::GetErrorString(nErr);
if (!aErr.isEmpty())
{
- mrFilterEntries.push_back(ScTypedStrData(aErr));
+ mrFilterEntries.push_back(ScTypedStrData(std::move(aErr), 0.0, 0.0, ScTypedStrData::Standard, false, mbFilteredRow));
return;
}
}
@@ -2477,7 +2640,7 @@ class FilterEntriesHandler
;
}
- SvNumFormatType nType = pFormatter->GetType(nFormat);
+ SvNumFormatType nType = rContext.NFGetType(nFormat);
bool bDate = false;
if ((nType & SvNumFormatType::DATE) && !(nType & SvNumFormatType::TIME))
{
@@ -2488,26 +2651,27 @@ class FilterEntriesHandler
bDate = true;
// Convert string representation to ISO 8601 date to eliminate
// locale dependent behaviour later when filtering for dates.
- sal_uInt32 nIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_YYYYMMDD);
- pFormatter->GetInputLineString( fVal, nIndex, aStr);
+ sal_uInt32 nIndex = rContext.NFGetFormatIndex( NF_DATE_DIN_YYYYMMDD);
+ rContext.NFGetInputLineString( fVal, nIndex, aStr);
}
else if (nType == SvNumFormatType::DATETIME)
{
// special case for datetime values.
// Convert string representation to ISO 8601 (with blank instead of T) datetime
// to eliminate locale dependent behaviour later when filtering for datetimes.
- sal_uInt32 nIndex = pFormatter->GetFormatIndex(NF_DATETIME_ISO_YYYYMMDD_HHMMSS);
- pFormatter->GetInputLineString(fVal, nIndex, aStr);
+ sal_uInt32 nIndex = rContext.NFGetFormatIndex(NF_DATETIME_ISO_YYYYMMDD_HHMMSS);
+ rContext.NFGetInputLineString(fVal, nIndex, aStr);
}
- /* use string compare later for formatted and filtered cell values
- to avoid duplicates in the filter lists with setting the mbIsFormatted */
- bool bFormFiltVal = mrColumn.HasFiltering() && nFormat;
- mrFilterEntries.push_back(ScTypedStrData(aStr, fVal, ScTypedStrData::Value, bDate, bFormFiltVal));
+ // store the formatted/rounded value for filtering
+ if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0 && !bDate)
+ mrFilterEntries.push_back(ScTypedStrData(std::move(aStr), fVal, rColumn.GetDoc().RoundValueAsShown(fVal, nFormat), ScTypedStrData::Value, bDate, mbFilteredRow));
+ else
+ mrFilterEntries.push_back(ScTypedStrData(std::move(aStr), fVal, fVal, ScTypedStrData::Value, bDate, mbFilteredRow));
}
public:
- FilterEntriesHandler(ScColumn& rColumn, ScFilterEntries& rFilterEntries) :
- mrColumn(rColumn), mrFilterEntries(rFilterEntries) {}
+ FilterEntriesHandler(ScColumn& rColumn, ScFilterEntries& rFilterEntries, bool bFiltering, bool bFilteredRow) :
+ mrColumn(rColumn), mrFilterEntries(rFilterEntries), mbFiltering(bFiltering), mbFilteredRow(bFilteredRow) {}
void operator() (size_t nRow, double fVal)
{
@@ -2535,17 +2699,8 @@ public:
void operator() (const int nElemType, size_t nRow, size_t /* nDataSize */)
{
- if ( nElemType == sc::element_type_empty )
- {
- if (!mrFilterEntries.mbHasEmpties)
- {
- mrFilterEntries.push_back(ScTypedStrData(OUString()));
- mrFilterEntries.mbHasEmpties = true;
- }
- return;
- }
ScRefCellValue aCell = mrColumn.GetCellValue(nRow);
- processCell(mrColumn, nRow, aCell);
+ processCell(mrColumn, nRow, aCell, nElemType == sc::element_type_empty);
}
};
@@ -2553,14 +2708,73 @@ public:
void ScColumn::GetFilterEntries(
sc::ColumnBlockConstPosition& rBlockPos, SCROW nStartRow, SCROW nEndRow,
- ScFilterEntries& rFilterEntries, bool bFiltering )
+ ScFilterEntries& rFilterEntries, bool bFiltering, bool bFilteredRow )
{
- mbFiltering = bFiltering;
- FilterEntriesHandler aFunc(*this, rFilterEntries);
+ FilterEntriesHandler aFunc(*this, rFilterEntries, bFiltering, bFilteredRow);
rBlockPos.miCellPos =
sc::ParseAll(rBlockPos.miCellPos, maCells, nStartRow, nEndRow, aFunc, aFunc);
}
+void ScColumn::GetBackColorFilterEntries(SCROW nRow1, SCROW nRow2, ScFilterEntries& rFilterEntries)
+{
+ Color aBackColor;
+ bool bCondBackColor = false;
+ ScAddress aCell(GetCol(), 0, GetTab());
+ ScConditionalFormat* pCondFormat = nullptr;
+
+ const SfxItemSet* pCondSet = nullptr;
+ const SvxBrushItem* pBrush = nullptr;
+ const ScPatternAttr* pPattern = nullptr;
+ const ScColorScaleFormat* pColFormat = nullptr;
+
+ if (!GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2))
+ return;
+
+ while (nRow1 <= nRow2)
+ {
+ aCell.SetRow(nRow1);
+ pPattern = GetDoc().GetPattern(aCell.Col(), aCell.Row(), aCell.Tab());
+ if (pPattern)
+ {
+ if (!pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData().empty())
+ {
+ pCondSet = GetDoc().GetCondResult(GetCol(), nRow1, GetTab());
+ pBrush = &pPattern->GetItem(ATTR_BACKGROUND, pCondSet);
+ aBackColor = pBrush->GetColor();
+ bCondBackColor = true;
+ }
+ }
+
+ pCondFormat = GetDoc().GetCondFormat(aCell.Col(), aCell.Row(), aCell.Tab());
+ if (pCondFormat)
+ {
+ for (size_t nFormat = 0; nFormat < pCondFormat->size(); nFormat++)
+ {
+ auto aEntry = pCondFormat->GetEntry(nFormat);
+ if (aEntry->GetType() == ScFormatEntry::Type::Colorscale)
+ {
+ pColFormat = static_cast<const ScColorScaleFormat*>(aEntry);
+ std::optional<Color> oColor = pColFormat->GetColor(aCell);
+ if (oColor)
+ {
+ aBackColor = *oColor;
+ bCondBackColor = true;
+ }
+ }
+ }
+ }
+
+ if (!bCondBackColor)
+ {
+ pBrush = GetDoc().GetAttr(aCell, ATTR_BACKGROUND);
+ aBackColor = pBrush->GetColor();
+ }
+
+ rFilterEntries.addBackgroundColor(aBackColor);
+ nRow1++;
+ }
+}
+
namespace {
/**
@@ -2591,11 +2805,6 @@ public:
return (maPos.first->type == sc::element_type_string || maPos.first->type == sc::element_type_edittext);
}
- bool isEmpty() const
- {
- return maPos.first->type == sc::element_type_empty;
- }
-
bool prev()
{
if (!has())
@@ -2603,7 +2812,7 @@ public:
// Not in a string block. Move back until we hit a string block.
while (!has())
{
- if (isEmpty() || maPos.first == miBeg)
+ if (maPos.first == miBeg)
return false;
--maPos.first; // move to the preceding block.
@@ -2629,10 +2838,6 @@ public:
// Move to the last cell of the previous block.
--maPos.first;
maPos.second = maPos.first->size - 1;
-
- if (isEmpty())
- return false;
-
if (has())
break;
}
@@ -2647,9 +2852,6 @@ public:
// Not in a string block. Move forward until we hit a string block.
while (!has())
{
- if (isEmpty())
- return false;
-
++maPos.first;
if (maPos.first == miEnd)
return false;
@@ -2671,10 +2873,6 @@ public:
return false;
maPos.second = 0;
-
- if (isEmpty())
- return false;
-
if (has())
break;
}
@@ -2710,12 +2908,16 @@ bool ScColumn::GetDataEntries(
// going upward and downward directions in parallel. The start position
// cell must be skipped.
- StrCellIterator aItrUp(maCells, nStartRow-1, &GetDoc());
+ StrCellIterator aItrUp(maCells, nStartRow, &GetDoc());
StrCellIterator aItrDown(maCells, nStartRow+1, &GetDoc());
bool bMoveUp = aItrUp.valid();
- if (bMoveUp && !aItrUp.has())
- bMoveUp = aItrUp.prev(); // Find the previous string cell position.
+ if (!bMoveUp)
+ // Current cell is invalid.
+ return false;
+
+ // Skip the start position cell.
+ bMoveUp = aItrUp.prev(); // Find the previous string cell position.
bool bMoveDown = aItrDown.valid();
if (bMoveDown && !aItrDown.has())
@@ -2728,7 +2930,7 @@ bool ScColumn::GetDataEntries(
OUString aStr = aItrUp.get();
if (!aStr.isEmpty())
{
- if (rStrings.insert(ScTypedStrData(aStr)).second)
+ if (rStrings.insert(ScTypedStrData(std::move(aStr))).second)
bFound = true;
}
@@ -2741,7 +2943,7 @@ bool ScColumn::GetDataEntries(
OUString aStr = aItrDown.get();
if (!aStr.isEmpty())
{
- if (rStrings.insert(ScTypedStrData(aStr)).second)
+ if (rStrings.insert(ScTypedStrData(std::move(aStr))).second)
bFound = true;
}
@@ -2785,13 +2987,13 @@ public:
for (const Entry& r : maEntries)
{
- switch (r.maValue.meType)
+ switch (r.maValue.getType())
{
case CELLTYPE_VALUE:
- rColumn.SetValue(aBlockPos, r.mnRow, r.maValue.mfValue, false);
+ rColumn.SetValue(aBlockPos, r.mnRow, r.maValue.getDouble(), false);
break;
case CELLTYPE_STRING:
- rColumn.SetRawString(aBlockPos, r.mnRow, *r.maValue.mpString, false);
+ rColumn.SetRawString(aBlockPos, r.mnRow, *r.maValue.getSharedString(), false);
break;
default:
;
@@ -2807,7 +3009,7 @@ void ScColumn::RemoveProtected( SCROW nStartRow, SCROW nEndRow )
FormulaToValueHandler aFunc;
sc::CellStoreType::const_iterator itPos = maCells.begin();
- ScAttrIterator aAttrIter( pAttrArray.get(), nStartRow, nEndRow, GetDoc().GetDefPattern() );
+ ScAttrIterator aAttrIter( pAttrArray.get(), nStartRow, nEndRow, &GetDoc().getCellAttributeHelper().getDefaultCellAttribute() );
SCROW nTop = -1;
SCROW nBottom = -1;
const ScPatternAttr* pPattern = aAttrIter.Next( nTop, nBottom );
@@ -2932,16 +3134,15 @@ void ScColumn::SetValue(
BroadcastNewCell(nRow);
}
-void ScColumn::GetString( const ScRefCellValue& aCell, SCROW nRow, OUString& rString, const ScInterpreterContext* pContext ) const
+OUString ScColumn::GetString( const ScRefCellValue& aCell, SCROW nRow, ScInterpreterContext* pContext ) const
{
// ugly hack for ordering problem with GetNumberFormat and missing inherited formats
- if (aCell.meType == CELLTYPE_FORMULA)
- aCell.mpFormula->MaybeInterpret();
+ if (aCell.getType() == CELLTYPE_FORMULA)
+ aCell.getFormula()->MaybeInterpret();
sal_uInt32 nFormat = GetNumberFormat( pContext ? *pContext : GetDoc().GetNonThreadedContext(), nRow);
const Color* pColor = nullptr;
- ScCellFormat::GetString(aCell, nFormat, rString, &pColor,
- pContext ? *(pContext->GetFormatTable()) : *(GetDoc().GetFormatTable()), GetDoc());
+ return ScCellFormat::GetString(aCell, nFormat, &pColor, pContext, GetDoc());
}
double* ScColumn::GetValueCell( SCROW nRow )
@@ -2957,10 +3158,10 @@ double* ScColumn::GetValueCell( SCROW nRow )
return &sc::numeric_block::at(*it->data, aPos.second);
}
-void ScColumn::GetInputString( const ScRefCellValue& aCell, SCROW nRow, OUString& rString ) const
+OUString ScColumn::GetInputString( const ScRefCellValue& aCell, SCROW nRow, bool bForceSystemLocale ) const
{
- sal_uLong nFormat = GetNumberFormat(GetDoc().GetNonThreadedContext(), nRow);
- ScCellFormat::GetInputString(aCell, nFormat, rString, *(GetDoc().GetFormatTable()), GetDoc());
+ sal_uInt32 nFormat = GetNumberFormat(GetDoc().GetNonThreadedContext(), nRow);
+ return ScCellFormat::GetInputString(aCell, nFormat, nullptr, GetDoc(), nullptr, false, bForceSystemLocale);
}
double ScColumn::GetValue( SCROW nRow ) const
@@ -3011,13 +3212,12 @@ void ScColumn::RemoveEditTextCharAttribs( SCROW nRow, const ScPatternAttr& rAttr
ScEditUtil::RemoveCharAttribs(*p, rAttr);
}
-void ScColumn::GetFormula( SCROW nRow, OUString& rFormula ) const
+OUString ScColumn::GetFormula( SCROW nRow ) const
{
const ScFormulaCell* p = FetchFormulaCell(nRow);
if (p)
- p->GetFormula(rFormula);
- else
- rFormula = EMPTY_OUSTRING;
+ return p->GetFormula();
+ return OUString();
}
const ScFormulaCell* ScColumn::GetFormulaCell( SCROW nRow ) const
@@ -3079,6 +3279,19 @@ SCSIZE ScColumn::GetCellCount() const
return aFunc.getCount();
}
+bool ScColumn::IsCellCountZero() const
+{
+ auto it = maCells.begin();
+ auto itEnd = maCells.end();
+ for (; it != itEnd; ++it)
+ {
+ const sc::CellStoreType::value_type& node = *it;
+ if (node.size != 0)
+ return false;
+ }
+ return true;
+}
+
FormulaError ScColumn::GetErrCode( SCROW nRow ) const
{
std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
@@ -3159,16 +3372,14 @@ class MaxStringLenHandler
{
sal_Int32 mnMaxLen;
const ScColumn& mrColumn;
- SvNumberFormatter* mpFormatter;
rtl_TextEncoding meCharSet;
bool mbOctetEncoding;
void processCell(size_t nRow, const ScRefCellValue& rCell)
{
const Color* pColor;
- OUString aString;
sal_uInt32 nFormat = mrColumn.GetAttr(nRow, ATTR_VALUE_FORMAT).GetValue();
- ScCellFormat::GetString(rCell, nFormat, aString, &pColor, *mpFormatter, mrColumn.GetDoc());
+ OUString aString = ScCellFormat::GetString(rCell, nFormat, &pColor, nullptr, mrColumn.GetDoc());
sal_Int32 nLen = 0;
if (mbOctetEncoding)
{
@@ -3195,7 +3406,6 @@ public:
MaxStringLenHandler(const ScColumn& rColumn, rtl_TextEncoding eCharSet) :
mnMaxLen(0),
mrColumn(rColumn),
- mpFormatter(rColumn.GetDoc().GetFormatTable()),
meCharSet(eCharSet),
mbOctetEncoding(rtl_isOctetTextEncoding(eCharSet))
{
@@ -3242,7 +3452,6 @@ namespace {
class MaxNumStringLenHandler
{
const ScColumn& mrColumn;
- SvNumberFormatter* mpFormatter;
sal_Int32 mnMaxLen;
sal_uInt16 mnPrecision;
sal_uInt16 mnMaxGeneralPrecision;
@@ -3251,9 +3460,9 @@ class MaxNumStringLenHandler
void processCell(size_t nRow, ScRefCellValue& rCell)
{
sal_uInt16 nCellPrecision = mnMaxGeneralPrecision;
- if (rCell.meType == CELLTYPE_FORMULA)
+ if (rCell.getType() == CELLTYPE_FORMULA)
{
- if (!rCell.mpFormula->IsValue())
+ if (!rCell.getFormula()->IsValue())
return;
// Limit unformatted formula cell precision to precision
@@ -3277,9 +3486,10 @@ class MaxNumStringLenHandler
mrColumn.GetAttr(nRow, ATTR_VALUE_FORMAT).GetValue();
if (nFormat % SV_COUNTRY_LANGUAGE_OFFSET)
{
- aSep = mpFormatter->GetFormatDecimalSep(nFormat);
- ScCellFormat::GetInputString(rCell, nFormat, aString, *mpFormatter, mrColumn.GetDoc());
- const SvNumberformat* pEntry = mpFormatter->GetEntry(nFormat);
+ ScInterpreterContext& rContext = mrColumn.GetDoc().GetNonThreadedContext();
+ aSep = rContext.NFGetFormatDecimalSep(nFormat);
+ aString = ScCellFormat::GetInputString(rCell, nFormat, &rContext, mrColumn.GetDoc());
+ const SvNumberformat* pEntry = rContext.NFGetFormatEntry(nFormat);
if (pEntry)
{
bool bThousand, bNegRed;
@@ -3287,7 +3497,7 @@ class MaxNumStringLenHandler
pEntry->GetFormatSpecialInfo(bThousand, bNegRed, nPrec, nLeading);
}
else
- nPrec = mpFormatter->GetFormatPrecision(nFormat);
+ nPrec = rContext.NFGetFormatPrecision(nFormat);
}
else
{
@@ -3362,7 +3572,7 @@ class MaxNumStringLenHandler
public:
MaxNumStringLenHandler(const ScColumn& rColumn, sal_uInt16 nMaxGeneralPrecision) :
- mrColumn(rColumn), mpFormatter(rColumn.GetDoc().GetFormatTable()),
+ mrColumn(rColumn),
mnMaxLen(0), mnPrecision(0), mnMaxGeneralPrecision(nMaxGeneralPrecision),
mbHaveSigned(false)
{
@@ -3512,6 +3722,8 @@ public:
{
// Both previous and current cells are regular cells.
assert(pPrev->aPos.Row() == static_cast<SCROW>(nRow - 1));
+ // silence set-but-unused warning for non-dbg build
+ (void) nRow;
xPrevGrp = pPrev->CreateCellGroup(2, eCompState == ScFormulaCell::EqualInvariant);
pCur->SetCellGroup(xPrevGrp);
++nRow;
diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx
index 54213f2cd582..c122a142ad5d 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -19,7 +19,6 @@
#include <clipcontext.hxx>
#include <attrib.hxx>
#include <patattr.hxx>
-#include <docpool.hxx>
#include <conditio.hxx>
#include <formulagroup.hxx>
#include <tokenarray.hxx>
@@ -29,6 +28,10 @@
#include <drwlayer.hxx>
#include <compiler.hxx>
#include <recursionhelper.hxx>
+#include <docsh.hxx>
+#include <broadcast.hxx>
+
+#include <SparklineGroup.hxx>
#include <o3tl/safeint.hxx>
#include <svl/sharedstringpool.hxx>
@@ -39,11 +42,6 @@
#include <vector>
#include <cassert>
-bool ScColumn::IsMerged( SCROW nRow ) const
-{
- return pAttrArray->IsMerged(nRow);
-}
-
sc::MultiDataCellState::StateType ScColumn::HasDataCellsInRange(
SCROW nRow1, SCROW nRow2, SCROW* pRow1 ) const
{
@@ -100,6 +98,56 @@ void ScColumn::DeleteBeforeCopyFromClip(
if (!rDocument.ValidRow(aRange.mnRow1) || !rDocument.ValidRow(aRange.mnRow2))
return;
+ sc::ColumnBlockPosition* pBlockPos = rCxt.getBlockPosition(nTab, nCol);
+ if (!pBlockPos)
+ return;
+
+ InsertDeleteFlags nDelFlag = rCxt.getDeleteFlag();
+
+ if (!rCxt.isSkipEmptyCells())
+ {
+ // Delete the whole destination range.
+
+ if (nDelFlag & InsertDeleteFlags::CONTENTS)
+ {
+ auto xResult = DeleteCells(*pBlockPos, aRange.mnRow1, aRange.mnRow2, nDelFlag);
+ rBroadcastSpans.set(GetDoc(), nTab, nCol, xResult->aDeletedRows, true);
+
+ for (const auto& rRange : xResult->aFormulaRanges)
+ rCxt.setListeningFormulaSpans(
+ nTab, nCol, rRange.first, nCol, rRange.second);
+ }
+
+ if (nDelFlag & InsertDeleteFlags::NOTE)
+ DeleteCellNotes(*pBlockPos, aRange.mnRow1, aRange.mnRow2, false);
+
+ if (nDelFlag & InsertDeleteFlags::SPARKLINES)
+ DeleteSparklineCells(*pBlockPos, aRange.mnRow1, aRange.mnRow2);
+
+ if (nDelFlag & InsertDeleteFlags::EDITATTR)
+ RemoveEditAttribs(*pBlockPos, aRange.mnRow1, aRange.mnRow2);
+
+ if (nDelFlag & InsertDeleteFlags::ATTRIB)
+ {
+ pAttrArray->DeleteArea(aRange.mnRow1, aRange.mnRow2);
+
+ if (rCxt.isTableProtected())
+ {
+ ScPatternAttr aPattern(rDocument.getCellAttributeHelper());
+ aPattern.GetItemSet().Put(ScProtectionAttr(false));
+ ApplyPatternArea(aRange.mnRow1, aRange.mnRow2, aPattern);
+ }
+
+ ScConditionalFormatList* pCondList = rCxt.getCondFormatList();
+ if (pCondList)
+ pCondList->DeleteArea(nCol, aRange.mnRow1, nCol, aRange.mnRow2);
+ }
+ else if ((nDelFlag & InsertDeleteFlags::HARDATTR) == InsertDeleteFlags::HARDATTR)
+ pAttrArray->DeleteHardAttr(aRange.mnRow1, aRange.mnRow2);
+
+ return;
+ }
+
ScRange aClipRange = rCxt.getClipDoc()->GetClipParam().getWholeRange();
SCROW nClipRow1 = aClipRange.aStart.Row();
SCROW nClipRow2 = aClipRange.aEnd.Row();
@@ -149,10 +197,6 @@ void ScColumn::DeleteBeforeCopyFromClip(
nDestOffset += nClipRowLen;
}
- InsertDeleteFlags nDelFlag = rCxt.getDeleteFlag();
- sc::ColumnBlockPosition aBlockPos;
- InitBlockPosition(aBlockPos);
-
for (const auto& rDestSpan : aDestSpans)
{
SCROW nRow1 = rDestSpan.mnRow1;
@@ -160,16 +204,22 @@ void ScColumn::DeleteBeforeCopyFromClip(
if (nDelFlag & InsertDeleteFlags::CONTENTS)
{
- sc::SingleColumnSpanSet aDeletedRows(GetDoc().GetSheetLimits());
- DeleteCells(aBlockPos, nRow1, nRow2, nDelFlag, aDeletedRows);
- rBroadcastSpans.set(GetDoc(), nTab, nCol, aDeletedRows, true);
+ auto xResult = DeleteCells(*pBlockPos, nRow1, nRow2, nDelFlag);
+ rBroadcastSpans.set(GetDoc(), nTab, nCol, xResult->aDeletedRows, true);
+
+ for (const auto& rRange : xResult->aFormulaRanges)
+ rCxt.setListeningFormulaSpans(
+ nTab, nCol, rRange.first, nCol, rRange.second);
}
if (nDelFlag & InsertDeleteFlags::NOTE)
- DeleteCellNotes(aBlockPos, nRow1, nRow2, false);
+ DeleteCellNotes(*pBlockPos, nRow1, nRow2, false);
+
+ if (nDelFlag & InsertDeleteFlags::SPARKLINES)
+ DeleteSparklineCells(*pBlockPos, nRow1, nRow2);
if (nDelFlag & InsertDeleteFlags::EDITATTR)
- RemoveEditAttribs(nRow1, nRow2);
+ RemoveEditAttribs(*pBlockPos, nRow1, nRow2);
// Delete attributes just now
if (nDelFlag & InsertDeleteFlags::ATTRIB)
@@ -178,7 +228,7 @@ void ScColumn::DeleteBeforeCopyFromClip(
if (rCxt.isTableProtected())
{
- ScPatternAttr aPattern(rDocument.GetPool());
+ ScPatternAttr aPattern(rDocument.getCellAttributeHelper());
aPattern.GetItemSet().Put(ScProtectionAttr(false));
ApplyPatternArea(nRow1, nRow2, aPattern);
}
@@ -211,17 +261,15 @@ void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1,
if ((nFlags & InsertDeleteFlags::ATTRIB) != InsertDeleteFlags::NONE)
{
- if (!rCxt.isSkipAttrForEmptyCells() || rSrcCell.meType != CELLTYPE_NONE)
+ if (!rCxt.isSkipEmptyCells() || rSrcCell.getType() != CELLTYPE_NONE)
{
- const ScPatternAttr* pAttr = (bSameDocPool ? rCxt.getSingleCellPattern(nColOffset) :
- rCxt.getSingleCellPattern(nColOffset)->PutInPool( &rDocument, rCxt.getClipDoc()));
-
- auto pNewPattern = std::make_unique<ScPatternAttr>(*pAttr);
- sal_uInt16 pItems[2];
- pItems[0] = ATTR_CONDITIONAL;
- pItems[1] = 0;
- pNewPattern->ClearItems(pItems);
- pAttrArray->SetPatternArea(nRow1, nRow2, std::move(pNewPattern), true);
+ CellAttributeHolder aNewPattern;
+ if (bSameDocPool)
+ aNewPattern.setScPatternAttr(rCxt.getSingleCellPattern(nColOffset));
+ else
+ aNewPattern = rCxt.getSingleCellPattern(nColOffset)->MigrateToDocument( &rDocument, rCxt.getClipDoc());
+
+ pAttrArray->SetPatternArea(nRow1, nRow2, aNewPattern);
}
}
@@ -229,11 +277,11 @@ void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1,
{
std::vector<sc::CellTextAttr> aTextAttrs(nDestSize, rSrcAttr);
- switch (rSrcCell.meType)
+ switch (rSrcCell.getType())
{
case CELLTYPE_VALUE:
{
- std::vector<double> aVals(nDestSize, rSrcCell.mfValue);
+ std::vector<double> aVals(nDestSize, rSrcCell.getDouble());
pBlockPos->miCellPos =
maCells.set(pBlockPos->miCellPos, nRow1, aVals.begin(), aVals.end());
pBlockPos->miCellTextAttrPos =
@@ -247,8 +295,8 @@ void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1,
// same document. If not, re-intern shared strings.
svl::SharedStringPool* pSharedStringPool = (bSameDocPool ? nullptr : &rDocument.GetSharedStringPool());
svl::SharedString aStr = (pSharedStringPool ?
- pSharedStringPool->intern( rSrcCell.mpString->getString()) :
- *rSrcCell.mpString);
+ pSharedStringPool->intern( rSrcCell.getSharedString()->getString()) :
+ *rSrcCell.getSharedString());
std::vector<svl::SharedString> aStrs(nDestSize, aStr);
pBlockPos->miCellPos =
@@ -263,7 +311,7 @@ void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1,
std::vector<EditTextObject*> aStrs;
aStrs.reserve(nDestSize);
for (size_t i = 0; i < nDestSize; ++i)
- aStrs.push_back(rSrcCell.mpEditText->Clone().release());
+ aStrs.push_back(rSrcCell.getEditText()->Clone().release());
pBlockPos->miCellPos =
maCells.set(pBlockPos->miCellPos, nRow1, aStrs.begin(), aStrs.end());
@@ -277,7 +325,7 @@ void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1,
std::vector<sc::RowSpan> aRanges;
aRanges.reserve(1);
aRanges.emplace_back(nRow1, nRow2);
- CloneFormulaCell(*rSrcCell.mpFormula, rSrcAttr, aRanges);
+ CloneFormulaCell(*pBlockPos, *rSrcCell.getFormula(), rSrcAttr, aRanges);
}
break;
default:
@@ -285,6 +333,11 @@ void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1,
}
}
+ ScAddress aDestPosition(nCol, nRow1, nTab);
+
+ duplicateSparkline(rCxt, pBlockPos, nColOffset, nDestSize, aDestPosition);
+
+ // Notes
const ScPostIt* pNote = rCxt.getSingleCellNote(nColOffset);
if (!(pNote && (nFlags & (InsertDeleteFlags::NOTE | InsertDeleteFlags::ADDNOTES)) != InsertDeleteFlags::NONE))
return;
@@ -294,18 +347,54 @@ void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1,
ScDocument* pClipDoc = rCxt.getClipDoc();
const ScAddress aSrcPos = pClipDoc->GetClipParam().getWholeRange().aStart;
std::vector<ScPostIt*> aNotes;
- ScAddress aDestPos(nCol, nRow1, nTab);
aNotes.reserve(nDestSize);
for (size_t i = 0; i < nDestSize; ++i)
{
bool bCloneCaption = (nFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE;
- aNotes.push_back(pNote->Clone(aSrcPos, rDocument, aDestPos, bCloneCaption).release());
- aDestPos.IncRow();
+ aNotes.push_back(pNote->Clone(aSrcPos, rDocument, aDestPosition, bCloneCaption).release());
+ aDestPosition.IncRow();
}
pBlockPos->miCellNotePos =
maCellNotes.set(
pBlockPos->miCellNotePos, nRow1, aNotes.begin(), aNotes.end());
+
+ // Notify our LOK clients.
+ aDestPosition.SetRow(nRow1);
+ for (size_t i = 0; i < nDestSize; ++i)
+ {
+ ScDocShell::LOKCommentNotify(LOKCommentNotificationType::Add, rDocument, aDestPosition, aNotes[i]);
+ aDestPosition.IncRow();
+ }
+}
+
+void ScColumn::duplicateSparkline(sc::CopyFromClipContext& rContext, sc::ColumnBlockPosition* pBlockPos,
+ size_t nColOffset, size_t nDestSize, ScAddress aDestPosition)
+{
+ if ((rContext.getInsertFlag() & InsertDeleteFlags::SPARKLINES) == InsertDeleteFlags::NONE)
+ return;
+
+ auto pSparkline = rContext.getSingleSparkline(nColOffset);
+ if (pSparkline)
+ {
+ auto const& pSparklineGroup = pSparkline->getSparklineGroup();
+
+ auto pDuplicatedGroup = GetDoc().SearchSparklineGroup(pSparklineGroup->getID());
+ if (!pDuplicatedGroup)
+ pDuplicatedGroup = std::make_shared<sc::SparklineGroup>(*pSparklineGroup);
+
+ std::vector<sc::SparklineCell*> aSparklines(nDestSize, nullptr);
+ ScAddress aCurrentPosition = aDestPosition;
+ for (size_t i = 0; i < nDestSize; ++i)
+ {
+ auto pNewSparkline = std::make_shared<sc::Sparkline>(aCurrentPosition.Col(), aCurrentPosition.Row(), pDuplicatedGroup);
+ pNewSparkline->setInputRange(pSparkline->getInputRange());
+ aSparklines[i] = new sc::SparklineCell(pNewSparkline);
+ aCurrentPosition.IncRow();
+ }
+
+ pBlockPos->miSparklinePos = maSparklines.set(pBlockPos->miSparklinePos, aDestPosition.Row(), aSparklines.begin(), aSparklines.end());
+ }
}
void ScColumn::SetValues( const SCROW nRow, const std::vector<double>& rVals )
@@ -393,13 +482,15 @@ namespace {
class ConvertFormulaToValueHandler
{
sc::CellValues maResValues;
+ ScDocument& mrDoc;
bool mbModified;
public:
- ConvertFormulaToValueHandler(ScSheetLimits const & rSheetLimits) :
+ ConvertFormulaToValueHandler(ScDocument& rDoc) :
+ mrDoc(rDoc),
mbModified(false)
{
- maResValues.reset(rSheetLimits.GetMaxRowCount());
+ maResValues.reset(mrDoc.GetSheetLimits().GetMaxRowCount());
}
void operator() ( size_t nRow, const ScFormulaCell* pCell )
@@ -411,7 +502,15 @@ public:
maResValues.setValue(nRow, aRes.mfValue);
break;
case sc::FormulaResultValue::String:
- maResValues.setValue(nRow, aRes.maString);
+ if (aRes.mbMultiLine)
+ {
+ std::unique_ptr<EditTextObject> pObj(mrDoc.CreateSharedStringTextObject(aRes.maString));
+ maResValues.setValue(nRow, std::move(pObj));
+ }
+ else
+ {
+ maResValues.setValue(nRow, aRes.maString);
+ }
break;
case sc::FormulaResultValue::Error:
case sc::FormulaResultValue::Invalid:
@@ -435,8 +534,7 @@ void ScColumn::ConvertFormulaToValue(
if (!GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2) || nRow1 > nRow2)
return;
- std::vector<SCROW> aBounds;
- aBounds.push_back(nRow1);
+ std::vector<SCROW> aBounds { nRow1 };
if (nRow2 < GetDoc().MaxRow()-1)
aBounds.push_back(nRow2+1);
@@ -444,13 +542,13 @@ void ScColumn::ConvertFormulaToValue(
sc::SharedFormulaUtil::splitFormulaCellGroups(GetDoc(), maCells, aBounds);
// Parse all formulas within the range and store their results into temporary storage.
- ConvertFormulaToValueHandler aFunc(GetDoc().GetSheetLimits());
+ ConvertFormulaToValueHandler aFunc(GetDoc());
sc::ParseFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
if (!aFunc.isModified())
// No formula cells encountered.
return;
- DetachFormulaCells(rCxt, nRow1, nRow2, nullptr);
+ DetachFormulaCells(rCxt, nRow1, nRow2);
// Undo storage to hold static values which will get swapped to the cell storage later.
sc::CellValues aUndoCells;
@@ -496,8 +594,7 @@ void ScColumn::SwapNonEmpty(
sc::TableValues& rValues, sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt )
{
const ScRange& rRange = rValues.getRange();
- std::vector<SCROW> aBounds;
- aBounds.push_back(rRange.aStart.Row());
+ std::vector<SCROW> aBounds { rRange.aStart.Row() };
if (rRange.aEnd.Row() < GetDoc().MaxRow()-1)
aBounds.push_back(rRange.aEnd.Row()+1);
@@ -538,12 +635,10 @@ void ScColumn::DeleteRanges( const std::vector<sc::RowSpan>& rRanges, InsertDele
}
void ScColumn::CloneFormulaCell(
+ sc::ColumnBlockPosition& rBlockPos,
const ScFormulaCell& rSrc, const sc::CellTextAttr& rAttr,
const std::vector<sc::RowSpan>& rRanges )
{
- sc::CellStoreType::iterator itPos = maCells.begin();
- sc::CellTextAttrStoreType::iterator itAttrPos = maCellTextAttrs.begin();
-
SCCOL nMatrixCols = 0;
SCROW nMatrixRows = 0;
ScMatrixMode nMatrixFlag = rSrc.GetMatrixFlag();
@@ -566,11 +661,15 @@ void ScColumn::CloneFormulaCell(
ScAddress aPos(nCol, nRow1, nTab);
- if (nLen == 1)
+ if (nLen == 1 || !rSrc.GetCode()->IsShareable())
{
- // Single, ungrouped formula cell.
- ScFormulaCell* pCell = new ScFormulaCell(rSrc, rDocument, aPos);
- aFormulas.push_back(pCell);
+ // Single, ungrouped formula cell, or create copies for
+ // non-shareable token arrays.
+ for (size_t i = 0; i < nLen; ++i, aPos.IncRow())
+ {
+ ScFormulaCell* pCell = new ScFormulaCell(rSrc, rDocument, aPos);
+ aFormulas.push_back(pCell);
+ }
}
else
{
@@ -592,10 +691,10 @@ void ScColumn::CloneFormulaCell(
}
}
- itPos = maCells.set(itPos, nRow1, aFormulas.begin(), aFormulas.end());
+ rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow1, aFormulas.begin(), aFormulas.end());
// Join the top and bottom of the pasted formula cells as needed.
- sc::CellStoreType::position_type aPosObj = maCells.position(itPos, nRow1);
+ sc::CellStoreType::position_type aPosObj = maCells.position(rBlockPos.miCellPos, nRow1);
assert(aPosObj.first->type == sc::element_type_formula);
ScFormulaCell* pCell = sc::formula_block::at(*aPosObj.first->data, aPosObj.second);
@@ -607,12 +706,22 @@ void ScColumn::CloneFormulaCell(
JoinNewFormulaCell(aPosObj, *pCell);
std::vector<sc::CellTextAttr> aTextAttrs(nLen, rAttr);
- itAttrPos = maCellTextAttrs.set(itAttrPos, nRow1, aTextAttrs.begin(), aTextAttrs.end());
+ rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
+ rBlockPos.miCellTextAttrPos, nRow1, aTextAttrs.begin(), aTextAttrs.end());
}
CellStorageModified();
}
+void ScColumn::CloneFormulaCell(
+ const ScFormulaCell& rSrc, const sc::CellTextAttr& rAttr,
+ const std::vector<sc::RowSpan>& rRanges )
+{
+ sc::ColumnBlockPosition aBlockPos;
+ InitBlockPosition(aBlockPos);
+ CloneFormulaCell(aBlockPos, rSrc, rAttr, rRanges);
+}
+
std::unique_ptr<ScPostIt> ScColumn::ReleaseNote( SCROW nRow )
{
if (!GetDoc().ValidRow(nRow))
@@ -748,7 +857,9 @@ public:
void ScColumn::GetAllNoteEntries( std::vector<sc::NoteEntry>& rNotes ) const
{
- std::for_each(maCellNotes.begin(), maCellNotes.end(), NoteEntryCollector(rNotes, nTab, nCol, 0, GetDoc().MaxRow()));
+ if (HasCellNotes())
+ std::for_each(maCellNotes.begin(), maCellNotes.end(),
+ NoteEntryCollector(rNotes, nTab, nCol, 0, GetDoc().MaxRow()));
}
void ScColumn::GetNotesInRange(SCROW nStartRow, SCROW nEndRow,
@@ -927,7 +1038,7 @@ public:
std::unique_ptr<ScTokenArray> pNewCode = aComp.CompileString(aFormula);
ScFormulaCellGroupRef xGroup = pTop->GetCellGroup();
assert(xGroup);
- xGroup->setCode(std::move(pNewCode));
+ xGroup->setCode(std::move(*pNewCode));
xGroup->compileCode(mrDoc, pTop->aPos, mrDoc.GetGrammar());
// Propagate the new token array to all formula cells in the group.
@@ -1015,7 +1126,7 @@ class ScriptTypeUpdater
sc::CellTextAttrStoreType& mrTextAttrs;
sc::CellTextAttrStoreType::iterator miPosAttr;
ScConditionalFormatList* mpCFList;
- SvNumberFormatter* mpFormatter;
+ ScInterpreterContext& mrContext;
ScAddress maPos;
bool mbUpdated;
@@ -1047,10 +1158,9 @@ private:
pCondSet = mrCol.GetDoc().GetCondResult(rCell, maPos, *mpCFList, rData);
}
- OUString aStr;
const Color* pColor;
- sal_uInt32 nFormat = pPat->GetNumberFormat(mpFormatter, pCondSet);
- ScCellFormat::GetString(rCell, nFormat, aStr, &pColor, *mpFormatter, mrCol.GetDoc());
+ sal_uInt32 nFormat = pPat->GetNumberFormat(mrContext, pCondSet);
+ OUString aStr = ScCellFormat::GetString(rCell, nFormat, &pColor, &mrContext, mrCol.GetDoc());
rAttr.mnScriptType = mrCol.GetDoc().GetStringScriptType(aStr);
mbUpdated = true;
@@ -1062,7 +1172,7 @@ public:
mrTextAttrs(rCol.GetCellAttrStore()),
miPosAttr(mrTextAttrs.begin()),
mpCFList(rCol.GetDoc().GetCondFormList(rCol.GetTab())),
- mpFormatter(rCol.GetDoc().GetFormatTable()),
+ mrContext(rCol.GetDoc().GetNonThreadedContext()),
maPos(rCol.GetCol(), 0, rCol.GetTab()),
mbUpdated(false)
{}
@@ -1139,12 +1249,11 @@ void ScColumn::Swap( ScColumn& rOther, SCROW nRow1, SCROW nRow2, bool bPattern )
{
const ScPatternAttr* pPat1 = GetPattern(nRow);
const ScPatternAttr* pPat2 = rOther.GetPattern(nRow);
- if (pPat1 != pPat2)
+ if (!ScPatternAttr::areSame(pPat1, pPat2))
{
- if (pPat1->GetRefCount() == 1)
- pPat1 = &rOther.GetDoc().GetPool()->Put(*pPat1);
+ CellAttributeHolder aTemp(pPat1);
SetPattern(nRow, *pPat2);
- rOther.SetPattern(nRow, *pPat1);
+ rOther.SetPattern(nRow, aTemp);
}
}
}
@@ -1663,12 +1772,12 @@ void ScColumn::SetNeedsListeningGroup( SCROW nRow )
(*pp)->SetNeedsListening(true);
}
-std::unique_ptr<sc::ColumnIterator> ScColumn::GetColumnIterator( SCROW nRow1, SCROW nRow2 ) const
+std::optional<sc::ColumnIterator> ScColumn::GetColumnIterator( SCROW nRow1, SCROW nRow2 ) const
{
if (!GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2) || nRow1 > nRow2)
- return std::unique_ptr<sc::ColumnIterator>();
+ return {};
- return std::make_unique<sc::ColumnIterator>(maCells, nRow1, nRow2);
+ return sc::ColumnIterator(maCells, nRow1, nRow2);
}
static bool lcl_InterpretSpan(sc::formula_block::const_iterator& rSpanIter, SCROW nStartOffset, SCROW nEndOffset,
@@ -1751,7 +1860,7 @@ static bool lcl_InterpretSpan(sc::formula_block::const_iterator& rSpanIter, SCRO
static void lcl_EvalDirty(sc::CellStoreType& rCells, SCROW nRow1, SCROW nRow2, ScDocument& rDoc,
const ScFormulaCellGroupRef& mxGroup, bool bThreadingDepEval, bool bSkipRunning,
- bool& bIsDirty, bool& bAllowThreading)
+ bool& bIsDirty, bool& bAllowThreading, ScAddress* pDirtiedAddress)
{
ScRecursionHelper& rRecursionHelper = rDoc.GetRecursionHelper();
std::pair<sc::CellStoreType::const_iterator,size_t> aPos = rCells.position(nRow1);
@@ -1857,6 +1966,8 @@ static void lcl_EvalDirty(sc::CellStoreType& rCells, SCROW nRow1, SCROW nRow2, S
{
// Set itCell as dirty as itCell may be interpreted in InterpretTail()
(*itCell)->SetDirtyVar();
+ if (pDirtiedAddress)
+ pDirtiedAddress->SetRow(nRow);
bAllowThreading = false;
return;
}
@@ -1892,17 +2003,17 @@ bool ScColumn::EnsureFormulaCellResults( SCROW nRow1, SCROW nRow2, bool bSkipRun
return false;
bool bAnyDirty = false, bTmp = false;
- lcl_EvalDirty(maCells, nRow1, nRow2, GetDoc(), nullptr, false, bSkipRunning, bAnyDirty, bTmp);
+ lcl_EvalDirty(maCells, nRow1, nRow2, GetDoc(), nullptr, false, bSkipRunning, bAnyDirty, bTmp, nullptr);
return bAnyDirty;
}
-bool ScColumn::HandleRefArrayForParallelism( SCROW nRow1, SCROW nRow2, const ScFormulaCellGroupRef& mxGroup )
+bool ScColumn::HandleRefArrayForParallelism( SCROW nRow1, SCROW nRow2, const ScFormulaCellGroupRef& mxGroup, ScAddress* pDirtiedAddress )
{
if (nRow1 > nRow2)
return false;
bool bAllowThreading = true, bTmp = false;
- lcl_EvalDirty(maCells, nRow1, nRow2, GetDoc(), mxGroup, true, false, bTmp, bAllowThreading);
+ lcl_EvalDirty(maCells, nRow1, nRow2, GetDoc(), mxGroup, true, false, bTmp, bAllowThreading, pDirtiedAddress);
return bAllowThreading;
}
@@ -1973,8 +2084,7 @@ public:
for (; it != itEnd; /* incrementing through std::advance*/)
{
const ScFormulaCell* pCell = *it;
- OUString aFormula;
- pCell->GetFormula(aFormula, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
+ OUString aFormula = pCell->GetFormula(formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
const auto& xCellGroup = pCell->GetCellGroup();
sal_uInt64 nGroupLength = 0;
if (xCellGroup)
@@ -2056,7 +2166,7 @@ void ScColumn::RestoreFromCache(SvStream& rStrm)
rStrm.ReadInt32(nStrLength);
std::unique_ptr<char[]> pStr(new char[nStrLength]);
rStrm.ReadBytes(pStr.get(), nStrLength);
- OString aOStr(pStr.get(), nStrLength);
+ std::string_view aOStr(pStr.get(), nStrLength);
OUString aStr = OStringToOUString(aOStr, RTL_TEXTENCODING_UTF8);
rString = rPool.intern(aStr);
}
@@ -2078,7 +2188,7 @@ void ScColumn::RestoreFromCache(SvStream& rStrm)
rStrm.ReadInt32(nStrLength);
std::unique_ptr<char[]> pStr(new char[nStrLength]);
rStrm.ReadBytes(pStr.get(), nStrLength);
- OString aOStr(pStr.get(), nStrLength);
+ std::string_view aOStr(pStr.get(), nStrLength);
OUString aStr = OStringToOUString(aOStr, RTL_TEXTENCODING_UTF8);
for (sal_uInt64 i = 0; i < nFormulaGroupSize; ++i)
{
@@ -2098,4 +2208,78 @@ void ScColumn::RestoreFromCache(SvStream& rStrm)
}
}
+void ScColumn::CheckIntegrity() const
+{
+ auto checkEventHandlerColumnRef = [this](const auto& rStore, std::string_view pStoreName)
+ {
+ if (const ScColumn* pColTest = rStore.event_handler().getColumn(); pColTest != this)
+ {
+ std::ostringstream os;
+ os << pStoreName << "'s event handler references wrong column instance (this=" << this
+ << "; stored=" << pColTest << ")";
+ throw std::runtime_error(os.str());
+ }
+ };
+
+ auto countBlocks = [](const auto& rStore, mdds::mtv::element_t nBlockType)
+ {
+ std::size_t nCount = std::count_if(rStore.cbegin(), rStore.cend(),
+ [nBlockType](const auto& blk) { return blk.type == nBlockType; }
+ );
+
+ return nCount;
+ };
+
+ auto checkCachedBlockCount = [countBlocks](
+ const auto& rStore, mdds::mtv::element_t nBlockType, std::size_t nCachedBlkCount,
+ std::string_view pName)
+ {
+ std::size_t nCount = countBlocks(rStore, nBlockType);
+
+ if (nCachedBlkCount != nCount)
+ {
+ std::ostringstream os;
+ os << "incorrect cached " << pName << " block count (expected=" << nCount << "; actual="
+ << nCachedBlkCount << ")";
+ throw std::runtime_error(os.str());
+ }
+ };
+
+ checkEventHandlerColumnRef(maCells, "cell store");
+ checkEventHandlerColumnRef(maCellNotes, "cell-note store");
+
+ checkCachedBlockCount(maCells, sc::element_type_formula, mnBlkCountFormula, "formula");
+ checkCachedBlockCount(maCellNotes, sc::element_type_cellnote, mnBlkCountCellNotes, "cell note");
+}
+
+void ScColumn::CollectBroadcasterState(sc::BroadcasterState& rState) const
+{
+ for (const auto& block : maBroadcasters)
+ {
+ if (block.type != sc::element_type_broadcaster)
+ continue;
+
+ auto itBeg = sc::broadcaster_block::begin(*block.data);
+ auto itEnd = sc::broadcaster_block::end(*block.data);
+
+ for (auto it = itBeg; it != itEnd; ++it)
+ {
+ ScAddress aBCPos(nCol, block.position + std::distance(itBeg, it), nTab);
+
+ auto aRes = rState.aCellListenerStore.try_emplace(aBCPos);
+ auto& rLisStore = aRes.first->second;
+
+ const SvtBroadcaster& rBC = **it;
+ for (const SvtListener* pLis : rBC.GetAllListeners())
+ {
+ const auto* pFC = dynamic_cast<const ScFormulaCell*>(pLis);
+ if (pFC)
+ rLisStore.emplace_back(pFC);
+ else
+ rLisStore.emplace_back(pLis);
+ }
+ }
+ }
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/columniterator.cxx b/sc/source/core/data/columniterator.cxx
index a65541fabb53..cec8f7a2028e 100644
--- a/sc/source/core/data/columniterator.cxx
+++ b/sc/source/core/data/columniterator.cxx
@@ -176,8 +176,6 @@ ColumnIterator::ColumnIterator( const CellStoreType& rCells, SCROW nRow1, SCROW
{
}
-ColumnIterator::~ColumnIterator() {}
-
void ColumnIterator::next()
{
if ( maPos == maPosEnd)
diff --git a/sc/source/core/data/columnspanset.cxx b/sc/source/core/data/columnspanset.cxx
index b400cd651c5a..69377bdba76c 100644
--- a/sc/source/core/data/columnspanset.cxx
+++ b/sc/source/core/data/columnspanset.cxx
@@ -17,7 +17,6 @@
#include <fstalgorithm.hxx>
#include <algorithm>
-#include <memory>
#include <o3tl/safeint.hxx>
@@ -25,12 +24,12 @@ namespace sc {
namespace {
-class ColumnScanner
+class ColumnNonEmptyRangesScanner
{
ColumnSpanSet::ColumnSpansType& mrRanges;
bool mbVal;
public:
- ColumnScanner(ColumnSpanSet::ColumnSpansType& rRanges, bool bVal) :
+ ColumnNonEmptyRangesScanner(ColumnSpanSet::ColumnSpansType& rRanges, bool bVal) :
mrRanges(rRanges), mbVal(bVal) {}
void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
@@ -53,6 +52,9 @@ ColRowSpan::ColRowSpan(SCCOLROW nStart, SCCOLROW nEnd) : mnStart(nStart), mnEnd(
ColumnSpanSet::ColumnType::ColumnType(SCROW nStart, SCROW nEnd, bool bInit) :
maSpans(nStart, nEnd+1, bInit), miPos(maSpans.begin()) {}
+ColumnSpanSet::ColumnType::ColumnType(const ColumnType& rOther) :
+ maSpans(rOther.maSpans), miPos(maSpans.begin()) {} // NB: copying maSpans invalidates miPos - reset it
+
ColumnSpanSet::Action::~Action() {}
void ColumnSpanSet::Action::startColumn(SCTAB /*nTab*/, SCCOL /*nCol*/) {}
@@ -69,15 +71,12 @@ ColumnSpanSet::ColumnType& ColumnSpanSet::getColumn(const ScDocument& rDoc, SCTA
if (o3tl::make_unsigned(nTab) >= maTables.size())
maTables.resize(nTab+1);
- if (!maTables[nTab])
- maTables[nTab].reset(new TableType);
-
- TableType& rTab = *maTables[nTab];
+ TableType& rTab = maTables[nTab];
if (o3tl::make_unsigned(nCol) >= rTab.size())
rTab.resize(nCol+1);
if (!rTab[nCol])
- rTab[nCol].reset(new ColumnType(0, rDoc.MaxRow(), /*bInit*/false));
+ rTab[nCol].emplace(0, rDoc.MaxRow(), /*bInit*/false);
return *rTab[nCol];
}
@@ -140,26 +139,36 @@ void ColumnSpanSet::scan(
const CellStoreType& rSrcCells = pTab->aCol[nCol].maCells;
- ColumnScanner aScanner(rCol.maSpans, bVal);
+ if( nRow1 > pTab->aCol[nCol].GetLastDataPos())
+ continue;
+
+ ColumnNonEmptyRangesScanner aScanner(rCol.maSpans, bVal);
ParseBlock(rSrcCells.begin(), rSrcCells, aScanner, nRow1, nRow2);
+ rCol.miPos = rCol.maSpans.begin();
}
}
-void ColumnSpanSet::executeAction(Action& ac) const
+void ColumnSpanSet::executeAction(ScDocument& rDoc, Action& ac) const
{
for (size_t nTab = 0; nTab < maTables.size(); ++nTab)
{
- if (!maTables[nTab])
+ if (maTables[nTab].empty())
+ continue;
+
+ ScTable* pTab = rDoc.FetchTable(nTab);
+ if (!pTab)
continue;
- const TableType& rTab = *maTables[nTab];
- for (size_t nCol = 0; nCol < rTab.size(); ++nCol)
+ const TableType& rTab = maTables[nTab];
+ for (SCCOL nCol = 0; nCol < static_cast<SCCOL>(rTab.size()); ++nCol)
{
if (!rTab[nCol])
continue;
+ if (nCol >= pTab->GetAllocatedColumnsCount())
+ break;
ac.startColumn(nTab, nCol);
- ColumnType& rCol = *rTab[nCol];
+ const ColumnType& rCol = *rTab[nCol];
ColumnSpansType::const_iterator it = rCol.maSpans.begin(), itEnd = rCol.maSpans.end();
SCROW nRow1, nRow2;
nRow1 = it->first;
@@ -180,29 +189,24 @@ void ColumnSpanSet::executeColumnAction(ScDocument& rDoc, ColumnAction& ac) cons
{
for (size_t nTab = 0; nTab < maTables.size(); ++nTab)
{
- if (!maTables[nTab])
+ if (maTables[nTab].empty())
continue;
- const TableType& rTab = *maTables[nTab];
+ ScTable* pTab = rDoc.FetchTable(nTab);
+ if (!pTab)
+ continue;
+
+ const TableType& rTab = maTables[nTab];
for (SCCOL nCol = 0; nCol < static_cast<SCCOL>(rTab.size()); ++nCol)
{
if (!rTab[nCol])
continue;
-
- ScTable* pTab = rDoc.FetchTable(nTab);
- if (!pTab)
- continue;
-
- if (!rDoc.ValidCol(nCol) || nCol >= pTab->GetAllocatedColumnsCount())
- {
- // End the loop.
- nCol = rTab.size();
- continue;
- }
+ if (nCol >= pTab->GetAllocatedColumnsCount())
+ break;
ScColumn& rColumn = pTab->aCol[nCol];
ac.startColumn(&rColumn);
- ColumnType& rCol = *rTab[nCol];
+ const ColumnType& rCol = *rTab[nCol];
ColumnSpansType::const_iterator it = rCol.maSpans.begin(), itEnd = rCol.maSpans.end();
SCROW nRow1, nRow2;
nRow1 = it->first;
@@ -221,11 +225,11 @@ void ColumnSpanSet::executeColumnAction(ScDocument& rDoc, ColumnAction& ac) cons
namespace {
-class Scanner
+class NonEmptyRangesScanner
{
SingleColumnSpanSet::ColumnSpansType& mrRanges;
public:
- explicit Scanner(SingleColumnSpanSet::ColumnSpansType& rRanges) : mrRanges(rRanges) {}
+ explicit NonEmptyRangesScanner(SingleColumnSpanSet::ColumnSpansType& rRanges) : mrRanges(rRanges) {}
void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
{
@@ -260,16 +264,20 @@ void SingleColumnSpanSet::scan(const ScColumn& rColumn)
void SingleColumnSpanSet::scan(const ScColumn& rColumn, SCROW nStart, SCROW nEnd)
{
+ if( nStart > rColumn.GetLastDataPos())
+ return;
const CellStoreType& rCells = rColumn.maCells;
- Scanner aScanner(maSpans);
+ NonEmptyRangesScanner aScanner(maSpans);
sc::ParseBlock(rCells.begin(), rCells, aScanner, nStart, nEnd);
}
void SingleColumnSpanSet::scan(
ColumnBlockConstPosition& rBlockPos, const ScColumn& rColumn, SCROW nStart, SCROW nEnd)
{
+ if( nStart > rColumn.GetLastDataPos())
+ return;
const CellStoreType& rCells = rColumn.maCells;
- Scanner aScanner(maSpans);
+ NonEmptyRangesScanner aScanner(maSpans);
rBlockPos.miCellPos = sc::ParseBlock(rBlockPos.miCellPos, rCells, aScanner, nStart, nEnd);
}
diff --git a/sc/source/core/data/compressedarray.cxx b/sc/source/core/data/compressedarray.cxx
index e585bed5a074..793b43b43a3b 100644
--- a/sc/source/core/data/compressedarray.cxx
+++ b/sc/source/core/data/compressedarray.cxx
@@ -32,11 +32,6 @@ ScCompressedArray<A,D>::ScCompressedArray( A nMaxAccessP, const D& rValue )
}
template< typename A, typename D >
-ScCompressedArray<A,D>::~ScCompressedArray()
-{
-}
-
-template< typename A, typename D >
size_t ScCompressedArray<A,D>::Search( A nAccess ) const
{
if (nAccess == 0)
diff --git a/sc/source/core/data/conditio.cxx b/sc/source/core/data/conditio.cxx
index 11e74fa258db..4c4ad49c67e7 100644
--- a/sc/source/core/data/conditio.cxx
+++ b/sc/source/core/data/conditio.cxx
@@ -18,7 +18,7 @@
*/
#include <scitems.hxx>
-#include <svl/zforlist.hxx>
+#include <svl/numformat.hxx>
#include <rtl/math.hxx>
#include <sal/log.hxx>
#include <unotools/collatorwrapper.hxx>
@@ -44,6 +44,7 @@
#include <svl/sharedstringpool.hxx>
#include <memory>
#include <numeric>
+#include <utility>
using namespace formula;
@@ -73,6 +74,10 @@ void ScFormatEntry::endRendering()
{
}
+void ScFormatEntry::updateValues()
+{
+}
+
static bool lcl_HasRelRef( ScDocument* pDoc, const ScTokenArray* pFormula, sal_uInt16 nRecursion = 0 )
{
if (pFormula)
@@ -155,12 +160,13 @@ void ScConditionEntry::StartListening()
if (!pCondFormat)
return;
+ mpRepaintTask = std::make_unique<RepaintInIdle>(pCondFormat);
const ScRangeList& rRanges = pCondFormat->GetRange();
mpListener->stopListening();
start_listen_to(*mpListener, pFormula1.get(), rRanges);
start_listen_to(*mpListener, pFormula2.get(), rRanges);
- mpListener->setCallback([&]() { pCondFormat->DoRepaint();});
+ mpListener->setCallback([&]() { mpRepaintTask->Start();});
}
void ScConditionEntry::SetParent(ScConditionalFormat* pParent)
@@ -190,7 +196,8 @@ ScConditionEntry::ScConditionEntry( const ScConditionEntry& r ) :
bFirstRun(true),
mpListener(new ScFormulaListener(*r.mpDoc)),
eConditionType( r.eConditionType ),
- pCondFormat(r.pCondFormat)
+ pCondFormat(r.pCondFormat),
+ mpRepaintTask()
{
// ScTokenArray copy ctor creates a flat copy
if (r.pFormula1)
@@ -223,7 +230,8 @@ ScConditionEntry::ScConditionEntry( ScDocument& rDocument, const ScConditionEntr
bFirstRun(true),
mpListener(new ScFormulaListener(rDocument)),
eConditionType( r.eConditionType),
- pCondFormat(r.pCondFormat)
+ pCondFormat(r.pCondFormat),
+ mpRepaintTask()
{
// Real copy of the formulas (for Ref Undo)
if (r.pFormula1)
@@ -257,7 +265,8 @@ ScConditionEntry::ScConditionEntry( ScConditionMode eOper,
bFirstRun(true),
mpListener(new ScFormulaListener(rDocument)),
eConditionType(eType),
- pCondFormat(nullptr)
+ pCondFormat(nullptr),
+ mpRepaintTask()
{
Compile( rExpr1, rExpr2, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2, false );
@@ -282,7 +291,8 @@ ScConditionEntry::ScConditionEntry( ScConditionMode eOper,
bFirstRun(true),
mpListener(new ScFormulaListener(rDocument)),
eConditionType(ScFormatEntry::Type::Condition),
- pCondFormat(nullptr)
+ pCondFormat(nullptr),
+ mpRepaintTask()
{
if ( pArr1 )
{
@@ -400,6 +410,7 @@ void ScConditionEntry::MakeCells( const ScAddress& rPos )
// pFCell1 will hold a flat-copied ScTokenArray sharing ref-counted
// code tokens with pFormula1
pFCell1.reset( new ScFormulaCell(*mpDoc, rPos, *pFormula1) );
+ pFCell1->SetFreeFlying(true);
pFCell1->StartListeningTo( *mpDoc );
}
@@ -408,6 +419,7 @@ void ScConditionEntry::MakeCells( const ScAddress& rPos )
// pFCell2 will hold a flat-copied ScTokenArray sharing ref-counted
// code tokens with pFormula2
pFCell2.reset( new ScFormulaCell(*mpDoc, rPos, *pFormula2) );
+ pFCell2->SetFreeFlying(true);
pFCell2->StartListeningTo( *mpDoc );
}
}
@@ -471,6 +483,7 @@ void ScConditionEntry::SetFormula1( const ScTokenArray& rArray )
if( rArray.GetLen() > 0 )
{
pFormula1.reset( new ScTokenArray( rArray ) );
+ SimplifyCompiledFormula(pFormula1, nVal1, bIsStr1, aStrVal1);
bRelRef1 = lcl_HasRelRef( mpDoc, pFormula1.get() );
}
@@ -483,6 +496,7 @@ void ScConditionEntry::SetFormula2( const ScTokenArray& rArray )
if( rArray.GetLen() > 0 )
{
pFormula2.reset( new ScTokenArray( rArray ) );
+ SimplifyCompiledFormula(pFormula2, nVal2, bIsStr2, aStrVal2);
bRelRef2 = lcl_HasRelRef( mpDoc, pFormula2.get() );
}
@@ -495,10 +509,10 @@ void ScConditionEntry::UpdateReference( sc::RefUpdateContext& rCxt )
aSrcPos = pCondFormat->GetRange().Combine().aStart;
ScAddress aOldSrcPos = aSrcPos;
bool bChangedPos = false;
- if (rCxt.meMode == URM_INSDEL && rCxt.maRange.In(aSrcPos))
+ if (rCxt.meMode == URM_INSDEL && rCxt.maRange.Contains(aSrcPos))
{
ScAddress aErrorPos( ScAddress::UNINITIALIZED );
- if (!aSrcPos.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorPos))
+ if (!aSrcPos.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorPos, *mpDoc))
{
assert(!"can't move ScConditionEntry");
}
@@ -581,20 +595,29 @@ void ScConditionEntry::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
StartListening();
}
-void ScConditionEntry::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt )
+void ScConditionEntry::UpdateMoveTab(sc::RefUpdateMoveTabContext& rCxt)
{
+ sc::RefUpdateResult aResFinal;
+ aResFinal.mnTab = aSrcPos.Tab();
if (pFormula1)
{
- pFormula1->AdjustReferenceOnMovedTab(rCxt, aSrcPos);
+ sc::RefUpdateResult aRes = pFormula1->AdjustReferenceOnMovedTab(rCxt, aSrcPos);
+ if (aRes.mbValueChanged)
+ aResFinal.mnTab = aRes.mnTab;
pFCell1.reset();
}
if (pFormula2)
{
- pFormula2->AdjustReferenceOnMovedTab(rCxt, aSrcPos);
+ sc::RefUpdateResult aRes = pFormula2->AdjustReferenceOnMovedTab(rCxt, aSrcPos);
+ if (aRes.mbValueChanged)
+ aResFinal.mnTab = aRes.mnTab;
pFCell2.reset();
}
+ if (aResFinal.mnTab != aSrcPos.Tab())
+ aSrcPos.SetTab(aResFinal.mnTab);
+
StartListening();
}
@@ -615,25 +638,25 @@ bool ScConditionEntry::IsEqual( const ScFormatEntry& rOther, bool bIgnoreSrcPos
const ScConditionEntry& r = static_cast<const ScConditionEntry&>(rOther);
- bool bEq = (eOp == r.eOp && nOptions == r.nOptions &&
- lcl_IsEqual( pFormula1, r.pFormula1 ) &&
- lcl_IsEqual( pFormula2, r.pFormula2 ));
+ if (eOp != r.eOp || nOptions != r.nOptions
+ || !lcl_IsEqual(pFormula1, r.pFormula1) || !lcl_IsEqual(pFormula2, r.pFormula2))
+ return false;
if (!bIgnoreSrcPos)
{
// for formulas, the reference positions must be compared, too
// (including aSrcString, for inserting the entries during XML import)
- if ( bEq && ( pFormula1 || pFormula2 ) && ( aSrcPos != r.aSrcPos || aSrcString != r.aSrcString ) )
- bEq = false;
+ if ( ( pFormula1 || pFormula2 ) && ( aSrcPos != r.aSrcPos || aSrcString != r.aSrcString ) )
+ return false;
}
// If not formulas, compare values
- if ( bEq && !pFormula1 && ( nVal1 != r.nVal1 || aStrVal1 != r.aStrVal1 || bIsStr1 != r.bIsStr1 ) )
- bEq = false;
- if ( bEq && !pFormula2 && ( nVal2 != r.nVal2 || aStrVal2 != r.aStrVal2 || bIsStr2 != r.bIsStr2 ) )
- bEq = false;
+ if ( !pFormula1 && ( nVal1 != r.nVal1 || aStrVal1 != r.aStrVal1 || bIsStr1 != r.bIsStr1 ) )
+ return false;
+ if ( !pFormula2 && ( nVal2 != r.nVal2 || aStrVal2 != r.aStrVal2 || bIsStr2 != r.bIsStr2 ) )
+ return false;
- return bEq;
+ return true;
}
void ScConditionEntry::Interpret( const ScAddress& rPos )
@@ -646,12 +669,16 @@ void ScConditionEntry::Interpret( const ScAddress& rPos )
// Evaluate formulas
bool bDirty = false; // 1 and 2 separate?
- std::unique_ptr<ScFormulaCell> pTemp1;
+ std::optional<ScFormulaCell> oTemp;
ScFormulaCell* pEff1 = pFCell1.get();
if ( bRelRef1 )
{
- pTemp1.reset(pFormula1 ? new ScFormulaCell(*mpDoc, rPos, *pFormula1) : new ScFormulaCell(*mpDoc, rPos));
- pEff1 = pTemp1.get();
+ if (pFormula1)
+ oTemp.emplace(*mpDoc, rPos, *pFormula1);
+ else
+ oTemp.emplace(*mpDoc, rPos);
+ pEff1 = &*oTemp;
+ pEff1->SetFreeFlying(true);
}
if ( pEff1 )
{
@@ -674,14 +701,17 @@ void ScConditionEntry::Interpret( const ScAddress& rPos )
}
}
}
- pTemp1.reset();
+ oTemp.reset();
- std::unique_ptr<ScFormulaCell> pTemp2;
ScFormulaCell* pEff2 = pFCell2.get(); //@ 1!=2
if ( bRelRef2 )
{
- pTemp2.reset(pFormula2 ? new ScFormulaCell(*mpDoc, rPos, *pFormula2) : new ScFormulaCell(*mpDoc, rPos));
- pEff2 = pTemp2.get();
+ if (pFormula2)
+ oTemp.emplace(*mpDoc, rPos, *pFormula2);
+ else
+ oTemp.emplace(*mpDoc, rPos);
+ pEff2 = &*oTemp;
+ pEff2->SetFreeFlying(true);
}
if ( pEff2 )
{
@@ -703,7 +733,7 @@ void ScConditionEntry::Interpret( const ScAddress& rPos )
}
}
}
- pTemp2.reset();
+ oTemp.reset();
// If IsRunning, the last values remain
if (bDirty && !bFirstRun)
@@ -724,27 +754,27 @@ static bool lcl_GetCellContent( ScRefCellValue& rCell, bool bIsStr1, double& rAr
bool bVal = true;
- switch (rCell.meType)
+ switch (rCell.getType())
{
case CELLTYPE_VALUE:
- rArg = rCell.mfValue;
+ rArg = rCell.getDouble();
break;
case CELLTYPE_FORMULA:
{
- bVal = rCell.mpFormula->IsValue();
+ bVal = rCell.getFormula()->IsValue();
if (bVal)
- rArg = rCell.mpFormula->GetValue();
+ rArg = rCell.getFormula()->GetValue();
else
- rArgStr = rCell.mpFormula->GetString().getString();
+ rArgStr = rCell.getFormula()->GetString().getString();
}
break;
case CELLTYPE_STRING:
case CELLTYPE_EDIT:
bVal = false;
- if (rCell.meType == CELLTYPE_STRING)
- rArgStr = rCell.mpString->getString();
- else if (rCell.mpEditText)
- rArgStr = ScEditUtil::GetString(*rCell.mpEditText, pDoc);
+ if (rCell.getType() == CELLTYPE_STRING)
+ rArgStr = rCell.getSharedString()->getString();
+ else if (rCell.getEditText())
+ rArgStr = ScEditUtil::GetString(*rCell.getEditText(), pDoc);
break;
default:
;
@@ -772,7 +802,7 @@ void ScConditionEntry::FillCache() const
// temporary fix to workaround slow duplicate entry
// conditions, prevent to use a whole row
- if(nRow == MAXROW)
+ if(nRow == mpDoc->MaxRow())
{
bool bShrunk = false;
mpDoc->ShrinkToUsedDataArea(bShrunk, nTab, nColStart, nRowStart,
@@ -946,9 +976,9 @@ bool ScConditionEntry::IsError( const ScAddress& rPos ) const
{
ScRefCellValue rCell(*mpDoc, rPos);
- if (rCell.meType == CELLTYPE_FORMULA)
+ if (rCell.getType() == CELLTYPE_FORMULA)
{
- if (rCell.mpFormula->GetErrCode() != FormulaError::NONE)
+ if (rCell.getFormula()->GetErrCode() != FormulaError::NONE)
return true;
}
@@ -983,10 +1013,8 @@ bool ScConditionEntry::IsValid( double nArg, const ScAddress& rPos ) const
if ( eOp == ScConditionMode::Between || eOp == ScConditionMode::NotBetween )
if ( nComp1 > nComp2 )
- {
// Right order for value range
- double nTemp = nComp1; nComp1 = nComp2; nComp2 = nTemp;
- }
+ std::swap( nComp1, nComp2 );
// All corner cases need to be tested with ::rtl::math::approxEqual!
bool bValid = false;
@@ -1126,8 +1154,13 @@ bool ScConditionEntry::IsValidStr( const OUString& rArg, const ScAddress& rPos )
}
}
+ if (eOp == ScConditionMode::Error)
+ return IsError(rPos);
+ if (eOp == ScConditionMode::NoError)
+ return !IsError(rPos);
+
// If number contains condition, always false, except for "not equal".
- if ( !bIsStr1 && (eOp != ScConditionMode::Error && eOp != ScConditionMode::NoError) )
+ if (!bIsStr1)
return ( eOp == ScConditionMode::NotEqual );
if ( eOp == ScConditionMode::Between || eOp == ScConditionMode::NotBetween )
if ( !bIsStr2 )
@@ -1136,22 +1169,13 @@ bool ScConditionEntry::IsValidStr( const OUString& rArg, const ScAddress& rPos )
OUString aUpVal1( aStrVal1 ); //TODO: As a member? (Also set in Interpret)
OUString aUpVal2( aStrVal2 );
- if ( eOp == ScConditionMode::Between || eOp == ScConditionMode::NotBetween )
- if (ScGlobal::GetCollator()->compareString( aUpVal1, aUpVal2 ) > 0)
- {
- // Right order for value range
- OUString aTemp( aUpVal1 ); aUpVal1 = aUpVal2; aUpVal2 = aTemp;
- }
-
switch ( eOp )
{
case ScConditionMode::Equal:
- bValid = (ScGlobal::GetCollator()->compareString(
- rArg, aUpVal1 ) == 0);
+ bValid = ScGlobal::GetTransliteration().isEqual(aUpVal1, rArg);
break;
case ScConditionMode::NotEqual:
- bValid = (ScGlobal::GetCollator()->compareString(
- rArg, aUpVal1 ) != 0);
+ bValid = !ScGlobal::GetTransliteration().isEqual(aUpVal1, rArg);
break;
case ScConditionMode::TopPercent:
case ScConditionMode::BottomPercent:
@@ -1160,27 +1184,38 @@ bool ScConditionEntry::IsValidStr( const OUString& rArg, const ScAddress& rPos )
case ScConditionMode::AboveAverage:
case ScConditionMode::BelowAverage:
return false;
- case ScConditionMode::Error:
- case ScConditionMode::NoError:
- bValid = IsError( rPos );
- if(eOp == ScConditionMode::NoError)
- bValid = !bValid;
- break;
case ScConditionMode::BeginsWith:
- bValid = rArg.startsWith(aUpVal1);
+ bValid = ScGlobal::GetTransliteration().isMatch(aUpVal1, rArg);
break;
case ScConditionMode::EndsWith:
- bValid = rArg.endsWith(aUpVal1);
+ {
+ sal_Int32 nStart = rArg.getLength();
+ const sal_Int32 nLen = aUpVal1.getLength();
+ if (nLen > nStart)
+ bValid = false;
+ else
+ {
+ nStart = nStart - nLen;
+ sal_Int32 nMatch1(0), nMatch2(0);
+ bValid = ScGlobal::GetTransliteration().equals(rArg, nStart, nLen, nMatch1,
+ aUpVal1, 0, nLen, nMatch2);
+ }
+ }
break;
case ScConditionMode::ContainsText:
case ScConditionMode::NotContainsText:
- bValid = rArg.indexOf(aUpVal1) != -1;
+ {
+ const OUString aArgStr(ScGlobal::getCharClass().lowercase(rArg));
+ const OUString aValStr(ScGlobal::getCharClass().lowercase(aUpVal1));
+ bValid = aArgStr.indexOf(aValStr) != -1;
+
if(eOp == ScConditionMode::NotContainsText)
bValid = !bValid;
+ }
break;
default:
{
- sal_Int32 nCompare = ScGlobal::GetCollator()->compareString(
+ sal_Int32 nCompare = ScGlobal::GetCollator().compareString(
rArg, aUpVal1 );
switch ( eOp )
{
@@ -1198,14 +1233,14 @@ bool ScConditionEntry::IsValidStr( const OUString& rArg, const ScAddress& rPos )
break;
case ScConditionMode::Between:
case ScConditionMode::NotBetween:
+ {
+ const sal_Int32 nCompare2 = ScGlobal::GetCollator().compareString(rArg, aUpVal2);
// Test for NOTBETWEEN:
- bValid = ( nCompare < 0 ||
- ScGlobal::GetCollator()->compareString( rArg,
- aUpVal2 ) > 0 );
+ bValid = (nCompare > 0 && nCompare2 > 0) || (nCompare < 0 && nCompare2 < 0);
if ( eOp == ScConditionMode::Between )
bValid = !bValid;
break;
- // ScConditionMode::Direct already handled above
+ }
default:
SAL_WARN("sc", "unknown operation in ScConditionEntry");
bValid = false;
@@ -1455,13 +1490,13 @@ bool ScConditionEntry::NeedsRepaint() const
ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper,
const OUString& rExpr1, const OUString& rExpr2,
ScDocument& rDocument, const ScAddress& rPos,
- const OUString& rStyle,
+ OUString aStyle,
const OUString& rExprNmsp1, const OUString& rExprNmsp2,
FormulaGrammar::Grammar eGrammar1,
FormulaGrammar::Grammar eGrammar2,
ScFormatEntry::Type eType ) :
ScConditionEntry( eOper, rExpr1, rExpr2, rDocument, rPos, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2, eType ),
- aStyleName( rStyle ),
+ aStyleName(std::move( aStyle )),
eCondFormatType( eType )
{
}
@@ -1469,9 +1504,9 @@ ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper,
ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper,
const ScTokenArray* pArr1, const ScTokenArray* pArr2,
ScDocument& rDocument, const ScAddress& rPos,
- const OUString& rStyle ) :
+ OUString aStyle ) :
ScConditionEntry( eOper, pArr1, pArr2, rDocument, rPos ),
- aStyleName( rStyle )
+ aStyleName(std::move( aStyle ))
{
}
@@ -1694,6 +1729,36 @@ void ScCondDateFormatEntry::endRendering()
mpCache.reset();
}
+ScColorFormatCache::ScColorFormatCache(ScDocument& rDoc, const ScRangeList& rRanges) :
+ mrDoc(rDoc)
+{
+ if (mrDoc.IsClipOrUndo())
+ return;
+
+ for (const ScRange& rRange: rRanges)
+ mrDoc.StartListeningArea(rRange, false, this);
+}
+
+ScColorFormatCache::~ScColorFormatCache()
+{
+ if (mrDoc.IsClipOrUndo())
+ return;
+
+ EndListeningAll();
+}
+
+void ScColorFormatCache::Notify(const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::Dying)
+ {
+ EndListeningAll();
+ return;
+ }
+
+ maValues.clear();
+}
+
+
ScConditionalFormat::ScConditionalFormat(sal_uInt32 nNewKey, ScDocument* pDocument) :
pDoc( pDocument ),
nKey( nNewKey )
@@ -1742,6 +1807,7 @@ void ScConditionalFormat::SetRange( const ScRangeList& rRanges )
{
maRanges = rRanges;
SAL_WARN_IF(maRanges.empty(), "sc", "the conditional format range is empty! will result in a crash later!");
+ ResetCache();
}
void ScConditionalFormat::AddEntry( ScFormatEntry* pNew )
@@ -1786,7 +1852,7 @@ const ScFormatEntry* ScConditionalFormat::GetEntry( sal_uInt16 nPos ) const
return nullptr;
}
-const OUString& ScConditionalFormat::GetCellStyle( ScRefCellValue& rCell, const ScAddress& rPos ) const
+OUString ScConditionalFormat::GetCellStyle( ScRefCellValue& rCell, const ScAddress& rPos ) const
{
for (const auto& rxEntry : maEntries)
{
@@ -1805,7 +1871,7 @@ const OUString& ScConditionalFormat::GetCellStyle( ScRefCellValue& rCell, const
}
}
- return EMPTY_OUSTRING;
+ return OUString();
}
ScCondFormatData ScConditionalFormat::GetData( ScRefCellValue& rCell, const ScAddress& rPos ) const
@@ -1885,16 +1951,20 @@ void ScConditionalFormat::UpdateReference( sc::RefUpdateContext& rCxt, bool bCop
rxEntry->UpdateReference(rCxt);
maRanges.UpdateReference(rCxt.meMode, pDoc, rCxt.maRange, rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
}
+
+ ResetCache();
}
void ScConditionalFormat::InsertRow(SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, SCROW nRowPos, SCSIZE nSize)
{
maRanges.InsertRow(nTab, nColStart, nColEnd, nRowPos, nSize);
+ ResetCache();
}
void ScConditionalFormat::InsertCol(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColPos, SCSIZE nSize)
{
maRanges.InsertCol(nTab, nRowStart, nRowEnd, nColPos, nSize);
+ ResetCache();
}
void ScConditionalFormat::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
@@ -1913,6 +1983,8 @@ void ScConditionalFormat::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
rRange.aEnd.IncTab(rCxt.mnSheets);
}
+ ResetCache();
+
for (auto& rxEntry : maEntries)
rxEntry->UpdateInsertTab(rCxt);
}
@@ -1942,6 +2014,8 @@ void ScConditionalFormat::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
rRange.aEnd.IncTab(-1*rCxt.mnSheets);
}
+ ResetCache();
+
for (auto& rxEntry : maEntries)
rxEntry->UpdateDeleteTab(rCxt);
}
@@ -1979,6 +2053,8 @@ void ScConditionalFormat::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt )
}
}
+ ResetCache();
+
for (auto& rxEntry : maEntries)
rxEntry->UpdateMoveTab(rCxt);
}
@@ -1990,6 +2066,7 @@ void ScConditionalFormat::DeleteArea( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCR
SCTAB nTab = maRanges[0].aStart.Tab();
maRanges.DeleteArea( nCol1, nRow1, nTab, nCol2, nRow2, nTab );
+ ResetCache();
}
void ScConditionalFormat::RenameCellStyle(std::u16string_view rOld, const OUString& rNew)
@@ -2036,6 +2113,14 @@ void ScConditionalFormat::endRendering()
}
}
+void ScConditionalFormat::updateValues()
+{
+ for(auto& rxEntry : maEntries)
+ {
+ rxEntry->updateValues();
+ }
+}
+
void ScConditionalFormat::CalcAll()
{
for(const auto& rxEntry : maEntries)
@@ -2049,6 +2134,27 @@ void ScConditionalFormat::CalcAll()
}
}
+void ScConditionalFormat::ResetCache() const
+{
+ if (!maRanges.empty() && pDoc)
+ mpCache = std::make_unique<ScColorFormatCache>(*pDoc, maRanges);
+ else
+ mpCache.reset();
+}
+
+void ScConditionalFormat::SetCache(const std::vector<double>& aValues) const
+{
+ if (!mpCache)
+ ResetCache();
+ if (mpCache)
+ mpCache->maValues = aValues;
+}
+
+std::vector<double>* ScConditionalFormat::GetCache() const
+{
+ return mpCache ? &mpCache->maValues : nullptr;
+}
+
ScConditionalFormatList::ScConditionalFormatList(const ScConditionalFormatList& rList)
{
for(const auto& rxFormat : rList)
@@ -2283,6 +2389,14 @@ void ScConditionalFormatList::endRendering()
}
}
+void ScConditionalFormatList::updateValues()
+{
+ for (auto const& it : m_ConditionalFormats)
+ {
+ it->updateValues();
+ }
+}
+
void ScConditionalFormatList::clear()
{
m_ConditionalFormats.clear();
diff --git a/sc/source/core/data/dbdocutl.cxx b/sc/source/core/data/dbdocutl.cxx
index d2fd0b8db01a..df373d991d17 100644
--- a/sc/source/core/data/dbdocutl.cxx
+++ b/sc/source/core/data/dbdocutl.cxx
@@ -20,6 +20,7 @@
#include <com/sun/star/sdbc/DataType.hpp>
#include <com/sun/star/sdbc/XRow.hpp>
+#include <svl/numformat.hxx>
#include <svl/zforlist.hxx>
#include <dbdocutl.hxx>
@@ -43,7 +44,7 @@ void ScDatabaseDocUtil::PutData(ScDocument& rDoc, SCCOL nCol, SCROW nRow, SCTAB
bool bValue = false;
bool bEmptyFlag = false;
bool bError = false;
- sal_uLong nFormatIndex = 0;
+ sal_uInt32 nFormatIndex = 0;
// wasNull calls only if null value was found?
diff --git a/sc/source/core/data/dociter.cxx b/sc/source/core/data/dociter.cxx
index deb9a8eaa6a1..00309ceb871b 100644
--- a/sc/source/core/data/dociter.cxx
+++ b/sc/source/core/data/dociter.cxx
@@ -17,18 +17,19 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
+#include <svl/numformat.hxx>
#include <svl/zforlist.hxx>
#include <global.hxx>
#include <dociter.hxx>
#include <document.hxx>
+#include <docsh.hxx>
#include <table.hxx>
#include <column.hxx>
#include <formulacell.hxx>
#include <attarray.hxx>
#include <patattr.hxx>
#include <docoptio.hxx>
-#include <cellform.hxx>
#include <segmenttree.hxx>
#include <progress.hxx>
#include <queryparam.hxx>
@@ -38,15 +39,17 @@
#include <cellvalue.hxx>
#include <scmatrix.hxx>
#include <rowheightcontext.hxx>
+#include <queryevaluator.hxx>
#include <o3tl/safeint.hxx>
#include <tools/fract.hxx>
#include <editeng/editobj.hxx>
#include <svl/sharedstring.hxx>
#include <unotools/collatorwrapper.hxx>
-#include <osl/diagnose.h>
+#include <sal/log.hxx>
#include <algorithm>
+#include <limits>
#include <vector>
using ::rtl::math::approxEqual;
@@ -57,26 +60,6 @@ using ::std::set;
// #define debugiter(...) fprintf(stderr, __VA_ARGS__)
#define debugiter(...)
-namespace {
-
-template<typename Iter>
-void incBlock(std::pair<Iter, size_t>& rPos)
-{
- // Move to the next block.
- ++rPos.first;
- rPos.second = 0;
-}
-
-template<typename Iter>
-void decBlock(std::pair<Iter, size_t>& rPos)
-{
- // Move to the last element of the previous block.
- --rPos.first;
- rPos.second = rPos.first->size - 1;
-}
-
-}
-
static void ScAttrArray_IterGetNumberFormat( sal_uInt32& nFormat, const ScAttrArray*& rpArr,
SCROW& nAttrEndRow, const ScAttrArray* pNewArr, SCROW nRow,
const ScDocument& rDoc, const ScInterpreterContext* pContext = nullptr )
@@ -89,19 +72,22 @@ static void ScAttrArray_IterGetNumberFormat( sal_uInt32& nFormat, const ScAttrAr
const ScPatternAttr* pPattern = pNewArr->GetPatternRange( nRowStart, nRowEnd, nRow );
if( !pPattern )
{
- pPattern = rDoc.GetDefPattern();
+ pPattern = &rDoc.getCellAttributeHelper().getDefaultCellAttribute();
nRowEnd = rDoc.MaxRow();
}
- nFormat = pPattern->GetNumberFormat( pContext ? pContext->GetFormatTable() : rDoc.GetFormatTable() );
+ if (pContext)
+ nFormat = pPattern->GetNumberFormat(*pContext);
+ else
+ nFormat = pPattern->GetNumberFormat(rDoc.GetFormatTable());
rpArr = pNewArr;
nAttrEndRow = nRowEnd;
}
-ScValueIterator::ScValueIterator( ScDocument& rDocument, const ScRange& rRange,
+ScValueIterator::ScValueIterator(ScInterpreterContext& rContext, const ScRange& rRange,
SubtotalFlags nSubTotalFlags, bool bTextZero )
- : mrDoc(rDocument)
- , pContext(nullptr)
+ : mrDoc(*rContext.mpDoc)
+ , mrContext(rContext)
, pAttrArray(nullptr)
, nNumFormat(0) // Initialized in GetNumberFormat
, nNumFmtIndex(0)
@@ -113,16 +99,16 @@ ScValueIterator::ScValueIterator( ScDocument& rDocument, const ScRange& rRange,
, mnSubTotalFlags(nSubTotalFlags)
, nNumFmtType(SvNumFormatType::UNDEFINED)
, bNumValid(false)
- , bCalcAsShown(rDocument.GetDocOptions().IsCalcAsShown())
+ , bCalcAsShown((*rContext.mpDoc).GetDocOptions().IsCalcAsShown())
, bTextAsZero(bTextZero)
, mpCells(nullptr)
{
- SCTAB nDocMaxTab = rDocument.GetTableCount() - 1;
+ SCTAB nDocMaxTab = mrDoc.GetTableCount() - 1;
- if (!rDocument.ValidCol(maStartPos.Col())) maStartPos.SetCol(mrDoc.MaxCol());
- if (!rDocument.ValidCol(maEndPos.Col())) maEndPos.SetCol(mrDoc.MaxCol());
- if (!rDocument.ValidRow(maStartPos.Row())) maStartPos.SetRow(mrDoc.MaxRow());
- if (!rDocument.ValidRow(maEndPos.Row())) maEndPos.SetRow(mrDoc.MaxRow());
+ if (!mrDoc.ValidCol(maStartPos.Col())) maStartPos.SetCol(mrDoc.MaxCol());
+ if (!mrDoc.ValidCol(maEndPos.Col())) maEndPos.SetCol(mrDoc.MaxCol());
+ if (!mrDoc.ValidRow(maStartPos.Row())) maStartPos.SetRow(mrDoc.MaxRow());
+ if (!mrDoc.ValidRow(maEndPos.Row())) maEndPos.SetRow(mrDoc.MaxRow());
if (!ValidTab(maStartPos.Tab()) || maStartPos.Tab() > nDocMaxTab) maStartPos.SetTab(nDocMaxTab);
if (!ValidTab(maEndPos.Tab()) || maEndPos.Tab() > nDocMaxTab) maEndPos.SetTab(nDocMaxTab);
}
@@ -170,14 +156,14 @@ bool ScValueIterator::GetThis(double& rValue, FormulaError& rErr)
do
{
++mnCol;
- if (mnCol > maEndPos.Col() || mnCol >= mrDoc.maTabs[mnTab]->GetAllocatedColumnsCount())
+ while (mnCol > maEndPos.Col() || mnCol >= mrDoc.maTabs[mnTab]->GetAllocatedColumnsCount())
{
mnCol = maStartPos.Col();
++mnTab;
if (mnTab > maEndPos.Tab())
{
rErr = FormulaError::NONE;
- return false; // Over and out
+ return false;
}
}
pCol = &(mrDoc.maTabs[mnTab])->aCol[mnCol];
@@ -210,8 +196,8 @@ bool ScValueIterator::GetThis(double& rValue, FormulaError& rErr)
if (bCalcAsShown)
{
ScAttrArray_IterGetNumberFormat(nNumFormat, pAttrArray,
- nAttrEndRow, pCol->pAttrArray.get(), nCurRow, mrDoc, pContext);
- rValue = mrDoc.RoundValueAsShown(rValue, nNumFormat, pContext);
+ nAttrEndRow, pCol->pAttrArray.get(), nCurRow, mrDoc, &mrContext);
+ rValue = mrDoc.RoundValueAsShown(rValue, nNumFormat, &mrContext);
}
return true; // Found it!
}
@@ -268,14 +254,14 @@ bool ScValueIterator::GetThis(double& rValue, FormulaError& rErr)
}
}
-void ScValueIterator::GetCurNumFmtInfo( const ScInterpreterContext& rContext, SvNumFormatType& nType, sal_uInt32& nIndex )
+void ScValueIterator::GetCurNumFmtInfo( SvNumFormatType& nType, sal_uInt32& nIndex )
{
if (!bNumValid && mnTab < mrDoc.GetTableCount())
{
SCROW nCurRow = GetRow();
const ScColumn* pCol = &(mrDoc.maTabs[mnTab])->aCol[mnCol];
- nNumFmtIndex = pCol->GetNumberFormat(rContext, nCurRow);
- nNumFmtType = rContext.GetNumberFormatType( nNumFmtIndex );
+ nNumFmtIndex = pCol->GetNumberFormat(mrContext, nCurRow);
+ nNumFmtType = mrContext.NFGetType(nNumFmtIndex);
bNumValid = true;
}
@@ -288,7 +274,7 @@ bool ScValueIterator::GetFirst(double& rValue, FormulaError& rErr)
mnCol = maStartPos.Col();
mnTab = maStartPos.Tab();
- ScTable* pTab = mrDoc.FetchTable(mnTab);
+ const ScTable* pTab = mrDoc.FetchTable(mnTab);
if (!pTab)
return false;
@@ -342,12 +328,12 @@ bool ScDBQueryDataIterator::IsQueryValid(
ScDocument& rDoc, const ScQueryParam& rParam, SCTAB nTab, SCROW nRow, const ScRefCellValue* pCell)
{
assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT");
- return rDoc.maTabs[nTab]->ValidQuery(nRow, rParam, pCell);
+ ScQueryEvaluator queryEvaluator(rDoc, *rDoc.maTabs[nTab], rParam);
+ return queryEvaluator.ValidQuery(nRow, pCell);
}
ScDBQueryDataIterator::DataAccessInternal::DataAccessInternal(ScDBQueryParamInternal* pParam, ScDocument& rDoc, const ScInterpreterContext& rContext)
- : DataAccess()
- , mpCells(nullptr)
+ : mpCells(nullptr)
, mpParam(pParam)
, mrDoc(rDoc)
, mrContext(rContext)
@@ -417,11 +403,11 @@ bool ScDBQueryDataIterator::DataAccessInternal::getCurrent(Value& rValue)
{
if (!pCell)
aCell = sc::toRefCell(maCurPos.first, maCurPos.second);
- switch (aCell.meType)
+ switch (aCell.getType())
{
case CELLTYPE_VALUE:
{
- rValue.mfValue = aCell.mfValue;
+ rValue.mfValue = aCell.getDouble();
rValue.mbIsNumber = true;
if ( bCalcAsShown )
{
@@ -439,22 +425,22 @@ bool ScDBQueryDataIterator::DataAccessInternal::getCurrent(Value& rValue)
case CELLTYPE_FORMULA:
{
- if (aCell.mpFormula->IsValue())
+ if (aCell.getFormula()->IsValue())
{
- rValue.mfValue = aCell.mpFormula->GetValue();
+ rValue.mfValue = aCell.getFormula()->GetValue();
rValue.mbIsNumber = true;
mrDoc.GetNumberFormatInfo(
mrContext, nNumFmtType, nNumFmtIndex, ScAddress(nCol, nRow, nTab));
- rValue.mnError = aCell.mpFormula->GetErrCode();
+ rValue.mnError = aCell.getFormula()->GetErrCode();
return true; // Found it!
}
else if(mpParam->mbSkipString)
incPos();
else
{
- rValue.maString = aCell.mpFormula->GetString().getString();
+ rValue.maString = aCell.getFormula()->GetString().getString();
rValue.mfValue = 0.0;
- rValue.mnError = aCell.mpFormula->GetErrCode();
+ rValue.mnError = aCell.getFormula()->GetErrCode();
rValue.mbIsNumber = false;
return true;
}
@@ -527,8 +513,7 @@ void ScDBQueryDataIterator::DataAccessInternal::incPos()
}
ScDBQueryDataIterator::DataAccessMatrix::DataAccessMatrix(ScDBQueryParamMatrix* pParam)
- : DataAccess()
- , mpParam(pParam)
+ : mpParam(pParam)
, mnCurRow(0)
{
SCSIZE nC, nR;
@@ -620,8 +605,7 @@ bool ScDBQueryDataIterator::DataAccessMatrix::isValidQuery(SCROW nRow, const ScM
vector<bool> aResults;
aResults.reserve(nEntryCount);
- const CollatorWrapper& rCollator =
- mpParam->bCaseSens ? *ScGlobal::GetCaseCollator() : *ScGlobal::GetCollator();
+ const CollatorWrapper& rCollator = ScGlobal::GetCollator(mpParam->bCaseSens);
for (SCSIZE i = 0; i < nEntryCount; ++i)
{
@@ -641,6 +625,8 @@ bool ScDBQueryDataIterator::DataAccessMatrix::isValidQuery(SCROW nRow, const ScM
break;
default:
// Only the above operators are supported.
+ SAL_WARN("sc.core", "Unsupported operator " << rEntry.eOp
+ << " in ScDBQueryDataIterator::DataAccessMatrix::isValidQuery()");
continue;
}
@@ -745,10 +731,10 @@ bool ScDBQueryDataIterator::DataAccessMatrix::isValidQuery(SCROW nRow, const ScM
return std::find(aResults.begin(), aResults.end(), true) != aResults.end();
}
-ScDBQueryDataIterator::Value::Value() :
- mnError(FormulaError::NONE), mbIsNumber(true)
+ScDBQueryDataIterator::Value::Value()
+ : mfValue(std::numeric_limits<double>::quiet_NaN())
+ , mnError(FormulaError::NONE), mbIsNumber(true)
{
- ::rtl::math::setNan(&mfValue);
}
ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument& rDocument, const ScInterpreterContext& rContext, std::unique_ptr<ScDBQueryParamBase> pParam) :
@@ -818,7 +804,7 @@ sc::FormulaGroupEntry* ScFormulaGroupIterator::next()
return nullptr;
}
ScTable *pTab = mrDoc.FetchTable(mnTab);
- ScColumn *pCol = pTab ? pTab->FetchColumn(mnCol) : nullptr;
+ ScColumn *pCol = (pTab && pTab->IsColValid(mnCol)) ? pTab->FetchColumn(mnCol) : nullptr;
if (pCol)
{
mbNullCol = false;
@@ -925,7 +911,7 @@ bool ScCellIterator::getCurrent()
do
{
maCurPos.IncCol();
- if (maCurPos.Col() >= mrDoc.GetAllocatedColumnsCount(maCurPos.Tab())
+ while (maCurPos.Col() >= mrDoc.GetAllocatedColumnsCount(maCurPos.Tab())
|| maCurPos.Col() > maEndPos.Col())
{
maCurPos.SetCol(maStartPos.Col());
@@ -933,7 +919,7 @@ bool ScCellIterator::getCurrent()
if (maCurPos.Tab() > maEndPos.Tab())
{
maCurCell.clear();
- return false; // Over and out
+ return false;
}
}
pCol = getColumn();
@@ -988,28 +974,23 @@ OUString ScCellIterator::getString() const
ScCellValue ScCellIterator::getCellValue() const
{
- ScCellValue aRet;
- aRet.meType = maCurCell.meType;
-
- switch (maCurCell.meType)
+ switch (maCurCell.getType())
{
case CELLTYPE_STRING:
- aRet.mpString = new svl::SharedString(*maCurCell.mpString);
+ return ScCellValue(maCurCell.getSharedString());
break;
case CELLTYPE_EDIT:
- aRet.mpEditText = maCurCell.mpEditText->Clone().release();
+ return ScCellValue(maCurCell.getEditText()->Clone());
break;
case CELLTYPE_VALUE:
- aRet.mfValue = maCurCell.mfValue;
+ return ScCellValue(maCurCell.getDouble());
break;
case CELLTYPE_FORMULA:
- aRet.mpFormula = maCurCell.mpFormula->Clone();
+ return ScCellValue(maCurCell.getFormula()->Clone());
break;
default:
- ;
+ return ScCellValue();
}
-
- return aRet;
}
bool ScCellIterator::hasString() const
@@ -1046,1027 +1027,6 @@ bool ScCellIterator::next()
return getCurrent();
}
-ScQueryCellIterator::ScQueryCellIterator(ScDocument& rDocument, const ScInterpreterContext& rContext, SCTAB nTable,
- const ScQueryParam& rParam, bool bMod ) :
- maParam(rParam),
- rDoc( rDocument ),
- mrContext( rContext ),
- nTab( nTable),
- nStopOnMismatch( nStopOnMismatchDisabled ),
- nTestEqualCondition( nTestEqualConditionDisabled ),
- bAdvanceQuery( false ),
- bIgnoreMismatchOnLeadingStrings( false )
-{
- nCol = maParam.nCol1;
- nRow = maParam.nRow1;
- SCSIZE i;
- if (!bMod) // Or else it's already inserted
- return;
-
- SCSIZE nCount = maParam.GetEntryCount();
- for (i = 0; (i < nCount) && (maParam.GetEntry(i).bDoQuery); ++i)
- {
- ScQueryEntry& rEntry = maParam.GetEntry(i);
- ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
- sal_uInt32 nIndex = 0;
- bool bNumber = mrContext.GetFormatTable()->IsNumberFormat(
- rItem.maString.getString(), nIndex, rItem.mfVal);
- rItem.meType = bNumber ? ScQueryEntry::ByValue : ScQueryEntry::ByString;
- }
-}
-
-void ScQueryCellIterator::InitPos()
-{
- nRow = maParam.nRow1;
- if (maParam.bHasHeader && maParam.bByRow)
- ++nRow;
- const ScColumn& rCol = rDoc.maTabs[nTab]->CreateColumnIfNotExists(nCol);
- maCurPos = rCol.maCells.position(nRow);
-}
-
-void ScQueryCellIterator::IncPos()
-{
- if (maCurPos.second + 1 < maCurPos.first->size)
- {
- // Move within the same block.
- ++maCurPos.second;
- ++nRow;
- }
- else
- // Move to the next block.
- IncBlock();
-}
-
-void ScQueryCellIterator::IncBlock()
-{
- ++maCurPos.first;
- maCurPos.second = 0;
-
- nRow = maCurPos.first->position;
-}
-
-bool ScQueryCellIterator::GetThis()
-{
- assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT");
- const ScQueryEntry& rEntry = maParam.GetEntry(0);
- const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
-
- SCCOLROW nFirstQueryField = rEntry.nField;
- bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings &&
- rItem.meType != ScQueryEntry::ByString;
- bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
- !maParam.bHasHeader && rItem.meType == ScQueryEntry::ByString &&
- ((maParam.bByRow && nRow == maParam.nRow1) ||
- (!maParam.bByRow && nCol == maParam.nCol1));
-
- ScColumn* pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
- while (true)
- {
- bool bNextColumn = maCurPos.first == pCol->maCells.end();
- if (!bNextColumn)
- {
- if (nRow > maParam.nRow2)
- bNextColumn = true;
- }
-
- if (bNextColumn)
- {
- do
- {
- ++nCol;
- if (nCol > maParam.nCol2 || nCol >= rDoc.maTabs[nTab]->GetAllocatedColumnsCount())
- return false; // Over and out
- if ( bAdvanceQuery )
- {
- AdvanceQueryParamEntryField();
- nFirstQueryField = rEntry.nField;
- }
- pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
- }
- while (!rItem.mbMatchEmpty && pCol->IsEmptyData());
-
- InitPos();
-
- bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
- !maParam.bHasHeader && rItem.meType == ScQueryEntry::ByString &&
- maParam.bByRow;
- }
-
- if (maCurPos.first->type == sc::element_type_empty)
- {
- if (rItem.mbMatchEmpty && rEntry.GetQueryItems().size() == 1)
- {
- // This shortcut, instead of determining if any SC_OR query
- // exists or this query is SC_AND'ed (which wouldn't make
- // sense, but..) and evaluating them in ValidQuery(), is
- // possible only because the interpreter is the only caller
- // that sets mbMatchEmpty and there is only one item in those
- // cases.
- // XXX this would have to be reworked if other filters used it
- // in different manners and evaluation would have to be done in
- // ValidQuery().
- return true;
- }
- else
- {
- IncBlock();
- continue;
- }
- }
-
- ScRefCellValue aCell = sc::toRefCell(maCurPos.first, maCurPos.second);
-
- if (bAllStringIgnore && aCell.hasString())
- IncPos();
- else
- {
- bool bTestEqualCondition = false;
- if ( rDoc.maTabs[nTab]->ValidQuery( nRow, maParam,
- (nCol == static_cast<SCCOL>(nFirstQueryField) ? &aCell : nullptr),
- (nTestEqualCondition ? &bTestEqualCondition : nullptr),
- &mrContext) )
- {
- if ( nTestEqualCondition && bTestEqualCondition )
- nTestEqualCondition |= nTestEqualConditionMatched;
- return !aCell.isEmpty(); // Found it!
- }
- else if ( nStopOnMismatch )
- {
- // Yes, even a mismatch may have a fulfilled equal
- // condition if regular expressions were involved and
- // SC_LESS_EQUAL or SC_GREATER_EQUAL were queried.
- if ( nTestEqualCondition && bTestEqualCondition )
- {
- nTestEqualCondition |= nTestEqualConditionMatched;
- nStopOnMismatch |= nStopOnMismatchOccurred;
- return false;
- }
- bool bStop;
- if (bFirstStringIgnore)
- {
- if (aCell.hasString())
- {
- IncPos();
- bStop = false;
- }
- else
- bStop = true;
- }
- else
- bStop = true;
- if (bStop)
- {
- nStopOnMismatch |= nStopOnMismatchOccurred;
- return false;
- }
- }
- else
- IncPos();
- }
- bFirstStringIgnore = false;
- }
-}
-
-bool ScQueryCellIterator::GetFirst()
-{
- assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT");
- nCol = maParam.nCol1;
- InitPos();
- return GetThis();
-}
-
-bool ScQueryCellIterator::GetNext()
-{
- IncPos();
- if ( nStopOnMismatch )
- nStopOnMismatch = nStopOnMismatchEnabled;
- if ( nTestEqualCondition )
- nTestEqualCondition = nTestEqualConditionEnabled;
- return GetThis();
-}
-
-void ScQueryCellIterator::AdvanceQueryParamEntryField()
-{
- SCSIZE nEntries = maParam.GetEntryCount();
- for ( SCSIZE j = 0; j < nEntries; j++ )
- {
- ScQueryEntry& rEntry = maParam.GetEntry( j );
- if ( rEntry.bDoQuery )
- {
- if ( rEntry.nField < rDoc.MaxCol() )
- rEntry.nField++;
- else
- {
- assert(!"AdvanceQueryParamEntryField: ++rEntry.nField > MAXCOL");
- }
- }
- else
- break; // for
- }
-}
-
-bool ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL& nFoundCol,
- SCROW& nFoundRow )
-{
- // Set and automatically reset mpParam->mbRangeLookup when returning. We
- // could use comphelper::FlagRestorationGuard, but really, that one is
- // overengineered for this simple purpose here.
- struct BoolResetter
- {
- bool& mr;
- bool mb;
- BoolResetter( bool& r, bool b ) : mr(r), mb(r) { r = b; }
- ~BoolResetter() { mr = mb; }
- } aRangeLookupResetter( maParam.mbRangeLookup, true);
-
- nFoundCol = rDoc.MaxCol()+1;
- nFoundRow = rDoc.MaxRow()+1;
- SetStopOnMismatch( true ); // assume sorted keys
- SetTestEqualCondition( true );
- bIgnoreMismatchOnLeadingStrings = true;
- bool bLiteral = maParam.eSearchType == utl::SearchParam::SearchType::Normal &&
- maParam.GetEntry(0).GetQueryItem().meType == ScQueryEntry::ByString;
- bool bBinary = maParam.bByRow &&
- (bLiteral || maParam.GetEntry(0).GetQueryItem().meType == ScQueryEntry::ByValue) &&
- (maParam.GetEntry(0).eOp == SC_LESS_EQUAL || maParam.GetEntry(0).eOp == SC_GREATER_EQUAL);
- bool bFound = false;
- if (bBinary)
- {
- if (BinarySearch())
- {
- // BinarySearch() already positions correctly and only needs real
- // query comparisons afterwards, skip the verification check below.
- maParam.mbRangeLookup = false;
- bFound = GetThis();
- }
- }
- else
- {
- bFound = GetFirst();
- }
- if (bFound)
- {
- // First equal entry or last smaller than (greater than) entry.
- PositionType aPosSave;
- bool bNext = false;
- do
- {
- nFoundCol = GetCol();
- nFoundRow = GetRow();
- aPosSave = maCurPos;
- if (IsEqualConditionFulfilled())
- break;
- bNext = GetNext();
- }
- while (bNext);
-
- // There may be no pNext but equal condition fulfilled if regular
- // expressions are involved. Keep the found entry and proceed.
- if (!bNext && !IsEqualConditionFulfilled())
- {
- // Step back to last in range and adjust position markers for
- // GetNumberFormat() or similar.
- SCCOL nColDiff = nCol - nFoundCol;
- nCol = nFoundCol;
- nRow = nFoundRow;
- maCurPos = aPosSave;
- if (maParam.mbRangeLookup)
- {
- // Verify that the found entry does not only fulfill the range
- // lookup but also the real query, i.e. not numeric was found
- // if query is ByString and vice versa.
- maParam.mbRangeLookup = false;
- // Step back the last field advance if GetNext() did one.
- if (bAdvanceQuery && nColDiff)
- {
- SCSIZE nEntries = maParam.GetEntryCount();
- for (SCSIZE j=0; j < nEntries; ++j)
- {
- ScQueryEntry& rEntry = maParam.GetEntry( j );
- if (rEntry.bDoQuery)
- {
- if (rEntry.nField - nColDiff >= 0)
- rEntry.nField -= nColDiff;
- else
- {
- assert(!"FindEqualOrSortedLastInRange: rEntry.nField -= nColDiff < 0");
- }
- }
- else
- break; // for
- }
- }
- // Check it.
- if (!GetThis())
- {
- nFoundCol = rDoc.MaxCol()+1;
- nFoundRow = rDoc.MaxRow()+1;
- }
- }
- }
- }
- if ( IsEqualConditionFulfilled() )
- {
- // Position on last equal entry.
- SCSIZE nEntries = maParam.GetEntryCount();
- for ( SCSIZE j = 0; j < nEntries; j++ )
- {
- ScQueryEntry& rEntry = maParam.GetEntry( j );
- if ( rEntry.bDoQuery )
- {
- switch ( rEntry.eOp )
- {
- case SC_LESS_EQUAL :
- case SC_GREATER_EQUAL :
- rEntry.eOp = SC_EQUAL;
- break;
- default:
- {
- // added to avoid warnings
- }
- }
- }
- else
- break; // for
- }
- PositionType aPosSave;
- bIgnoreMismatchOnLeadingStrings = false;
- SetTestEqualCondition( false );
- do
- {
- nFoundCol = GetCol();
- nFoundRow = GetRow();
- aPosSave = maCurPos;
- } while (GetNext());
-
- // Step back conditions are the same as above
- nCol = nFoundCol;
- nRow = nFoundRow;
- maCurPos = aPosSave;
- return true;
- }
- if ( (maParam.eSearchType != utl::SearchParam::SearchType::Normal) &&
- StoppedOnMismatch() )
- {
- // Assume found entry to be the last value less than respectively
- // greater than the query. But keep on searching for an equal match.
- SCSIZE nEntries = maParam.GetEntryCount();
- for ( SCSIZE j = 0; j < nEntries; j++ )
- {
- ScQueryEntry& rEntry = maParam.GetEntry( j );
- if ( rEntry.bDoQuery )
- {
- switch ( rEntry.eOp )
- {
- case SC_LESS_EQUAL :
- case SC_GREATER_EQUAL :
- rEntry.eOp = SC_EQUAL;
- break;
- default:
- {
- // added to avoid warnings
- }
- }
- }
- else
- break; // for
- }
- SetStopOnMismatch( false );
- SetTestEqualCondition( false );
- if (GetNext())
- {
- // Last of a consecutive area, avoid searching the entire parameter
- // range as it is a real performance bottleneck in case of regular
- // expressions.
- PositionType aPosSave;
- do
- {
- nFoundCol = GetCol();
- nFoundRow = GetRow();
- aPosSave = maCurPos;
- SetStopOnMismatch( true );
- } while (GetNext());
- nCol = nFoundCol;
- nRow = nFoundRow;
- maCurPos = aPosSave;
- }
- }
- return (nFoundCol <= rDoc.MaxCol()) && (nFoundRow <= rDoc.MaxRow());
-}
-
-ScCountIfCellIterator::ScCountIfCellIterator(ScDocument& rDocument, const ScInterpreterContext& rContext, SCTAB nTable,
- const ScQueryParam& rParam ) :
- maParam(rParam),
- rDoc( rDocument ),
- mrContext( rContext ),
- nTab( nTable)
-{
- maParam.nCol1 = rDoc.maTabs[nTable]->ClampToAllocatedColumns(maParam.nCol1);
- maParam.nCol2 = rDoc.maTabs[nTable]->ClampToAllocatedColumns(maParam.nCol2);
- nCol = maParam.nCol1;
- nRow = maParam.nRow1;
-}
-
-void ScCountIfCellIterator::InitPos()
-{
- nRow = maParam.nRow1;
- if (maParam.bHasHeader && maParam.bByRow)
- ++nRow;
- ScColumn* pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
- maCurPos = pCol->maCells.position(nRow);
-}
-
-void ScCountIfCellIterator::IncPos()
-{
- if (maCurPos.second + 1 < maCurPos.first->size)
- {
- // Move within the same block.
- ++maCurPos.second;
- ++nRow;
- }
- else
- // Move to the next block.
- IncBlock();
-}
-
-void ScCountIfCellIterator::IncBlock()
-{
- ++maCurPos.first;
- maCurPos.second = 0;
-
- nRow = maCurPos.first->position;
-}
-
-int ScCountIfCellIterator::GetCount()
-{
- assert(nTab < rDoc.GetTableCount() && "try to access index out of bounds, FIX IT");
- nCol = maParam.nCol1;
- InitPos();
-
- const ScQueryEntry& rEntry = maParam.GetEntry(0);
- const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
- const bool bSingleQueryItem = rEntry.GetQueryItems().size() == 1;
- int count = 0;
-
- ScColumn* pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
- while (true)
- {
- bool bNextColumn = maCurPos.first == pCol->maCells.end();
- if (!bNextColumn)
- {
- if (nRow > maParam.nRow2)
- bNextColumn = true;
- }
-
- if (bNextColumn)
- {
- do
- {
- ++nCol;
- if (nCol > maParam.nCol2 || nCol >= rDoc.maTabs[nTab]->GetAllocatedColumnsCount())
- return count; // Over and out
- AdvanceQueryParamEntryField();
- pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
- }
- while (!rItem.mbMatchEmpty && pCol->IsEmptyData());
-
- InitPos();
- }
-
- if (maCurPos.first->type == sc::element_type_empty)
- {
- if (rItem.mbMatchEmpty && bSingleQueryItem)
- {
- // This shortcut, instead of determining if any SC_OR query
- // exists or this query is SC_AND'ed (which wouldn't make
- // sense, but..) and evaluating them in ValidQuery(), is
- // possible only because the interpreter is the only caller
- // that sets mbMatchEmpty and there is only one item in those
- // cases.
- // XXX this would have to be reworked if other filters used it
- // in different manners and evaluation would have to be done in
- // ValidQuery().
- count++;
- IncPos();
- continue;
- }
- else
- {
- IncBlock();
- continue;
- }
- }
-
- ScRefCellValue aCell = sc::toRefCell(maCurPos.first, maCurPos.second);
-
- if ( rDoc.maTabs[nTab]->ValidQuery( nRow, maParam,
- (nCol == static_cast<SCCOL>(rEntry.nField) ? &aCell : nullptr),
- nullptr,
- &mrContext) )
- {
- if (aCell.isEmpty())
- return count;
- count++;
- IncPos();
- continue;
- }
- else
- IncPos();
- }
- return count;
-}
-
-void ScCountIfCellIterator::AdvanceQueryParamEntryField()
-{
- SCSIZE nEntries = maParam.GetEntryCount();
- for ( SCSIZE j = 0; j < nEntries; j++ )
- {
- ScQueryEntry& rEntry = maParam.GetEntry( j );
- if ( rEntry.bDoQuery )
- {
- if ( rEntry.nField < rDoc.MaxCol() )
- rEntry.nField++;
- else
- {
- OSL_FAIL( "AdvanceQueryParamEntryField: ++rEntry.nField > MAXCOL" );
- }
- }
- else
- break; // for
- }
-}
-
-namespace {
-
-/**
- * This class sequentially indexes non-empty cells in order, from the top of
- * the block where the start row position is, to the bottom of the block
- * where the end row position is. It skips all empty blocks that may be
- * present in between.
- *
- * The index value is an offset from the first element of the first block
- * disregarding all empty cell blocks.
- */
-class NonEmptyCellIndexer
-{
- typedef std::map<size_t, sc::CellStoreType::const_iterator> BlockMapType;
-
- BlockMapType maBlockMap;
-
- const sc::CellStoreType& mrCells;
-
- size_t mnLowIndex;
- size_t mnHighIndex;
-
- bool mbValid;
-
-public:
-
- typedef std::pair<ScRefCellValue, SCROW> CellType;
-
- /**
- * @param rCells cell storage container
- * @param nStartRow logical start row position
- * @param nEndRow logical end row position, inclusive.
- * @param bSkipTopStrBlock when true, skip all leading string cells.
- */
- NonEmptyCellIndexer(
- const sc::CellStoreType& rCells, SCROW nStartRow, SCROW nEndRow, bool bSkipTopStrBlock ) :
- mrCells(rCells), mnLowIndex(0), mnHighIndex(0), mbValid(true)
- {
- if (nEndRow < nStartRow)
- {
- mbValid = false;
- return;
- }
-
- // Find the low position.
-
- sc::CellStoreType::const_position_type aLoPos = mrCells.position(nStartRow);
- if (aLoPos.first->type == sc::element_type_empty)
- incBlock(aLoPos);
-
- if (aLoPos.first == rCells.end())
- {
- mbValid = false;
- return;
- }
-
- if (bSkipTopStrBlock)
- {
- // Skip all leading string or empty blocks.
- while (aLoPos.first->type == sc::element_type_string ||
- aLoPos.first->type == sc::element_type_edittext ||
- aLoPos.first->type == sc::element_type_empty)
- {
- incBlock(aLoPos);
- if (aLoPos.first == rCells.end())
- {
- mbValid = false;
- return;
- }
- }
- }
-
- SCROW nFirstRow = aLoPos.first->position;
- SCROW nLastRow = aLoPos.first->position + aLoPos.first->size - 1;
-
- if (nFirstRow > nEndRow)
- {
- // Both start and end row positions are within the leading skipped
- // blocks.
- mbValid = false;
- return;
- }
-
- // Calculate the index of the low position.
- if (nFirstRow < nStartRow)
- mnLowIndex = nStartRow - nFirstRow;
- else
- {
- // Start row is within the skipped block(s). Set it to the first
- // element of the low block.
- mnLowIndex = 0;
- }
-
- if (nEndRow < nLastRow)
- {
- assert(nEndRow >= nFirstRow);
- mnHighIndex = nEndRow - nFirstRow;
-
- maBlockMap.emplace(aLoPos.first->size, aLoPos.first);
- return;
- }
-
- // Find the high position.
-
- sc::CellStoreType::const_position_type aHiPos = mrCells.position(aLoPos.first, nEndRow);
- if (aHiPos.first->type == sc::element_type_empty)
- {
- // Move to the last position of the previous block.
- decBlock(aHiPos);
-
- // Check the row position of the end of the previous block, and make sure it's valid.
- SCROW nBlockEndRow = aHiPos.first->position + aHiPos.first->size - 1;
- if (nBlockEndRow < nStartRow)
- {
- mbValid = false;
- return;
- }
- }
-
- // Tag the start and end blocks, and all blocks in between in order
- // but skip all empty blocks.
-
- size_t nPos = 0;
- sc::CellStoreType::const_iterator itBlk = aLoPos.first;
- while (itBlk != aHiPos.first)
- {
- if (itBlk->type == sc::element_type_empty)
- {
- ++itBlk;
- continue;
- }
-
- nPos += itBlk->size;
- maBlockMap.emplace(nPos, itBlk);
- ++itBlk;
-
- if (itBlk->type == sc::element_type_empty)
- ++itBlk;
-
- assert(itBlk != mrCells.end());
- }
-
- assert(itBlk == aHiPos.first);
- nPos += itBlk->size;
- maBlockMap.emplace(nPos, itBlk);
-
- // Calculate the high index.
- BlockMapType::const_reverse_iterator ri = maBlockMap.rbegin();
- mnHighIndex = ri->first;
- mnHighIndex -= ri->second->size;
- mnHighIndex += aHiPos.second;
- }
-
- sc::CellStoreType::const_position_type getPosition( size_t nIndex ) const
- {
- assert(mbValid);
- assert(mnLowIndex <= nIndex);
- assert(nIndex <= mnHighIndex);
-
- sc::CellStoreType::const_position_type aRet(mrCells.end(), 0);
-
- BlockMapType::const_iterator it = maBlockMap.upper_bound(nIndex);
- if (it == maBlockMap.end())
- return aRet;
-
- sc::CellStoreType::const_iterator itBlk = it->second;
- size_t nBlkIndex = it->first - itBlk->size; // index of the first element of the block.
- assert(nBlkIndex <= nIndex);
- assert(nIndex < it->first);
-
- size_t nOffset = nIndex - nBlkIndex;
- aRet.first = itBlk;
- aRet.second = nOffset;
- return aRet;
- }
-
- CellType getCell( size_t nIndex ) const
- {
- std::pair<ScRefCellValue, SCROW> aRet;
- aRet.second = -1;
-
- sc::CellStoreType::const_position_type aPos = getPosition(nIndex);
- if (aPos.first == mrCells.end())
- return aRet;
-
- aRet.first = sc::toRefCell(aPos.first, aPos.second);
- aRet.second = aPos.first->position + aPos.second;
- return aRet;
- }
-
- size_t getLowIndex() const { return mnLowIndex; }
-
- size_t getHighIndex() const { return mnHighIndex; }
-
- bool isValid() const { return mbValid; }
-};
-
-}
-
-bool ScQueryCellIterator::BinarySearch()
-{
- // TODO: This will be extremely slow with mdds::multi_type_vector.
-
- assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT");
- nCol = maParam.nCol1;
-
- if (nCol >= rDoc.maTabs[nTab]->GetAllocatedColumnsCount())
- return false;
-
- ScColumn* pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
- if (pCol->IsEmptyData())
- return false;
-
- CollatorWrapper* pCollator = (maParam.bCaseSens ? ScGlobal::GetCaseCollator() :
- ScGlobal::GetCollator());
- SvNumberFormatter& rFormatter = *(mrContext.GetFormatTable());
- const ScQueryEntry& rEntry = maParam.GetEntry(0);
- const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
- bool bLessEqual = rEntry.eOp == SC_LESS_EQUAL;
- bool bByString = rItem.meType == ScQueryEntry::ByString;
- bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings && !bByString;
- bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
- !maParam.bHasHeader && bByString;
-
- nRow = maParam.nRow1;
- if (maParam.bHasHeader)
- ++nRow;
-
- ScRefCellValue aCell;
- if (bFirstStringIgnore)
- {
- sc::CellStoreType::const_position_type aPos = pCol->maCells.position(nRow);
- if (aPos.first->type == sc::element_type_string || aPos.first->type == sc::element_type_edittext)
- {
- aCell = sc::toRefCell(aPos.first, aPos.second);
- sal_uInt32 nFormat = pCol->GetNumberFormat(mrContext, nRow);
- OUString aCellStr;
- ScCellFormat::GetInputString(aCell, nFormat, aCellStr, rFormatter, rDoc);
- sal_Int32 nTmp = pCollator->compareString(aCellStr, rEntry.GetQueryItem().maString.getString());
- if ((rEntry.eOp == SC_LESS_EQUAL && nTmp > 0) ||
- (rEntry.eOp == SC_GREATER_EQUAL && nTmp < 0) ||
- (rEntry.eOp == SC_EQUAL && nTmp != 0))
- ++nRow;
- }
- }
-
- NonEmptyCellIndexer aIndexer(pCol->maCells, nRow, maParam.nRow2, bAllStringIgnore);
- if (!aIndexer.isValid())
- return false;
-
- size_t nLo = aIndexer.getLowIndex();
- size_t nHi = aIndexer.getHighIndex();
- NonEmptyCellIndexer::CellType aCellData;
-
- // Bookkeeping values for breaking up the binary search in case the data
- // range isn't strictly sorted.
- size_t nLastInRange = nLo;
- size_t nFirstLastInRange = nLastInRange;
- double fLastInRangeValue = bLessEqual ?
- -(::std::numeric_limits<double>::max()) :
- ::std::numeric_limits<double>::max();
- OUString aLastInRangeString;
- if (!bLessEqual)
- aLastInRangeString = OUString(u'\xFFFF');
-
- aCellData = aIndexer.getCell(nLastInRange);
- aCell = aCellData.first;
- if (aCell.hasString())
- {
- sal_uInt32 nFormat = pCol->GetNumberFormat(mrContext, aCellData.second);
- OUString aStr;
- ScCellFormat::GetInputString(aCell, nFormat, aStr, rFormatter, rDoc);
- aLastInRangeString = aStr;
- }
- else
- {
- switch (aCell.meType)
- {
- case CELLTYPE_VALUE :
- fLastInRangeValue = aCell.mfValue;
- break;
- case CELLTYPE_FORMULA :
- fLastInRangeValue = aCell.mpFormula->GetValue();
- break;
- default:
- {
- // added to avoid warnings
- }
- }
- }
-
- sal_Int32 nRes = 0;
- bool bFound = false;
- bool bDone = false;
- while (nLo <= nHi && !bDone)
- {
- size_t nMid = (nLo+nHi)/2;
- size_t i = nMid;
-
- aCellData = aIndexer.getCell(i);
- aCell = aCellData.first;
- bool bStr = aCell.hasString();
- nRes = 0;
-
- // compares are content<query:-1, content>query:1
- // Cell value comparison similar to ScTable::ValidQuery()
- if (!bStr && !bByString)
- {
- double nCellVal;
- switch (aCell.meType)
- {
- case CELLTYPE_VALUE :
- case CELLTYPE_FORMULA :
- nCellVal = aCell.getValue();
- break;
- default:
- nCellVal = 0.0;
- }
- if ((nCellVal < rItem.mfVal) && !::rtl::math::approxEqual(
- nCellVal, rItem.mfVal))
- {
- nRes = -1;
- if (bLessEqual)
- {
- if (fLastInRangeValue < nCellVal)
- {
- fLastInRangeValue = nCellVal;
- nLastInRange = i;
- }
- else if (fLastInRangeValue > nCellVal)
- {
- // not strictly sorted, continue with GetThis()
- nLastInRange = nFirstLastInRange;
- bDone = true;
- }
- }
- }
- else if ((nCellVal > rItem.mfVal) && !::rtl::math::approxEqual(
- nCellVal, rItem.mfVal))
- {
- nRes = 1;
- if (!bLessEqual)
- {
- if (fLastInRangeValue > nCellVal)
- {
- fLastInRangeValue = nCellVal;
- nLastInRange = i;
- }
- else if (fLastInRangeValue < nCellVal)
- {
- // not strictly sorted, continue with GetThis()
- nLastInRange = nFirstLastInRange;
- bDone = true;
- }
- }
- }
- }
- else if (bStr && bByString)
- {
- OUString aCellStr;
- sal_uInt32 nFormat = pCol->GetNumberFormat(mrContext, aCellData.second);
- ScCellFormat::GetInputString(aCell, nFormat, aCellStr, rFormatter, rDoc);
-
- nRes = pCollator->compareString(aCellStr, rEntry.GetQueryItem().maString.getString());
- if (nRes < 0 && bLessEqual)
- {
- sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
- aCellStr);
- if (nTmp < 0)
- {
- aLastInRangeString = aCellStr;
- nLastInRange = i;
- }
- else if (nTmp > 0)
- {
- // not strictly sorted, continue with GetThis()
- nLastInRange = nFirstLastInRange;
- bDone = true;
- }
- }
- else if (nRes > 0 && !bLessEqual)
- {
- sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
- aCellStr);
- if (nTmp > 0)
- {
- aLastInRangeString = aCellStr;
- nLastInRange = i;
- }
- else if (nTmp < 0)
- {
- // not strictly sorted, continue with GetThis()
- nLastInRange = nFirstLastInRange;
- bDone = true;
- }
- }
- }
- else if (!bStr && bByString)
- {
- nRes = -1; // numeric < string
- if (bLessEqual)
- nLastInRange = i;
- }
- else // if (bStr && !bByString)
- {
- nRes = 1; // string > numeric
- if (!bLessEqual)
- nLastInRange = i;
- }
- if (nRes < 0)
- {
- if (bLessEqual)
- nLo = nMid + 1;
- else // assumed to be SC_GREATER_EQUAL
- {
- if (nMid > 0)
- nHi = nMid - 1;
- else
- bDone = true;
- }
- }
- else if (nRes > 0)
- {
- if (bLessEqual)
- {
- if (nMid > 0)
- nHi = nMid - 1;
- else
- bDone = true;
- }
- else // assumed to be SC_GREATER_EQUAL
- nLo = nMid + 1;
- }
- else
- {
- nLo = i;
- bDone = bFound = true;
- }
- }
-
- if (!bFound)
- {
- // If all hits didn't result in a moving limit there's something
- // strange, e.g. data range not properly sorted, or only identical
- // values encountered, which doesn't mean there aren't any others in
- // between... leave it to GetThis(). The condition for this would be
- // if (nLastInRange == nFirstLastInRange) nLo = nFirstLastInRange;
- // Else, in case no exact match was found, we step back for a
- // subsequent GetThis() to find the last in range. Effectively this is
- // --nLo with nLastInRange == nLo-1. Both conditions combined yield:
- nLo = nLastInRange;
- }
-
- aCellData = aIndexer.getCell(nLo);
- if (nLo <= nHi && aCellData.second <= maParam.nRow2)
- {
- nRow = aCellData.second;
- maCurPos = aIndexer.getPosition(nLo);
- return true;
- }
- else
- {
- nRow = maParam.nRow2 + 1;
- // Set current position to the last possible row.
- maCurPos.first = pCol->maCells.end();
- --maCurPos.first;
- maCurPos.second = maCurPos.first->size - 1;
- return false;
- }
-}
-
ScHorizontalCellIterator::ScHorizontalCellIterator(ScDocument& rDocument, SCTAB nTable,
SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
rDoc( rDocument ),
@@ -2081,7 +1041,11 @@ ScHorizontalCellIterator::ScHorizontalCellIterator(ScDocument& rDocument, SCTAB
{
assert(mnTab < rDoc.GetTableCount() && "index out of bounds, FIX IT");
- nEndCol = rDoc.maTabs[mnTab]->ClampToAllocatedColumns(nEndCol);
+ const ScTable* pTab = rDoc.FetchTable(mnTab);
+ if (!pTab)
+ return;
+
+ nEndCol = pTab->ClampToAllocatedColumns(nEndCol);
if (nEndCol < nStartCol) // E.g., somewhere completely outside allocated area
nEndCol = nStartCol - 1; // Empty
@@ -2348,11 +1312,11 @@ bool ScHorizontalValueIterator::GetNext( double& rValue, FormulaError& rErr )
else
return false;
}
- switch (pCell->meType)
+ switch (pCell->getType())
{
case CELLTYPE_VALUE:
{
- rValue = pCell->mfValue;
+ rValue = pCell->getDouble();
rErr = FormulaError::NONE;
if ( bCalcAsShown )
{
@@ -2366,10 +1330,10 @@ bool ScHorizontalValueIterator::GetNext( double& rValue, FormulaError& rErr )
break;
case CELLTYPE_FORMULA:
{
- rErr = pCell->mpFormula->GetErrCode();
- if (rErr != FormulaError::NONE || pCell->mpFormula->IsValue())
+ rErr = pCell->getFormula()->GetErrCode();
+ if (rErr != FormulaError::NONE || pCell->getFormula()->IsValue())
{
- rValue = pCell->mpFormula->GetValue();
+ rValue = pCell->getFormula()->GetValue();
bFound = true;
}
}
@@ -2395,11 +1359,8 @@ ScHorizontalAttrIterator::ScHorizontalAttrIterator( ScDocument& rDocument, SCTAB
assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT");
assert(rDoc.maTabs[nTab]);
- nEndCol = rDoc.maTabs[nTab]->ClampToAllocatedColumns(nEndCol);
-
nRow = nStartRow;
nCol = nStartCol;
- bRowEmpty = false;
pIndices.reset( new SCSIZE[nEndCol-nStartCol+1] );
pNextEnd.reset( new SCROW[nEndCol-nStartCol+1] );
@@ -2415,7 +1376,6 @@ ScHorizontalAttrIterator::~ScHorizontalAttrIterator()
void ScHorizontalAttrIterator::InitForNextRow(bool bInitialization)
{
- bool bEmpty = true;
nMinNextEnd = rDoc.MaxRow();
SCCOL nThisHead = 0;
@@ -2424,14 +1384,13 @@ void ScHorizontalAttrIterator::InitForNextRow(bool bInitialization)
SCCOL nPos = i - nStartCol;
if ( bInitialization || pNextEnd[nPos] < nRow )
{
- const ScAttrArray* pArray = rDoc.maTabs[nTab]->aCol[i].pAttrArray.get();
- assert(pArray);
+ const ScAttrArray& pArray = rDoc.maTabs[nTab]->GetColumnData(i).AttrArray();
SCSIZE nIndex;
if (bInitialization)
{
- if ( pArray->Count() )
- pArray->Search( nStartRow, nIndex );
+ if ( pArray.Count() )
+ pArray.Search( nStartRow, nIndex );
else
nIndex = 0;
pIndices[nPos] = nIndex;
@@ -2440,22 +1399,16 @@ void ScHorizontalAttrIterator::InitForNextRow(bool bInitialization)
else
nIndex = ++pIndices[nPos];
- if ( !nIndex && !pArray->Count() )
+ if ( !nIndex && !pArray.Count() )
{
pNextEnd[nPos] = rDoc.MaxRow();
assert( pNextEnd[nPos] >= nRow && "Sequence out of order" );
- ppPatterns[nPos] = nullptr;
+ ppPatterns[nPos] = &rDoc.getCellAttributeHelper().getDefaultCellAttribute();
}
- else if ( nIndex < pArray->Count() )
+ else if ( nIndex < pArray.Count() )
{
- const ScPatternAttr* pPattern = pArray->mvData[nIndex].pPattern;
- SCROW nThisEnd = pArray->mvData[nIndex].nEndRow;
-
- if ( IsDefaultItem( pPattern ) )
- pPattern = nullptr;
- else
- bEmpty = false; // Found attributes
-
+ const ScPatternAttr* pPattern = pArray.mvData[nIndex].getScPatternAttr();
+ SCROW nThisEnd = pArray.mvData[nIndex].nEndRow;
pNextEnd[nPos] = nThisEnd;
assert( pNextEnd[nPos] >= nRow && "Sequence out of order" );
ppPatterns[nPos] = pPattern;
@@ -2467,38 +1420,19 @@ void ScHorizontalAttrIterator::InitForNextRow(bool bInitialization)
ppPatterns[nPos] = nullptr;
}
}
- else if ( ppPatterns[nPos] )
- bEmpty = false; // Area not at the end yet
if ( nMinNextEnd > pNextEnd[nPos] )
nMinNextEnd = pNextEnd[nPos];
// store positions of ScHorizontalAttrIterator elements (minimizing expensive ScPatternAttr comparisons)
- if (i > nStartCol && ppPatterns[nThisHead] != ppPatterns[nPos])
+ if (i > nStartCol && !ScPatternAttr::areSame(ppPatterns[nThisHead], ppPatterns[nPos]))
{
pHorizEnd[nThisHead] = i - 1;
nThisHead = nPos; // start position of the next horizontal group
}
}
- if (bEmpty)
- nRow = nMinNextEnd; // Skip until end of next section
- else
- pHorizEnd[nThisHead] = nEndCol; // set the end position of the last horizontal group, too
- bRowEmpty = bEmpty;
-}
-
-bool ScHorizontalAttrIterator::InitForNextAttr()
-{
- if ( !ppPatterns[nCol-nStartCol] ) // Skip default items
- {
- assert( pHorizEnd[nCol-nStartCol] < rDoc.MaxCol()+1 && "missing stored data" );
- nCol = pHorizEnd[nCol-nStartCol] + 1;
- if ( nCol > nEndCol )
- return false;
- }
-
- return true;
+ pHorizEnd[nThisHead] = nEndCol; // set the end position of the last horizontal group, too
}
const ScPatternAttr* ScHorizontalAttrIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2, SCROW& rRow )
@@ -2506,7 +1440,7 @@ const ScPatternAttr* ScHorizontalAttrIterator::GetNext( SCCOL& rCol1, SCCOL& rCo
assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT");
for (;;)
{
- if ( !bRowEmpty && nCol <= nEndCol && InitForNextAttr() )
+ if ( nCol <= nEndCol )
{
const ScPatternAttr* pPat = ppPatterns[nCol-nStartCol];
rRow = nRow;
@@ -2524,7 +1458,7 @@ const ScPatternAttr* ScHorizontalAttrIterator::GetNext( SCCOL& rCol1, SCCOL& rCo
return nullptr; // Found nothing
nCol = nStartCol; // Start at the left again
- if ( bRowEmpty || nRow > nMinNextEnd )
+ if ( nRow > nMinNextEnd )
InitForNextRow(false);
}
}
@@ -2645,23 +1579,15 @@ ScDocAttrIterator::ScDocAttrIterator(ScDocument& rDocument, SCTAB nTable,
nEndRow( nRow2 ),
nCol( nCol1 )
{
- if ( ValidTab(nTab) && nTab < rDoc.GetTableCount() && rDoc.maTabs[nTab]
- && nCol < rDoc.maTabs[nTab]->GetAllocatedColumnsCount())
- {
- nEndCol = rDoc.maTabs[nTab]->ClampToAllocatedColumns(nEndCol);
- pColIter = rDoc.maTabs[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
- }
-}
-
-ScDocAttrIterator::~ScDocAttrIterator()
-{
+ if ( ValidTab(nTab) && nTab < rDoc.GetTableCount() && rDoc.maTabs[nTab] )
+ moColIter = rDoc.maTabs[nTab]->GetColumnData(nCol).CreateAttrIterator( nStartRow, nEndRow );
}
const ScPatternAttr* ScDocAttrIterator::GetNext( SCCOL& rCol, SCROW& rRow1, SCROW& rRow2 )
{
- while ( pColIter )
+ while ( moColIter )
{
- const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
+ const ScPatternAttr* pPattern = moColIter->Next( rRow1, rRow2 );
if ( pPattern )
{
rCol = nCol;
@@ -2670,9 +1596,9 @@ const ScPatternAttr* ScDocAttrIterator::GetNext( SCCOL& rCol, SCROW& rRow1, SCRO
++nCol;
if ( nCol <= nEndCol )
- pColIter = rDoc.maTabs[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
+ moColIter = rDoc.maTabs[nTab]->GetColumnData(nCol).CreateAttrIterator( nStartRow, nEndRow );
else
- pColIter.reset();
+ moColIter.reset();
}
return nullptr; // Nothing anymore
}
@@ -2687,16 +1613,16 @@ ScDocRowHeightUpdater::ScDocRowHeightUpdater(ScDocument& rDoc, OutputDevice* pOu
{
}
-void ScDocRowHeightUpdater::update()
+void ScDocRowHeightUpdater::update(const bool bOnlyUsedRows)
{
if (!mpTabRangesArray || mpTabRangesArray->empty())
{
// No ranges defined. Update all rows in all tables.
- updateAll();
+ updateAll(bOnlyUsedRows);
return;
}
- sal_uLong nCellCount = 0;
+ sal_uInt64 nCellCount = 0;
for (const auto& rTabRanges : *mpTabRangesArray)
{
const SCTAB nTab = rTabRanges.mnTab;
@@ -2717,7 +1643,7 @@ void ScDocRowHeightUpdater::update()
ScProgress aProgress(mrDoc.GetDocumentShell(), ScResId(STR_PROGRESS_HEIGHTING), nCellCount, true);
Fraction aZoom(1, 1);
- sal_uLong nProgressStart = 0;
+ sal_uInt64 nProgressStart = 0;
for (const auto& rTabRanges : *mpTabRangesArray)
{
const SCTAB nTab = rTabRanges.mnTab;
@@ -2740,9 +1666,9 @@ void ScDocRowHeightUpdater::update()
}
}
-void ScDocRowHeightUpdater::updateAll()
+void ScDocRowHeightUpdater::updateAll(const bool bOnlyUsedRows)
{
- sal_uInt32 nCellCount = 0;
+ sal_uInt64 nCellCount = 0;
for (SCTAB nTab = 0; nTab < mrDoc.GetTableCount(); ++nTab)
{
if (!ValidTab(nTab) || !mrDoc.maTabs[nTab])
@@ -2754,14 +1680,17 @@ void ScDocRowHeightUpdater::updateAll()
ScProgress aProgress(mrDoc.GetDocumentShell(), ScResId(STR_PROGRESS_HEIGHTING), nCellCount, true);
Fraction aZoom(1, 1);
- sc::RowHeightContext aCxt(mrDoc.MaxRow(), mfPPTX, mfPPTY, aZoom, aZoom, mpOutDev);
- sal_uLong nProgressStart = 0;
+ sal_uInt64 nProgressStart = 0;
for (SCTAB nTab = 0; nTab < mrDoc.GetTableCount(); ++nTab)
{
if (!ValidTab(nTab) || !mrDoc.maTabs[nTab])
continue;
- mrDoc.maTabs[nTab]->SetOptimalHeight(aCxt, 0, mrDoc.MaxRow(), true, &aProgress, nProgressStart);
+ sc::RowHeightContext aCxt(mrDoc.MaxRow(), mfPPTX, mfPPTY, aZoom, aZoom, mpOutDev);
+ SCCOL nEndCol = 0;
+ SCROW nEndRow = mrDoc.MaxRow();
+ if (!bOnlyUsedRows || mrDoc.GetPrintArea(nTab, nEndCol, nEndRow))
+ mrDoc.maTabs[nTab]->SetOptimalHeight(aCxt, 0, nEndRow, true, &aProgress, nProgressStart);
nProgressStart += mrDoc.maTabs[nTab]->GetWeightedCount();
}
}
@@ -2777,39 +1706,31 @@ ScAttrRectIterator::ScAttrRectIterator(ScDocument& rDocument, SCTAB nTable,
nIterStartCol( nCol1 ),
nIterEndCol( nCol1 )
{
- if ( ValidTab(nTab) && nTab < rDoc.GetTableCount() && rDoc.maTabs[nTab]
- && nCol1 < rDoc.maTabs[nTab]->GetAllocatedColumnsCount())
+ if ( ValidTab(nTab) && nTab < rDoc.GetTableCount() && rDoc.maTabs[nTab] )
{
- nEndCol = rDoc.maTabs[nTab]->ClampToAllocatedColumns(nEndCol);
- pColIter = rDoc.maTabs[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
+ moColIter = rDoc.maTabs[nTab]->GetColumnData(nIterStartCol).CreateAttrIterator( nStartRow, nEndRow );
while ( nIterEndCol < nEndCol &&
- rDoc.maTabs[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
- rDoc.maTabs[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
+ rDoc.maTabs[nTab]->GetColumnData(nIterEndCol).IsAllAttrEqual(
+ rDoc.maTabs[nTab]->GetColumnData(nIterEndCol+1), nStartRow, nEndRow ) )
++nIterEndCol;
}
- else
- pColIter = nullptr;
-}
-
-ScAttrRectIterator::~ScAttrRectIterator()
-{
}
void ScAttrRectIterator::DataChanged()
{
- if (pColIter)
+ if (moColIter)
{
- SCROW nNextRow = pColIter->GetNextRow();
- pColIter = rDoc.maTabs[nTab]->aCol[nIterStartCol].CreateAttrIterator( nNextRow, nEndRow );
+ SCROW nNextRow = moColIter->GetNextRow();
+ moColIter = rDoc.maTabs[nTab]->GetColumnData(nIterStartCol).CreateAttrIterator( nNextRow, nEndRow );
}
}
const ScPatternAttr* ScAttrRectIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2,
SCROW& rRow1, SCROW& rRow2 )
{
- while ( pColIter )
+ while ( moColIter )
{
- const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
+ const ScPatternAttr* pPattern = moColIter->Next( rRow1, rRow2 );
if ( pPattern )
{
rCol1 = nIterStartCol;
@@ -2821,14 +1742,14 @@ const ScPatternAttr* ScAttrRectIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2,
if ( nIterStartCol <= nEndCol )
{
nIterEndCol = nIterStartCol;
- pColIter = rDoc.maTabs[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
+ moColIter = rDoc.maTabs[nTab]->GetColumnData(nIterStartCol).CreateAttrIterator( nStartRow, nEndRow );
while ( nIterEndCol < nEndCol &&
- rDoc.maTabs[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
- rDoc.maTabs[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
+ rDoc.maTabs[nTab]->GetColumnData(nIterEndCol).IsAllAttrEqual(
+ rDoc.maTabs[nTab]->GetColumnData(nIterEndCol+1), nStartRow, nEndRow ) )
++nIterEndCol;
}
else
- pColIter.reset();
+ moColIter.reset();
}
return nullptr; // Nothing anymore
}
diff --git a/sc/source/core/data/docpool.cxx b/sc/source/core/data/docpool.cxx
index 628c3686e2d0..5ef4c4a4091f 100644
--- a/sc/source/core/data/docpool.cxx
+++ b/sc/source/core/data/docpool.cxx
@@ -19,8 +19,6 @@
#include <sal/config.h>
-#include <utility>
-
#include <scitems.hxx>
#include <comphelper/string.hxx>
@@ -67,7 +65,6 @@
#include <docpool.hxx>
#include <global.hxx>
#include <attrib.hxx>
-#include <patattr.hxx>
#include <globstr.hrc>
#include <scresid.hxx>
#include <scmod.hxx>
@@ -88,297 +85,192 @@ SvxFontItem* getDefaultFontItem(LanguageType eLang, DefaultFontType nFontType, s
}
-SfxItemInfo const aItemInfos[] =
-{
- { SID_ATTR_CHAR_FONT, true }, // ATTR_FONT
- { SID_ATTR_CHAR_FONTHEIGHT, true }, // ATTR_FONT_HEIGHT
- { SID_ATTR_CHAR_WEIGHT, true }, // ATTR_FONT_WEIGHT
- { SID_ATTR_CHAR_POSTURE, true }, // ATTR_FONT_POSTURE
- { SID_ATTR_CHAR_UNDERLINE, true }, // ATTR_FONT_UNDERLINE
- { SID_ATTR_CHAR_OVERLINE, true }, // ATTR_FONT_OVERLINE
- { SID_ATTR_CHAR_STRIKEOUT, true }, // ATTR_FONT_CROSSEDOUT
- { SID_ATTR_CHAR_CONTOUR, true }, // ATTR_FONT_CONTOUR
- { SID_ATTR_CHAR_SHADOWED, true }, // ATTR_FONT_SHADOWED
- { SID_ATTR_CHAR_COLOR, true }, // ATTR_FONT_COLOR
- { SID_ATTR_CHAR_LANGUAGE, true }, // ATTR_FONT_LANGUAGE
- { SID_ATTR_CHAR_CJK_FONT, true }, // ATTR_CJK_FONT from 614
- { SID_ATTR_CHAR_CJK_FONTHEIGHT, true }, // ATTR_CJK_FONT_HEIGHT from 614
- { SID_ATTR_CHAR_CJK_WEIGHT, true }, // ATTR_CJK_FONT_WEIGHT from 614
- { SID_ATTR_CHAR_CJK_POSTURE, true }, // ATTR_CJK_FONT_POSTURE from 614
- { SID_ATTR_CHAR_CJK_LANGUAGE, true }, // ATTR_CJK_FONT_LANGUAGE from 614
- { SID_ATTR_CHAR_CTL_FONT, true }, // ATTR_CTL_FONT from 614
- { SID_ATTR_CHAR_CTL_FONTHEIGHT, true }, // ATTR_CTL_FONT_HEIGHT from 614
- { SID_ATTR_CHAR_CTL_WEIGHT, true }, // ATTR_CTL_FONT_WEIGHT from 614
- { SID_ATTR_CHAR_CTL_POSTURE, true }, // ATTR_CTL_FONT_POSTURE from 614
- { SID_ATTR_CHAR_CTL_LANGUAGE, true }, // ATTR_CTL_FONT_LANGUAGE from 614
- { SID_ATTR_CHAR_EMPHASISMARK, true }, // ATTR_FONT_EMPHASISMARK from 614
- { 0, true }, // ATTR_USERDEF from 614 / 641c
- { SID_ATTR_CHAR_WORDLINEMODE, true }, // ATTR_FONT_WORDLINE from 632b
- { SID_ATTR_CHAR_RELIEF, true }, // ATTR_FONT_RELIEF from 632b
- { SID_ATTR_ALIGN_HYPHENATION, true }, // ATTR_HYPHENATE from 632b
- { 0, true }, // ATTR_SCRIPTSPACE from 614d
- { 0, true }, // ATTR_HANGPUNCTUATION from 614d
- { SID_ATTR_PARA_FORBIDDEN_RULES,true }, // ATTR_FORBIDDEN_RULES from 614d
- { SID_ATTR_ALIGN_HOR_JUSTIFY, true }, // ATTR_HOR_JUSTIFY
- { SID_ATTR_ALIGN_HOR_JUSTIFY_METHOD, true }, // ATTR_HOR_JUSTIFY_METHOD
- { SID_ATTR_ALIGN_INDENT, true }, // ATTR_INDENT from 350
- { SID_ATTR_ALIGN_VER_JUSTIFY, true }, // ATTR_VER_JUSTIFY
- { SID_ATTR_ALIGN_VER_JUSTIFY_METHOD, true }, // ATTR_VER_JUSTIFY_METHOD
- { SID_ATTR_ALIGN_STACKED, true }, // ATTR_STACKED from 680/dr14 (replaces ATTR_ORIENTATION)
- { SID_ATTR_ALIGN_DEGREES, true }, // ATTR_ROTATE_VALUE from 367
- { SID_ATTR_ALIGN_LOCKPOS, true }, // ATTR_ROTATE_MODE from 367
- { SID_ATTR_ALIGN_ASIANVERTICAL, true }, // ATTR_VERTICAL_ASIAN from 642
- { SID_ATTR_FRAMEDIRECTION, true }, // ATTR_WRITINGDIR from 643
- { SID_ATTR_ALIGN_LINEBREAK, true }, // ATTR_LINEBREAK
- { SID_ATTR_ALIGN_SHRINKTOFIT, true }, // ATTR_SHRINKTOFIT from 680/dr14
- { SID_ATTR_BORDER_DIAG_TLBR, true }, // ATTR_BORDER_TLBR from 680/dr14
- { SID_ATTR_BORDER_DIAG_BLTR, true }, // ATTR_BORDER_BLTR from 680/dr14
- { SID_ATTR_ALIGN_MARGIN, true }, // ATTR_MARGIN
- { 0, true }, // ATTR_MERGE
- { 0, true }, // ATTR_MERGE_FLAG
- { SID_ATTR_NUMBERFORMAT_VALUE, true }, // ATTR_VALUE_FORMAT
- { ATTR_LANGUAGE_FORMAT, true }, // ATTR_LANGUAGE_FORMAT from 329, is combined with SID_ATTR_NUMBERFORMAT_VALUE in the dialog
- { SID_ATTR_BRUSH, true }, // ATTR_BACKGROUND
- { SID_SCATTR_PROTECTION, true }, // ATTR_PROTECTION
- { SID_ATTR_BORDER_OUTER, true }, // ATTR_BORDER
- { SID_ATTR_BORDER_INNER, true }, // ATTR_BORDER_INNER
- { SID_ATTR_BORDER_SHADOW, true }, // ATTR_SHADOW
- { 0, true }, // ATTR_VALIDDATA
- { 0, true }, // ATTR_CONDITIONAL
- { 0, true }, // ATTR_HYPERLINK
- { 0, true }, // ATTR_PATTERN
- { SID_ATTR_LRSPACE, true }, // ATTR_LRSPACE
- { SID_ATTR_ULSPACE, true }, // ATTR_ULSPACE
- { SID_ATTR_PAGE, true }, // ATTR_PAGE
- { SID_ATTR_PAGE_PAPERBIN, true }, // ATTR_PAGE_PAPERBIN
- { SID_ATTR_PAGE_SIZE, true }, // ATTR_PAGE_SIZE
- { SID_ATTR_PAGE_EXT1, true }, // ATTR_PAGE_HORCENTER
- { SID_ATTR_PAGE_EXT2, true }, // ATTR_PAGE_VERCENTER
- { SID_ATTR_PAGE_ON, true }, // ATTR_PAGE_ON
- { SID_ATTR_PAGE_DYNAMIC, true }, // ATTR_PAGE_DYNAMIC
- { SID_ATTR_PAGE_SHARED, true }, // ATTR_PAGE_SHARED
- { SID_SCATTR_PAGE_NOTES, true }, // ATTR_PAGE_NOTES
- { SID_SCATTR_PAGE_GRID, true }, // ATTR_PAGE_GRID
- { SID_SCATTR_PAGE_HEADERS, true }, // ATTR_PAGE_HEADERS
- { SID_SCATTR_PAGE_CHARTS, true }, // ATTR_PAGE_CHARTS
- { SID_SCATTR_PAGE_OBJECTS, true }, // ATTR_PAGE_OBJECTS
- { SID_SCATTR_PAGE_DRAWINGS, true }, // ATTR_PAGE_DRAWINGS
- { SID_SCATTR_PAGE_TOPDOWN, true }, // ATTR_PAGE_TOPDOWN
- { SID_SCATTR_PAGE_SCALE, true }, // ATTR_PAGE_SCALE
- { SID_SCATTR_PAGE_SCALETOPAGES, true }, // ATTR_PAGE_SCALETOPAGES
- { SID_SCATTR_PAGE_FIRSTPAGENO, true }, // ATTR_PAGE_FIRSTPAGENO
- { SID_SCATTR_PAGE_HEADERLEFT, true }, // ATTR_PAGE_HEADERLEFT
- { SID_SCATTR_PAGE_FOOTERLEFT, true }, // ATTR_PAGE_FOOTERLEFT
- { SID_SCATTR_PAGE_HEADERRIGHT, true }, // ATTR_PAGE_HEADERRIGHT
- { SID_SCATTR_PAGE_FOOTERRIGHT, true }, // ATTR_PAGE_FOOTERRIGHT
- { SID_ATTR_PAGE_HEADERSET, true }, // ATTR_PAGE_HEADERSET
- { SID_ATTR_PAGE_FOOTERSET, true }, // ATTR_PAGE_FOOTERSET
- { SID_SCATTR_PAGE_FORMULAS, true }, // ATTR_PAGE_FORMULAS
- { SID_SCATTR_PAGE_NULLVALS, true }, // ATTR_PAGE_NULLVALS
- { SID_SCATTR_PAGE_SCALETO, true }, // ATTR_PAGE_SCALETO
- { 0, true } // ATTR_HIDDEN
-};
-static_assert(
- SAL_N_ELEMENTS(aItemInfos) == ATTR_ENDINDEX - ATTR_STARTINDEX + 1, "these must match");
-
-ScDocumentPool::ScDocumentPool()
-
- : SfxItemPool ( "ScDocumentPool",
- ATTR_STARTINDEX, ATTR_ENDINDEX,
- aItemInfos, nullptr ),
- mvPoolDefaults(ATTR_ENDINDEX-ATTR_STARTINDEX+1),
- mnCurrentMaxKey(0)
+static ItemInfoPackage& getItemInfoPackageScDocument()
{
+ class ItemInfoPackageScDocument : public ItemInfoPackage
+ {
+ typedef std::array<ItemInfoStatic, ATTR_ENDINDEX - ATTR_STARTINDEX + 1> ItemInfoArrayScDocument;
+ ItemInfoArrayScDocument maItemInfos {{
+ // m_nWhich, m_pItem, m_nSlotID, m_nItemInfoFlags
+ { ATTR_FONT, nullptr, SID_ATTR_CHAR_FONT, SFX_ITEMINFOFLAG_SUPPORT_SURROGATE },
+ { ATTR_FONT_HEIGHT, new SvxFontHeightItem( 200, 100, ATTR_FONT_HEIGHT ), SID_ATTR_CHAR_FONTHEIGHT, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_FONT_WEIGHT, new SvxWeightItem( WEIGHT_NORMAL, ATTR_FONT_WEIGHT ), SID_ATTR_CHAR_WEIGHT, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_FONT_POSTURE, new SvxPostureItem( ITALIC_NONE, ATTR_FONT_POSTURE ), SID_ATTR_CHAR_POSTURE, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_FONT_UNDERLINE, new SvxUnderlineItem( LINESTYLE_NONE, ATTR_FONT_UNDERLINE ), SID_ATTR_CHAR_UNDERLINE, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_FONT_OVERLINE, new SvxOverlineItem( LINESTYLE_NONE, ATTR_FONT_OVERLINE ), SID_ATTR_CHAR_OVERLINE, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_FONT_CROSSEDOUT, new SvxCrossedOutItem( STRIKEOUT_NONE, ATTR_FONT_CROSSEDOUT ), SID_ATTR_CHAR_STRIKEOUT, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_FONT_CONTOUR, new SvxContourItem( false, ATTR_FONT_CONTOUR ), SID_ATTR_CHAR_CONTOUR, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_FONT_SHADOWED, new SvxShadowedItem( false, ATTR_FONT_SHADOWED ), SID_ATTR_CHAR_SHADOWED, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_FONT_COLOR, new SvxColorItem( COL_AUTO, ATTR_FONT_COLOR ), SID_ATTR_CHAR_COLOR, SFX_ITEMINFOFLAG_SUPPORT_SURROGATE },
+ { ATTR_FONT_LANGUAGE, new SvxLanguageItem( LANGUAGE_DONTKNOW, ATTR_FONT_LANGUAGE ), SID_ATTR_CHAR_LANGUAGE, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_CJK_FONT, nullptr, SID_ATTR_CHAR_CJK_FONT, SFX_ITEMINFOFLAG_SUPPORT_SURROGATE },
+ { ATTR_CJK_FONT_HEIGHT, new SvxFontHeightItem( 200, 100, ATTR_CJK_FONT_HEIGHT ), SID_ATTR_CHAR_CJK_FONTHEIGHT, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_CJK_FONT_WEIGHT, new SvxWeightItem( WEIGHT_NORMAL, ATTR_CJK_FONT_WEIGHT ), SID_ATTR_CHAR_CJK_WEIGHT, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_CJK_FONT_POSTURE, new SvxPostureItem( ITALIC_NONE, ATTR_CJK_FONT_POSTURE ), SID_ATTR_CHAR_CJK_POSTURE, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_CJK_FONT_LANGUAGE, new SvxLanguageItem( LANGUAGE_DONTKNOW, ATTR_CJK_FONT_LANGUAGE ), SID_ATTR_CHAR_CJK_LANGUAGE, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_CTL_FONT, nullptr, SID_ATTR_CHAR_CTL_FONT, SFX_ITEMINFOFLAG_SUPPORT_SURROGATE },
+ { ATTR_CTL_FONT_HEIGHT, new SvxFontHeightItem( 200, 100, ATTR_CTL_FONT_HEIGHT ), SID_ATTR_CHAR_CTL_FONTHEIGHT, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_CTL_FONT_WEIGHT, new SvxWeightItem( WEIGHT_NORMAL, ATTR_CTL_FONT_WEIGHT ), SID_ATTR_CHAR_CTL_WEIGHT, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_CTL_FONT_POSTURE, new SvxPostureItem( ITALIC_NONE, ATTR_CTL_FONT_POSTURE ), SID_ATTR_CHAR_CTL_POSTURE, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_CTL_FONT_LANGUAGE, new SvxLanguageItem( LANGUAGE_DONTKNOW, ATTR_CTL_FONT_LANGUAGE ), SID_ATTR_CHAR_CTL_LANGUAGE, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_FONT_EMPHASISMARK, new SvxEmphasisMarkItem( FontEmphasisMark::NONE, ATTR_FONT_EMPHASISMARK ), SID_ATTR_CHAR_EMPHASISMARK, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_USERDEF, new SvXMLAttrContainerItem( ATTR_USERDEF ), 0, SFX_ITEMINFOFLAG_SUPPORT_SURROGATE },
+ { ATTR_FONT_WORDLINE, new SvxWordLineModeItem(false, ATTR_FONT_WORDLINE ), SID_ATTR_CHAR_WORDLINEMODE, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_FONT_RELIEF, new SvxCharReliefItem( FontRelief::NONE, ATTR_FONT_RELIEF ), SID_ATTR_CHAR_RELIEF, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_HYPHENATE, new ScHyphenateCell(), SID_ATTR_ALIGN_HYPHENATION, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_SCRIPTSPACE, new SvxScriptSpaceItem( false, ATTR_SCRIPTSPACE), 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_HANGPUNCTUATION, new SvxHangingPunctuationItem( false, ATTR_HANGPUNCTUATION), 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_FORBIDDEN_RULES, new SvxForbiddenRuleItem( false, ATTR_FORBIDDEN_RULES), SID_ATTR_PARA_FORBIDDEN_RULES, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_HOR_JUSTIFY, new SvxHorJustifyItem( SvxCellHorJustify::Standard, ATTR_HOR_JUSTIFY), SID_ATTR_ALIGN_HOR_JUSTIFY, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_HOR_JUSTIFY_METHOD, new SvxJustifyMethodItem( SvxCellJustifyMethod::Auto, ATTR_HOR_JUSTIFY_METHOD), SID_ATTR_ALIGN_HOR_JUSTIFY_METHOD, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_INDENT, new ScIndentItem( 0 ), SID_ATTR_ALIGN_INDENT, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_VER_JUSTIFY, new SvxVerJustifyItem( SvxCellVerJustify::Standard, ATTR_VER_JUSTIFY), SID_ATTR_ALIGN_VER_JUSTIFY, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_VER_JUSTIFY_METHOD, new SvxJustifyMethodItem( SvxCellJustifyMethod::Auto, ATTR_VER_JUSTIFY_METHOD), SID_ATTR_ALIGN_VER_JUSTIFY_METHOD, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_STACKED, new ScVerticalStackCell(false), SID_ATTR_ALIGN_STACKED, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_ROTATE_VALUE, new ScRotateValueItem( 0_deg100 ), SID_ATTR_ALIGN_DEGREES, SFX_ITEMINFOFLAG_SUPPORT_SURROGATE },
+ { ATTR_ROTATE_MODE, new SvxRotateModeItem( SVX_ROTATE_MODE_BOTTOM, ATTR_ROTATE_MODE ), SID_ATTR_ALIGN_LOCKPOS, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_VERTICAL_ASIAN, new SfxBoolItem( ATTR_VERTICAL_ASIAN ), SID_ATTR_ALIGN_ASIANVERTICAL, SFX_ITEMINFOFLAG_NONE },
+
+ // The default for the ATTR_WRITINGDIR cell attribute must by SvxFrameDirection::Environment,
+ // so that value is returned when asking for a default cell's attributes.
+ // The value from the page style is set as DefaultHorizontalTextDirection for the EditEngine.
+ { ATTR_WRITINGDIR, new SvxFrameDirectionItem( SvxFrameDirection::Environment, ATTR_WRITINGDIR ), SID_ATTR_FRAMEDIRECTION, SFX_ITEMINFOFLAG_NONE },
+
+ { ATTR_LINEBREAK, new ScLineBreakCell(), SID_ATTR_ALIGN_LINEBREAK, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_SHRINKTOFIT, new ScShrinkToFitCell(), SID_ATTR_ALIGN_SHRINKTOFIT, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_BORDER_TLBR, new SvxLineItem( ATTR_BORDER_TLBR ), SID_ATTR_BORDER_DIAG_TLBR, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_BORDER_BLTR, new SvxLineItem( ATTR_BORDER_BLTR ), SID_ATTR_BORDER_DIAG_BLTR, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_MARGIN, new SvxMarginItem( ATTR_MARGIN ), SID_ATTR_ALIGN_MARGIN, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_MERGE, new ScMergeAttr, 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_MERGE_FLAG, new ScMergeFlagAttr, 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_VALUE_FORMAT, new SfxUInt32Item( ATTR_VALUE_FORMAT, 0 ), SID_ATTR_NUMBERFORMAT_VALUE, SFX_ITEMINFOFLAG_SUPPORT_SURROGATE },
+ { ATTR_LANGUAGE_FORMAT, new SvxLanguageItem( ScGlobal::eLnge, ATTR_LANGUAGE_FORMAT ), 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_BACKGROUND, new SvxBrushItem( COL_TRANSPARENT, ATTR_BACKGROUND ), SID_ATTR_BRUSH, SFX_ITEMINFOFLAG_SUPPORT_SURROGATE },
+ { ATTR_PROTECTION, new ScProtectionAttr, SID_SCATTR_PROTECTION, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_BORDER, new SvxBoxItem( ATTR_BORDER ), SID_ATTR_BORDER_OUTER, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_BORDER_INNER,nullptr, SID_ATTR_BORDER_INNER, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_SHADOW, new SvxShadowItem( ATTR_SHADOW ), SID_ATTR_BORDER_SHADOW, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_VALIDDATA, new SfxUInt32Item( ATTR_VALIDDATA, 0 ), 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_CONDITIONAL, new ScCondFormatItem, 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_HYPERLINK, new SfxStringItem( ATTR_HYPERLINK, OUString() ) , 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_LRSPACE, new SvxLRSpaceItem( ATTR_LRSPACE ), SID_ATTR_LRSPACE, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_ULSPACE, new SvxULSpaceItem( ATTR_ULSPACE ), SID_ATTR_ULSPACE, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE, new SvxPageItem( ATTR_PAGE ), SID_ATTR_PAGE, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_PAPERBIN, new SvxPaperBinItem( ATTR_PAGE_PAPERBIN ), SID_ATTR_PAGE_PAPERBIN, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_SIZE, new SvxSizeItem( ATTR_PAGE_SIZE ), SID_ATTR_PAGE_SIZE, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_HORCENTER, new SfxBoolItem( ATTR_PAGE_HORCENTER ), SID_ATTR_PAGE_EXT1, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_VERCENTER, new SfxBoolItem( ATTR_PAGE_VERCENTER ), SID_ATTR_PAGE_EXT2, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_ON, new SfxBoolItem( ATTR_PAGE_ON, true ), SID_ATTR_PAGE_ON, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_DYNAMIC, new SfxBoolItem( ATTR_PAGE_DYNAMIC, true ), SID_ATTR_PAGE_DYNAMIC, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_SHARED, new SfxBoolItem( ATTR_PAGE_SHARED, true ), SID_ATTR_PAGE_SHARED, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_SHARED_FIRST, new SfxBoolItem( ATTR_PAGE_SHARED_FIRST, true ), SID_ATTR_PAGE_SHARED_FIRST, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_NOTES, new SfxBoolItem( ATTR_PAGE_NOTES, false ), 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_GRID, new SfxBoolItem( ATTR_PAGE_GRID, false ), 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_HEADERS, new SfxBoolItem( ATTR_PAGE_HEADERS, false ), 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_CHARTS, new ScViewObjectModeItem( ATTR_PAGE_CHARTS ), 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_OBJECTS, new ScViewObjectModeItem( ATTR_PAGE_OBJECTS ), 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_DRAWINGS, new ScViewObjectModeItem( ATTR_PAGE_DRAWINGS ), 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_TOPDOWN, new SfxBoolItem( ATTR_PAGE_TOPDOWN, true ), 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_SCALE, new SfxUInt16Item( ATTR_PAGE_SCALE, 100 ), 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_SCALETOPAGES, new SfxUInt16Item( ATTR_PAGE_SCALETOPAGES, 1 ), 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_FIRSTPAGENO, new SfxUInt16Item( ATTR_PAGE_FIRSTPAGENO, 1 ), 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_HEADERLEFT, new ScPageHFItem( ATTR_PAGE_HEADERLEFT ), 0, SFX_ITEMINFOFLAG_SUPPORT_SURROGATE },
+ { ATTR_PAGE_FOOTERLEFT, new ScPageHFItem( ATTR_PAGE_FOOTERLEFT ), 0, SFX_ITEMINFOFLAG_SUPPORT_SURROGATE },
+ { ATTR_PAGE_HEADERRIGHT, new ScPageHFItem( ATTR_PAGE_HEADERRIGHT ), 0, SFX_ITEMINFOFLAG_SUPPORT_SURROGATE },
+ { ATTR_PAGE_FOOTERRIGHT, new ScPageHFItem( ATTR_PAGE_FOOTERRIGHT ), 0, SFX_ITEMINFOFLAG_SUPPORT_SURROGATE },
+ { ATTR_PAGE_HEADERFIRST, new ScPageHFItem( ATTR_PAGE_HEADERFIRST ), 0, SFX_ITEMINFOFLAG_SUPPORT_SURROGATE },
+ { ATTR_PAGE_FOOTERFIRST, new ScPageHFItem( ATTR_PAGE_FOOTERFIRST ), 0, SFX_ITEMINFOFLAG_SUPPORT_SURROGATE },
+ { ATTR_PAGE_HEADERSET, nullptr, SID_ATTR_PAGE_HEADERSET, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_FOOTERSET, nullptr, SID_ATTR_PAGE_FOOTERSET, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_FORMULAS, new SfxBoolItem( ATTR_PAGE_FORMULAS, false ), 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_NULLVALS, new SfxBoolItem( ATTR_PAGE_NULLVALS, true ), 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_PAGE_SCALETO, new ScPageScaleToItem( 1, 1 ), 0, SFX_ITEMINFOFLAG_NONE },
+ { ATTR_HIDDEN, new SfxBoolItem( ATTR_HIDDEN, false ), 0, SFX_ITEMINFOFLAG_NONE }
+ }};
+
+ virtual const ItemInfoStatic& getItemInfoStatic(size_t nIndex) const override { return maItemInfos[nIndex]; }
+
+ public:
+ ItemInfoPackageScDocument()
+ {
+ LanguageType nDefLang, nCjkLang, nCtlLang;
+ ScModule::GetSpellSettings( nDefLang, nCjkLang, nCtlLang );
+
+ // latin font from GetDefaultFonts is not used, DEFAULTFONT_LATIN_SPREADSHEET instead
+ SvxFontItem* pStdFont = getDefaultFontItem(nDefLang, DefaultFontType::LATIN_SPREADSHEET, ATTR_FONT);
+ SvxFontItem* pCjkFont = getDefaultFontItem(nCjkLang, DefaultFontType::CJK_SPREADSHEET, ATTR_CJK_FONT);
+ SvxFontItem* pCtlFont = getDefaultFontItem(nCtlLang, DefaultFontType::CTL_SPREADSHEET, ATTR_CTL_FONT);
+ setItemAtItemInfoStatic(pStdFont, maItemInfos[ATTR_FONT - ATTR_STARTINDEX]);
+ setItemAtItemInfoStatic(pCjkFont, maItemInfos[ATTR_CJK_FONT - ATTR_STARTINDEX]);
+ setItemAtItemInfoStatic(pCtlFont, maItemInfos[ATTR_CTL_FONT - ATTR_STARTINDEX]);
+
+ SvxBoxInfoItem* pGlobalBorderInnerAttr = new SvxBoxInfoItem( ATTR_BORDER_INNER );
+ pGlobalBorderInnerAttr->SetLine(nullptr, SvxBoxInfoItemLine::HORI);
+ pGlobalBorderInnerAttr->SetLine(nullptr, SvxBoxInfoItemLine::VERT);
+ pGlobalBorderInnerAttr->SetTable(true);
+ pGlobalBorderInnerAttr->SetDist(true);
+ pGlobalBorderInnerAttr->SetMinDist(false);
+ setItemAtItemInfoStatic(pGlobalBorderInnerAttr, maItemInfos[ATTR_BORDER_INNER - ATTR_STARTINDEX]);
+ }
+ virtual size_t size() const override { return maItemInfos.size(); }
+ virtual const ItemInfo& getItemInfo(size_t nIndex, SfxItemPool& rPool) override
+ {
+ const ItemInfo& rRetval(maItemInfos[nIndex]);
- LanguageType nDefLang, nCjkLang, nCtlLang;
- bool bAutoSpell;
- ScModule::GetSpellSettings( nDefLang, nCjkLang, nCtlLang, bAutoSpell );
-
- // latin font from GetDefaultFonts is not used, DEFAULTFONT_LATIN_SPREADSHEET instead
- SvxFontItem* pStdFont = getDefaultFontItem(nDefLang, DefaultFontType::LATIN_SPREADSHEET, ATTR_FONT);
- SvxFontItem* pCjkFont = getDefaultFontItem(nCjkLang, DefaultFontType::CJK_SPREADSHEET, ATTR_CJK_FONT);
- SvxFontItem* pCtlFont = getDefaultFontItem(nCtlLang, DefaultFontType::CTL_SPREADSHEET, ATTR_CTL_FONT);
-
- SvxBoxInfoItem* pGlobalBorderInnerAttr = new SvxBoxInfoItem( ATTR_BORDER_INNER );
- auto pSet = std::make_unique<SfxItemSet>( *this, svl::Items<ATTR_PATTERN_START, ATTR_PATTERN_END>{} );
- SfxItemSet aSetItemItemSet( *this,
- svl::Items<ATTR_BACKGROUND, ATTR_BACKGROUND,
- ATTR_BORDER, ATTR_SHADOW,
- ATTR_LRSPACE, ATTR_ULSPACE,
- ATTR_PAGE_SIZE, ATTR_PAGE_SIZE,
- ATTR_PAGE_ON, ATTR_PAGE_SHARED>{} );
-
- pGlobalBorderInnerAttr->SetLine(nullptr, SvxBoxInfoItemLine::HORI);
- pGlobalBorderInnerAttr->SetLine(nullptr, SvxBoxInfoItemLine::VERT);
- pGlobalBorderInnerAttr->SetTable(true);
- pGlobalBorderInnerAttr->SetDist(true);
- pGlobalBorderInnerAttr->SetMinDist(false);
-
- mvPoolDefaults[ ATTR_FONT - ATTR_STARTINDEX ] = pStdFont;
- mvPoolDefaults[ ATTR_FONT_HEIGHT - ATTR_STARTINDEX ] = new SvxFontHeightItem( 200, 100, ATTR_FONT_HEIGHT ); // 10 pt;
- mvPoolDefaults[ ATTR_FONT_WEIGHT - ATTR_STARTINDEX ] = new SvxWeightItem( WEIGHT_NORMAL, ATTR_FONT_WEIGHT );
- mvPoolDefaults[ ATTR_FONT_POSTURE - ATTR_STARTINDEX ] = new SvxPostureItem( ITALIC_NONE, ATTR_FONT_POSTURE );
- mvPoolDefaults[ ATTR_FONT_UNDERLINE - ATTR_STARTINDEX ] = new SvxUnderlineItem( LINESTYLE_NONE, ATTR_FONT_UNDERLINE );
- mvPoolDefaults[ ATTR_FONT_OVERLINE - ATTR_STARTINDEX ] = new SvxOverlineItem( LINESTYLE_NONE, ATTR_FONT_OVERLINE );
- mvPoolDefaults[ ATTR_FONT_CROSSEDOUT - ATTR_STARTINDEX ] = new SvxCrossedOutItem( STRIKEOUT_NONE, ATTR_FONT_CROSSEDOUT );
- mvPoolDefaults[ ATTR_FONT_CONTOUR - ATTR_STARTINDEX ] = new SvxContourItem( false, ATTR_FONT_CONTOUR );
- mvPoolDefaults[ ATTR_FONT_SHADOWED - ATTR_STARTINDEX ] = new SvxShadowedItem( false, ATTR_FONT_SHADOWED );
- mvPoolDefaults[ ATTR_FONT_COLOR - ATTR_STARTINDEX ] = new SvxColorItem( COL_AUTO, ATTR_FONT_COLOR );
- mvPoolDefaults[ ATTR_FONT_LANGUAGE - ATTR_STARTINDEX ] = new SvxLanguageItem( LANGUAGE_DONTKNOW, ATTR_FONT_LANGUAGE );
- mvPoolDefaults[ ATTR_CJK_FONT - ATTR_STARTINDEX ] = pCjkFont;
- mvPoolDefaults[ ATTR_CJK_FONT_HEIGHT - ATTR_STARTINDEX ] = new SvxFontHeightItem( 200, 100, ATTR_CJK_FONT_HEIGHT );
- mvPoolDefaults[ ATTR_CJK_FONT_WEIGHT - ATTR_STARTINDEX ] = new SvxWeightItem( WEIGHT_NORMAL, ATTR_CJK_FONT_WEIGHT );
- mvPoolDefaults[ ATTR_CJK_FONT_POSTURE- ATTR_STARTINDEX ] = new SvxPostureItem( ITALIC_NONE, ATTR_CJK_FONT_POSTURE );
- mvPoolDefaults[ ATTR_CJK_FONT_LANGUAGE-ATTR_STARTINDEX ] = new SvxLanguageItem( LANGUAGE_DONTKNOW, ATTR_CJK_FONT_LANGUAGE );
- mvPoolDefaults[ ATTR_CTL_FONT - ATTR_STARTINDEX ] = pCtlFont;
- mvPoolDefaults[ ATTR_CTL_FONT_HEIGHT - ATTR_STARTINDEX ] = new SvxFontHeightItem( 200, 100, ATTR_CTL_FONT_HEIGHT );
- mvPoolDefaults[ ATTR_CTL_FONT_WEIGHT - ATTR_STARTINDEX ] = new SvxWeightItem( WEIGHT_NORMAL, ATTR_CTL_FONT_WEIGHT );
- mvPoolDefaults[ ATTR_CTL_FONT_POSTURE- ATTR_STARTINDEX ] = new SvxPostureItem( ITALIC_NONE, ATTR_CTL_FONT_POSTURE );
- mvPoolDefaults[ ATTR_CTL_FONT_LANGUAGE-ATTR_STARTINDEX ] = new SvxLanguageItem( LANGUAGE_DONTKNOW, ATTR_CTL_FONT_LANGUAGE );
- mvPoolDefaults[ ATTR_FONT_EMPHASISMARK-ATTR_STARTINDEX ] = new SvxEmphasisMarkItem( FontEmphasisMark::NONE, ATTR_FONT_EMPHASISMARK );
- mvPoolDefaults[ ATTR_USERDEF - ATTR_STARTINDEX ] = new SvXMLAttrContainerItem( ATTR_USERDEF );
- mvPoolDefaults[ ATTR_FONT_WORDLINE - ATTR_STARTINDEX ] = new SvxWordLineModeItem(false, ATTR_FONT_WORDLINE );
- mvPoolDefaults[ ATTR_FONT_RELIEF - ATTR_STARTINDEX ] = new SvxCharReliefItem( FontRelief::NONE, ATTR_FONT_RELIEF );
- mvPoolDefaults[ ATTR_HYPHENATE - ATTR_STARTINDEX ] = new ScHyphenateCell();
- mvPoolDefaults[ ATTR_SCRIPTSPACE - ATTR_STARTINDEX ] = new SvxScriptSpaceItem( false, ATTR_SCRIPTSPACE);
- mvPoolDefaults[ ATTR_HANGPUNCTUATION - ATTR_STARTINDEX ] = new SvxHangingPunctuationItem( false, ATTR_HANGPUNCTUATION);
- mvPoolDefaults[ ATTR_FORBIDDEN_RULES - ATTR_STARTINDEX ] = new SvxForbiddenRuleItem( false, ATTR_FORBIDDEN_RULES);
- mvPoolDefaults[ ATTR_HOR_JUSTIFY - ATTR_STARTINDEX ] = new SvxHorJustifyItem( SvxCellHorJustify::Standard, ATTR_HOR_JUSTIFY);
- mvPoolDefaults[ ATTR_HOR_JUSTIFY_METHOD - ATTR_STARTINDEX ] = new SvxJustifyMethodItem( SvxCellJustifyMethod::Auto, ATTR_HOR_JUSTIFY_METHOD);
- mvPoolDefaults[ ATTR_INDENT - ATTR_STARTINDEX ] = new ScIndentItem( 0 );
- mvPoolDefaults[ ATTR_VER_JUSTIFY - ATTR_STARTINDEX ] = new SvxVerJustifyItem( SvxCellVerJustify::Standard, ATTR_VER_JUSTIFY);
- mvPoolDefaults[ ATTR_VER_JUSTIFY_METHOD - ATTR_STARTINDEX ] = new SvxJustifyMethodItem( SvxCellJustifyMethod::Auto, ATTR_VER_JUSTIFY_METHOD);
- mvPoolDefaults[ ATTR_STACKED - ATTR_STARTINDEX ] = new ScVerticalStackCell(false);
- mvPoolDefaults[ ATTR_ROTATE_VALUE - ATTR_STARTINDEX ] = new ScRotateValueItem( 0_deg100 );
- mvPoolDefaults[ ATTR_ROTATE_MODE - ATTR_STARTINDEX ] = new SvxRotateModeItem( SVX_ROTATE_MODE_BOTTOM, ATTR_ROTATE_MODE );
- mvPoolDefaults[ ATTR_VERTICAL_ASIAN - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_VERTICAL_ASIAN );
- // The default for the ATTR_WRITINGDIR cell attribute must by SvxFrameDirection::Environment,
- // so that value is returned when asking for a default cell's attributes.
- // The value from the page style is set as DefaultHorizontalTextDirection for the EditEngine.
- mvPoolDefaults[ ATTR_WRITINGDIR - ATTR_STARTINDEX ] = new SvxFrameDirectionItem( SvxFrameDirection::Environment, ATTR_WRITINGDIR );
- mvPoolDefaults[ ATTR_LINEBREAK - ATTR_STARTINDEX ] = new ScLineBreakCell();
- mvPoolDefaults[ ATTR_SHRINKTOFIT - ATTR_STARTINDEX ] = new ScShrinkToFitCell();
- mvPoolDefaults[ ATTR_BORDER_TLBR - ATTR_STARTINDEX ] = new SvxLineItem( ATTR_BORDER_TLBR );
- mvPoolDefaults[ ATTR_BORDER_BLTR - ATTR_STARTINDEX ] = new SvxLineItem( ATTR_BORDER_BLTR );
- mvPoolDefaults[ ATTR_MARGIN - ATTR_STARTINDEX ] = new SvxMarginItem( ATTR_MARGIN );
- mvPoolDefaults[ ATTR_MERGE - ATTR_STARTINDEX ] = new ScMergeAttr;
- mvPoolDefaults[ ATTR_MERGE_FLAG - ATTR_STARTINDEX ] = new ScMergeFlagAttr;
- mvPoolDefaults[ ATTR_VALUE_FORMAT - ATTR_STARTINDEX ] = new SfxUInt32Item( ATTR_VALUE_FORMAT, 0 );
- mvPoolDefaults[ ATTR_LANGUAGE_FORMAT - ATTR_STARTINDEX ] = new SvxLanguageItem( ScGlobal::eLnge, ATTR_LANGUAGE_FORMAT );
- mvPoolDefaults[ ATTR_BACKGROUND - ATTR_STARTINDEX ] = new SvxBrushItem( COL_TRANSPARENT, ATTR_BACKGROUND );
- mvPoolDefaults[ ATTR_PROTECTION - ATTR_STARTINDEX ] = new ScProtectionAttr;
- mvPoolDefaults[ ATTR_BORDER - ATTR_STARTINDEX ] = new SvxBoxItem( ATTR_BORDER );
- mvPoolDefaults[ ATTR_BORDER_INNER - ATTR_STARTINDEX ] = pGlobalBorderInnerAttr;
- mvPoolDefaults[ ATTR_SHADOW - ATTR_STARTINDEX ] = new SvxShadowItem( ATTR_SHADOW );
- mvPoolDefaults[ ATTR_VALIDDATA - ATTR_STARTINDEX ] = new SfxUInt32Item( ATTR_VALIDDATA, 0 );
- mvPoolDefaults[ ATTR_CONDITIONAL - ATTR_STARTINDEX ] = new ScCondFormatItem;
- mvPoolDefaults[ ATTR_HYPERLINK - ATTR_STARTINDEX ] = new SfxStringItem( ATTR_HYPERLINK, OUString() ) ;
-
- // GetRscString only works after ScGlobal::Init (indicated by the EmptyBrushItem)
- // TODO: Write additional method ScGlobal::IsInit() or somesuch
- // or detect whether this is the Secondary Pool for a MessagePool
- if ( ScGlobal::GetEmptyBrushItem() )
- mvPoolDefaults[ ATTR_PATTERN - ATTR_STARTINDEX ] = new ScPatternAttr( std::move(pSet), ScResId(STR_STYLENAME_STANDARD) );
- else
- mvPoolDefaults[ ATTR_PATTERN - ATTR_STARTINDEX ] = new ScPatternAttr( std::move(pSet), STRING_STANDARD ); // FIXME: without name?
-
- mvPoolDefaults[ ATTR_LRSPACE - ATTR_STARTINDEX ] = new SvxLRSpaceItem( ATTR_LRSPACE );
- mvPoolDefaults[ ATTR_ULSPACE - ATTR_STARTINDEX ] = new SvxULSpaceItem( ATTR_ULSPACE );
- mvPoolDefaults[ ATTR_PAGE - ATTR_STARTINDEX ] = new SvxPageItem( ATTR_PAGE );
- mvPoolDefaults[ ATTR_PAGE_PAPERBIN - ATTR_STARTINDEX ] = new SvxPaperBinItem( ATTR_PAGE_PAPERBIN );
- mvPoolDefaults[ ATTR_PAGE_SIZE - ATTR_STARTINDEX ] = new SvxSizeItem( ATTR_PAGE_SIZE );
- mvPoolDefaults[ ATTR_PAGE_HORCENTER - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_HORCENTER );
- mvPoolDefaults[ ATTR_PAGE_VERCENTER - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_VERCENTER );
- mvPoolDefaults[ ATTR_PAGE_ON - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_ON, true );
- mvPoolDefaults[ ATTR_PAGE_DYNAMIC - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_DYNAMIC, true );
- mvPoolDefaults[ ATTR_PAGE_SHARED - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_SHARED, true );
- mvPoolDefaults[ ATTR_PAGE_NOTES - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_NOTES, false );
- mvPoolDefaults[ ATTR_PAGE_GRID - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_GRID, false );
- mvPoolDefaults[ ATTR_PAGE_HEADERS - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_HEADERS, false );
- mvPoolDefaults[ ATTR_PAGE_CHARTS - ATTR_STARTINDEX ] = new ScViewObjectModeItem( ATTR_PAGE_CHARTS );
- mvPoolDefaults[ ATTR_PAGE_OBJECTS - ATTR_STARTINDEX ] = new ScViewObjectModeItem( ATTR_PAGE_OBJECTS );
- mvPoolDefaults[ ATTR_PAGE_DRAWINGS - ATTR_STARTINDEX ] = new ScViewObjectModeItem( ATTR_PAGE_DRAWINGS );
- mvPoolDefaults[ ATTR_PAGE_TOPDOWN - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_TOPDOWN, true );
- mvPoolDefaults[ ATTR_PAGE_SCALE - ATTR_STARTINDEX ] = new SfxUInt16Item( ATTR_PAGE_SCALE, 100 );
- mvPoolDefaults[ ATTR_PAGE_SCALETOPAGES-ATTR_STARTINDEX ] = new SfxUInt16Item( ATTR_PAGE_SCALETOPAGES, 1 );
- mvPoolDefaults[ ATTR_PAGE_FIRSTPAGENO- ATTR_STARTINDEX ] = new SfxUInt16Item( ATTR_PAGE_FIRSTPAGENO, 1 );
- mvPoolDefaults[ ATTR_PAGE_HEADERLEFT - ATTR_STARTINDEX ] = new ScPageHFItem( ATTR_PAGE_HEADERLEFT );
- mvPoolDefaults[ ATTR_PAGE_FOOTERLEFT - ATTR_STARTINDEX ] = new ScPageHFItem( ATTR_PAGE_FOOTERLEFT );
- mvPoolDefaults[ ATTR_PAGE_HEADERRIGHT- ATTR_STARTINDEX ] = new ScPageHFItem( ATTR_PAGE_HEADERRIGHT );
- mvPoolDefaults[ ATTR_PAGE_FOOTERRIGHT- ATTR_STARTINDEX ] = new ScPageHFItem( ATTR_PAGE_FOOTERRIGHT );
- mvPoolDefaults[ ATTR_PAGE_HEADERSET - ATTR_STARTINDEX ] = new SvxSetItem( ATTR_PAGE_HEADERSET, aSetItemItemSet );
- mvPoolDefaults[ ATTR_PAGE_FOOTERSET - ATTR_STARTINDEX ] = new SvxSetItem( ATTR_PAGE_FOOTERSET, aSetItemItemSet );
- mvPoolDefaults[ ATTR_PAGE_FORMULAS - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_FORMULAS, false );
- mvPoolDefaults[ ATTR_PAGE_NULLVALS - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_NULLVALS, true );
- mvPoolDefaults[ ATTR_PAGE_SCALETO - ATTR_STARTINDEX ] = new ScPageScaleToItem( 1, 1 );
- mvPoolDefaults[ ATTR_HIDDEN - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_HIDDEN, false );
-
- SetDefaults( &mvPoolDefaults );
-}
-
-ScDocumentPool::~ScDocumentPool()
-{
- Delete();
+ // return immediately if we have the static entry and Item
+ if (nullptr != rRetval.getItem())
+ return rRetval;
- for ( sal_uInt16 i=0; i < ATTR_ENDINDEX-ATTR_STARTINDEX+1; i++ )
- {
- ClearRefCount( *mvPoolDefaults[i] );
- delete mvPoolDefaults[i];
- }
-}
+ if (ATTR_PAGE_HEADERSET == rRetval.getWhich())
+ {
+ SfxItemSet aSetItemItemSet(rPool,
+ svl::Items<
+ ATTR_BACKGROUND, ATTR_BACKGROUND,
+ ATTR_BORDER, ATTR_SHADOW,
+ ATTR_LRSPACE, ATTR_ULSPACE,
+ ATTR_PAGE_SIZE, ATTR_PAGE_SIZE,
+ ATTR_PAGE_ON, ATTR_PAGE_SHARED_FIRST>);
+ return *new ItemInfoDynamic(rRetval, new SvxSetItem(ATTR_PAGE_HEADERSET, aSetItemItemSet));
+ }
-const SfxPoolItem& ScDocumentPool::PutImpl( const SfxPoolItem& rItem, sal_uInt16 nWhich, bool bPassingOwnership )
-{
- if ( rItem.Which() != ATTR_PATTERN ) // Only Pattern is special
- return SfxItemPool::PutImpl( rItem, nWhich, bPassingOwnership );
+ if (ATTR_PAGE_FOOTERSET == rRetval.getWhich())
+ {
+ SfxItemSet aSetItemItemSet(rPool,
+ svl::Items<
+ ATTR_BACKGROUND, ATTR_BACKGROUND,
+ ATTR_BORDER, ATTR_SHADOW,
+ ATTR_LRSPACE, ATTR_ULSPACE,
+ ATTR_PAGE_SIZE, ATTR_PAGE_SIZE,
+ ATTR_PAGE_ON, ATTR_PAGE_SHARED_FIRST>);
+ return *new ItemInfoDynamic(rRetval, new SvxSetItem(ATTR_PAGE_FOOTERSET, aSetItemItemSet));
+ }
- // Don't copy the default pattern of this Pool
- if (&rItem == mvPoolDefaults[ ATTR_PATTERN - ATTR_STARTINDEX ])
- return rItem;
+ // return in any case
+ return rRetval;
+ }
+ };
- // Else Put must always happen, because it could be another Pool
- const SfxPoolItem& rNew = SfxItemPool::PutImpl( rItem, nWhich, bPassingOwnership );
- sal_uInt32 nRef = rNew.GetRefCount();
- if (nRef == 1)
- {
- ++mnCurrentMaxKey;
- const_cast<ScPatternAttr&>(static_cast<const ScPatternAttr&>(rNew)).SetKey(mnCurrentMaxKey);
- }
- return rNew;
+ static std::unique_ptr<ItemInfoPackageScDocument> g_aItemInfoPackageScDocument;
+ if (!g_aItemInfoPackageScDocument)
+ g_aItemInfoPackageScDocument.reset(new ItemInfoPackageScDocument);
+ return *g_aItemInfoPackageScDocument;
}
-void ScDocumentPool::StyleDeleted( const ScStyleSheet* pStyle )
+ScDocumentPool::ScDocumentPool()
+: SfxItemPool("ScDocumentPool")
{
- for (const SfxPoolItem* pItem : GetItemSurrogates( ATTR_PATTERN ))
- {
- ScPatternAttr* pPattern = const_cast<ScPatternAttr*>(dynamic_cast<const ScPatternAttr*>(pItem));
- if ( pPattern && pPattern->GetStyleSheet() == pStyle )
- pPattern->StyleToName();
- }
+ registerItemInfoPackage(getItemInfoPackageScDocument());
}
-void ScDocumentPool::CellStyleCreated( std::u16string_view rName, const ScDocument& rDoc )
+ScDocumentPool::~ScDocumentPool()
{
- // If a style was created, don't keep any pattern with its name string in the pool,
- // because it would compare equal to a pattern with a pointer to the new style.
- // Calling StyleSheetChanged isn't enough because the pool may still contain items
- // for undo or clipboard content.
-
- for (const SfxPoolItem* pItem : GetItemSurrogates( ATTR_PATTERN ))
- {
- auto pPattern = const_cast<ScPatternAttr*>(dynamic_cast<const ScPatternAttr*>(pItem));
- if ( pPattern && pPattern->GetStyleSheet() == nullptr )
- {
- const OUString* pStyleName = pPattern->GetStyleName();
- if ( pStyleName && *pStyleName == rName )
- pPattern->UpdateStyleSheet(rDoc); // find and store style pointer
- }
- }
+ sendShutdownHint();
+ SetSecondaryPool(nullptr);
}
rtl::Reference<SfxItemPool> ScDocumentPool::Clone() const
{
- return new SfxItemPool (*this, true);
+ return new SfxItemPool(*this);
}
static bool lcl_HFPresentation
@@ -391,17 +283,16 @@ static bool lcl_HFPresentation
)
{
const SfxItemSet& rSet = static_cast<const SfxSetItem&>(rItem).GetItemSet();
- const SfxPoolItem* pItem;
- if ( SfxItemState::SET == rSet.GetItemState(ATTR_PAGE_ON,false,&pItem) )
+ if ( const SfxBoolItem* pItem = rSet.GetItemIfSet(ATTR_PAGE_ON,false) )
{
- if( !static_cast<const SfxBoolItem*>(pItem)->GetValue() )
+ if( !pItem->GetValue() )
return false;
}
SfxItemIter aIter( rSet );
- for (pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
+ for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
{
sal_uInt16 nWhich = pItem->Which();
@@ -412,6 +303,7 @@ static bool lcl_HFPresentation
case ATTR_PAGE_ON:
case ATTR_PAGE_DYNAMIC:
case ATTR_PAGE_SHARED:
+ case ATTR_PAGE_SHARED_FIRST:
break;
case ATTR_LRSPACE:
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 3191e3d5f816..3fa9ab662c70 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -20,7 +20,6 @@
#include <scextopt.hxx>
#include <autonamecache.hxx>
-#include <o3tl/safeint.hxx>
#include <osl/thread.h>
#include <svx/xtable.hxx>
#include <sfx2/bindings.hxx>
@@ -36,7 +35,7 @@
#include <comphelper/threadpool.hxx>
#include <sal/log.hxx>
#include <osl/diagnose.h>
-#include <unotools/configmgr.hxx>
+#include <comphelper/configuration.hxx>
#include <scmod.hxx>
#include <document.hxx>
@@ -67,6 +66,7 @@
#include <listenercalls.hxx>
#include <recursionhelper.hxx>
#include <lookupcache.hxx>
+#include <rangecache.hxx>
#include <externalrefmgr.hxx>
#include <viewdata.hxx>
#include <viewutil.hxx>
@@ -87,22 +87,45 @@
#include <listenercontext.hxx>
#include <datamapper.hxx>
#include <drwlayer.hxx>
+#include <sharedstringpoolpurge.hxx>
+#include <docpool.hxx>
+#include <config_features.h>
using namespace com::sun::star;
const sal_uInt16 ScDocument::nSrcVer = SC_CURRENT_VERSION;
-static ScSheetLimits* CreateSheetLimits()
+ScSheetLimits ScSheetLimits::CreateDefault()
{
- const ScDefaultsOptions& rOpt = SC_MOD()->GetDefaultsOptions();
- if (rOpt.GetInitJumboSheets())
- return new ScSheetLimits(MAXCOL_JUMBO, MAXROW_JUMBO);
+#if HAVE_FEATURE_JUMBO_SHEETS
+ bool jumboSheets = false;
+ if( SC_MOD())
+ jumboSheets = SC_MOD()->GetDefaultsOptions().GetInitJumboSheets();
else
- return new ScSheetLimits(MAXCOL, MAXROW);
+ assert( getenv("LO_TESTNAME") != nullptr ); // in unittests
+ if (jumboSheets)
+ return ScSheetLimits(MAXCOL_JUMBO, MAXROW_JUMBO);
+ else
+#endif
+ return ScSheetLimits(MAXCOL, MAXROW);
+}
+
+CellAttributeHelper& ScDocument::getCellAttributeHelper() const
+{
+ if (!mpCellAttributeHelper)
+ {
+ assert(!IsClipOrUndo() && "CellAttributeHelper needs to be shared using SharePooledResources, not created (!)");
+ SfxItemPool* pPool(const_cast<ScDocument*>(this)->GetPool());
+ assert(nullptr != pPool && "No SfxItemPool for this ScDocument (!)");
+ mpCellAttributeHelper.reset(new CellAttributeHelper(*pPool));
+ }
+
+ return *mpCellAttributeHelper;
}
-ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
- mpCellStringPool(std::make_shared<svl::SharedStringPool>(*ScGlobal::getCharClassPtr())),
+ScDocument::ScDocument( ScDocumentMode eMode, ScDocShell* pDocShell ) :
+ mpCellAttributeHelper(),
+ mpCellStringPool(std::make_shared<svl::SharedStringPool>(ScGlobal::getCharClass())),
mpDocLinkMgr(new sc::DocumentLinkManager(pDocShell)),
mbFormulaGroupCxtBlockDiscard(false),
maCalcConfig( ScInterpreter::GetGlobalConfig()),
@@ -111,7 +134,7 @@ ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
mpPrinter( nullptr ),
mpVirtualDevice_100th_mm( nullptr ),
pFormatExchangeList( nullptr ),
- mxSheetLimits(CreateSheetLimits()),
+ mxSheetLimits(new ScSheetLimits(ScSheetLimits::CreateDefault())),
pFormulaTree( nullptr ),
pEOFormulaTree( nullptr ),
pFormulaTrack( nullptr ),
@@ -128,6 +151,7 @@ ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
nMacroInterpretLevel(0),
nInterpreterTableOpLevel(0),
maInterpreterContext( *this, nullptr ),
+ mxScSortedRangeCache(new ScSortedRangeCacheMap),
nFormulaTrackCount(0),
eHardRecalcState(HardRecalcState::OFF),
nVisibleTab( 0 ),
@@ -155,6 +179,7 @@ ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
bInDtorClear( false ),
bExpandRefs( false ),
bDetectiveDirty( false ),
+ bDelayedDeletingBroadcasters( false ),
bLinkFormulaNeedingCheck( false ),
nAsianCompression(CharCompressType::Invalid),
nAsianKerning(SC_ASIANKERNING_INVALID),
@@ -176,9 +201,11 @@ ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
mbEmbedFontScriptLatin(true),
mbEmbedFontScriptAsian(true),
mbEmbedFontScriptComplex(true),
+ mnImagePreferredDPI(0),
mbTrackFormulasPending(false),
mbFinalTrackFormulas(false),
mbDocShellRecalc(false),
+ mbLayoutStrings(false),
mnMutationGuardFlags(0)
{
maPreviewSelection = { *mxSheetLimits };
@@ -193,7 +220,7 @@ ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
if ( eMode == SCDOCMODE_DOCUMENT || eMode == SCDOCMODE_FUNCTIONACCESS )
{
mxPoolHelper = new ScPoolHelper( *this );
- if (!utl::ConfigManager::IsFuzzing()) //just too slow
+ if (!comphelper::IsFuzzing()) //just too slow
pBASM.reset( new ScBroadcastAreaSlotMachine( this ) );
pChartListenerCollection.reset( new ScChartListenerCollection( *this ) );
pRefreshTimerControl.reset( new ScRefreshTimerControl );
@@ -202,6 +229,7 @@ ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
{
pChartListenerCollection = nullptr;
}
+
pDBCollection.reset( new ScDBCollection(*this) );
pSelectionAttr = nullptr;
apTemporaryChartLock.reset( new ScTemporaryChartLock(this) );
@@ -263,11 +291,17 @@ sal_uInt32 ScDocument::GetDocumentID() const
void ScDocument::StartChangeTracking()
{
if (!pChangeTrack)
+ {
pChangeTrack.reset( new ScChangeTrack( *this ) );
+ if (mpShell)
+ mpShell->SetModified();
+ }
}
void ScDocument::EndChangeTracking()
{
+ if (pChangeTrack && mpShell)
+ mpShell->SetModified();
pChangeTrack.reset();
}
@@ -366,7 +400,7 @@ ScDocument::~ScDocument()
pDBCollection.reset();
pSelectionAttr.reset();
apTemporaryChartLock.reset();
- DeleteDrawLayer();
+ mpDrawLayer.reset();
mpPrinter.disposeAndClear();
ImplDeleteOptions();
pConsolidateDlgData.reset();
@@ -398,7 +432,14 @@ ScDocument::~ScDocument()
mpFormulaGroupCxt.reset();
// Purge unused items if the string pool will be still used (e.g. by undo history).
if(mpCellStringPool.use_count() > 1)
- mpCellStringPool->purge();
+ {
+ // Calling purge() may be somewhat expensive with large documents, so
+ // try to delay and compress it for temporary documents.
+ if(IsClipOrUndo())
+ ScGlobal::GetSharedStringPoolPurge().delayedPurge(mpCellStringPool);
+ else
+ mpCellStringPool->purge();
+ }
mpCellStringPool.reset();
assert( pDelayedFormulaGrouping == nullptr );
@@ -458,7 +499,7 @@ ScFieldEditEngine& ScDocument::GetEditEngine()
if ( !mpEditEngine )
{
mpEditEngine.reset( new ScFieldEditEngine(this, GetEnginePool(), GetEditPool()) );
- mpEditEngine->SetUpdateMode( false );
+ mpEditEngine->SetUpdateLayout( false );
mpEditEngine->EnableUndo( false );
mpEditEngine->SetRefMapMode(MapMode(MapUnit::Map100thMM));
ApplyAsianEditSettings( *mpEditEngine );
@@ -472,37 +513,48 @@ ScNoteEditEngine& ScDocument::GetNoteEngine()
{
ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
mpNoteEngine.reset( new ScNoteEditEngine( GetEnginePool(), GetEditPool() ) );
- mpNoteEngine->SetUpdateMode( false );
+ mpNoteEngine->SetUpdateLayout( false );
mpNoteEngine->EnableUndo( false );
mpNoteEngine->SetRefMapMode(MapMode(MapUnit::Map100thMM));
ApplyAsianEditSettings( *mpNoteEngine );
- const SfxItemSet& rItemSet = GetDefPattern()->GetItemSet();
- std::unique_ptr<SfxItemSet> pEEItemSet(new SfxItemSet( mpNoteEngine->GetEmptyItemSet() ));
- ScPatternAttr::FillToEditItemSet( *pEEItemSet, rItemSet );
- mpNoteEngine->SetDefaults( std::move(pEEItemSet) ); // edit engine takes ownership
+ const SfxItemSet& rItemSet(getCellAttributeHelper().getDefaultCellAttribute().GetItemSet());
+ SfxItemSet aEEItemSet( mpNoteEngine->GetEmptyItemSet() );
+ ScPatternAttr::FillToEditItemSet( aEEItemSet, rItemSet );
+ mpNoteEngine->SetDefaults( std::move(aEEItemSet) ); // edit engine takes ownership
}
return *mpNoteEngine;
}
+std::unique_ptr<EditTextObject> ScDocument::CreateSharedStringTextObject( const svl::SharedString& rSS )
+{
+ /* TODO: Add shared string support to the edit engine to make this process
+ * simpler. */
+ ScFieldEditEngine& rEngine = GetEditEngine();
+ rEngine.SetTextCurrentDefaults( rSS.getString());
+ std::unique_ptr<EditTextObject> pObj( rEngine.CreateTextObject());
+ pObj->NormalizeString( GetSharedStringPool());
+ return pObj;
+}
+
void ScDocument::ResetClip( ScDocument* pSourceDoc, const ScMarkData* pMarks )
{
if (bIsClip)
{
InitClipPtrs(pSourceDoc);
- for (SCTAB i = 0; i < static_cast<SCTAB>(pSourceDoc->maTabs.size()); i++)
+ for (SCTAB i = 0; i < pSourceDoc->GetTableCount(); i++)
if (pSourceDoc->maTabs[i])
if (!pMarks || pMarks->GetTableSelect(i))
{
OUString aString = pSourceDoc->maTabs[i]->GetName();
- if ( i < static_cast<SCTAB>(maTabs.size()) )
+ if (i < GetTableCount())
{
maTabs[i].reset( new ScTable(*this, i, aString) );
}
else
{
- if( i > static_cast<SCTAB>(maTabs.size()) )
+ if (i > GetTableCount())
{
maTabs.resize(i);
}
@@ -522,12 +574,12 @@ void ScDocument::ResetClip( ScDocument* pSourceDoc, SCTAB nTab )
if (bIsClip)
{
InitClipPtrs(pSourceDoc);
- if (nTab >= static_cast<SCTAB>(maTabs.size()))
+ if (nTab >= GetTableCount())
{
maTabs.resize(nTab+1);
}
maTabs[nTab].reset( new ScTable(*this, nTab, "baeh") );
- if (nTab < static_cast<SCTAB>(pSourceDoc->maTabs.size()) && pSourceDoc->maTabs[nTab])
+ if (nTab < pSourceDoc->GetTableCount() && pSourceDoc->maTabs[nTab])
maTabs[nTab]->SetLayoutRTL( pSourceDoc->maTabs[nTab]->IsLayoutRTL() );
}
else
@@ -539,7 +591,7 @@ void ScDocument::ResetClip( ScDocument* pSourceDoc, SCTAB nTab )
void ScDocument::EnsureTable( SCTAB nTab )
{
bool bExtras = !bIsUndo; // Column-Widths, Row-Heights, Flags
- if (o3tl::make_unsigned(nTab) >= maTabs.size())
+ if (nTab >= GetTableCount())
maTabs.resize(nTab+1);
if (!maTabs[nTab])
@@ -548,18 +600,16 @@ void ScDocument::EnsureTable( SCTAB nTab )
ScRefCellValue ScDocument::GetRefCellValue( const ScAddress& rPos )
{
- if (!TableExists(rPos.Tab()))
- return ScRefCellValue(); // empty
-
- return maTabs[rPos.Tab()]->GetRefCellValue(rPos.Col(), rPos.Row());
+ if (ScTable* pTable = FetchTable(rPos.Tab()))
+ return pTable->GetRefCellValue(rPos.Col(), rPos.Row());
+ return ScRefCellValue(); // empty
}
ScRefCellValue ScDocument::GetRefCellValue( const ScAddress& rPos, sc::ColumnBlockPosition& rBlockPos )
{
- if (!TableExists(rPos.Tab()))
- return ScRefCellValue(); // empty
-
- return maTabs[rPos.Tab()]->GetRefCellValue(rPos.Col(), rPos.Row(), rBlockPos);
+ if (ScTable* pTable = FetchTable(rPos.Tab()))
+ return pTable->GetRefCellValue(rPos.Col(), rPos.Row(), rBlockPos);
+ return ScRefCellValue(); // empty
}
svl::SharedStringPool& ScDocument::GetSharedStringPool()
@@ -575,9 +625,9 @@ const svl::SharedStringPool& ScDocument::GetSharedStringPool() const
bool ScDocument::GetPrintArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow,
bool bNotes) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
+ if (const ScTable* pTable = FetchTable(nTab))
{
- bool bAny = maTabs[nTab]->GetPrintArea( rEndCol, rEndRow, bNotes, /*bCalcHiddens*/false);
+ bool bAny = pTable->GetPrintArea( rEndCol, rEndRow, bNotes, /*bCalcHiddens*/false);
if (mpDrawLayer)
{
ScRange aDrawRange(0,0,nTab, MaxCol(),MaxRow(),nTab);
@@ -599,9 +649,9 @@ bool ScDocument::GetPrintArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow,
bool ScDocument::GetPrintAreaHor( SCTAB nTab, SCROW nStartRow, SCROW nEndRow,
SCCOL& rEndCol ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
+ if (const ScTable* pTable = FetchTable(nTab))
{
- bool bAny = maTabs[nTab]->GetPrintAreaHor( nStartRow, nEndRow, rEndCol );
+ bool bAny = pTable->GetPrintAreaHor( nStartRow, nEndRow, rEndCol );
if (mpDrawLayer)
{
ScRange aDrawRange(0,nStartRow,nTab, MaxCol(),nEndRow,nTab);
@@ -621,9 +671,9 @@ bool ScDocument::GetPrintAreaHor( SCTAB nTab, SCROW nStartRow, SCROW nEndRow,
bool ScDocument::GetPrintAreaVer( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol,
SCROW& rEndRow, bool bNotes ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
+ if (const ScTable* pTable = FetchTable(nTab))
{
- bool bAny = maTabs[nTab]->GetPrintAreaVer( nStartCol, nEndCol, rEndRow, bNotes );
+ bool bAny = pTable->GetPrintAreaVer( nStartCol, nEndCol, rEndRow, bNotes );
if (mpDrawLayer)
{
ScRange aDrawRange(nStartCol,0,nTab, nEndCol,MaxRow(),nTab);
@@ -642,9 +692,9 @@ bool ScDocument::GetPrintAreaVer( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol,
bool ScDocument::GetDataStart( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
+ if (const ScTable* pTable = FetchTable(nTab))
{
- bool bAny = maTabs[nTab]->GetDataStart( rStartCol, rStartRow );
+ bool bAny = pTable->GetDataStart( rStartCol, rStartRow );
if (mpDrawLayer)
{
ScRange aDrawRange(0,0,nTab, MaxCol(),MaxRow(),nTab);
@@ -665,7 +715,7 @@ bool ScDocument::GetDataStart( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow )
void ScDocument::GetTiledRenderingArea(SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow) const
{
- bool bHasPrintArea = GetPrintArea(nTab, rEndCol, rEndRow, false);
+ bool bHasPrintArea = GetCellArea(nTab, rEndCol, rEndRow);
// we need some reasonable minimal document size
ScViewData* pViewData = ScDocShell::GetViewData();
@@ -699,7 +749,7 @@ bool ScDocument::MoveTab( SCTAB nOldPos, SCTAB nNewPos, ScProgress* pProgress )
if (nOldPos == nNewPos)
return false;
- SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
+ SCTAB nTabCount = GetTableCount();
if(nTabCount < 2)
return false;
@@ -709,6 +759,7 @@ bool ScDocument::MoveTab( SCTAB nOldPos, SCTAB nNewPos, ScProgress* pProgress )
if (maTabs[nOldPos])
{
sc::AutoCalcSwitch aACSwitch(*this, false);
+ sc::DelayDeletingBroadcasters delayDeletingBroadcasters(*this);
SetNoListening( true );
if (nNewPos == SC_TAB_APPEND || nNewPos >= nTabCount)
@@ -766,8 +817,8 @@ bool ScDocument::MoveTab( SCTAB nOldPos, SCTAB nNewPos, ScProgress* pProgress )
bool ScDocument::CopyTab( SCTAB nOldPos, SCTAB nNewPos, const ScMarkData* pOnlyMarked )
{
- if (SC_TAB_APPEND == nNewPos || nNewPos >= static_cast<SCTAB>(maTabs.size()))
- nNewPos = static_cast<SCTAB>(maTabs.size());
+ if (SC_TAB_APPEND == nNewPos || nNewPos >= GetTableCount())
+ nNewPos = GetTableCount();
OUString aName;
GetName(nOldPos, aName);
@@ -789,14 +840,14 @@ bool ScDocument::CopyTab( SCTAB nOldPos, SCTAB nNewPos, const ScMarkData* pOnlyM
if (bValid)
{
- if (nNewPos >= static_cast<SCTAB>(maTabs.size()))
+ if (nNewPos >= GetTableCount())
{
- nNewPos = static_cast<SCTAB>(maTabs.size());
+ nNewPos = GetTableCount();
maTabs.emplace_back(new ScTable(*this, nNewPos, aName));
}
else
{
- if (ValidTab(nNewPos) && (nNewPos < static_cast<SCTAB>(maTabs.size())))
+ if (ValidTab(nNewPos) && nNewPos < GetTableCount())
{
SetNoListening( true );
@@ -835,7 +886,7 @@ bool ScDocument::CopyTab( SCTAB nOldPos, SCTAB nNewPos, const ScMarkData* pOnlyM
if (pValidationList)
pValidationList->UpdateInsertTab(aCxt);
- }
+ }
else
bValid = false;
}
@@ -853,6 +904,7 @@ bool ScDocument::CopyTab( SCTAB nOldPos, SCTAB nNewPos, const ScMarkData* pOnlyM
GetRangeName()->CopyUsedNames( -1, nRealOldPos, nNewPos, *this, *this, bGlobalNamesToLocal);
sc::CopyToDocContext aCopyDocCxt(*this);
+ pDBCollection->CopyToTable(nOldPos, nNewPos);
maTabs[nOldPos]->CopyToTable(aCopyDocCxt, 0, 0, MaxCol(), MaxRow(), InsertDeleteFlags::ALL,
(pOnlyMarked != nullptr), maTabs[nNewPos].get(), pOnlyMarked,
false /*bAsLink*/, true /*bColRowFlags*/, bGlobalNamesToLocal, false /*bCopyCaptions*/ );
@@ -905,13 +957,11 @@ bool ScDocument::CopyTab( SCTAB nOldPos, SCTAB nNewPos, const ScMarkData* pOnlyM
return bValid;
}
-sal_uLong ScDocument::TransferTab( ScDocument& rSrcDoc, SCTAB nSrcPos,
+bool ScDocument::TransferTab( ScDocument& rSrcDoc, SCTAB nSrcPos,
SCTAB nDestPos, bool bInsertNew,
bool bResultsOnly )
{
- sal_uLong nRetVal = 1; // 0 => error 1 = ok
- // 3 => NameBox
- // 4 => both
+ bool bRetVal = true;
if (rSrcDoc.mpShell->GetMedium())
{
@@ -939,9 +989,9 @@ sal_uLong ScDocument::TransferTab( ScDocument& rSrcDoc, SCTAB nSrcPos,
}
else // replace existing tables
{
- if (ValidTab(nDestPos) && nDestPos < static_cast<SCTAB>(maTabs.size()) && maTabs[nDestPos])
+ if (ScTable* pTable = FetchTable(nDestPos))
{
- maTabs[nDestPos]->DeleteArea( 0,0, MaxCol(),MaxRow(), InsertDeleteFlags::ALL );
+ pTable->DeleteArea(0, 0, MaxCol(), MaxRow(), InsertDeleteFlags::ALL);
}
else
bValid = false;
@@ -983,6 +1033,38 @@ sal_uLong ScDocument::TransferTab( ScDocument& rSrcDoc, SCTAB nSrcPos,
maTabs[nDestPos]->SetTabNo(nDestPos);
maTabs[nDestPos]->SetTabBgColor(rSrcDoc.maTabs[nSrcPos]->GetTabBgColor());
+ // tdf#66613 - copy existing print ranges and col/row repetitions
+ if (auto aRepeatColRange = rSrcDoc.maTabs[nSrcPos]->GetRepeatColRange())
+ {
+ aRepeatColRange->aStart.SetTab(nDestPos);
+ aRepeatColRange->aEnd.SetTab(nDestPos);
+ maTabs[nDestPos]->SetRepeatColRange(aRepeatColRange);
+ }
+
+ if (auto aRepeatRowRange = rSrcDoc.maTabs[nSrcPos]->GetRepeatRowRange())
+ {
+ aRepeatRowRange->aStart.SetTab(nDestPos);
+ aRepeatRowRange->aEnd.SetTab(nDestPos);
+ maTabs[nDestPos]->SetRepeatRowRange(aRepeatRowRange);
+ }
+
+ if (rSrcDoc.IsPrintEntireSheet(nSrcPos))
+ maTabs[nDestPos]->SetPrintEntireSheet();
+ else
+ {
+ // tdf#157897 - clear print ranges before adding additional ones
+ maTabs[nDestPos]->ClearPrintRanges();
+ const auto nPrintRangeCount = rSrcDoc.maTabs[nSrcPos]->GetPrintRangeCount();
+ for (auto nPos = 0; nPos < nPrintRangeCount; nPos++)
+ {
+ // Adjust the tab for the print range at the new position
+ ScRange aSrcPrintRange(*rSrcDoc.maTabs[nSrcPos]->GetPrintRange(nPos));
+ aSrcPrintRange.aStart.SetTab(nDestPos);
+ aSrcPrintRange.aEnd.SetTab(nDestPos);
+ maTabs[nDestPos]->AddPrintRange(aSrcPrintRange);
+ }
+ }
+
if ( !bResultsOnly )
{
sc::RefUpdateContext aRefCxt(*this);
@@ -1017,20 +1099,22 @@ sal_uLong ScDocument::TransferTab( ScDocument& rSrcDoc, SCTAB nSrcPos,
maTabs[nDestPos]->SetPendingRowHeights( rSrcDoc.maTabs[nSrcPos]->IsPendingRowHeights() );
}
if (!bValid)
- nRetVal = 0;
+ bRetVal = false;
bool bVbaEnabled = IsInVBAMode();
if ( bVbaEnabled )
{
- SfxObjectShell* pSrcShell = rSrcDoc.GetDocumentShell();
+ ScDocShell* pSrcShell = rSrcDoc.GetDocumentShell();
if ( pSrcShell )
{
OUString aLibName("Standard");
+#if HAVE_FEATURE_SCRIPTING
const BasicManager *pBasicManager = pSrcShell->GetBasicManager();
if (pBasicManager && !pBasicManager->GetName().isEmpty())
{
aLibName = pSrcShell->GetBasicManager()->GetName();
}
+#endif
OUString sSource;
uno::Reference< script::XLibraryContainer > xLibContainer = pSrcShell->GetBasicContainer();
uno::Reference< container::XNameContainer > xLib;
@@ -1045,50 +1129,44 @@ sal_uLong ScDocument::TransferTab( ScDocument& rSrcDoc, SCTAB nSrcPos,
OUString sSrcCodeName;
rSrcDoc.GetCodeName( nSrcPos, sSrcCodeName );
OUString sRTLSource;
- xLib->getByName( sSrcCodeName ) >>= sRTLSource;
+ if (xLib->hasByName( sSrcCodeName ))
+ xLib->getByName( sSrcCodeName ) >>= sRTLSource;
sSource = sRTLSource;
}
VBA_InsertModule( *this, nDestPos, sSource );
}
}
- return nRetVal;
+ return bRetVal;
}
void ScDocument::SetError( SCCOL nCol, SCROW nRow, SCTAB nTab, const FormulaError nError)
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
- if (maTabs[nTab])
- maTabs[nTab]->SetError( nCol, nRow, nError );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetError(nCol, nRow, nError);
}
void ScDocument::SetFormula(
const ScAddress& rPos, const ScTokenArray& rArray )
{
- if (!TableExists(rPos.Tab()))
- return;
-
- maTabs[rPos.Tab()]->SetFormula(rPos.Col(), rPos.Row(), rArray, formula::FormulaGrammar::GRAM_DEFAULT);
+ if (ScTable* pTable = FetchTable(rPos.Tab()))
+ pTable->SetFormula(rPos.Col(), rPos.Row(), rArray, formula::FormulaGrammar::GRAM_DEFAULT);
}
void ScDocument::SetFormula(
const ScAddress& rPos, const OUString& rFormula, formula::FormulaGrammar::Grammar eGram )
{
- if (!TableExists(rPos.Tab()))
- return;
-
- maTabs[rPos.Tab()]->SetFormula(rPos.Col(), rPos.Row(), rFormula, eGram);
+ if (ScTable* pTable = FetchTable(rPos.Tab()))
+ pTable->SetFormula(rPos.Col(), rPos.Row(), rFormula, eGram);
}
ScFormulaCell* ScDocument::SetFormulaCell( const ScAddress& rPos, ScFormulaCell* pCell )
{
- if (!TableExists(rPos.Tab()))
- {
- delete pCell;
- return nullptr;
- }
+ if (ScTable* pTable = FetchTable(rPos.Tab()))
+ return pTable->SetFormulaCell(rPos.Col(), rPos.Row(), pCell);
- return maTabs[rPos.Tab()]->SetFormulaCell(rPos.Col(), rPos.Row(), pCell);
+ delete pCell;
+ return nullptr;
}
bool ScDocument::SetFormulaCells( const ScAddress& rPos, std::vector<ScFormulaCell*>& rCells )
@@ -1096,11 +1174,9 @@ bool ScDocument::SetFormulaCells( const ScAddress& rPos, std::vector<ScFormulaCe
if (rCells.empty())
return false;
- ScTable* pTab = FetchTable(rPos.Tab());
- if (!pTab)
- return false;
-
- return pTab->SetFormulaCells(rPos.Col(), rPos.Row(), rCells);
+ if (ScTable* pTable = FetchTable(rPos.Tab()))
+ return pTable->SetFormulaCells(rPos.Col(), rPos.Row(), rCells);
+ return false;
}
void ScDocument::SetConsolidateDlgData( std::unique_ptr<ScConsolidateParam> pData )
@@ -1108,6 +1184,11 @@ void ScDocument::SetConsolidateDlgData( std::unique_ptr<ScConsolidateParam> pDat
pConsolidateDlgData = std::move(pData);
}
+void ScDocument::SetEasyConditionalFormatDialogData(std::unique_ptr<ScConditionMode> pMode)
+{
+ pConditionalFormatDialogMode = std::move(pMode);
+}
+
void ScDocument::SetChangeViewSettings(const ScChangeViewSettings& rNew)
{
if (pChangeViewSettings==nullptr)
@@ -1130,8 +1211,7 @@ std::unique_ptr<ScFieldEditEngine> ScDocument::CreateFieldEditEngine()
{
// #i66209# previous use might not have restored update mode,
// ensure same state as for a new EditEngine (UpdateMode = true)
- if ( !pCacheFieldEditEngine->GetUpdateMode() )
- pCacheFieldEditEngine->SetUpdateMode(true);
+ pCacheFieldEditEngine->SetUpdateLayout(true);
}
pNewEditEngine = std::move(pCacheFieldEditEngine);
@@ -1164,7 +1244,7 @@ ScLookupCache & ScDocument::GetLookupCache( const ScRange & rRange, ScInterprete
pCache = findIt->second.get();
// The StartListeningArea() call is not thread-safe, as all threads
// would access the same SvtBroadcaster.
- osl::MutexGuard guard( mScLookupMutex );
+ std::unique_lock guard( mScLookupMutex );
StartListeningArea(rRange, false, pCache);
}
else
@@ -1173,6 +1253,40 @@ ScLookupCache & ScDocument::GetLookupCache( const ScRange & rRange, ScInterprete
return *pCache;
}
+ScSortedRangeCache& ScDocument::GetSortedRangeCache( const ScRange & rRange, const ScQueryParam& param,
+ ScInterpreterContext* pContext )
+{
+ assert(mxScSortedRangeCache);
+ ScSortedRangeCache::HashKey key = ScSortedRangeCache::makeHashKey(rRange, param);
+ // This should be created just once for one range, and repeated calls should reuse it, even
+ // between threads (it doesn't make sense to use ScInterpreterContext and have all threads
+ // build their own copy of the same data). So first try read-only access, which should
+ // in most cases be enough.
+ {
+ std::shared_lock guard(mScLookupMutex);
+ auto findIt = mxScSortedRangeCache->aCacheMap.find(key);
+ if( findIt != mxScSortedRangeCache->aCacheMap.end())
+ return *findIt->second;
+ }
+ // Avoid recursive calls because of some cells in the range being dirty and triggering
+ // interpreting, which may call into this again. Threaded calculation makes sure
+ // no cells are dirty. If some cells in the range cannot be interpreted and remain
+ // dirty e.g. because of circular dependencies, create only an invalid empty cache to prevent
+ // a possible recursive deadlock.
+ bool invalid = false;
+ if(!IsThreadedGroupCalcInProgress())
+ if(!InterpretCellsIfNeeded(rRange))
+ invalid = true;
+ std::unique_lock guard(mScLookupMutex);
+ auto [findIt, bInserted] = mxScSortedRangeCache->aCacheMap.emplace(key, nullptr);
+ if (bInserted)
+ {
+ findIt->second = std::make_unique<ScSortedRangeCache>(this, rRange, param, pContext, invalid);
+ StartListeningArea(rRange, false, findIt->second.get());
+ }
+ return *findIt->second;
+}
+
void ScDocument::RemoveLookupCache( ScLookupCache & rCache )
{
// Data changes leading to this should never happen during calculation (they are either
@@ -1183,21 +1297,40 @@ void ScDocument::RemoveLookupCache( ScLookupCache & rCache )
auto it(cacheMap.aCacheMap.find(rCache.getRange()));
if (it != cacheMap.aCacheMap.end())
{
- ScLookupCache* pCache = (*it).second.release();
+ std::unique_ptr<ScLookupCache> xCache = std::move(it->second);
cacheMap.aCacheMap.erase(it);
assert(!IsThreadedGroupCalcInProgress()); // EndListeningArea() is not thread-safe
- EndListeningArea(pCache->getRange(), false, &rCache);
+ EndListeningArea(xCache->getRange(), false, &rCache);
return;
}
OSL_FAIL( "ScDocument::RemoveLookupCache: range not found in hash map");
}
+void ScDocument::RemoveSortedRangeCache( ScSortedRangeCache & rCache )
+{
+ // Data changes leading to this should never happen during calculation (they are either
+ // a result of user input or recalc). If it turns out this can be the case, locking is needed
+ // here and also in ScSortedRangeCache::Notify().
+ assert(!IsThreadedGroupCalcInProgress());
+ auto it(mxScSortedRangeCache->aCacheMap.find(rCache.getHashKey()));
+ if (it != mxScSortedRangeCache->aCacheMap.end())
+ {
+ std::unique_ptr<ScSortedRangeCache> xCache = std::move(it->second);
+ mxScSortedRangeCache->aCacheMap.erase(it);
+ assert(!IsThreadedGroupCalcInProgress()); // EndListeningArea() is not thread-safe
+ EndListeningArea(xCache->getRange(), false, &rCache);
+ return;
+ }
+ OSL_FAIL( "ScDocument::RemoveSortedRangeCache: range not found in hash map");
+}
+
void ScDocument::ClearLookupCaches()
{
assert(!IsThreadedGroupCalcInProgress());
GetNonThreadedContext().mxScLookupCache.reset();
+ mxScSortedRangeCache->aCacheMap.clear();
// Clear lookup cache in all interpreter-contexts in the (threaded/non-threaded) pools.
- ScInterpreterContextPool::ClearLookupCaches();
+ ScInterpreterContextPool::ClearLookupCaches(this);
}
bool ScDocument::IsCellInChangeTrack(const ScAddress &cell,Color *pColCellBorder)
@@ -1218,14 +1351,14 @@ bool ScDocument::IsCellInChangeTrack(const ScAddress &cell,Color *pColCellBorder
const ScBigRange& rBig = pAction->GetBigRange();
if ( rBig.aStart.Tab() == cell.Tab())
{
- ScRange aRange = rBig.MakeRange();
+ ScRange aRange = rBig.MakeRange( *this );
if ( eType == SC_CAT_DELETE_ROWS )
aRange.aEnd.SetRow( aRange.aStart.Row() );
else if ( eType == SC_CAT_DELETE_COLS )
aRange.aEnd.SetCol( aRange.aStart.Col() );
if (ScViewUtil::IsActionShown( *pAction, *pSettings, *this ) )
{
- if (aRange.In(cell))
+ if (aRange.Contains(cell))
{
if (pColCellBorder != nullptr)
{
@@ -1242,10 +1375,10 @@ bool ScDocument::IsCellInChangeTrack(const ScAddress &cell,Color *pColCellBorder
GetFromRange().aStart.Tab() == cell.Col() )
{
ScRange aRange = static_cast<const ScChangeActionMove*>(pAction)->
- GetFromRange().MakeRange();
+ GetFromRange().MakeRange( *this );
if (ScViewUtil::IsActionShown( *pAction, *pSettings, *this ) )
{
- if (aRange.In(cell))
+ if (aRange.Contains(cell))
{
if (pColCellBorder != nullptr)
{
@@ -1285,12 +1418,12 @@ void ScDocument::GetCellChangeTrackNote( const ScAddress &aCellPos, OUString &aT
const ScBigRange& rBig = pAction->GetBigRange();
if ( rBig.aStart.Tab() == aCellPos.Tab())
{
- ScRange aRange = rBig.MakeRange();
+ ScRange aRange = rBig.MakeRange( *this );
if ( eType == SC_CAT_DELETE_ROWS )
aRange.aEnd.SetRow( aRange.aStart.Row() );
else if ( eType == SC_CAT_DELETE_COLS )
aRange.aEnd.SetCol( aRange.aStart.Col() );
- if ( aRange.In( aCellPos ) )
+ if ( aRange.Contains( aCellPos ) )
{
pFound = pAction; // the last wins
switch ( eType )
@@ -1310,8 +1443,8 @@ void ScDocument::GetCellChangeTrackNote( const ScAddress &aCellPos, OUString &aT
{
ScRange aRange =
static_cast<const ScChangeActionMove*>(pAction)->
- GetFromRange().MakeRange();
- if ( aRange.In( aCellPos ) )
+ GetFromRange().MakeRange( *this );
+ if ( aRange.Contains( aCellPos ) )
{
pFound = pAction;
}
@@ -1334,9 +1467,9 @@ void ScDocument::GetCellChangeTrackNote( const ScAddress &aCellPos, OUString &aT
DateTime aDT = pFound->GetDateTime();
aTrackText = pFound->GetUser();
aTrackText += ", ";
- aTrackText += ScGlobal::getLocaleDataPtr()->getDate(aDT);
+ aTrackText += ScGlobal::getLocaleData().getDate(aDT);
aTrackText += " ";
- aTrackText += ScGlobal::getLocaleDataPtr()->getTime(aDT);
+ aTrackText += ScGlobal::getLocaleData().getTime(aDT);
aTrackText += ":\n";
OUString aComStr = pFound->GetComment();
if(!aComStr.isEmpty())
@@ -1344,7 +1477,7 @@ void ScDocument::GetCellChangeTrackNote( const ScAddress &aCellPos, OUString &aT
aTrackText += aComStr;
aTrackText += "\n( ";
}
- pFound->GetDescription( aTrackText, *this );
+ aTrackText = pFound->GetDescription( *this );
if (!aComStr.isEmpty())
{
aTrackText += ")";
diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx
index 8d6f6a2baadf..e31c111a3786 100644
--- a/sc/source/core/data/documen3.cxx
+++ b/sc/source/core/data/documen3.cxx
@@ -17,6 +17,7 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
+#include <sal/types.h>
#include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
#include <com/sun/star/sheet/TableValidationVisibility.hpp>
#include <scitems.hxx>
@@ -24,17 +25,18 @@
#include <svl/srchitem.hxx>
#include <sfx2/linkmgr.hxx>
#include <sfx2/bindings.hxx>
-#include <sfx2/objsh.hxx>
#include <sfx2/viewsh.hxx>
#include <vcl/svapp.hxx>
#include <osl/thread.hxx>
#include <osl/diagnose.h>
+#include <tools/duration.hxx>
#include <document.hxx>
#include <attrib.hxx>
#include <table.hxx>
#include <rangenam.hxx>
#include <dbdata.hxx>
#include <docpool.hxx>
+#include <docsh.hxx>
#include <poolhelp.hxx>
#include <rangelst.hxx>
#include <chartlock.hxx>
@@ -83,17 +85,23 @@ void sortAndRemoveDuplicates(std::vector<ScTypedStrData>& rStrings, bool bCaseSe
{
if (bCaseSens)
{
- std::sort(rStrings.begin(), rStrings.end(), ScTypedStrData::LessCaseSensitive());
+ std::stable_sort(rStrings.begin(), rStrings.end(), ScTypedStrData::LessCaseSensitive());
std::vector<ScTypedStrData>::iterator it =
std::unique(rStrings.begin(), rStrings.end(), ScTypedStrData::EqualCaseSensitive());
rStrings.erase(it, rStrings.end());
+ std::stable_sort(rStrings.begin(), rStrings.end(), ScTypedStrData::LessSortCaseSensitive());
}
else
{
- std::sort(rStrings.begin(), rStrings.end(), ScTypedStrData::LessCaseInsensitive());
+ std::stable_sort(rStrings.begin(), rStrings.end(), ScTypedStrData::LessCaseInsensitive());
std::vector<ScTypedStrData>::iterator it =
std::unique(rStrings.begin(), rStrings.end(), ScTypedStrData::EqualCaseInsensitive());
rStrings.erase(it, rStrings.end());
+ std::stable_sort(rStrings.begin(), rStrings.end(), ScTypedStrData::LessSortCaseInsensitive());
+ }
+ if (std::any_of(rStrings.begin(), rStrings.end(),
+ [](ScTypedStrData& rString) { return rString.IsHiddenByFilter(); })) {
+ std::stable_sort(rStrings.begin(), rStrings.end(), ScTypedStrData::LessHiddenRows());
}
}
@@ -102,7 +110,7 @@ void sortAndRemoveDuplicates(std::vector<ScTypedStrData>& rStrings, bool bCaseSe
void ScDocument::GetAllTabRangeNames(ScRangeName::TabNameCopyMap& rNames) const
{
ScRangeName::TabNameCopyMap aNames;
- for (SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); ++i)
+ for (SCTAB i = 0; i < GetTableCount(); ++i)
{
if (!maTabs[i])
// no more tables to iterate through.
@@ -118,34 +126,32 @@ void ScDocument::GetAllTabRangeNames(ScRangeName::TabNameCopyMap& rNames) const
rNames.swap(aNames);
}
-void ScDocument::SetAllRangeNames(const std::map<OUString, std::unique_ptr<ScRangeName>>& rRangeMap)
+void ScDocument::SetAllRangeNames(const std::map<OUString, ScRangeName>& rRangeMap)
{
- for (const auto& [rName, rxRangeName] : rRangeMap)
+ for (const auto& [rName, rRangeName] : rRangeMap)
{
if (rName == STR_GLOBAL_RANGE_NAME)
{
pRangeName.reset();
- const ScRangeName *const pName = rxRangeName.get();
- if (!pName->empty())
- pRangeName.reset( new ScRangeName( *pName ) );
+ if (!rRangeName.empty())
+ pRangeName.reset( new ScRangeName( rRangeName ) );
}
else
{
- const ScRangeName *const pName = rxRangeName.get();
SCTAB nTab;
bool bFound = GetTable(rName, nTab);
assert(bFound); (void)bFound; // fouled up?
- if (pName->empty())
+ if (rRangeName.empty())
SetRangeName( nTab, nullptr );
else
- SetRangeName( nTab, std::unique_ptr<ScRangeName>(new ScRangeName( *pName )) );
+ SetRangeName( nTab, std::unique_ptr<ScRangeName>(new ScRangeName( rRangeName )) );
}
}
}
void ScDocument::GetRangeNameMap(std::map<OUString, ScRangeName*>& aRangeNameMap)
{
- for (SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); ++i)
+ for (SCTAB i = 0; i < GetTableCount(); ++i)
{
if (!maTabs[i])
continue;
@@ -167,10 +173,9 @@ void ScDocument::GetRangeNameMap(std::map<OUString, ScRangeName*>& aRangeNameMap
ScRangeName* ScDocument::GetRangeName(SCTAB nTab) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return nullptr;
-
- return maTabs[nTab]->GetRangeName();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetRangeName();
+ return nullptr;
}
ScRangeName* ScDocument::GetRangeName() const
@@ -182,10 +187,8 @@ ScRangeName* ScDocument::GetRangeName() const
void ScDocument::SetRangeName(SCTAB nTab, std::unique_ptr<ScRangeName> pNew)
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return;
-
- return maTabs[nTab]->SetRangeName(std::move(pNew));
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetRangeName(std::move(pNew));
}
void ScDocument::SetRangeName( std::unique_ptr<ScRangeName> pNewRangeName )
@@ -207,7 +210,7 @@ bool ScDocument::IsAddressInRangeName( RangeNameScope eScope, const ScAddress& r
{
if (rEntry.second->IsValidReference(aNameRange))
{
- if (aNameRange.In(rAddress))
+ if (aNameRange.Contains(rAddress))
return true;
}
}
@@ -382,7 +385,7 @@ ScDPObject* ScDocument::GetDPAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab) const
sal_uInt16 nCount = pDPCollection->GetCount();
ScAddress aPos( nCol, nRow, nTab );
for (sal_uInt16 i=0; i<nCount; i++)
- if ( (*pDPCollection)[i].GetOutRange().In( aPos ) )
+ if ( (*pDPCollection)[i].GetOutRange().Contains( aPos ) )
return &(*pDPCollection)[i];
return nullptr;
@@ -397,7 +400,7 @@ ScDPObject* ScDocument::GetDPAtBlock( const ScRange & rBlock ) const
* approximation of MS Excels 'most recent' effect. */
sal_uInt16 i = pDPCollection->GetCount();
while ( i-- > 0 )
- if ( (*pDPCollection)[i].GetOutRange().In( rBlock ) )
+ if ( (*pDPCollection)[i].GetOutRange().Contains( rBlock ) )
return &(*pDPCollection)[i];
return nullptr;
@@ -425,70 +428,68 @@ void ScDocument::SetChartListenerCollection(
void ScDocument::SetScenario( SCTAB nTab, bool bFlag )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->SetScenario(bFlag);
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetScenario(bFlag);
}
bool ScDocument::IsScenario( SCTAB nTab ) const
{
- return ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] &&maTabs[nTab]->IsScenario();
+ const ScTable* pTable = FetchTable(nTab);
+ return pTable && pTable->IsScenario();
}
void ScDocument::SetScenarioData( SCTAB nTab, const OUString& rComment,
const Color& rColor, ScScenarioFlags nFlags )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->IsScenario())
+ if (ScTable* pTable = FetchTable(nTab); pTable && pTable->IsScenario())
{
- maTabs[nTab]->SetScenarioComment( rComment );
- maTabs[nTab]->SetScenarioColor( rColor );
- maTabs[nTab]->SetScenarioFlags( nFlags );
+ pTable->SetScenarioComment( rComment );
+ pTable->SetScenarioColor( rColor );
+ pTable->SetScenarioFlags( nFlags );
}
}
Color ScDocument::GetTabBgColor( SCTAB nTab ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetTabBgColor();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetTabBgColor();
return COL_AUTO;
}
void ScDocument::SetTabBgColor( SCTAB nTab, const Color& rColor )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->SetTabBgColor(rColor);
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetTabBgColor(rColor);
}
bool ScDocument::IsDefaultTabBgColor( SCTAB nTab ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetTabBgColor() == COL_AUTO;
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetTabBgColor() == COL_AUTO;
return true;
}
void ScDocument::GetScenarioData( SCTAB nTab, OUString& rComment,
Color& rColor, ScScenarioFlags& rFlags ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->IsScenario())
+ if (const ScTable* pTable = FetchTable(nTab); pTable && pTable->IsScenario())
{
- maTabs[nTab]->GetScenarioComment( rComment );
- rColor = maTabs[nTab]->GetScenarioColor();
- rFlags = maTabs[nTab]->GetScenarioFlags();
+ pTable->GetScenarioComment( rComment );
+ rColor = pTable->GetScenarioColor();
+ rFlags = pTable->GetScenarioFlags();
}
}
void ScDocument::GetScenarioFlags( SCTAB nTab, ScScenarioFlags& rFlags ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->IsScenario())
- rFlags = maTabs[nTab]->GetScenarioFlags();
+ if (const ScTable* pTable = FetchTable(nTab); pTable && pTable->IsScenario())
+ rFlags = pTable->GetScenarioFlags();
}
bool ScDocument::IsLinked( SCTAB nTab ) const
{
- return ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->IsLinked();
- // equivalent to
- //if (ValidTab(nTab) && pTab[nTab])
- // return pTab[nTab]->IsLinked();
- //return false;
+ const ScTable* pTable = FetchTable(nTab);
+ return pTable && pTable->IsLinked();
}
formula::FormulaGrammar::AddressConvention ScDocument::GetAddressConvention() const
@@ -503,58 +504,58 @@ void ScDocument::SetGrammar( formula::FormulaGrammar::Grammar eGram )
ScLinkMode ScDocument::GetLinkMode( SCTAB nTab ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetLinkMode();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetLinkMode();
return ScLinkMode::NONE;
}
OUString ScDocument::GetLinkDoc( SCTAB nTab ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetLinkDoc();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetLinkDoc();
return OUString();
}
OUString ScDocument::GetLinkFlt( SCTAB nTab ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetLinkFlt();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetLinkFlt();
return OUString();
}
OUString ScDocument::GetLinkOpt( SCTAB nTab ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetLinkOpt();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetLinkOpt();
return OUString();
}
OUString ScDocument::GetLinkTab( SCTAB nTab ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetLinkTab();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetLinkTab();
return OUString();
}
-sal_uLong ScDocument::GetLinkRefreshDelay( SCTAB nTab ) const
+sal_Int32 ScDocument::GetLinkRefreshDelay( SCTAB nTab ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetLinkRefreshDelay();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetLinkRefreshDelay();
return 0;
}
void ScDocument::SetLink( SCTAB nTab, ScLinkMode nMode, const OUString& rDoc,
const OUString& rFilter, const OUString& rOptions,
- const OUString& rTabName, sal_uLong nRefreshDelay )
+ const OUString& rTabName, sal_Int32 nRefreshDelay )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->SetLink( nMode, rDoc, rFilter, rOptions, rTabName, nRefreshDelay );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetLink(nMode, rDoc, rFilter, rOptions, rTabName, nRefreshDelay);
}
bool ScDocument::HasLink( std::u16string_view rDoc,
std::u16string_view rFilter, std::u16string_view rOptions ) const
{
- SCTAB nCount = static_cast<SCTAB>(maTabs.size());
+ SCTAB nCount = GetTableCount();
for (SCTAB i=0; i<nCount; i++)
if (maTabs[i]->IsLinked()
&& maTabs[i]->GetLinkDoc() == rDoc
@@ -575,8 +576,11 @@ bool ScDocument::LinkExternalTab( SCTAB& rTab, const OUString& aDocTab,
}
rTab = 0;
#if ENABLE_FUZZERS
+ (void)aDocTab;
+ (void)aFileName;
+ (void)aTabName;
return false;
-#endif
+#else
OUString aFilterName; // Is filled by the Loader
OUString aOptions; // Filter options
sal_uInt32 nLinkCnt = pExtDocOptions ? pExtDocOptions->GetDocSettings().mnLinkCnt : 0;
@@ -601,7 +605,7 @@ bool ScDocument::LinkExternalTab( SCTAB& rTab, const OUString& aDocTab,
else
return false;
- sal_uLong nRefreshDelay = 0;
+ sal_Int32 nRefreshDelay = 0;
bool bWasThere = HasLink( aFileName, aFilterName, aOptions );
SetLink( rTab, ScLinkMode::VALUE, aFileName, aFilterName, aOptions, aTabName, nRefreshDelay );
@@ -618,6 +622,7 @@ bool ScDocument::LinkExternalTab( SCTAB& rTab, const OUString& aDocTab,
pBindings->Invalidate( SID_LINKS );
}
return true;
+#endif
}
ScExternalRefManager* ScDocument::GetExternalRefManager() const
@@ -658,30 +663,29 @@ ScFormulaParserPool& ScDocument::GetFormulaParserPool() const
const ScSheetEvents* ScDocument::GetSheetEvents( SCTAB nTab ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetSheetEvents();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetSheetEvents();
return nullptr;
}
void ScDocument::SetSheetEvents( SCTAB nTab, std::unique_ptr<ScSheetEvents> pNew )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->SetSheetEvents( std::move(pNew) );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetSheetEvents( std::move(pNew) );
}
bool ScDocument::HasSheetEventScript( SCTAB nTab, ScSheetEventId nEvent, bool bWithVbaEvents ) const
{
- if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
+ if (const ScTable* pTable = FetchTable(nTab))
{
// check if any event handler script has been configured
- const ScSheetEvents* pEvents = maTabs[nTab]->GetSheetEvents();
+ const ScSheetEvents* pEvents = pTable->GetSheetEvents();
if ( pEvents && pEvents->GetScript( nEvent ) )
return true;
// check if VBA event handlers exist
if (bWithVbaEvents && mxVbaEvents.is()) try
{
- uno::Sequence< uno::Any > aArgs( 1 );
- aArgs[ 0 ] <<= nTab;
+ uno::Sequence< uno::Any > aArgs{ uno::Any(nTab) };
if (mxVbaEvents->hasVbaEventHandler( ScSheetEvents::GetVbaSheetEventId( nEvent ), aArgs ) ||
mxVbaEvents->hasVbaEventHandler( ScSheetEvents::GetVbaDocumentEventId( nEvent ), uno::Sequence< uno::Any >() ))
return true;
@@ -695,7 +699,7 @@ bool ScDocument::HasSheetEventScript( SCTAB nTab, ScSheetEventId nEvent, bool bW
bool ScDocument::HasAnySheetEventScript( ScSheetEventId nEvent, bool bWithVbaEvents ) const
{
- SCTAB nSize = static_cast<SCTAB>(maTabs.size());
+ SCTAB nSize = GetTableCount();
for (SCTAB nTab = 0; nTab < nSize; nTab++)
if (HasSheetEventScript( nTab, nEvent, bWithVbaEvents ))
return true;
@@ -704,7 +708,7 @@ bool ScDocument::HasAnySheetEventScript( ScSheetEventId nEvent, bool bWithVbaEve
bool ScDocument::HasAnyCalcNotification() const
{
- SCTAB nSize = static_cast<SCTAB>(maTabs.size());
+ SCTAB nSize = GetTableCount();
for (SCTAB nTab = 0; nTab < nSize; nTab++)
if (maTabs[nTab] && maTabs[nTab]->GetCalcNotification())
return true;
@@ -713,21 +717,21 @@ bool ScDocument::HasAnyCalcNotification() const
bool ScDocument::HasCalcNotification( SCTAB nTab ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetCalcNotification();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetCalcNotification();
return false;
}
void ScDocument::SetCalcNotification( SCTAB nTab )
{
// set only if not set before
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && !maTabs[nTab]->GetCalcNotification())
- maTabs[nTab]->SetCalcNotification(true);
+ if (ScTable* pTable = FetchTable(nTab) ; pTable && !pTable->GetCalcNotification())
+ pTable->SetCalcNotification(true);
}
void ScDocument::ResetCalcNotifications()
{
- SCTAB nSize = static_cast<SCTAB>(maTabs.size());
+ SCTAB nSize = GetTableCount();
for (SCTAB nTab = 0; nTab < nSize; nTab++)
if (maTabs[nTab] && maTabs[nTab]->GetCalcNotification())
maTabs[nTab]->SetCalcNotification(false);
@@ -737,46 +741,48 @@ ScOutlineTable* ScDocument::GetOutlineTable( SCTAB nTab, bool bCreate )
{
ScOutlineTable* pVal = nullptr;
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
- if (maTabs[nTab])
+ if (ScTable* pTable = FetchTable(nTab))
+ {
+ pVal = pTable->GetOutlineTable();
+ if (!pVal && bCreate)
{
- pVal = maTabs[nTab]->GetOutlineTable();
- if (!pVal && bCreate)
- {
- maTabs[nTab]->StartOutlineTable();
- pVal = maTabs[nTab]->GetOutlineTable();
- }
+ pTable->StartOutlineTable();
+ pVal = pTable->GetOutlineTable();
}
+ }
return pVal;
}
bool ScDocument::SetOutlineTable( SCTAB nTab, const ScOutlineTable* pNewOutline )
{
- return ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->SetOutlineTable(pNewOutline);
+ ScTable* pTable = FetchTable(nTab);
+ return pTable && pTable->SetOutlineTable(pNewOutline);
}
void ScDocument::DoAutoOutline( SCCOL nStartCol, SCROW nStartRow,
SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->DoAutoOutline( nStartCol, nStartRow, nEndCol, nEndRow );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->DoAutoOutline( nStartCol, nStartRow, nEndCol, nEndRow );
}
bool ScDocument::TestRemoveSubTotals( SCTAB nTab, const ScSubTotalParam& rParam )
{
- return ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->TestRemoveSubTotals( rParam );
+ ScTable* pTable = FetchTable(nTab);
+ return pTable && pTable->TestRemoveSubTotals(rParam);
}
void ScDocument::RemoveSubTotals( SCTAB nTab, ScSubTotalParam& rParam )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->RemoveSubTotals( rParam );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->RemoveSubTotals( rParam );
}
bool ScDocument::DoSubTotals( SCTAB nTab, ScSubTotalParam& rParam )
{
- return ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->DoSubTotals( rParam );
+ ScTable* pTable = FetchTable(nTab);
+ return pTable && pTable->DoSubTotals(rParam);
}
bool ScDocument::HasSubTotalCells( const ScRange& rRange )
@@ -799,7 +805,7 @@ bool ScDocument::HasSubTotalCells( const ScRange& rRange )
*/
void ScDocument::CopyUpdated( ScDocument* pPosDoc, ScDocument* pDestDoc )
{
- SCTAB nCount = static_cast<SCTAB>(maTabs.size());
+ SCTAB nCount = GetTableCount();
for (SCTAB nTab=0; nTab<nCount; nTab++)
if (maTabs[nTab] && pPosDoc->maTabs[nTab] && pDestDoc->maTabs[nTab])
maTabs[nTab]->CopyUpdated( pPosDoc->maTabs[nTab].get(), pDestDoc->maTabs[nTab].get() );
@@ -807,8 +813,7 @@ void ScDocument::CopyUpdated( ScDocument* pPosDoc, ScDocument* pDestDoc )
void ScDocument::CopyScenario( SCTAB nSrcTab, SCTAB nDestTab, bool bNewScenario )
{
- if (!(ValidTab(nSrcTab) && ValidTab(nDestTab) && nSrcTab < static_cast<SCTAB>(maTabs.size())
- && nDestTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nSrcTab] && maTabs[nDestTab]))
+ if (!HasTable(nSrcTab) || !HasTable(nDestTab))
return;
// Set flags correctly for active scenarios
@@ -817,7 +822,7 @@ void ScDocument::CopyScenario( SCTAB nSrcTab, SCTAB nDestTab, bool bNewScenario
// nDestTab is the target table
for ( SCTAB nTab = nDestTab+1;
- nTab< static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->IsScenario();
+ nTab < GetTableCount() && maTabs[nTab] && maTabs[nTab]->IsScenario();
nTab++ )
{
if ( maTabs[nTab]->IsActiveScenario() ) // Even if it's the same scenario
@@ -855,41 +860,42 @@ void ScDocument::MarkScenario( SCTAB nSrcTab, SCTAB nDestTab, ScMarkData& rDestM
if (bResetMark)
rDestMark.ResetMark();
- if (ValidTab(nSrcTab) && nSrcTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nSrcTab])
- maTabs[nSrcTab]->MarkScenarioIn( rDestMark, nNeededBits );
+ if (const ScTable* pTable = FetchTable(nSrcTab))
+ pTable->MarkScenarioIn(rDestMark, nNeededBits);
- rDestMark.SetAreaTab( nDestTab );
+ rDestMark.SetAreaTab( nDestTab);
}
bool ScDocument::HasScenarioRange( SCTAB nTab, const ScRange& rRange ) const
{
- return ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->HasScenarioRange( rRange );
+ const ScTable* pTable = FetchTable(nTab);
+ return pTable && pTable->HasScenarioRange(rRange);
}
const ScRangeList* ScDocument::GetScenarioRanges( SCTAB nTab ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetScenarioRanges();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetScenarioRanges();
return nullptr;
}
bool ScDocument::IsActiveScenario( SCTAB nTab ) const
{
- return ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->IsActiveScenario( );
+ const ScTable* pTable = FetchTable(nTab);
+ return pTable && pTable->IsActiveScenario();
}
void ScDocument::SetActiveScenario( SCTAB nTab, bool bActive )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->SetActiveScenario( bActive );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetActiveScenario( bActive );
}
bool ScDocument::TestCopyScenario( SCTAB nSrcTab, SCTAB nDestTab ) const
{
- if (ValidTab(nSrcTab) && nSrcTab < static_cast<SCTAB>(maTabs.size())
- && nDestTab < static_cast<SCTAB>(maTabs.size())&& ValidTab(nDestTab))
- return maTabs[nSrcTab]->TestCopyScenarioTo( maTabs[nDestTab].get() );
+ if (HasTable(nSrcTab) && HasTable(nDestTab))
+ return maTabs[nSrcTab]->TestCopyScenarioTo(maTabs[nDestTab].get());
OSL_FAIL("wrong table at TestCopyScenario");
return false;
@@ -1007,9 +1013,9 @@ void ScDocument::UpdateReference(
{
if (!ValidRange(rCxt.maRange) && !(rCxt.meMode == URM_INSDEL &&
((rCxt.mnColDelta < 0 && // convention from ScDocument::DeleteCol()
- rCxt.maRange.aStart.Col() == MAXCOLCOUNT && rCxt.maRange.aEnd.Col() == MAXCOLCOUNT) ||
+ rCxt.maRange.aStart.Col() == GetMaxColCount() && rCxt.maRange.aEnd.Col() == GetMaxColCount()) ||
(rCxt.mnRowDelta < 0 && // convention from ScDocument::DeleteRow()
- rCxt.maRange.aStart.Row() == GetSheetLimits().GetMaxRowCount() && rCxt.maRange.aEnd.Row() == GetSheetLimits().GetMaxRowCount()))))
+ rCxt.maRange.aStart.Row() == GetMaxRowCount() && rCxt.maRange.aEnd.Row() == GetMaxRowCount()))))
return;
std::unique_ptr<sc::ExpandRefsSwitch> pExpandRefsSwitch;
@@ -1118,7 +1124,7 @@ void ScDocument::UpdateTranspose( const ScAddress& rDestPos, ScDocument* pClipDo
ScAddress aDest = rDestPos;
SCTAB nClipTab = 0;
- for (SCTAB nDestTab=0; nDestTab< static_cast<SCTAB>(maTabs.size()) && maTabs[nDestTab]; nDestTab++)
+ for (SCTAB nDestTab = 0; nDestTab < GetTableCount() && maTabs[nDestTab]; nDestTab++)
if (rMark.GetTableSelect(nDestTab))
{
while (!pClipDoc->maTabs[nClipTab]) nClipTab = (nClipTab+1) % (MAXTAB+1);
@@ -1129,7 +1135,7 @@ void ScDocument::UpdateTranspose( const ScAddress& rDestPos, ScDocument* pClipDo
// Like UpdateReference
if (pRangeName)
pRangeName->UpdateTranspose( aSource, aDest ); // Before the cells!
- for (SCTAB i=0; i< static_cast<SCTAB>(maTabs.size()); i++)
+ for (SCTAB i = 0; i < GetTableCount(); i++)
if (maTabs[i])
maTabs[i]->UpdateTranspose( aSource, aDest, pUndoDoc );
@@ -1146,18 +1152,17 @@ void ScDocument::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
if (pRangeName)
pRangeName->UpdateGrow( rArea, nGrowX, nGrowY );
- for (SCTAB i=0; i< static_cast<SCTAB>(maTabs.size()) && maTabs[i]; i++)
+ for (SCTAB i = 0; i < GetTableCount() && maTabs[i]; i++)
maTabs[i]->UpdateGrow( rArea, nGrowX, nGrowY );
}
void ScDocument::Fill(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScProgress* pProgress, const ScMarkData& rMark,
- sal_uLong nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
+ sal_uInt64 nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
double nStepValue, double nMaxValue)
{
PutInOrder( nCol1, nCol2 );
PutInOrder( nRow1, nRow2 );
- ScRange aRange;
- rMark.GetMarkArea(aRange);
+ const ScRange& aRange = rMark.GetMarkArea();
SCTAB nMax = maTabs.size();
for (const auto& rTab : rMark)
{
@@ -1167,7 +1172,7 @@ void ScDocument::Fill(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScProg
{
maTabs[rTab]->Fill(nCol1, nRow1, nCol2, nRow2,
nFillCount, eFillDir, eFillCmd, eFillDateCmd,
- nStepValue, nMaxValue, pProgress);
+ nStepValue, tools::Duration(), nMaxValue, pProgress);
RefreshAutoFilter(aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(), rTab);
}
}
@@ -1176,7 +1181,7 @@ void ScDocument::Fill(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScProg
OUString ScDocument::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW nEndY )
{
SCTAB nTab = rSource.aStart.Tab();
- if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
+ if (nTab < GetTableCount() && maTabs[nTab])
return maTabs[nTab]->GetAutoFillPreview( rSource, nEndX, nEndY );
return OUString();
@@ -1200,14 +1205,11 @@ void ScDocument::AutoFormat( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SC
void ScDocument::GetAutoFormatData(SCTAB nTab, SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
ScAutoFormatData& rData)
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
+ if (ScTable* pTable = FetchTable(nTab))
{
- if (maTabs[nTab])
- {
- PutInOrder(nStartCol, nEndCol);
- PutInOrder(nStartRow, nEndRow);
- maTabs[nTab]->GetAutoFormatData(nStartCol, nStartRow, nEndCol, nEndRow, rData);
- }
+ PutInOrder(nStartCol, nEndCol);
+ PutInOrder(nStartRow, nEndRow);
+ pTable->GetAutoFormatData(nStartCol, nStartRow, nEndCol, nEndRow, rData);
}
}
@@ -1297,14 +1299,22 @@ void ScDocument::GetSearchAndReplaceStart( const SvxSearchItem& rSearchItem,
}
}
+// static
+bool ScDocument::IsEmptyCellSearch( const SvxSearchItem& rSearchItem )
+{
+ return !rSearchItem.GetPattern() && (rSearchItem.GetCellType() != SvxSearchCellType::NOTE)
+ && (rSearchItem.GetSearchOptions().searchString.isEmpty()
+ || (rSearchItem.GetRegExp() && rSearchItem.GetSearchOptions().searchString == "^$"));
+}
+
bool ScDocument::SearchAndReplace(
const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow, SCTAB& rTab,
const ScMarkData& rMark, ScRangeList& rMatchedRanges,
- OUString& rUndoStr, ScDocument* pUndoDoc)
+ OUString& rUndoStr, ScDocument* pUndoDoc, bool& bMatchedRangesWereClamped)
{
// FIXME: Manage separated marks per table!
bool bFound = false;
- if (rTab >= static_cast<SCTAB>(maTabs.size()))
+ if (rTab >= GetTableCount())
OSL_FAIL("table out of range");
if (ValidTab(rTab))
{
@@ -1325,7 +1335,7 @@ bool ScDocument::SearchAndReplace(
nCol = 0;
nRow = 0;
bFound |= maTabs[rMarkedTab]->SearchAndReplace(
- rSearchItem, nCol, nRow, rMark, rMatchedRanges, rUndoStr, pUndoDoc);
+ rSearchItem, nCol, nRow, rMark, rMatchedRanges, rUndoStr, pUndoDoc, bMatchedRangesWereClamped);
}
}
@@ -1343,7 +1353,7 @@ bool ScDocument::SearchAndReplace(
if (rMark.GetTableSelect(nTab))
{
bFound = maTabs[nTab]->SearchAndReplace(
- rSearchItem, nCol, nRow, rMark, rMatchedRanges, rUndoStr, pUndoDoc);
+ rSearchItem, nCol, nRow, rMark, rMatchedRanges, rUndoStr, pUndoDoc, bMatchedRangesWereClamped);
if (bFound)
{
rCol = nCol;
@@ -1360,7 +1370,7 @@ bool ScDocument::SearchAndReplace(
{
OString aPayload = OString::number(nTab);
if (SfxViewShell* pViewShell = SfxViewShell::Current())
- pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_SET_PART, aPayload.getStr());
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_SET_PART, aPayload);
}
}
}
@@ -1368,13 +1378,13 @@ bool ScDocument::SearchAndReplace(
}
else
{
- for (nTab = rTab; (nTab < static_cast<SCTAB>(maTabs.size())) && !bFound; nTab++)
+ for (nTab = rTab; (nTab < GetTableCount()) && !bFound; nTab++)
if (maTabs[nTab])
{
if (rMark.GetTableSelect(nTab))
{
bFound = maTabs[nTab]->SearchAndReplace(
- rSearchItem, nCol, nRow, rMark, rMatchedRanges, rUndoStr, pUndoDoc);
+ rSearchItem, nCol, nRow, rMark, rMatchedRanges, rUndoStr, pUndoDoc, bMatchedRangesWereClamped);
if (bFound)
{
rCol = nCol;
@@ -1391,7 +1401,7 @@ bool ScDocument::SearchAndReplace(
{
OString aPayload = OString::number(nTab);
if(SfxViewShell* pViewShell = SfxViewShell::Current())
- pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_SET_PART, aPayload.getStr());
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_SET_PART, aPayload);
}
}
}
@@ -1407,8 +1417,8 @@ bool ScDocument::SearchAndReplace(
*/
bool ScDocument::UpdateOutlineCol( SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bShow )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->UpdateOutlineCol( nStartCol, nEndCol, bShow );
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->UpdateOutlineCol(nStartCol, nEndCol, bShow);
OSL_FAIL("missing tab");
return false;
@@ -1416,8 +1426,8 @@ bool ScDocument::UpdateOutlineCol( SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, b
bool ScDocument::UpdateOutlineRow( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bShow )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->UpdateOutlineRow( nStartRow, nEndRow, bShow );
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->UpdateOutlineRow(nStartRow, nEndRow, bShow);
OSL_FAIL("missing tab");
return false;
@@ -1427,66 +1437,61 @@ void ScDocument::Sort(
SCTAB nTab, const ScSortParam& rSortParam, bool bKeepQuery, bool bUpdateRefs,
ScProgress* pProgress, sc::ReorderParam* pUndo )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
+ if (ScTable* pTable = FetchTable(nTab))
{
bool bOldEnableIdle = IsIdleEnabled();
EnableIdle(false);
- maTabs[nTab]->Sort(rSortParam, bKeepQuery, bUpdateRefs, pProgress, pUndo);
+ pTable->Sort(rSortParam, bKeepQuery, bUpdateRefs, pProgress, pUndo);
EnableIdle(bOldEnableIdle);
}
}
void ScDocument::Reorder( const sc::ReorderParam& rParam )
{
- ScTable* pTab = FetchTable(rParam.maSortRange.aStart.Tab());
- if (!pTab)
+ ScTable* pTable = FetchTable(rParam.maSortRange.aStart.Tab());
+ if (!pTable)
return;
bool bOldEnableIdle = IsIdleEnabled();
EnableIdle(false);
- pTab->Reorder(rParam);
+ pTable->Reorder(rParam);
EnableIdle(bOldEnableIdle);
}
void ScDocument::PrepareQuery( SCTAB nTab, ScQueryParam& rQueryParam )
{
- if( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->PrepareQuery(rQueryParam);
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->PrepareQuery(rQueryParam);
else
{
OSL_FAIL("missing tab");
- return;
}
}
SCSIZE ScDocument::Query(SCTAB nTab, const ScQueryParam& rQueryParam, bool bKeepSub)
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->Query(rQueryParam, bKeepSub);
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->Query(rQueryParam, bKeepSub);
OSL_FAIL("missing tab");
return 0;
}
-void ScDocument::GetUpperCellString(SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rStr)
+OUString ScDocument::GetUpperCellString(SCCOL nCol, SCROW nRow, SCTAB nTab)
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->GetUpperCellString( nCol, nRow, rStr );
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->GetUpperCellString( nCol, nRow );
else
- rStr.clear();
+ return OUString();
}
bool ScDocument::CreateQueryParam( const ScRange& rRange, ScQueryParam& rQueryParam )
{
- ScTable* pTab = FetchTable(rRange.aStart.Tab());
- if (!pTab)
- {
- OSL_FAIL("missing tab");
- return false;
- }
+ if (ScTable* pTable = FetchTable(rRange.aStart.Tab()))
+ return pTable->CreateQueryParam(rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(), rQueryParam);
- return pTab->CreateQueryParam(
- rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(), rQueryParam);
+ OSL_FAIL("missing tab");
+ return false;
}
bool ScDocument::HasAutoFilter( SCCOL nCurCol, SCROW nCurRow, SCTAB nCurTab )
@@ -1524,20 +1529,23 @@ bool ScDocument::HasAutoFilter( SCCOL nCurCol, SCROW nCurRow, SCTAB nCurTab )
bool ScDocument::HasColHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
SCTAB nTab )
{
- return ValidTab(nTab) && maTabs[nTab] && maTabs[nTab]->HasColHeader( nStartCol, nStartRow, nEndCol, nEndRow );
+ ScTable* pTable = FetchTable(nTab);
+ return pTable && pTable->HasColHeader(nStartCol, nStartRow, nEndCol, nEndRow);
}
bool ScDocument::HasRowHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
SCTAB nTab )
{
- return ValidTab(nTab) && maTabs[nTab] && maTabs[nTab]->HasRowHeader( nStartCol, nStartRow, nEndCol, nEndRow );
+ ScTable* pTable = FetchTable(nTab);
+ return pTable && pTable->HasRowHeader(nStartCol, nStartRow, nEndCol, nEndRow);
}
void ScDocument::GetFilterSelCount( SCCOL nCol, SCROW nRow, SCTAB nTab, SCSIZE& nSelected, SCSIZE& nTotal )
{
nSelected = 0;
nTotal = 0;
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
+
+ if (HasTable(nTab))
{
ScDBData* pDBData = GetDBAtCursor( nCol, nRow, nTab, ScDBDataPortion::AREA );
if( pDBData && pDBData->HasAutoFilter() )
@@ -1551,7 +1559,7 @@ void ScDocument::GetFilterSelCount( SCCOL nCol, SCROW nRow, SCTAB nTab, SCSIZE&
void ScDocument::GetFilterEntries(
SCCOL nCol, SCROW nRow, SCTAB nTab, ScFilterEntries& rFilterEntries )
{
- if ( !(ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && pDBCollection) )
+ if (!HasTable(nTab) || !pDBCollection)
return;
ScDBData* pDBData = pDBCollection->GetDBAtCursor(nCol, nRow, nTab, ScDBDataPortion::AREA); //!??
@@ -1604,10 +1612,10 @@ void ScDocument::GetFilterEntriesArea(
SCCOL nCol, SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bCaseSens,
ScFilterEntries& rFilterEntries )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
+ if (ScTable* pTable = FetchTable(nTab))
{
- maTabs[nTab]->GetFilterEntries( nCol, nStartRow, nEndRow, rFilterEntries, true );
- sortAndRemoveDuplicates( rFilterEntries.maStrData, bCaseSens);
+ pTable->GetFilterEntries(nCol, nStartRow, nEndRow, rFilterEntries, true);
+ sortAndRemoveDuplicates(rFilterEntries.maStrData, bCaseSens);
}
}
@@ -1637,10 +1645,7 @@ void ScDocument::GetDataEntries(
}
}
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()))
- return;
-
- if (!maTabs[nTab])
+ if (!HasTable(nTab))
return;
std::set<ScTypedStrData> aStrings;
@@ -1661,7 +1666,7 @@ void ScDocument::GetFormulaEntries( ScTypedCaseStrSet& rStrings )
if ( pRangeName )
{
for (const auto& rEntry : *pRangeName)
- rStrings.insert(ScTypedStrData(rEntry.second->GetName(), 0.0, ScTypedStrData::Name));
+ rStrings.insert(ScTypedStrData(rEntry.second->GetName(), 0.0, 0.0, ScTypedStrData::Name));
}
// Database collection
@@ -1669,7 +1674,7 @@ void ScDocument::GetFormulaEntries( ScTypedCaseStrSet& rStrings )
{
const ScDBCollection::NamedDBs& rDBs = pDBCollection->getNamedDBs();
for (const auto& rxDB : rDBs)
- rStrings.insert(ScTypedStrData(rxDB->GetName(), 0.0, ScTypedStrData::DbName));
+ rStrings.insert(ScTypedStrData(rxDB->GetName(), 0.0, 0.0, ScTypedStrData::DbName));
}
// Content of name ranges
@@ -1692,7 +1697,7 @@ void ScDocument::GetFormulaEntries( ScTypedCaseStrSet& rStrings )
continue;
OUString aStr = aIter.getString();
- rStrings.insert(ScTypedStrData(aStr, 0.0, ScTypedStrData::Header));
+ rStrings.insert(ScTypedStrData(aStr, 0.0, 0.0, ScTypedStrData::Header));
}
}
}
@@ -1707,7 +1712,7 @@ tools::Rectangle ScDocument::GetEmbeddedRect() const // 1/100 mm
{
tools::Rectangle aRect;
ScTable* pTable = nullptr;
- if ( aEmbedRange.aStart.Tab() < static_cast<SCTAB>(maTabs.size()) )
+ if (aEmbedRange.aStart.Tab() < GetTableCount())
pTable = maTabs[aEmbedRange.aStart.Tab()].get();
else
OSL_FAIL("table out of range");
@@ -1728,10 +1733,7 @@ tools::Rectangle ScDocument::GetEmbeddedRect() const // 1/100 mm
aRect.SetBottom( aRect.Top() );
aRect.AdjustBottom(pTable->GetRowHeight( aEmbedRange.aStart.Row(), aEmbedRange.aEnd.Row()) );
- aRect.SetLeft( static_cast<tools::Long>( aRect.Left() * HMM_PER_TWIPS ) );
- aRect.SetRight( static_cast<tools::Long>( aRect.Right() * HMM_PER_TWIPS ) );
- aRect.SetTop( static_cast<tools::Long>( aRect.Top() * HMM_PER_TWIPS ) );
- aRect.SetBottom( static_cast<tools::Long>( aRect.Bottom() * HMM_PER_TWIPS ) );
+ aRect = o3tl::convert(aRect, o3tl::Length::twip, o3tl::Length::mm100);
}
return aRect;
}
@@ -1798,7 +1800,7 @@ static bool lcl_AddTwipsWhile( tools::Long & rTwips, tools::Long nStopTwips, SCR
ScRange ScDocument::GetRange( SCTAB nTab, const tools::Rectangle& rMMRect, bool bHiddenAsZero ) const
{
ScTable* pTable = nullptr;
- if (nTab < static_cast<SCTAB>(maTabs.size()))
+ if (nTab < GetTableCount())
pTable = maTabs[nTab].get();
else
OSL_FAIL("table out of range");
@@ -1808,7 +1810,7 @@ ScRange ScDocument::GetRange( SCTAB nTab, const tools::Rectangle& rMMRect, bool
return ScRange();
}
- tools::Rectangle aPosRect = rMMRect;
+ tools::Rectangle aPosRect = o3tl::convert(rMMRect, o3tl::Length::mm100, o3tl::Length::twip);
if ( IsNegativePage( nTab ) )
ScDrawLayer::MirrorRectRTL( aPosRect ); // Always with positive (LTR) values
@@ -1818,13 +1820,13 @@ ScRange ScDocument::GetRange( SCTAB nTab, const tools::Rectangle& rMMRect, bool
bool bEnd;
nSize = 0;
- nTwips = static_cast<tools::Long>(aPosRect.Left() / HMM_PER_TWIPS);
+ nTwips = aPosRect.Left();
SCCOL nX1 = 0;
bEnd = false;
while (!bEnd)
{
- nAdd = static_cast<tools::Long>(pTable->GetColWidth(nX1, bHiddenAsZero));
+ nAdd = pTable->GetColWidth(nX1, bHiddenAsZero);
if (nSize+nAdd <= nTwips+1 && nX1<MaxCol())
{
nSize += nAdd;
@@ -1839,10 +1841,10 @@ ScRange ScDocument::GetRange( SCTAB nTab, const tools::Rectangle& rMMRect, bool
if (!aPosRect.IsEmpty())
{
bEnd = false;
- nTwips = static_cast<tools::Long>(aPosRect.Right() / HMM_PER_TWIPS);
+ nTwips = aPosRect.Right();
while (!bEnd)
{
- nAdd = static_cast<tools::Long>(pTable->GetColWidth(nX2, bHiddenAsZero));
+ nAdd = pTable->GetColWidth(nX2, bHiddenAsZero);
if (nSize+nAdd < nTwips && nX2<MaxCol())
{
nSize += nAdd;
@@ -1854,7 +1856,7 @@ ScRange ScDocument::GetRange( SCTAB nTab, const tools::Rectangle& rMMRect, bool
}
nSize = 0;
- nTwips = static_cast<tools::Long>(aPosRect.Top() / HMM_PER_TWIPS);
+ nTwips = aPosRect.Top();
SCROW nY1 = 0;
// Was if(nSize+nAdd<=nTwips+1) inside loop => if(nSize+nAdd<nTwips+2)
@@ -1864,7 +1866,7 @@ ScRange ScDocument::GetRange( SCTAB nTab, const tools::Rectangle& rMMRect, bool
SCROW nY2 = nY1;
if (!aPosRect.IsEmpty())
{
- nTwips = static_cast<tools::Long>(aPosRect.Bottom() / HMM_PER_TWIPS);
+ nTwips = aPosRect.Bottom();
// Was if(nSize+nAdd<nTwips) inside loop => if(nSize+nAdd<nTwips)
if (lcl_AddTwipsWhile( nSize, nTwips, nY2, MaxRow(), pTable, bHiddenAsZero) && nY2 < MaxRow())
++nY2; // original loop ended on last matched +1 unless that was rDoc.MaxRow()
@@ -1905,8 +1907,8 @@ bool ScDocument::IsDocEditable() const
bool ScDocument::IsTabProtected( SCTAB nTab ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->IsProtected();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->IsProtected();
OSL_FAIL("Wrong table number");
return false;
@@ -1914,23 +1916,21 @@ bool ScDocument::IsTabProtected( SCTAB nTab ) const
const ScTableProtection* ScDocument::GetTabProtection(SCTAB nTab) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetProtection();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetProtection();
return nullptr;
}
void ScDocument::SetTabProtection(SCTAB nTab, const ScTableProtection* pProtect)
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()))
- return;
-
- maTabs[nTab]->SetProtection(pProtect);
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetProtection(pProtect);
}
void ScDocument::CopyTabProtection(SCTAB nTabSrc, SCTAB nTabDest)
{
- if (!ValidTab(nTabSrc) || nTabSrc >= static_cast<SCTAB>(maTabs.size()) || nTabDest >= static_cast<SCTAB>(maTabs.size()) || !ValidTab(nTabDest))
+ if (!HasTable(nTabSrc) || !HasTable(nTabDest))
return;
maTabs[nTabDest]->SetProtection( maTabs[nTabSrc]->GetProtection() );
@@ -1947,7 +1947,8 @@ void ScDocument::SetDocOptions( const ScDocOptions& rOpt )
assert(pDocOptions && "No DocOptions! :-(");
*pDocOptions = rOpt;
- mxPoolHelper->SetFormTableOpt(rOpt);
+ if (mxPoolHelper)
+ mxPoolHelper->SetFormTableOpt(rOpt);
}
const ScViewOptions& ScDocument::GetViewOptions() const
@@ -1977,9 +1978,9 @@ void ScDocument::SetLanguage( LanguageType eLatin, LanguageType eCjk, LanguageTy
if ( mxPoolHelper.is() )
{
ScDocumentPool* pPool = mxPoolHelper->GetDocPool();
- pPool->SetPoolDefaultItem( SvxLanguageItem( eLanguage, ATTR_FONT_LANGUAGE ) );
- pPool->SetPoolDefaultItem( SvxLanguageItem( eCjkLanguage, ATTR_CJK_FONT_LANGUAGE ) );
- pPool->SetPoolDefaultItem( SvxLanguageItem( eCtlLanguage, ATTR_CTL_FONT_LANGUAGE ) );
+ pPool->SetUserDefaultItem( SvxLanguageItem( eLanguage, ATTR_FONT_LANGUAGE ) );
+ pPool->SetUserDefaultItem( SvxLanguageItem( eCjkLanguage, ATTR_CJK_FONT_LANGUAGE ) );
+ pPool->SetUserDefaultItem( SvxLanguageItem( eCtlLanguage, ATTR_CTL_FONT_LANGUAGE ) );
}
UpdateDrawLanguages(); // Set edit engine defaults in drawing layer pool
@@ -1987,7 +1988,7 @@ void ScDocument::SetLanguage( LanguageType eLatin, LanguageType eCjk, LanguageTy
tools::Rectangle ScDocument::GetMMRect( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, bool bHiddenAsZero ) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
+ if (!HasTable(nTab))
{
OSL_FAIL("GetMMRect: wrong table");
return tools::Rectangle(0,0,0,0);
@@ -2007,10 +2008,7 @@ tools::Rectangle ScDocument::GetMMRect( SCCOL nStartCol, SCROW nStartRow, SCCOL
aRect.AdjustRight(GetColWidth(i,nTab, bHiddenAsZero) );
aRect.AdjustBottom(GetRowHeight( nStartRow, nEndRow, nTab, bHiddenAsZero ) );
- aRect.SetLeft( static_cast<tools::Long>(aRect.Left() * HMM_PER_TWIPS) );
- aRect.SetRight( static_cast<tools::Long>(aRect.Right() * HMM_PER_TWIPS) );
- aRect.SetTop( static_cast<tools::Long>(aRect.Top() * HMM_PER_TWIPS) );
- aRect.SetBottom( static_cast<tools::Long>(aRect.Bottom() * HMM_PER_TWIPS) );
+ aRect = o3tl::convert(aRect, o3tl::Length::twip, o3tl::Length::mm100);
if ( IsNegativePage( nTab ) )
ScDrawLayer::MirrorRectRTL( aRect );
@@ -2028,13 +2026,14 @@ void ScDocument::SetClipOptions(std::unique_ptr<ScClipOptions> pClipOptions)
mpClipOptions = std::move(pClipOptions);
}
-void ScDocument::DoMergeContents( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
- SCCOL nEndCol, SCROW nEndRow )
+void ScDocument::DoMergeContents( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
{
OUStringBuffer aTotal;
OUString aCellStr;
SCCOL nCol;
SCROW nRow;
+ ScCellValue aCell;
for (nRow=nStartRow; nRow<=nEndRow; nRow++)
for (nCol=nStartCol; nCol<=nEndCol; nCol++)
{
@@ -2044,16 +2043,22 @@ void ScDocument::DoMergeContents( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
if (!aTotal.isEmpty())
aTotal.append(' ');
aTotal.append(aCellStr);
+ ScAddress aPos(nCol, nRow, nTab);
+ if ((GetCellType(aPos) == CELLTYPE_EDIT) && aCell.isEmpty())
+ aCell = ScRefCellValue(*this, aPos);
}
if (nCol != nStartCol || nRow != nStartRow)
SetString(nCol,nRow,nTab,"");
}
- SetString(nStartCol,nStartRow,nTab,aTotal.makeStringAndClear());
+ if (aCell.isEmpty() || !GetString(nStartCol, nStartRow, nTab).isEmpty())
+ SetString(nStartCol, nStartRow, nTab, aTotal.makeStringAndClear());
+ else
+ aCell.release(*this, ScAddress(nStartCol, nStartRow, nTab));
}
-void ScDocument::DoEmptyBlock( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
- SCCOL nEndCol, SCROW nEndRow )
+void ScDocument::DoEmptyBlock( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
{
SCCOL nCol;
SCROW nRow;
@@ -2065,8 +2070,8 @@ void ScDocument::DoEmptyBlock( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
}
}
-void ScDocument::DoMerge( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
- SCCOL nEndCol, SCROW nEndRow, bool bDeleteCaptions )
+void ScDocument::DoMerge( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, bool bDeleteCaptions )
{
ScTable* pTab = FetchTable(nTab);
if (!pTab)
@@ -2094,37 +2099,36 @@ void ScDocument::RemoveMerge( SCCOL nCol, SCROW nRow, SCTAB nTab )
RemoveFlagsTab( nCol, nRow, nEndCol, nEndRow, nTab, ScMF::Hor | ScMF::Ver );
- const ScMergeAttr* pDefAttr = &mxPoolHelper->GetDocPool()->GetDefaultItem( ATTR_MERGE );
+ const ScMergeAttr* pDefAttr = &mxPoolHelper->GetDocPool()->GetUserOrPoolDefaultItem( ATTR_MERGE );
ApplyAttr( nCol, nRow, nTab, *pDefAttr );
}
void ScDocument::ExtendPrintArea( OutputDevice* pDev, SCTAB nTab,
SCCOL nStartCol, SCROW nStartRow, SCCOL& rEndCol, SCROW nEndRow ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->ExtendPrintArea( pDev, nStartCol, nStartRow, rEndCol, nEndRow );
+ if (HasTable(nTab))
+ maTabs[nTab]->ExtendPrintArea(pDev, nStartCol, nStartRow, rEndCol, nEndRow);
}
SCSIZE ScDocument::GetPatternCount( SCTAB nTab, SCCOL nCol ) const
{
- if( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetPatternCount( nCol );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetPatternCount( nCol );
else
return 0;
}
SCSIZE ScDocument::GetPatternCount( SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const
{
- if( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetPatternCount( nCol, nRow1, nRow2 );
- else
- return 0;
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetPatternCount(nCol, nRow1, nRow2);
+ return 0;
}
void ScDocument::ReservePatternCount( SCTAB nTab, SCCOL nCol, SCSIZE nReserve )
{
- if( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->ReservePatternCount( nCol, nReserve );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->ReservePatternCount(nCol, nReserve);
}
void ScDocument::GetSortParam( ScSortParam& rParam, SCTAB nTab )
diff --git a/sc/source/core/data/documen4.cxx b/sc/source/core/data/documen4.cxx
index aee431660d0a..107c7fe80c5d 100644
--- a/sc/source/core/data/documen4.cxx
+++ b/sc/source/core/data/documen4.cxx
@@ -17,14 +17,17 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
+#include <svl/numformat.hxx>
#include <svl/zforlist.hxx>
#include <svl/zformat.hxx>
#include <formula/token.hxx>
#include <sal/log.hxx>
-#include <unotools/configmgr.hxx>
+#include <comphelper/configuration.hxx>
#include <osl/diagnose.h>
+#include <o3tl/string_view.hxx>
#include <document.hxx>
+#include <docsh.hxx>
#include <table.hxx>
#include <globstr.hrc>
#include <scresid.hxx>
@@ -75,12 +78,11 @@ bool ScDocument::Solver(SCCOL nFCol, SCROW nFRow, SCTAB nFTab,
nX = 0.0;
if ( ValidColRow( nFCol, nFRow ) && ValidTab( nFTab ) &&
ValidColRow( nVCol, nVRow ) && ValidTab( nVTab ) &&
- nFTab < static_cast<SCTAB>( maTabs.size() ) && maTabs[nFTab] &&
- nVTab < static_cast<SCTAB>( maTabs.size() ) && maTabs[nVTab] )
+ nFTab < GetTableCount() && maTabs[nFTab] &&
+ nVTab < GetTableCount() && maTabs[nVTab] )
{
- CellType eFType, eVType;
- GetCellType(nFCol, nFRow, nFTab, eFType);
- GetCellType(nVCol, nVRow, nVTab, eVType);
+ CellType eFType = GetCellType(nFCol, nFRow, nFTab);
+ CellType eVType = GetCellType(nVCol, nVRow, nVTab);
// #i108005# convert target value to number using default format,
// as previously done in ScInterpreter::GetDouble
ScFormulaCell* pFormula = nullptr;
@@ -153,7 +155,7 @@ bool ScDocument::Solver(SCCOL nFCol, SCROW nFRow, SCTAB nFTab,
while ( !bDoneHorMove && !bHorMoveError && nHorIter++ < nHorMaxIter )
{
double fHorAngle = fHorStepAngle * static_cast<double>( nHorIter );
- double fHorTangent = ::rtl::math::tan(basegfx::deg2rad(fHorAngle));
+ double fHorTangent = std::tan(basegfx::deg2rad(fHorAngle));
sal_uInt16 nIdx = 0;
while( nIdx++ < 2 && !bDoneHorMove )
@@ -271,8 +273,14 @@ void ScDocument::InsertMatrixFormula(SCCOL nCol1, SCROW nRow1,
SAL_WARN("sc", "ScDocument::InsertMatrixFormula: No table marked");
return;
}
- if (utl::ConfigManager::IsFuzzing()) //just too slow
- return;
+ if (comphelper::IsFuzzing())
+ {
+ // just too slow
+ if (nCol2 - nCol1 > 64)
+ return;
+ if (nRow2 - nRow1 > 64)
+ return;
+ }
assert( ValidColRow( nCol1, nRow1) && ValidColRow( nCol2, nRow2));
SCTAB nTab1 = *rMark.begin();
@@ -284,7 +292,7 @@ void ScDocument::InsertMatrixFormula(SCCOL nCol1, SCROW nRow1,
else
pCell = new ScFormulaCell(*this, aPos, rFormula, eGram, ScMatrixMode::Formula);
pCell->SetMatColsRows( nCol2 - nCol1 + 1, nRow2 - nRow1 + 1 );
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -306,13 +314,11 @@ void ScDocument::InsertMatrixFormula(SCCOL nCol1, SCROW nRow1,
*pCell, *this, ScAddress(nCol1, nRow1, rTab), ScCloneFlags::StartListening));
}
- ScAddress aBasePos(nCol1, nRow1, nTab1);
ScSingleRefData aRefData;
aRefData.InitFlags();
- aRefData.SetColRel( true );
- aRefData.SetRowRel( true );
- aRefData.SetTabRel( true );
- aRefData.SetAddress(GetSheetLimits(), aBasePos, aBasePos);
+ aRefData.SetRelCol(0);
+ aRefData.SetRelRow(0);
+ aRefData.SetRelTab(0); // 2D matrix, always same sheet
ScTokenArray aArr(*this); // consists only of one single reference token.
formula::FormulaToken* t = aArr.AddMatrixSingleReference(aRefData);
@@ -326,27 +332,22 @@ void ScDocument::InsertMatrixFormula(SCCOL nCol1, SCROW nRow1,
if (!pTab)
continue;
- if (nTab != nTab1)
- {
- aRefData.SetRelTab(nTab - aBasePos.Tab());
- *t->GetSingleRef() = aRefData;
- }
-
- for (SCCOL nCol : GetColumnsRange(nTab1, nCol1, nCol2))
+ for (SCCOL nCol : GetWritableColumnsRange(nTab, nCol1, nCol2))
{
+ aRefData.SetRelCol(nCol1 - nCol);
for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
{
if (nCol == nCol1 && nRow == nRow1)
// Skip the base position.
continue;
- // Token array must be cloned so that each formula cell receives its own copy.
- aPos = ScAddress(nCol, nRow, nTab);
// Reference in each cell must point to the origin cell relative to the current cell.
- aRefData.SetAddress(GetSheetLimits(), aBasePos, aPos);
+ aRefData.SetRelRow(nRow1 - nRow);
*t->GetSingleRef() = aRefData;
- std::unique_ptr<ScTokenArray> pTokArr(aArr.Clone());
- pCell = new ScFormulaCell(*this, aPos, *pTokArr, eGram, ScMatrixMode::Reference);
+ // Token array must be cloned so that each formula cell receives its own copy.
+ ScTokenArray aTokArr(aArr.CloneValue());
+ aPos = ScAddress(nCol, nRow, nTab);
+ pCell = new ScFormulaCell(*this, aPos, aTokArr, eGram, ScMatrixMode::Reference);
pTab->SetFormulaCell(nCol, nRow, pCell);
}
}
@@ -365,7 +366,7 @@ void ScDocument::InsertTableOp(const ScTabOpParam& rParam, // multiple (repeate
SCROW k;
i = 0;
bool bStop = false;
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -386,19 +387,18 @@ void ScDocument::InsertTableOp(const ScTabOpParam& rParam, // multiple (repeate
}
ScRefAddress aRef;
- OUStringBuffer aForString;
- aForString.append('=');
- aForString.append(ScCompiler::GetNativeSymbol(ocTableOp));
- aForString.append(ScCompiler::GetNativeSymbol( ocOpen));
+ OUStringBuffer aForString("="
+ + ScCompiler::GetNativeSymbol(ocTableOp)
+ + ScCompiler::GetNativeSymbol( ocOpen));
const OUString& sSep = ScCompiler::GetNativeSymbol( ocSep);
if (rParam.meMode == ScTabOpParam::Column) // column only
{
aRef.Set( rParam.aRefFormulaCell.GetAddress(), true, false, false );
- aForString.append(aRef.GetRefString(*this, nTab1));
- aForString.append(sSep);
- aForString.append(rParam.aRefColCell.GetRefString(*this, nTab1));
- aForString.append(sSep);
+ aForString.append(aRef.GetRefString(*this, nTab1)
+ + sSep
+ + rParam.aRefColCell.GetRefString(*this, nTab1)
+ + sSep);
aRef.Set( nCol1, nRow1, nTab1, false, true, true );
aForString.append(aRef.GetRefString(*this, nTab1));
nCol1++;
@@ -408,10 +408,10 @@ void ScDocument::InsertTableOp(const ScTabOpParam& rParam, // multiple (repeate
else if (rParam.meMode == ScTabOpParam::Row) // row only
{
aRef.Set( rParam.aRefFormulaCell.GetAddress(), false, true, false );
- aForString.append(aRef.GetRefString(*this, nTab1));
- aForString.append(sSep);
- aForString.append(rParam.aRefRowCell.GetRefString(*this, nTab1));
- aForString.append(sSep);
+ aForString.append(aRef.GetRefString(*this, nTab1)
+ + sSep
+ + rParam.aRefRowCell.GetRefString(*this, nTab1)
+ + sSep);
aRef.Set( nCol1, nRow1, nTab1, true, false, true );
aForString.append(aRef.GetRefString(*this, nTab1));
nRow1++;
@@ -420,15 +420,15 @@ void ScDocument::InsertTableOp(const ScTabOpParam& rParam, // multiple (repeate
}
else // both
{
- aForString.append(rParam.aRefFormulaCell.GetRefString(*this, nTab1));
- aForString.append(sSep);
- aForString.append(rParam.aRefColCell.GetRefString(*this, nTab1));
- aForString.append(sSep);
+ aForString.append(rParam.aRefFormulaCell.GetRefString(*this, nTab1)
+ + sSep
+ + rParam.aRefColCell.GetRefString(*this, nTab1)
+ + sSep);
aRef.Set( nCol1, nRow1 + 1, nTab1, false, true, true );
- aForString.append(aRef.GetRefString(*this, nTab1));
- aForString.append(sSep);
- aForString.append(rParam.aRefRowCell.GetRefString(*this, nTab1));
- aForString.append(sSep);
+ aForString.append(aRef.GetRefString(*this, nTab1)
+ + sSep
+ + rParam.aRefRowCell.GetRefString(*this, nTab1)
+ + sSep);
aRef.Set( nCol1 + 1, nRow1, nTab1, true, false, true );
aForString.append(aRef.GetRefString(*this, nTab1));
nCol1++; nRow1++;
@@ -439,7 +439,7 @@ void ScDocument::InsertTableOp(const ScTabOpParam& rParam, // multiple (repeate
formula::FormulaGrammar::GRAM_NATIVE, ScMatrixMode::NONE );
for( j = nCol1; j <= nCol2; j++ )
for( k = nRow1; k <= nRow2; k++ )
- for (i = 0; i < static_cast<SCTAB>(maTabs.size()); i++)
+ for (i = 0; i < GetTableCount(); i++)
{
for (const auto& rTab : rMark)
{
@@ -531,27 +531,25 @@ bool ScDocument::MarkUsedExternalReferences( const ScTokenArray& rArr, const ScA
bool ScDocument::GetNextSpellingCell(SCCOL& nCol, SCROW& nRow, SCTAB nTab,
bool bInSel, const ScMarkData& rMark) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetNextSpellingCell( nCol, nRow, bInSel, rMark );
- else
- return false;
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetNextSpellingCell( nCol, nRow, bInSel, rMark );
+ return false;
}
bool ScDocument::GetNextMarkedCell( SCCOL& rCol, SCROW& rRow, SCTAB nTab,
const ScMarkData& rMark )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetNextMarkedCell( rCol, rRow, rMark );
- else
- return false;
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->GetNextMarkedCell( rCol, rRow, rMark );
+ return false;
}
void ScDocument::ReplaceStyle(const SvxSearchItem& rSearchItem,
SCCOL nCol, SCROW nRow, SCTAB nTab,
const ScMarkData& rMark)
{
- if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->ReplaceStyle(rSearchItem, nCol, nRow, rMark, true/*bIsUndoP*/);
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->ReplaceStyle(rSearchItem, nCol, nRow, rMark, true/*bIsUndoP*/);
}
void ScDocument::CompileDBFormula()
@@ -589,21 +587,17 @@ void ScDocument::InvalidateTableArea()
sal_Int32 ScDocument::GetMaxStringLen( SCTAB nTab, SCCOL nCol,
SCROW nRowStart, SCROW nRowEnd, rtl_TextEncoding eCharSet ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetMaxStringLen( nCol, nRowStart, nRowEnd, eCharSet );
- else
- return 0;
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetMaxStringLen(nCol, nRowStart, nRowEnd, eCharSet);
+ return 0;
}
sal_Int32 ScDocument::GetMaxNumberStringLen( sal_uInt16& nPrecision, SCTAB nTab,
- SCCOL nCol,
- SCROW nRowStart, SCROW nRowEnd ) const
+ SCCOL nCol, SCROW nRowStart, SCROW nRowEnd ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetMaxNumberStringLen( nPrecision, nCol,
- nRowStart, nRowEnd );
- else
- return 0;
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetMaxNumberStringLen(nPrecision, nCol, nRowStart, nRowEnd);
+ return 0;
}
bool ScDocument::GetSelectionFunction( ScSubTotalFunc eFunc,
@@ -617,7 +611,7 @@ bool ScDocument::GetSelectionFunction( ScSubTotalFunc eFunc,
if (!aMark.IsMultiMarked() && !aMark.IsCellMarked(rCursor.Col(), rCursor.Row()))
aMark.SetMarkArea(rCursor);
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
ScMarkData::const_iterator itr = aMark.begin(), itrEnd = aMark.end();
for (; itr != itrEnd && *itr < nMax && !aData.getError(); ++itr)
@@ -640,8 +634,12 @@ double ScDocument::RoundValueAsShown( double fVal, sal_uInt32 nFormat, const ScI
SvNumFormatType nType = pFormat->GetMaskedType();
if (nType != SvNumFormatType::DATE && nType != SvNumFormatType::TIME && nType != SvNumFormatType::DATETIME )
{
- short nPrecision;
- if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
+ // MSVC doesn't recognize all paths init nPrecision and wails about
+ // "potentially uninitialized local variable 'nPrecision' used"
+ // so init to some random sensible value preserving all decimals.
+ short nPrecision = 20;
+ bool bStdPrecision = ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0);
+ if (!bStdPrecision)
{
sal_uInt16 nIdx = pFormat->GetSubformatIndex( fVal );
nPrecision = static_cast<short>(pFormat->GetFormatPrecision( nIdx ));
@@ -678,13 +676,18 @@ double ScDocument::RoundValueAsShown( double fVal, sal_uInt32 nFormat, const ScI
case SvNumFormatType::NUMBER:
case SvNumFormatType::CURRENCY:
{ // tdf#106253 Thousands divisors for format "0,"
- nPrecision -= pFormat->GetThousandDivisorPrecision( nIdx );
+ const sal_uInt16 nTD = pFormat->GetThousandDivisorPrecision( nIdx );
+ if (nTD == SvNumberFormatter::UNLIMITED_PRECISION)
+ // Format contains General keyword, handled below.
+ bStdPrecision = true;
+ else
+ nPrecision -= nTD;
break;
}
default: break;
}
}
- else
+ if (bStdPrecision)
{
nPrecision = static_cast<short>(GetDocOptions().GetStdPrecision());
// #i115512# no rounding for automatic decimals
@@ -703,18 +706,18 @@ double ScDocument::RoundValueAsShown( double fVal, sal_uInt32 nFormat, const ScI
// conditional formats and validation ranges
-sal_uLong ScDocument::AddCondFormat( std::unique_ptr<ScConditionalFormat> pNew, SCTAB nTab )
+sal_uInt32 ScDocument::AddCondFormat( std::unique_ptr<ScConditionalFormat> pNew, SCTAB nTab )
{
if(!pNew)
return 0;
- if(ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->AddCondFormat( std::move(pNew) );
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->AddCondFormat(std::move(pNew));
return 0;
}
-sal_uLong ScDocument::AddValidationEntry( const ScValidationData& rNew )
+sal_uInt32 ScDocument::AddValidationEntry( const ScValidationData& rNew )
{
if (rNew.IsEmpty())
return 0; // empty is always 0
@@ -725,20 +728,19 @@ sal_uLong ScDocument::AddValidationEntry( const ScValidationData& rNew )
pValidationList.reset(new ScValidationDataList);
}
- sal_uLong nMax = 0;
+ sal_uInt32 nMax = 0;
for( const auto& rxData : *pValidationList )
{
const ScValidationData* pData = rxData.get();
- sal_uLong nKey = pData->GetKey();
+ sal_uInt32 nKey = pData->GetKey();
if ( pData->EqualEntries( rNew ) )
return nKey;
if ( nKey > nMax )
nMax = nKey;
}
- // might be called from ScPatternAttr::PutInPool; thus clone (real copy)
-
- sal_uLong nNewKey = nMax + 1;
+ // might be called from ScPatternAttr::MigrateToDocument; thus clone (real copy)
+ sal_uInt32 nNewKey = nMax + 1;
std::unique_ptr<ScValidationData> pInsert(rNew.Clone(this));
pInsert->SetKey( nNewKey );
ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
@@ -753,8 +755,7 @@ const SfxPoolItem* ScDocument::GetEffItem(
if ( pPattern )
{
const SfxItemSet& rSet = pPattern->GetItemSet();
- const SfxPoolItem* pItem;
- if ( rSet.GetItemState( ATTR_CONDITIONAL, true, &pItem ) == SfxItemState::SET )
+ if ( rSet.GetItemState( ATTR_CONDITIONAL ) == SfxItemState::SET )
{
const ScCondFormatIndexes& rIndex = pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData();
ScConditionalFormatList* pCondFormList = GetCondFormList( nTab );
@@ -772,6 +773,7 @@ const SfxPoolItem* ScDocument::GetEffItem(
{
SfxStyleSheetBase* pStyleSheet = mxPoolHelper->GetStylePool()->Find(
aStyle, SfxStyleFamily::Para );
+ const SfxPoolItem* pItem = nullptr;
if ( pStyleSheet && pStyleSheet->GetItemSet().GetItemState(
nWhich, true, &pItem ) == SfxItemState::SET )
return pItem;
@@ -857,19 +859,18 @@ ScConditionalFormat* ScDocument::GetCondFormat(
ScConditionalFormatList* ScDocument::GetCondFormList(SCTAB nTab) const
{
- if(ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
+ if (HasTable(nTab))
return maTabs[nTab]->GetCondFormList();
-
return nullptr;
}
void ScDocument::SetCondFormList( ScConditionalFormatList* pList, SCTAB nTab )
{
- if(ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->SetCondFormList(pList);
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetCondFormList(pList);
}
-const ScValidationData* ScDocument::GetValidationEntry( sal_uLong nIndex ) const
+const ScValidationData* ScDocument::GetValidationEntry( sal_uInt32 nIndex ) const
{
if ( pValidationList )
return pValidationList->GetData( nIndex );
@@ -879,8 +880,8 @@ const ScValidationData* ScDocument::GetValidationEntry( sal_uLong nIndex ) const
void ScDocument::DeleteConditionalFormat(sal_uLong nOldIndex, SCTAB nTab)
{
- if(ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->DeleteConditionalFormat(nOldIndex);
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->DeleteConditionalFormat(nOldIndex);
}
bool ScDocument::HasDetectiveOperations() const
@@ -893,7 +894,7 @@ void ScDocument::AddDetectiveOperation( const ScDetOpData& rData )
if (!pDetOpList)
pDetOpList.reset(new ScDetOpList);
- pDetOpList->Append( new ScDetOpData( rData ) );
+ pDetOpList->Append( rData );
}
void ScDocument::ClearDetectiveOperations()
@@ -959,8 +960,8 @@ sal_uInt16 ScDocument::ColDifferences( SCCOL nThisCol, SCTAB nThisTab,
//TODO: optimize e.g. with iterator?
- sal_uLong nDif = 0;
- sal_uLong nUsed = 0;
+ sal_uInt64 nDif = 0;
+ sal_uInt64 nUsed = 0;
for (SCROW nThisRow=0; nThisRow<=nMaxRow; nThisRow++)
{
SCROW nOtherRow;
@@ -995,7 +996,7 @@ sal_uInt16 ScDocument::ColDifferences( SCCOL nThisCol, SCTAB nThisTab,
void ScDocument::FindOrder( SCCOLROW* pOtherRows, SCCOLROW nThisEndRow, SCCOLROW nOtherEndRow,
bool bColumns, ScDocument& rOtherDoc, SCTAB nThisTab, SCTAB nOtherTab,
- SCCOLROW nEndCol, const SCCOLROW* pTranslate, ScProgress* pProgress, sal_uLong nProAdd )
+ SCCOLROW nEndCol, const SCCOLROW* pTranslate, ScProgress* pProgress, sal_uInt64 nProAdd )
{
// bColumns=true: rows are columns and vice versa
@@ -1175,9 +1176,9 @@ void ScDocument::CompareDocument( ScDocument& rOtherDoc )
GetName( nThisTab, aTabName );
OUString aTemplate = ScResId(STR_PROGRESS_COMPARING);
sal_Int32 nIndex = 0;
- OUString aProText = aTemplate.getToken( 0, '#', nIndex ) +
+ OUString aProText = o3tl::getToken(aTemplate, 0, '#', nIndex ) +
aTabName +
- aTemplate.getToken( 0, '#', nIndex );
+ o3tl::getToken(aTemplate, 0, '#', nIndex );
ScProgress aProgress( GetDocumentShell(), aProText, 3*nThisEndRow, true ); // 2x FindOrder, 1x here
tools::Long nProgressStart = 2*nThisEndRow; // start for here
diff --git a/sc/source/core/data/documen5.cxx b/sc/source/core/data/documen5.cxx
index 1933601aa7db..8a592b63a1c0 100644
--- a/sc/source/core/data/documen5.cxx
+++ b/sc/source/core/data/documen5.cxx
@@ -24,12 +24,12 @@
#include <com/sun/star/chart2/data/XDataReceiver.hpp>
#include <com/sun/star/embed/XEmbeddedObject.hpp>
-#include <sfx2/objsh.hxx>
#include <svx/svditer.hxx>
#include <svx/svdoole2.hxx>
#include <svtools/embedhlp.hxx>
#include <document.hxx>
+#include <docsh.hxx>
#include <table.hxx>
#include <drwlayer.hxx>
#include <chartlis.hxx>
@@ -80,19 +80,20 @@ static void lcl_SetChartParameters( const uno::Reference< chart2::data::XDataRec
if ( !xReceiver.is() )
return;
- uno::Sequence< beans::PropertyValue > aArgs( 4 );
- aArgs[0] = beans::PropertyValue(
- "CellRangeRepresentation", -1,
- uno::makeAny( rRanges ), beans::PropertyState_DIRECT_VALUE );
- aArgs[1] = beans::PropertyValue(
- "HasCategories", -1,
- uno::makeAny( bHasCategories ), beans::PropertyState_DIRECT_VALUE );
- aArgs[2] = beans::PropertyValue(
- "FirstCellAsLabel", -1,
- uno::makeAny( bFirstCellAsLabel ), beans::PropertyState_DIRECT_VALUE );
- aArgs[3] = beans::PropertyValue(
- "DataRowSource", -1,
- uno::makeAny( eDataRowSource ), beans::PropertyState_DIRECT_VALUE );
+ uno::Sequence< beans::PropertyValue > aArgs{
+ beans::PropertyValue(
+ "CellRangeRepresentation", -1,
+ uno::Any( rRanges ), beans::PropertyState_DIRECT_VALUE ),
+ beans::PropertyValue(
+ "HasCategories", -1,
+ uno::Any( bHasCategories ), beans::PropertyState_DIRECT_VALUE ),
+ beans::PropertyValue(
+ "FirstCellAsLabel", -1,
+ uno::Any( bFirstCellAsLabel ), beans::PropertyState_DIRECT_VALUE ),
+ beans::PropertyValue(
+ "DataRowSource", -1,
+ uno::Any( eDataRowSource ), beans::PropertyState_DIRECT_VALUE )
+ };
xReceiver->setArguments( aArgs );
}
@@ -107,8 +108,8 @@ bool ScDocument::HasChartAtPoint( SCTAB nTab, const Point& rPos, OUString& rName
SdrObject* pObject = aIter.Next();
while (pObject)
{
- if ( pObject->GetObjIdentifier() == OBJ_OLE2 &&
- pObject->GetCurrentBoundRect().IsInside(rPos) )
+ if ( pObject->GetObjIdentifier() == SdrObjKind::OLE2 &&
+ pObject->GetCurrentBoundRect().Contains(rPos) )
{
// also Chart-Objects that are not in the Collection
@@ -151,7 +152,7 @@ uno::Reference< chart2::XChartDocument > ScDocument::GetChartByName( std::u16str
SdrObject* pObject = aIter.Next();
while (pObject)
{
- if ( pObject->GetObjIdentifier() == OBJ_OLE2 &&
+ if ( pObject->GetObjIdentifier() == SdrObjKind::OLE2 &&
static_cast<SdrOle2Obj*>(pObject)->GetPersistName() == rChartName )
{
xReturn.set( ScChartHelper::GetChartFromSdrObject( pObject ) );
@@ -189,12 +190,13 @@ void ScDocument::SetChartRanges( std::u16string_view rChartName, const ::std::ve
sal_Int32 nCount = static_cast<sal_Int32>( rRangesVector.size() );
uno::Sequence< OUString > aRangeStrings(nCount);
+ auto aRangeStringsRange = asNonConstRange(aRangeStrings);
for( sal_Int32 nN=0; nN<nCount; nN++ )
{
ScRangeList aScRangeList( rRangesVector[nN] );
OUString sRangeStr;
aScRangeList.Format( sRangeStr, ScRefFlags::RANGE_ABS_3D, *this, GetAddressConvention() );
- aRangeStrings[nN]=sRangeStr;
+ aRangeStringsRange[nN]=sRangeStr;
}
ScChartHelper::SetChartRanges( xChartDoc, aRangeStrings );
}
@@ -217,7 +219,7 @@ void ScDocument::GetOldChartParameters( std::u16string_view rName,
SdrObject* pObject = aIter.Next();
while (pObject)
{
- if ( pObject->GetObjIdentifier() == OBJ_OLE2 &&
+ if ( pObject->GetObjIdentifier() == SdrObjKind::OLE2 &&
static_cast<SdrOle2Obj*>(pObject)->GetPersistName() == rName )
{
uno::Reference< chart2::XChartDocument > xChartDoc( ScChartHelper::GetChartFromSdrObject( pObject ) );
@@ -229,7 +231,7 @@ void ScDocument::GetOldChartParameters( std::u16string_view rName,
OUString aRangesStr;
lcl_GetChartParameters( xChartDoc, aRangesStr, eDataRowSource, bHasCategories, bFirstCellAsLabel );
- rRanges.Parse( aRangesStr, *this );
+ rRanges.Parse( aRangesStr, *this, GetAddressConvention());
if ( eDataRowSource == chart::ChartDataRowSource_COLUMNS )
{
rRowHeaders = bHasCategories;
@@ -264,7 +266,7 @@ void ScDocument::UpdateChartArea( const OUString& rChartName,
SdrObject* pObject = aIter.Next();
while (pObject)
{
- if ( pObject->GetObjIdentifier() == OBJ_OLE2 &&
+ if ( pObject->GetObjIdentifier() == SdrObjKind::OLE2 &&
static_cast<SdrOle2Obj*>(pObject)->GetPersistName() == rChartName )
{
uno::Reference< chart2::XChartDocument > xChartDoc( ScChartHelper::GetChartFromSdrObject( pObject ) );
@@ -285,10 +287,8 @@ void ScDocument::UpdateChartArea( const OUString& rChartName,
// append to old ranges, keep other settings
aNewRanges = new ScRangeList;
- aNewRanges->Parse( aRangesStr, *this );
-
- for ( size_t nAdd = 0, nAddCount = rNewList->size(); nAdd < nAddCount; ++nAdd )
- aNewRanges->push_back( (*rNewList)[nAdd] );
+ aNewRanges->Parse( aRangesStr, *this, GetAddressConvention());
+ aNewRanges->insert( aNewRanges->begin(), rNewList->begin(), rNewList->end() );
}
else
{
@@ -313,7 +313,7 @@ void ScDocument::UpdateChartArea( const OUString& rChartName,
uno::Reference< chart2::data::XDataProvider > xDataProvider = new ScChart2DataProvider( this );
xReceiver->attachDataProvider( xDataProvider );
uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier(
- mpShell->GetModel(), uno::UNO_QUERY );
+ static_cast<cppu::OWeakObject*>(mpShell->GetModel()), uno::UNO_QUERY );
xReceiver->attachNumberFormatsSupplier( xNumberFormatsSupplier );
}
@@ -362,6 +362,9 @@ void ScDocument::UpdateChart( const OUString& rChartName )
void ScDocument::RestoreChartListener( const OUString& rName )
{
+ if (!pChartListenerCollection)
+ return;
+
// Read the data ranges from the chart object, and start listening to those ranges again
// (called when a chart is saved, because then it might be swapped out and stop listening itself).
@@ -450,7 +453,7 @@ void ScDocument::UpdateChartRef( UpdateRefMode eUpdateRefMode,
uno::Reference<embed::XEmbeddedObject> xIPObj =
FindOleObjectByName(pChartListener->GetName());
- svt::EmbeddedObjectRef::TryRunningState( xIPObj );
+ (void)svt::EmbeddedObjectRef::TryRunningState( xIPObj );
// After the change, chart keeps track of its own data source ranges,
// the listener doesn't need to listen anymore, except the chart has
@@ -496,7 +499,7 @@ void ScDocument::SetChartRangeList( std::u16string_view rChartName,
SdrObject* pObject = aIter.Next();
while (pObject)
{
- if ( pObject->GetObjIdentifier() == OBJ_OLE2 &&
+ if ( pObject->GetObjIdentifier() == SdrObjKind::OLE2 &&
static_cast<SdrOle2Obj*>(pObject)->GetPersistName() == rChartName )
{
uno::Reference< chart2::XChartDocument > xChartDoc( ScChartHelper::GetChartFromSdrObject( pObject ) );
@@ -525,11 +528,9 @@ void ScDocument::SetChartRangeList( std::u16string_view rChartName,
bool ScDocument::HasData( SCCOL nCol, SCROW nRow, SCTAB nTab )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab]
- && nCol < maTabs[nTab]->GetAllocatedColumnsCount())
- return maTabs[nTab]->HasData( nCol, nRow );
- else
- return false;
+ if (ScTable* pTable = FetchTable(nTab) ; pTable && nCol < pTable->GetAllocatedColumnsCount())
+ return pTable->HasData(nCol, nRow);
+ return false;
}
uno::Reference< embed::XEmbeddedObject >
@@ -551,7 +552,7 @@ uno::Reference< embed::XEmbeddedObject >
SdrObject* pObject = aIter.Next();
while (pObject)
{
- if ( pObject->GetObjIdentifier() == OBJ_OLE2 )
+ if ( pObject->GetObjIdentifier() == SdrObjKind::OLE2 )
{
SdrOle2Obj * pOleObject ( dynamic_cast< SdrOle2Obj * >( pObject ));
if( pOleObject &&
@@ -592,7 +593,7 @@ void ScDocument::UpdateChartListenerCollection()
for (SdrObject* pObject = aIter.Next(); pObject; pObject = aIter.Next())
{
- if ( pObject->GetObjIdentifier() != OBJ_OLE2 )
+ if ( pObject->GetObjIdentifier() != SdrObjKind::OLE2 )
continue;
OUString aObjName = static_cast<SdrOle2Obj*>(pObject)->GetPersistName();
diff --git a/sc/source/core/data/documen6.cxx b/sc/source/core/data/documen6.cxx
index a4b58131e29b..ef13ecb7aa6a 100644
--- a/sc/source/core/data/documen6.cxx
+++ b/sc/source/core/data/documen6.cxx
@@ -118,9 +118,9 @@ SvtScriptType ScDocument::GetCellScriptType( const ScAddress& rPos, sal_uInt32 n
const Color* pColor;
OUString aStr;
if( pCell )
- ScCellFormat::GetString(*pCell, nNumberFormat, aStr, &pColor, *mxPoolHelper->GetFormTable(), *this);
+ aStr = ScCellFormat::GetString(*pCell, nNumberFormat, &pColor, nullptr, *this);
else
- aStr = ScCellFormat::GetString(*this, rPos, nNumberFormat, &pColor, *mxPoolHelper->GetFormTable());
+ aStr = ScCellFormat::GetString(*this, rPos, nNumberFormat, &pColor, nullptr);
SvtScriptType nRet = GetStringScriptType( aStr );
@@ -146,7 +146,7 @@ SvtScriptType ScDocument::GetScriptType( SCCOL nCol, SCROW nRow, SCTAB nTab, con
if ( !pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData().empty() )
pCondSet = GetCondResult( nCol, nRow, nTab );
- sal_uInt32 nFormat = pPattern->GetNumberFormat( mxPoolHelper->GetFormTable(), pCondSet );
+ sal_uInt32 nFormat = pPattern->GetNumberFormat( GetFormatTable(), pCondSet );
return GetCellScriptType(aPos, nFormat, pCell);
}
@@ -183,7 +183,7 @@ public:
SvtScriptType ScDocument::GetRangeScriptType(
sc::ColumnBlockPosition& rBlockPos, const ScAddress& rPos, SCROW nLength )
{
- if (!TableExists(rPos.Tab()))
+ if (!HasTable(rPos.Tab()))
return SvtScriptType::NONE;
return maTabs[rPos.Tab()]->GetRangeScriptType(rBlockPos, rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
@@ -203,7 +203,7 @@ SvtScriptType ScDocument::GetRangeScriptType( const ScRangeList& rRanges )
}
ScriptTypeAggregator aAction(*this);
- aSet.executeAction(aAction);
+ aSet.executeAction(*this, aAction);
return aAction.getScriptType();
}
diff --git a/sc/source/core/data/documen7.cxx b/sc/source/core/data/documen7.cxx
index eaaaf285c4b8..f69585167c66 100644
--- a/sc/source/core/data/documen7.cxx
+++ b/sc/source/core/data/documen7.cxx
@@ -121,25 +121,40 @@ void ScDocument::Broadcast( const ScHint& rHint )
if ( eHardRecalcState == HardRecalcState::OFF )
{
ScBulkBroadcast aBulkBroadcast( pBASM.get(), rHint.GetId()); // scoped bulk broadcast
- bool bIsBroadcasted = false;
- SvtBroadcaster* pBC = GetBroadcaster(rHint.GetAddress());
- if ( pBC )
- {
- pBC->Broadcast( rHint );
- bIsBroadcasted = true;
- }
+ bool bIsBroadcasted = BroadcastHintInternal(rHint);
if ( pBASM->AreaBroadcast( rHint ) || bIsBroadcasted )
TrackFormulas( rHint.GetId() );
}
- if ( rHint.GetAddress() != BCA_BRDCST_ALWAYS )
+ if ( rHint.GetStartAddress() != BCA_BRDCST_ALWAYS )
{
- SCTAB nTab = rHint.GetAddress().Tab();
- if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
+ SCTAB nTab = rHint.GetStartAddress().Tab();
+ if (nTab < GetTableCount() && maTabs[nTab])
maTabs[nTab]->SetStreamValid(false);
}
}
+bool ScDocument::BroadcastHintInternal( const ScHint& rHint )
+{
+ bool bIsBroadcasted = false;
+ const ScAddress address(rHint.GetStartAddress());
+ SvtBroadcaster* pLastBC = nullptr;
+ // Process all broadcasters for the given row range.
+ for( SCROW nRow = 0; nRow < rHint.GetRowCount(); ++nRow )
+ {
+ ScAddress a(address);
+ a.SetRow(address.Row() + nRow);
+ SvtBroadcaster* pBC = GetBroadcaster(a);
+ if ( pBC && pBC != pLastBC )
+ {
+ pBC->Broadcast( rHint );
+ bIsBroadcasted = true;
+ pLastBC = pBC;
+ }
+ }
+ return bIsBroadcasted;
+}
+
void ScDocument::BroadcastCells( const ScRange& rRange, SfxHintId nHint, bool bBroadcastSingleBroadcasters )
{
PrepareFormulaCalc();
@@ -161,15 +176,13 @@ void ScDocument::BroadcastCells( const ScRange& rRange, SfxHintId nHint, bool bB
if (bBroadcastSingleBroadcasters)
{
- ScHint aHint(nHint, ScAddress());
-
for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
{
ScTable* pTab = FetchTable(nTab);
if (!pTab)
continue;
- bIsBroadcasted |= pTab->BroadcastBroadcasters( nCol1, nRow1, nCol2, nRow2, aHint);
+ bIsBroadcasted |= pTab->BroadcastBroadcasters( nCol1, nRow1, nCol2, nRow2, nHint);
}
}
@@ -210,8 +223,8 @@ void ScDocument::StartListeningCell( const ScAddress& rAddress,
{
OSL_ENSURE(pListener, "StartListeningCell: pListener Null");
SCTAB nTab = rAddress.Tab();
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->StartListening( rAddress, pListener );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->StartListening(rAddress, pListener);
}
void ScDocument::EndListeningCell( const ScAddress& rAddress,
@@ -219,28 +232,22 @@ void ScDocument::EndListeningCell( const ScAddress& rAddress,
{
OSL_ENSURE(pListener, "EndListeningCell: pListener Null");
SCTAB nTab = rAddress.Tab();
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->EndListening( rAddress, pListener );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->EndListening( rAddress, pListener );
}
void ScDocument::StartListeningCell(
sc::StartListeningContext& rCxt, const ScAddress& rPos, SvtListener& rListener )
{
- ScTable* pTab = FetchTable(rPos.Tab());
- if (!pTab)
- return;
-
- pTab->StartListening(rCxt, rPos, rListener);
+ if (ScTable* pTable = FetchTable(rPos.Tab()))
+ pTable->StartListening(rCxt, rPos, rListener);
}
void ScDocument::EndListeningCell(
sc::EndListeningContext& rCxt, const ScAddress& rPos, SvtListener& rListener )
{
- ScTable* pTab = FetchTable(rPos.Tab());
- if (!pTab)
- return;
-
- pTab->EndListening(rCxt, rPos, rListener);
+ if (ScTable* pTable = FetchTable(rPos.Tab()))
+ pTable->EndListening(rCxt, rPos, rListener);
}
void ScDocument::EndListeningFormulaCells( std::vector<ScFormulaCell*>& rCells )
@@ -318,11 +325,6 @@ void ScDocument::RemoveFromFormulaTree( ScFormulaCell* pCell )
}
}
-bool ScDocument::IsInFormulaTree( const ScFormulaCell* pCell ) const
-{
- return pCell->GetPrevious() || pFormulaTree == pCell;
-}
-
void ScDocument::CalcFormulaTree( bool bOnlyForced, bool bProgressBar, bool bSetAllDirty )
{
OSL_ENSURE( !IsCalculatingFormulaTree(), "CalcFormulaTree recursion" );
@@ -498,11 +500,6 @@ void ScDocument::RemoveFromFormulaTrack( ScFormulaCell* pCell )
--nFormulaTrackCount;
}
-bool ScDocument::IsInFormulaTrack( const ScFormulaCell* pCell ) const
-{
- return pCell->GetPreviousTrack() || pFormulaTrack == pCell;
-}
-
void ScDocument::FinalTrackFormulas( SfxHintId nHintId )
{
mbTrackFormulasPending = false;
@@ -540,32 +537,35 @@ void ScDocument::TrackFormulas( SfxHintId nHintId )
{
// outside the loop, check if any sheet has a "calculate" event script
bool bCalcEvent = HasAnySheetEventScript( ScSheetEventId::CALCULATE, true );
- ScFormulaCell* pTrack;
- ScFormulaCell* pNext;
- pTrack = pFormulaTrack;
- do
+ for( ScFormulaCell* pTrack = pFormulaTrack; pTrack != nullptr; pTrack = pTrack->GetNextTrack())
{
- SvtBroadcaster* pBC = GetBroadcaster(pTrack->aPos);
- ScHint aHint(nHintId, pTrack->aPos);
- if (pBC)
- pBC->Broadcast( aHint );
+ SCROW rowCount = 1;
+ ScAddress address = pTrack->aPos;
+ // Compress to include all adjacent cells in the same column.
+ for(ScFormulaCell* pNext = pTrack->GetNextTrack(); pNext != nullptr; pNext = pNext->GetNextTrack())
+ {
+ if(pNext->aPos != ScAddress(address.Col(), address.Row() + rowCount, address.Tab()))
+ break;
+ ++rowCount;
+ pTrack = pNext;
+ }
+ ScHint aHint( nHintId, address, rowCount );
+ BroadcastHintInternal( aHint );
pBASM->AreaBroadcast( aHint );
// for "calculate" event, keep track of which sheets are affected by tracked formulas
if ( bCalcEvent )
- SetCalcNotification( pTrack->aPos.Tab() );
- pTrack = pTrack->GetNextTrack();
- } while ( pTrack );
- pTrack = pFormulaTrack;
+ SetCalcNotification( address.Tab() );
+ }
bool bHaveForced = false;
- do
+ for( ScFormulaCell* pTrack = pFormulaTrack; pTrack != nullptr;)
{
- pNext = pTrack->GetNextTrack();
+ ScFormulaCell* pNext = pTrack->GetNextTrack();
RemoveFromFormulaTrack( pTrack );
PutInFormulaTree( pTrack );
if ( pTrack->GetCode()->IsRecalcModeForced() )
bHaveForced = true;
pTrack = pNext;
- } while ( pTrack );
+ }
if ( bHaveForced )
{
SetForcedFormulas( true );
@@ -582,9 +582,9 @@ void ScDocument::TrackFormulas( SfxHintId nHintId )
void ScDocument::StartAllListeners()
{
sc::StartListeningContext aCxt(*this);
- for ( SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); ++i )
- if ( maTabs[i] )
- maTabs[i]->StartListeners(aCxt, true);
+ for ( auto const & i: maTabs )
+ if ( i )
+ i->StartListeners(aCxt, true);
}
void ScDocument::UpdateBroadcastAreas( UpdateRefMode eUpdateRefMode,
diff --git a/sc/source/core/data/documen8.cxx b/sc/source/core/data/documen8.cxx
index d9321a6634cb..e584a9016626 100644
--- a/sc/source/core/data/documen8.cxx
+++ b/sc/source/core/data/documen8.cxx
@@ -20,21 +20,20 @@
#include <scitems.hxx>
#include <comphelper/fileformat.h>
#include <comphelper/processfactory.hxx>
-#include <comphelper/servicehelper.hxx>
#include <officecfg/Office/Common.hxx>
#include <tools/urlobj.hxx>
#include <editeng/frmdiritem.hxx>
#include <editeng/langitem.hxx>
#include <sfx2/linkmgr.hxx>
#include <sfx2/bindings.hxx>
-#include <sfx2/objsh.hxx>
#include <sfx2/printer.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/viewsh.hxx>
#include <svl/flagitem.hxx>
#include <svl/intitem.hxx>
-#include <svl/zforlist.hxx>
+#include <svl/numformat.hxx>
#include <svl/zformat.hxx>
+#include <svl/ctloptions.hxx>
#include <unotools/transliterationwrapper.hxx>
#include <sal/log.hxx>
#include <osl/diagnose.h>
@@ -50,6 +49,7 @@
#include <column.hxx>
#include <poolhelp.hxx>
#include <docpool.hxx>
+#include <docsh.hxx>
#include <stlpool.hxx>
#include <stlsheet.hxx>
#include <docoptio.hxx>
@@ -112,14 +112,14 @@ void ScDocument::ImplDeleteOptions()
SfxPrinter* ScDocument::GetPrinter(bool bCreateIfNotExist)
{
- if ( !mpPrinter && bCreateIfNotExist )
+ if (!mpPrinter && bCreateIfNotExist && mxPoolHelper)
{
auto pSet =
- std::make_unique<SfxItemSet>( *mxPoolHelper->GetDocPool(),
- svl::Items<SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN,
+ std::make_unique<SfxItemSetFixed
+ <SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN,
SID_PRINTER_CHANGESTODOC, SID_PRINTER_CHANGESTODOC,
SID_PRINT_SELECTEDSHEET, SID_PRINT_SELECTEDSHEET,
- SID_SCPRINTOPTIONS, SID_SCPRINTOPTIONS>{} );
+ SID_SCPRINTOPTIONS, SID_SCPRINTOPTIONS>>(*mxPoolHelper->GetDocPool());
SfxPrinterChangeFlags nFlags = SfxPrinterChangeFlags::NONE;
if (officecfg::Office::Common::Print::Warning::PaperOrientation::get())
@@ -132,7 +132,7 @@ SfxPrinter* ScDocument::GetPrinter(bool bCreateIfNotExist)
mpPrinter = VclPtr<SfxPrinter>::Create( std::move(pSet) );
mpPrinter->SetMapMode(MapMode(MapUnit::Map100thMM));
UpdateDrawPrinter();
- mpPrinter->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
+ mpPrinter->SetDigitLanguage( ScModule::GetOptDigitLanguage() );
}
return mpPrinter;
@@ -152,7 +152,7 @@ void ScDocument::SetPrinter( VclPtr<SfxPrinter> const & pNewPrinter )
ScopedVclPtr<SfxPrinter> xKeepAlive( mpPrinter );
mpPrinter = pNewPrinter;
UpdateDrawPrinter();
- mpPrinter->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
+ mpPrinter->SetDigitLanguage( ScModule::GetOptDigitLanguage() );
}
InvalidateTextWidth(nullptr, nullptr, false); // in both cases
}
@@ -185,7 +185,7 @@ VirtualDevice* ScDocument::GetVirtualDevice_100th_mm()
#ifdef IOS
mpVirtualDevice_100th_mm = VclPtr<VirtualDevice>::Create(DeviceFormat::GRAYSCALE);
#else
- mpVirtualDevice_100th_mm = VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT);
+ mpVirtualDevice_100th_mm = VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA);
#endif
mpVirtualDevice_100th_mm->SetReferenceDevice(VirtualDevice::RefDevMode::MSO1);
MapMode aMapMode( mpVirtualDevice_100th_mm->GetMapMode() );
@@ -195,13 +195,16 @@ VirtualDevice* ScDocument::GetVirtualDevice_100th_mm()
return mpVirtualDevice_100th_mm;
}
-OutputDevice* ScDocument::GetRefDevice()
+OutputDevice* ScDocument::GetRefDevice(bool bForceVirtDev)
{
// Create printer like ref device, see Writer...
OutputDevice* pRefDevice = nullptr;
- if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() )
+ if ( !bForceVirtDev && SC_MOD()->GetInputOptions().GetTextWysiwyg() )
+ {
pRefDevice = GetPrinter();
- else
+ SAL_WARN_IF(!pRefDevice, "sc", "unable to get a printer, fallback to virdev");
+ }
+ if (!pRefDevice)
pRefDevice = GetVirtualDevice_100th_mm();
return pRefDevice;
}
@@ -224,10 +227,9 @@ void ScDocument::ModifyStyleSheet( SfxStyleSheetBase& rStyleSheet,
if ( (nOldScale != nNewScale) || (nOldScaleToPages != nNewScaleToPages) )
InvalidateTextWidth( rStyleSheet.GetName() );
- if( SvtLanguageOptions().IsCTLFontEnabled() )
+ if( SvtCTLOptions::IsCTLFontEnabled() )
{
- const SfxPoolItem *pItem = nullptr;
- if( rChanges.GetItemState(ATTR_WRITINGDIR, true, &pItem ) == SfxItemState::SET )
+ if( rChanges.GetItemState(ATTR_WRITINGDIR ) == SfxItemState::SET )
ScChartHelper::DoUpdateAllCharts( *this );
}
}
@@ -244,9 +246,9 @@ void ScDocument::ModifyStyleSheet( SfxStyleSheetBase& rStyleSheet,
if (maTabs[nTab])
maTabs[nTab]->SetStreamValid( false );
- sal_uLong nOldFormat =
+ sal_uInt32 nOldFormat =
rSet.Get( ATTR_VALUE_FORMAT ).GetValue();
- sal_uLong nNewFormat =
+ sal_uInt32 nNewFormat =
rChanges.Get( ATTR_VALUE_FORMAT ).GetValue();
LanguageType eNewLang, eOldLang;
eNewLang = eOldLang = LANGUAGE_DONTKNOW;
@@ -268,7 +270,7 @@ void ScDocument::ModifyStyleSheet( SfxStyleSheetBase& rStyleSheet,
SfxItemState eState = rChanges.GetItemState( nWhich, false, &pItem );
if ( eState == SfxItemState::SET )
rSet.Put( *pItem );
- else if ( eState == SfxItemState::DONTCARE )
+ else if ( eState == SfxItemState::INVALID )
rSet.ClearItem( nWhich );
// when Default nothing
}
@@ -549,7 +551,7 @@ bool ScDocument::IdleCalcTextWidth() // true = try next again
aScope.incTab();
}
- if (!ValidTab(aScope.Tab()) || aScope.Tab() >= static_cast<SCTAB>(maTabs.size()) || !maTabs[aScope.Tab()])
+ if (!HasTable(aScope.Tab()))
aScope.setTab(0);
ScTable* pTab = maTabs[aScope.Tab()].get();
@@ -628,7 +630,7 @@ bool ScDocument::IdleCalcTextWidth() // true = try next again
bNewTab = true;
}
- if (!ValidTab(aScope.Tab()) || aScope.Tab() >= static_cast<SCTAB>(maTabs.size()) || !maTabs[aScope.Tab()] )
+ if (!HasTable(aScope.Tab()))
{
// Sheet doesn't exist at specified sheet position. Restart at sheet 0.
aScope.setTab(0);
@@ -690,7 +692,7 @@ void ScDocument::RepaintRange( const ScRange& rRange )
{
if ( bIsVisible && mpShell )
{
- ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>( mpShell->GetModel() );
+ ScModelObj* pModel = mpShell->GetModel();
if ( pModel )
pModel->RepaintRange( rRange ); // locked repaints are checked there
}
@@ -700,7 +702,7 @@ void ScDocument::RepaintRange( const ScRangeList& rRange )
{
if ( bIsVisible && mpShell )
{
- ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>( mpShell->GetModel() );
+ ScModelObj* pModel = mpShell->GetModel();
if ( pModel )
pModel->RepaintRange( rRange ); // locked repaints are checked there
}
@@ -911,12 +913,10 @@ ScDdeLink* lclGetDdeLink(
if( pLinkManager )
{
const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
- size_t nCount = rLinks.size();
if( pnDdePos ) *pnDdePos = 0;
- for( size_t nIndex = 0; nIndex < nCount; ++nIndex )
+ for( const auto& nLinks : rLinks )
{
- ::sfx2::SvBaseLink* pLink = rLinks[ nIndex ].get();
- if( ScDdeLink* pDdeLink = dynamic_cast<ScDdeLink*>( pLink ) )
+ if( ScDdeLink* pDdeLink = dynamic_cast<ScDdeLink*>( nLinks.get() ) )
{
if( (pDdeLink->GetAppl() == rAppl) &&
(pDdeLink->GetTopic() == rTopic) &&
@@ -937,13 +937,10 @@ ScDdeLink* lclGetDdeLink( const sfx2::LinkManager* pLinkManager, size_t nDdePos
{
if( pLinkManager )
{
- const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
- size_t nCount = rLinks.size();
size_t nDdeIndex = 0; // counts only the DDE links
- for( size_t nIndex = 0; nIndex < nCount; ++nIndex )
+ for( const auto& pLink : pLinkManager->GetLinks() )
{
- ::sfx2::SvBaseLink* pLink = rLinks[ nIndex ].get();
- if( ScDdeLink* pDdeLink = dynamic_cast<ScDdeLink*>( pLink ) )
+ if( ScDdeLink* pDdeLink = dynamic_cast<ScDdeLink*>( pLink.get() ) )
{
if( nDdeIndex == nDdePos )
return pDdeLink;
@@ -1239,8 +1236,8 @@ void ScDocument::TransliterateText( const ScMarkData& rMultiMark, Transliteratio
// fdo#32786 TITLE_CASE/SENTENCE_CASE need the extra handling in EditEngine (loop over words/sentences).
// Still use TransliterationWrapper directly for text cells with other transliteration types,
// for performance reasons.
- if (aCell.meType == CELLTYPE_EDIT ||
- (aCell.meType == CELLTYPE_STRING &&
+ if (aCell.getType() == CELLTYPE_EDIT ||
+ (aCell.getType() == CELLTYPE_STRING &&
( nType == TransliterationFlags::SENTENCE_CASE || nType == TransliterationFlags::TITLE_CASE)))
{
if (!pEngine)
@@ -1248,23 +1245,23 @@ void ScDocument::TransliterateText( const ScMarkData& rMultiMark, Transliteratio
// defaults from cell attributes must be set so right language is used
const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab );
- std::unique_ptr<SfxItemSet> pDefaults(new SfxItemSet( pEngine->GetEmptyItemSet() ));
+ SfxItemSet aDefaults( pEngine->GetEmptyItemSet() );
if ( ScStyleSheet* pPreviewStyle = GetPreviewCellStyle( nCol, nRow, nTab ) )
{
ScPatternAttr aPreviewPattern( *pPattern );
aPreviewPattern.SetStyleSheet(pPreviewStyle);
- aPreviewPattern.FillEditItemSet( pDefaults.get() );
+ aPreviewPattern.FillEditItemSet( &aDefaults );
}
else
{
SfxItemSet* pFontSet = GetPreviewFont( nCol, nRow, nTab );
- pPattern->FillEditItemSet( pDefaults.get(), pFontSet );
+ pPattern->FillEditItemSet( &aDefaults, pFontSet );
}
- pEngine->SetDefaults( std::move(pDefaults) );
- if (aCell.meType == CELLTYPE_STRING)
- pEngine->SetTextCurrentDefaults(aCell.mpString->getString());
- else if (aCell.mpEditText)
- pEngine->SetTextCurrentDefaults(*aCell.mpEditText);
+ pEngine->SetDefaults( std::move(aDefaults) );
+ if (aCell.getType() == CELLTYPE_STRING)
+ pEngine->SetTextCurrentDefaults(aCell.getSharedString()->getString());
+ else if (aCell.getEditText())
+ pEngine->SetTextCurrentDefaults(*aCell.getEditText());
pEngine->ClearModifyFlag();
@@ -1296,9 +1293,9 @@ void ScDocument::TransliterateText( const ScMarkData& rMultiMark, Transliteratio
}
}
- else if (aCell.meType == CELLTYPE_STRING)
+ else if (aCell.getType() == CELLTYPE_STRING)
{
- OUString aOldStr = aCell.mpString->getString();
+ OUString aOldStr = aCell.getSharedString()->getString();
sal_Int32 nOldLen = aOldStr.getLength();
if ( bConsiderLanguage )
diff --git a/sc/source/core/data/documen9.cxx b/sc/source/core/data/documen9.cxx
index 5c6defa59f40..0a3c8f30c2c3 100644
--- a/sc/source/core/data/documen9.cxx
+++ b/sc/source/core/data/documen9.cxx
@@ -33,11 +33,11 @@
#include <svx/svdpage.hxx>
#include <svx/svdundo.hxx>
#include <svx/xtable.hxx>
-#include <sfx2/objsh.hxx>
#include <sfx2/printer.hxx>
#include <document.hxx>
#include <docoptio.hxx>
+#include <docsh.hxx>
#include <table.hxx>
#include <drwlayer.hxx>
#include <markdata.hxx>
@@ -45,6 +45,7 @@
#include <rechead.hxx>
#include <poolhelp.hxx>
#include <docpool.hxx>
+#include <stlpool.hxx>
#include <editutil.hxx>
#include <charthelper.hxx>
#include <conditio.hxx>
@@ -76,10 +77,16 @@ void ScDocument::TransferDrawPage(const ScDocument& rSrcDoc, SCTAB nSrcPos, SCTA
SdrObject* pOldObject = aIter.Next();
while (pOldObject)
{
+ // Copy style sheet
+ auto pStyleSheet = pOldObject->GetStyleSheet();
+ if (pStyleSheet)
+ GetStyleSheetPool()->CopyStyleFrom(rSrcDoc.GetStyleSheetPool(),
+ pStyleSheet->GetName(), pStyleSheet->GetFamily(), true);
+
// Clone to target SdrModel
- SdrObject* pNewObject(pOldObject->CloneSdrObject(*mpDrawLayer));
+ rtl::Reference<SdrObject> pNewObject(pOldObject->CloneSdrObject(*mpDrawLayer));
pNewObject->NbcMove(Size(0,0));
- pNewPage->InsertObject( pNewObject );
+ pNewPage->InsertObject( pNewObject.get() );
if (mpDrawLayer->IsRecording())
mpDrawLayer->AddCalcUndo( std::make_unique<SdrUndoInsertObj>( *pNewObject ) );
@@ -95,7 +102,7 @@ void ScDocument::TransferDrawPage(const ScDocument& rSrcDoc, SCTAB nSrcPos, SCTA
ScChartHelper::UpdateChartsOnDestinationPage(*this, nDestPos);
}
-void ScDocument::InitDrawLayer( SfxObjectShell* pDocShell )
+void ScDocument::InitDrawLayer( ScDocShell* pDocShell )
{
if (pDocShell && !mpShell)
{
@@ -130,6 +137,7 @@ void ScDocument::InitDrawLayer( SfxObjectShell* pDocShell )
OSL_ENSURE(!pLocalPool->GetSecondaryPool(), "OOps, already a secondary pool set where the DrawingLayer ItemPool is to be placed (!)");
pLocalPool->SetSecondaryPool(&mpDrawLayer->GetItemPool());
}
+ mpDrawLayer->CreateDefaultStyles();
}
// Drawing pages are accessed by table number, so they must also be present
@@ -138,11 +146,11 @@ void ScDocument::InitDrawLayer( SfxObjectShell* pDocShell )
SCTAB nDrawPages = 0;
SCTAB nTab;
- for (nTab=0; nTab < static_cast<SCTAB>(maTabs.size()); nTab++)
+ for (nTab = 0; nTab < GetTableCount(); nTab++)
if (maTabs[nTab])
nDrawPages = nTab + 1; // needed number of pages
- for (nTab=0; nTab<nDrawPages && nTab < static_cast<SCTAB>(maTabs.size()); nTab++)
+ for (nTab = 0; nTab < nDrawPages && nTab < GetTableCount(); nTab++)
{
mpDrawLayer->ScAddPage( nTab ); // always add page, with or without the table
if (maTabs[nTab])
@@ -160,7 +168,7 @@ void ScDocument::InitDrawLayer( SfxObjectShell* pDocShell )
// set draw defaults directly
SfxItemPool& rDrawPool = mpDrawLayer->GetItemPool();
- rDrawPool.SetPoolDefaultItem( SvxAutoKernItem( true, EE_CHAR_PAIRKERNING ) );
+ rDrawPool.SetUserDefaultItem( SvxAutoKernItem( true, EE_CHAR_PAIRKERNING ) );
UpdateDrawLanguages();
if (bImportingXML)
@@ -176,9 +184,9 @@ void ScDocument::UpdateDrawLanguages()
if (mpDrawLayer)
{
SfxItemPool& rDrawPool = mpDrawLayer->GetItemPool();
- rDrawPool.SetPoolDefaultItem( SvxLanguageItem( eLanguage, EE_CHAR_LANGUAGE ) );
- rDrawPool.SetPoolDefaultItem( SvxLanguageItem( eCjkLanguage, EE_CHAR_LANGUAGE_CJK ) );
- rDrawPool.SetPoolDefaultItem( SvxLanguageItem( eCtlLanguage, EE_CHAR_LANGUAGE_CTL ) );
+ rDrawPool.SetUserDefaultItem( SvxLanguageItem( eLanguage, EE_CHAR_LANGUAGE ) );
+ rDrawPool.SetUserDefaultItem( SvxLanguageItem( eCjkLanguage, EE_CHAR_LANGUAGE_CJK ) );
+ rDrawPool.SetUserDefaultItem( SvxLanguageItem( eCtlLanguage, EE_CHAR_LANGUAGE_CTL ) );
}
}
@@ -194,16 +202,14 @@ void ScDocument::UpdateDrawPrinter()
void ScDocument::SetDrawPageSize(SCTAB nTab)
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return;
-
- maTabs[nTab]->SetDrawPageSize();
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetDrawPageSize();
}
bool ScDocument::IsChart( const SdrObject* pObject )
{
// IsChart() implementation moved to svx drawinglayer
- if(pObject && OBJ_OLE2 == pObject->GetObjIdentifier())
+ if(pObject && SdrObjKind::OLE2 == pObject->GetObjIdentifier())
{
return static_cast<const SdrOle2Obj*>(pObject)->IsChart();
}
@@ -226,24 +232,6 @@ IMPL_LINK( ScDocument, GetUserDefinedColor, sal_uInt16, nColorIndex, Color* )
return const_cast<Color*>(&(xColorList->GetColor(nColorIndex)->GetColor()));
}
-void ScDocument::DeleteDrawLayer()
-{
- ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
-
- // remove DrawingLayer's SfxItemPool from Calc's SfxItemPool where
- // it is registered as secondary pool
- if (mxPoolHelper.is() && !IsClipOrUndo()) //Using IsClipOrUndo as a proxy for SharePooledResources called
- {
- ScDocumentPool* pLocalPool = mxPoolHelper->GetDocPool();
-
- if(pLocalPool && pLocalPool->GetSecondaryPool())
- {
- pLocalPool->SetSecondaryPool(nullptr);
- }
- }
- mpDrawLayer.reset();
-}
-
bool ScDocument::DrawGetPrintArea( ScRange& rRange, bool bSetHor, bool bSetVer ) const
{
return mpDrawLayer->GetPrintArea( rRange, bSetHor, bSetVer );
@@ -281,7 +269,7 @@ bool ScDocument::HasOLEObjectsInArea( const ScRange& rRange, const ScMarkData* p
return false;
SCTAB nStartTab = 0;
- SCTAB nEndTab = static_cast<SCTAB>(maTabs.size());
+ SCTAB nEndTab = GetTableCount();
if ( !pTabMark )
{
nStartTab = rRange.aStart.Tab();
@@ -303,8 +291,8 @@ bool ScDocument::HasOLEObjectsInArea( const ScRange& rRange, const ScMarkData* p
SdrObject* pObject = aIter.Next();
while (pObject)
{
- if ( pObject->GetObjIdentifier() == OBJ_OLE2 &&
- aMMRect.IsInside( pObject->GetCurrentBoundRect() ) )
+ if ( pObject->GetObjIdentifier() == SdrObjKind::OLE2 &&
+ aMMRect.Contains( pObject->GetCurrentBoundRect() ) )
return true;
pObject = aIter.Next();
@@ -357,7 +345,7 @@ bool ScDocument::HasBackgroundDraw( SCTAB nTab, const tools::Rectangle& rMMRect
SdrObject* pObject = aIter.Next();
while (pObject && !bFound)
{
- if ( pObject->GetLayer() == SC_LAYER_BACK && pObject->GetCurrentBoundRect().IsOver( rMMRect ) )
+ if ( pObject->GetLayer() == SC_LAYER_BACK && pObject->GetCurrentBoundRect().Overlaps( rMMRect ) )
bFound = true;
pObject = aIter.Next();
}
@@ -382,7 +370,7 @@ bool ScDocument::HasAnyDraw( SCTAB nTab, const tools::Rectangle& rMMRect ) const
SdrObject* pObject = aIter.Next();
while (pObject && !bFound)
{
- if ( pObject->GetCurrentBoundRect().IsOver( rMMRect ) )
+ if ( pObject->GetCurrentBoundRect().Overlaps( rMMRect ) )
bFound = true;
pObject = aIter.Next();
}
@@ -400,7 +388,7 @@ SdrObject* ScDocument::GetObjectAtPoint( SCTAB nTab, const Point& rPos )
{
// for Drag&Drop on draw object
SdrObject* pFound = nullptr;
- if (mpDrawLayer && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
+ if (mpDrawLayer && nTab < GetTableCount() && maTabs[nTab])
{
SdrPage* pPage = mpDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
OSL_ENSURE(pPage,"Page ?");
@@ -410,7 +398,7 @@ SdrObject* ScDocument::GetObjectAtPoint( SCTAB nTab, const Point& rPos )
SdrObject* pObject = aIter.Next();
while (pObject)
{
- if ( pObject->GetCurrentBoundRect().IsInside(rPos) )
+ if ( pObject->GetCurrentBoundRect().Contains(rPos) )
{
// Intern is of no interest
// Only object form background layer, when no object form another layer is found
@@ -432,11 +420,12 @@ SdrObject* ScDocument::GetObjectAtPoint( SCTAB nTab, const Point& rPos )
return pFound;
}
-bool ScDocument::IsPrintEmpty( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
- SCCOL nEndCol, SCROW nEndRow, bool bLeftIsEmpty,
+bool ScDocument::IsPrintEmpty( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow,
+ SCTAB nTab, bool bLeftIsEmpty,
ScRange* pLastRange, tools::Rectangle* pLastMM ) const
{
- if (!IsBlockEmpty( nTab, nStartCol, nStartRow, nEndCol, nEndRow ))
+ if (!IsBlockEmpty( nStartCol, nStartRow, nEndCol, nEndRow, nTab ))
return false;
if (HasAttrib(ScRange(nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab), HasAttrFlags::Lines))
@@ -450,13 +439,8 @@ bool ScDocument::IsPrintEmpty( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
// keep vertical part of aMMRect, only update horizontal position
aMMRect = *pLastMM;
- tools::Long nLeft = 0;
- SCCOL i;
- for (i=0; i<nStartCol; i++)
- nLeft += GetColWidth(i,nTab);
- tools::Long nRight = nLeft;
- for (i=nStartCol; i<=nEndCol; i++)
- nRight += GetColWidth(i,nTab);
+ tools::Long nLeft = GetColWidth(0, nStartCol-1, nTab);
+ tools::Long nRight = nLeft + GetColWidth(nStartCol,nEndCol, nTab);
aMMRect.SetLeft(o3tl::convert(nLeft, o3tl::Length::twip, o3tl::Length::mm100));
aMMRect.SetRight(o3tl::convert(nRight, o3tl::Length::twip, o3tl::Length::mm100));
@@ -556,24 +540,32 @@ void ScDocument::UpdateFontCharSet()
return;
ScDocumentPool* pPool = mxPoolHelper->GetDocPool();
- for (const SfxPoolItem* pItem : pPool->GetItemSurrogates(ATTR_FONT))
+
+ pPool->iterateItemSurrogates(ATTR_FONT, [&](SfxItemPool::SurrogateData& rData)
{
- auto pFontItem = const_cast<SvxFontItem*>(dynamic_cast<const SvxFontItem*>(pItem));
- if ( pFontItem && ( pFontItem->GetCharSet() == eSrcSet ||
- ( bUpdateOld && pFontItem->GetCharSet() != RTL_TEXTENCODING_SYMBOL ) ) )
- pFontItem->SetCharSet(eSysSet);
- }
+ const SvxFontItem& rSvxFontItem(static_cast<const SvxFontItem&>(rData.getItem()));
+ if (eSrcSet == rSvxFontItem.GetCharSet() || (bUpdateOld && RTL_TEXTENCODING_SYMBOL != rSvxFontItem.GetCharSet()))
+ {
+ SvxFontItem* pNew(rSvxFontItem.Clone(pPool));
+ pNew->SetCharSet(eSysSet);
+ rData.setItem(std::unique_ptr<SfxPoolItem>(pNew));
+ }
+ return true; // continue callbacks
+ });
if ( mpDrawLayer )
{
- SfxItemPool& rDrawPool = mpDrawLayer->GetItemPool();
- for (const SfxPoolItem* pItem : rDrawPool.GetItemSurrogates(EE_CHAR_FONTINFO))
+ pPool->iterateItemSurrogates(EE_CHAR_FONTINFO, [&](SfxItemPool::SurrogateData& rData)
{
- SvxFontItem* pFontItem = const_cast<SvxFontItem*>(dynamic_cast<const SvxFontItem*>(pItem));
- if ( pFontItem && ( pFontItem->GetCharSet() == eSrcSet ||
- ( bUpdateOld && pFontItem->GetCharSet() != RTL_TEXTENCODING_SYMBOL ) ) )
- pFontItem->SetCharSet( eSysSet );
- }
+ const SvxFontItem& rSvxFontItem(static_cast<const SvxFontItem&>(rData.getItem()));
+ if (eSrcSet == rSvxFontItem.GetCharSet() || (bUpdateOld && RTL_TEXTENCODING_SYMBOL != rSvxFontItem.GetCharSet()))
+ {
+ SvxFontItem* pNew(rSvxFontItem.Clone(pPool));
+ pNew->SetCharSet(eSysSet);
+ rData.setItem(std::unique_ptr<SfxPoolItem>(pNew));
+ }
+ return true; // continue callbacks
+ });
}
}
@@ -599,7 +591,7 @@ void ScDocument::SetImportingXML( bool bVal )
{
// #i57869# after loading, do the real RTL mirroring for the sheets that have the LoadingRTL flag set
- for ( SCTAB nTab=0; nTab< static_cast<SCTAB>(maTabs.size()) && maTabs[nTab]; nTab++ )
+ for (SCTAB nTab = 0; nTab < GetTableCount() && maTabs[nTab]; nTab++)
if ( maTabs[nTab]->IsLoadingRTL() )
{
// SetLayoutRTL => SetDrawPageSize => ScDrawLayer::SetPageSize, includes RTL-mirroring;
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index c9a30aedc012..6aef04f9bf1c 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -21,12 +21,10 @@
#include <editeng/boxitem.hxx>
#include <editeng/editobj.hxx>
-#include <o3tl/safeint.hxx>
-#include <svx/sdrundomanager.hxx>
#include <svx/svditer.hxx>
-#include <sfx2/objsh.hxx>
#include <sfx2/docfile.hxx>
-#include <svl/poolcach.hxx>
+#include <svl/numformat.hxx>
+#include <poolcach.hxx>
#include <svl/zforlist.hxx>
#include <unotools/charclass.hxx>
#include <unotools/transliterationwrapper.hxx>
@@ -40,6 +38,7 @@
#include <com/sun/star/lang/NotInitializedException.hpp>
#include <document.hxx>
+#include <docsh.hxx>
#include <docuno.hxx>
#include <table.hxx>
#include <column.hxx>
@@ -64,7 +63,6 @@
#include <hints.hxx>
#include <detdata.hxx>
#include <dpobject.hxx>
-#include <detfunc.hxx>
#include <scmod.hxx>
#include <dociter.hxx>
#include <progress.hxx>
@@ -85,15 +83,18 @@
#include <tokenstringcontext.hxx>
#include <compressedarray.hxx>
#include <recursionhelper.hxx>
+#include <SparklineGroup.hxx>
+#include <SparklineList.hxx>
+#include <undomanager.hxx>
#include <formula/vectortoken.hxx>
#include <limits>
#include <memory>
#include <utility>
+#include <unordered_map>
#include <comphelper/lok.hxx>
-#include <comphelper/servicehelper.hxx>
#include <vcl/uitest/logger.hxx>
#include <vcl/uitest/eventdescription.hxx>
@@ -132,12 +133,12 @@ std::pair<SCTAB,SCTAB> getMarkedTableRange(const std::vector<ScTableUniquePtr>&
return std::pair<SCTAB,SCTAB>(nTabStart,nTabEnd);
}
-void collectUIInformation(const std::map<OUString, OUString>& aParameters, const OUString& rAction)
+void collectUIInformation(std::map<OUString, OUString>&& aParameters, const OUString& rAction)
{
EventDescription aDescription;
aDescription.aID = "grid_window";
aDescription.aAction = rAction;
- aDescription.aParameters = aParameters;
+ aDescription.aParameters = std::move(aParameters);
aDescription.aParent = "MainWindow";
aDescription.aKeyWord = "ScGridWinUIObject";
@@ -146,27 +147,17 @@ void collectUIInformation(const std::map<OUString, OUString>& aParameters, const
struct ScDefaultAttr
{
- const ScPatternAttr* pAttr;
- SCROW nFirst;
- SCSIZE nCount;
- explicit ScDefaultAttr(const ScPatternAttr* pPatAttr) : pAttr(pPatAttr), nFirst(0), nCount(0) {}
-};
-
-struct ScLessDefaultAttr
-{
- bool operator() (const ScDefaultAttr& rValue1, const ScDefaultAttr& rValue2) const
- {
- return rValue1.pAttr < rValue2.pAttr;
- }
+ SCROW nFirst { 0 };
+ SCSIZE nCount { 0 };
};
}
-typedef std::set<ScDefaultAttr, ScLessDefaultAttr> ScDefaultAttrSet;
+typedef std::unordered_map<const ScPatternAttr*, ScDefaultAttr> ScDefaultAttrMap;
void ScDocument::MakeTable( SCTAB nTab,bool _bNeedsNameCheck )
{
- if ( !(ValidTab(nTab) && ( nTab >= static_cast<SCTAB>(maTabs.size()) ||!maTabs[nTab])) )
+ if (!ValidTab(nTab) || HasTable(nTab))
return;
// Get Custom prefix
@@ -174,50 +165,35 @@ void ScDocument::MakeTable( SCTAB nTab,bool _bNeedsNameCheck )
OUString aString = rOpt.GetInitTabPrefix() + OUString::number(nTab+1);
if ( _bNeedsNameCheck )
CreateValidTabName( aString ); // no doubles
- if (nTab < static_cast<SCTAB>(maTabs.size()))
+ if (nTab < GetTableCount())
{
maTabs[nTab].reset( new ScTable(*this, nTab, aString) );
}
else
{
- while(nTab > static_cast<SCTAB>(maTabs.size()))
+ while (nTab > GetTableCount())
maTabs.push_back(nullptr);
maTabs.emplace_back( new ScTable(*this, nTab, aString) );
}
maTabs[nTab]->SetLoadingMedium(bLoadingMedium);
}
-bool ScDocument::HasTable( SCTAB nTab ) const
-{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
- if (maTabs[nTab])
- return true;
-
- return false;
-}
-
bool ScDocument::GetHashCode( SCTAB nTab, sal_Int64& rHashCode ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
+ if (const ScTable* pTable = FetchTable(nTab))
{
- if (maTabs[nTab])
- {
- rHashCode = maTabs[nTab]->GetHashCode();
- return true;
- }
+ rHashCode = pTable->GetHashCode();
+ return true;
}
return false;
}
bool ScDocument::GetName( SCTAB nTab, OUString& rName ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
+ if (const ScTable* pTable = FetchTable(nTab))
{
- if (maTabs[nTab])
- {
- rName = maTabs[nTab]->GetName();
- return true;
- }
+ rName = pTable->GetName();
+ return true;
}
rName.clear();
return false;
@@ -232,13 +208,10 @@ OUString ScDocument::GetCopyTabName( SCTAB nTab ) const
bool ScDocument::SetCodeName( SCTAB nTab, const OUString& rName )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
+ if (ScTable* pTable = FetchTable(nTab))
{
- if (maTabs[nTab])
- {
- maTabs[nTab]->SetCodeName( rName );
- return true;
- }
+ pTable->SetCodeName(rName);
+ return true;
}
SAL_WARN("sc", "can't set code name " << rName );
return false;
@@ -246,19 +219,17 @@ bool ScDocument::SetCodeName( SCTAB nTab, const OUString& rName )
bool ScDocument::GetCodeName( SCTAB nTab, OUString& rName ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
- if (maTabs[nTab])
- {
- rName = maTabs[nTab]->GetCodeName();
- return true;
- }
+ if (const ScTable* pTable = FetchTable(nTab))
+ {
+ rName = pTable->GetCodeName();
+ return true;
+ }
rName.clear();
return false;
}
bool ScDocument::GetTable( const OUString& rName, SCTAB& rTab ) const
{
- OUString aUpperName;
static OUString aCacheName, aCacheUpperName;
assert(!IsThreadedGroupCalcInProgress());
@@ -266,11 +237,11 @@ bool ScDocument::GetTable( const OUString& rName, SCTAB& rTab ) const
{
aCacheName = rName;
// surprisingly slow ...
- aCacheUpperName = ScGlobal::getCharClassPtr()->uppercase(rName);
+ aCacheUpperName = ScGlobal::getCharClass().uppercase(rName);
}
- aUpperName = aCacheUpperName;
+ const OUString aUpperName = aCacheUpperName;
- for (SCTAB i=0; i< static_cast<SCTAB>(maTabs.size()); i++)
+ for (SCTAB i = 0; i < GetTableCount(); i++)
if (maTabs[i])
{
if (aUpperName == maTabs[i]->GetUpperName())
@@ -305,8 +276,8 @@ std::vector<OUString> ScDocument::GetAllTableNames() const
ScDBData* ScDocument::GetAnonymousDBData(SCTAB nTab)
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetAnonymousDBData();
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->GetAnonymousDBData();
return nullptr;
}
@@ -317,8 +288,8 @@ SCTAB ScDocument::GetTableCount() const
void ScDocument::SetAnonymousDBData(SCTAB nTab, std::unique_ptr<ScDBData> pDBData)
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->SetAnonymousDBData(std::move(pDBData));
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetAnonymousDBData(std::move(pDBData));
}
void ScDocument::SetAnonymousDBData( std::unique_ptr<ScDBData> pDBData )
@@ -375,7 +346,7 @@ bool ScDocument::ValidNewTabName( const OUString& rName ) const
bool bValid = ValidTabName(rName);
if (!bValid)
return false;
- OUString aUpperName = ScGlobal::getCharClassPtr()->uppercase(rName);
+ OUString aUpperName = ScGlobal::getCharClass().uppercase(rName);
for (const auto& a : maTabs)
{
if (!a)
@@ -405,7 +376,7 @@ void ScDocument::CreateValidTabName(OUString& rName) const
OSL_ENSURE(bPrefix, "Invalid Table Name");
SCTAB nDummy;
- for ( SCTAB i = static_cast<SCTAB>(maTabs.size())+1; !bOk ; i++ )
+ for (SCTAB i = GetTableCount() + 1; !bOk ; i++)
{
rName = aStrTable + OUString::number(static_cast<sal_Int32>(i));
if (bPrefix)
@@ -421,16 +392,14 @@ void ScDocument::CreateValidTabName(OUString& rName) const
if ( !ValidNewTabName(rName) )
{
SCTAB i = 1;
- OUStringBuffer aName;
+ OUString aName;
do
{
i++;
- aName = rName;
- aName.append('_');
- aName.append(static_cast<sal_Int32>(i));
+ aName = rName + "_" + OUString::number(static_cast<sal_Int32>(i));
}
- while (!ValidNewTabName(aName.toString()) && (i < MAXTAB+1));
- rName = aName.makeStringAndClear();
+ while (!ValidNewTabName(aName) && (i < MAXTAB+1));
+ rName = aName;
}
}
}
@@ -449,7 +418,7 @@ void ScDocument::CreateValidTabNames(std::vector<OUString>& aNames, SCTAB nCount
bool bPrefix = ValidTabName( aStrTable );
OSL_ENSURE(bPrefix, "Invalid Table Name");
SCTAB nDummy;
- SCTAB i = static_cast<SCTAB>(maTabs.size())+1;
+ SCTAB i = GetTableCount() + 1;
for (SCTAB j = 0; j < nCount; ++j)
{
@@ -470,7 +439,7 @@ void ScDocument::CreateValidTabNames(std::vector<OUString>& aNames, SCTAB nCount
void ScDocument::AppendTabOnLoad(const OUString& rName)
{
- SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
+ SCTAB nTabCount = GetTableCount();
if (!ValidTab(nTabCount))
// max table count reached. No more tables.
return;
@@ -482,7 +451,7 @@ void ScDocument::AppendTabOnLoad(const OUString& rName)
void ScDocument::SetTabNameOnLoad(SCTAB nTab, const OUString& rName)
{
- if (!ValidTab(nTab) || static_cast<SCTAB>(maTabs.size()) <= nTab)
+ if (!ValidTab(nTab) || GetTableCount() <= nTab)
return;
if (!ValidTabName(rName))
@@ -503,8 +472,13 @@ void ScDocument::InvalidateStreamOnSave()
bool ScDocument::InsertTab(
SCTAB nPos, const OUString& rName, bool bExternalDocument, bool bUndoDeleteTab )
{
- SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
- bool bValid = ValidTab(nTabCount);
+ // auto-accept any in-process input to prevent move the cell into next sheet in online.
+ if (comphelper::LibreOfficeKit::isActive())
+ if (!SC_MOD()->IsFormulaMode())
+ SC_MOD()->InputEnterHandler();
+
+ SCTAB nTabCount = GetTableCount();
+ bool bValid = ValidTab(nTabCount);
if ( !bExternalDocument ) // else test rName == "'Doc'!Tab" first
bValid = (bValid && ValidNewTabName(rName));
if (bValid)
@@ -580,7 +554,7 @@ bool ScDocument::InsertTab(
if (comphelper::LibreOfficeKit::isActive() && GetDrawLayer())
{
- ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>(this->GetDocumentShell()->GetModel());
+ ScModelObj* pModel = GetDocumentShell()->GetModel();
SfxLokHelper::notifyDocumentSizeChangedAllViews(pModel);
}
}
@@ -591,9 +565,9 @@ bool ScDocument::InsertTab(
bool ScDocument::InsertTabs( SCTAB nPos, const std::vector<OUString>& rNames,
bool bNamesValid )
{
- SCTAB nNewSheets = static_cast<SCTAB>(rNames.size());
- SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
- bool bValid = bNamesValid || ValidTab(nTabCount+nNewSheets);
+ SCTAB nNewSheets = static_cast<SCTAB>(rNames.size());
+ SCTAB nTabCount = GetTableCount();
+ bool bValid = bNamesValid || ValidTab(nTabCount+nNewSheets);
if (bValid)
{
@@ -672,86 +646,91 @@ bool ScDocument::InsertTabs( SCTAB nPos, const std::vector<OUString>& rNames,
bool ScDocument::DeleteTab( SCTAB nTab )
{
bool bValid = false;
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
+ if (HasTable(nTab))
{
- if (maTabs[nTab])
+ SCTAB nTabCount = GetTableCount();
+ if (nTabCount > 1)
{
- SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
- if (nTabCount > 1)
+ sc::AutoCalcSwitch aACSwitch(*this, false);
+ sc::RefUpdateDeleteTabContext aCxt( *this, nTab, 1);
+ sc::DelayDeletingBroadcasters delayDeletingBroadcasters(*this);
+
+ ScRange aRange( 0, 0, nTab, MaxCol(), MaxRow(), nTab );
+ DelBroadcastAreasInRange( aRange );
+
+ // #i8180# remove database ranges etc. that are on the deleted tab
+ // (restored in undo with ScRefUndoData)
+
+ xColNameRanges->DeleteOnTab( nTab );
+ xRowNameRanges->DeleteOnTab( nTab );
+ pDBCollection->DeleteOnTab( nTab );
+ if (pDPCollection)
+ pDPCollection->DeleteOnTab( nTab );
+ if (pDetOpList)
+ pDetOpList->DeleteOnTab( nTab );
+ DeleteAreaLinksOnTab( nTab );
+
+ // normal reference update
+
+ aRange.aEnd.SetTab(GetTableCount() - 1);
+ xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
+ xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
+ if (pRangeName)
+ pRangeName->UpdateDeleteTab(aCxt);
+ pDBCollection->UpdateReference(
+ URM_INSDEL, 0,0,nTab, MaxCol(),MaxRow(),MAXTAB, 0,0,-1 );
+ if (pDPCollection)
+ pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
+ if (pDetOpList)
+ pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,-1 );
+ UpdateChartRef( URM_INSDEL, 0,0,nTab, MaxCol(),MaxRow(),MAXTAB, 0,0,-1 );
+ UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,-1 );
+ if (pValidationList)
{
- sc::AutoCalcSwitch aACSwitch(*this, false);
- sc::RefUpdateDeleteTabContext aCxt( *this, nTab, 1);
-
- ScRange aRange( 0, 0, nTab, MaxCol(), MaxRow(), nTab );
- DelBroadcastAreasInRange( aRange );
-
- // #i8180# remove database ranges etc. that are on the deleted tab
- // (restored in undo with ScRefUndoData)
-
- xColNameRanges->DeleteOnTab( nTab );
- xRowNameRanges->DeleteOnTab( nTab );
- pDBCollection->DeleteOnTab( nTab );
- if (pDPCollection)
- pDPCollection->DeleteOnTab( nTab );
- if (pDetOpList)
- pDetOpList->DeleteOnTab( nTab );
- DeleteAreaLinksOnTab( nTab );
-
- // normal reference update
-
- aRange.aEnd.SetTab( static_cast<SCTAB>(maTabs.size())-1 );
- xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
- xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
- if (pRangeName)
- pRangeName->UpdateDeleteTab(aCxt);
- pDBCollection->UpdateReference(
- URM_INSDEL, 0,0,nTab, MaxCol(),MaxRow(),MAXTAB, 0,0,-1 );
- if (pDPCollection)
- pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
- if (pDetOpList)
- pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,-1 );
- UpdateChartRef( URM_INSDEL, 0,0,nTab, MaxCol(),MaxRow(),MAXTAB, 0,0,-1 );
- UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,-1 );
- if (pValidationList)
- {
- ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
- pValidationList->UpdateDeleteTab(aCxt);
- }
- if ( pUnoBroadcaster )
- pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1 ) );
-
- for (auto & pTab : maTabs)
- if (pTab)
- pTab->UpdateDeleteTab(aCxt);
-
- maTabs.erase(maTabs.begin() + nTab);
- // UpdateBroadcastAreas must be called between UpdateDeleteTab,
- // which ends listening, and StartAllListeners, to not modify
- // areas that are to be inserted by starting listeners.
- UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,-1);
- for (const auto& a : maTabs)
- {
- if (a)
- a->UpdateCompile();
- }
- // Excel-Filter deletes some Tables while loading, Listeners will
- // only be triggered after the loading is done.
- if ( !bInsertingFromOtherDoc )
- {
- StartAllListeners();
-
- sc::SetFormulaDirtyContext aFormulaDirtyCxt;
- SetAllFormulasDirty(aFormulaDirtyCxt);
- }
+ ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
+ pValidationList->UpdateDeleteTab(aCxt);
+ }
+ if ( pUnoBroadcaster )
+ pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1 ) );
+
+ for (auto & pTab : maTabs)
+ if (pTab)
+ pTab->UpdateDeleteTab(aCxt);
+
+ // tdf#149502 make sure ScTable destructor called after the erase is finished, when
+ // maTabs[x].nTab==x is true again, as it should be always true.
+ // In the end of maTabs.erase, maTabs indexes change, but nTab updated before erase.
+ // ~ScTable expect that maTabs[x].nTab==x so it shouldn't be called during erase.
+ ScTableUniquePtr pErasedTab = std::move(maTabs[nTab]);
+ maTabs.erase(maTabs.begin() + nTab);
+ delete pErasedTab.release();
+
+ // UpdateBroadcastAreas must be called between UpdateDeleteTab,
+ // which ends listening, and StartAllListeners, to not modify
+ // areas that are to be inserted by starting listeners.
+ UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,-1);
+ for (const auto& a : maTabs)
+ {
+ if (a)
+ a->UpdateCompile();
+ }
+ // Excel-Filter deletes some Tables while loading, Listeners will
+ // only be triggered after the loading is done.
+ if ( !bInsertingFromOtherDoc )
+ {
+ StartAllListeners();
- if (comphelper::LibreOfficeKit::isActive())
- {
- ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>(this->GetDocumentShell()->GetModel());
- SfxLokHelper::notifyDocumentSizeChangedAllViews(pModel);
- }
+ sc::SetFormulaDirtyContext aFormulaDirtyCxt;
+ SetAllFormulasDirty(aFormulaDirtyCxt);
+ }
- bValid = true;
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScModelObj* pModel = GetDocumentShell()->GetModel();
+ SfxLokHelper::notifyDocumentSizeChangedAllViews(pModel);
}
+
+ bValid = true;
}
}
return bValid;
@@ -760,90 +739,88 @@ bool ScDocument::DeleteTab( SCTAB nTab )
bool ScDocument::DeleteTabs( SCTAB nTab, SCTAB nSheets )
{
bool bValid = false;
- if (ValidTab(nTab) && (nTab + nSheets) <= static_cast<SCTAB>(maTabs.size()))
+ if (HasTable(nTab) && (nTab + nSheets) <= GetTableCount())
{
- if (maTabs[nTab])
+ SCTAB nTabCount = GetTableCount();
+ if (nTabCount > nSheets)
{
- SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
- if (nTabCount > nSheets)
- {
- sc::AutoCalcSwitch aACSwitch(*this, false);
- sc::RefUpdateDeleteTabContext aCxt( *this, nTab, nSheets);
+ sc::AutoCalcSwitch aACSwitch(*this, false);
+ sc::RefUpdateDeleteTabContext aCxt( *this, nTab, nSheets);
+ sc::DelayDeletingBroadcasters delayDeletingBroadcasters(*this);
- for (SCTAB aTab = 0; aTab < nSheets; ++aTab)
- {
- ScRange aRange( 0, 0, nTab, MaxCol(), MaxRow(), nTab + aTab );
- DelBroadcastAreasInRange( aRange );
-
- // #i8180# remove database ranges etc. that are on the deleted tab
- // (restored in undo with ScRefUndoData)
-
- xColNameRanges->DeleteOnTab( nTab + aTab );
- xRowNameRanges->DeleteOnTab( nTab + aTab );
- pDBCollection->DeleteOnTab( nTab + aTab );
- if (pDPCollection)
- pDPCollection->DeleteOnTab( nTab + aTab );
- if (pDetOpList)
- pDetOpList->DeleteOnTab( nTab + aTab );
- DeleteAreaLinksOnTab( nTab + aTab );
- }
-
- if (pRangeName)
- pRangeName->UpdateDeleteTab(aCxt);
+ for (SCTAB aTab = 0; aTab < nSheets; ++aTab)
+ {
+ ScRange aRange( 0, 0, nTab, MaxCol(), MaxRow(), nTab + aTab );
+ DelBroadcastAreasInRange( aRange );
- // normal reference update
+ // #i8180# remove database ranges etc. that are on the deleted tab
+ // (restored in undo with ScRefUndoData)
- ScRange aRange( 0, 0, nTab, MaxCol(), MaxRow(), nTabCount - 1 );
- xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1*nSheets );
- xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1*nSheets );
- pDBCollection->UpdateReference(
- URM_INSDEL, 0,0,nTab, MaxCol(),MaxRow(),MAXTAB, 0,0,-1*nSheets );
+ xColNameRanges->DeleteOnTab( nTab + aTab );
+ xRowNameRanges->DeleteOnTab( nTab + aTab );
+ pDBCollection->DeleteOnTab( nTab + aTab );
if (pDPCollection)
- pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,-1*nSheets );
+ pDPCollection->DeleteOnTab( nTab + aTab );
if (pDetOpList)
- pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,-1*nSheets );
- UpdateChartRef( URM_INSDEL, 0,0,nTab, MaxCol(),MaxRow(),MAXTAB, 0,0,-1*nSheets );
- UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,-1*nSheets );
- if (pValidationList)
- {
- ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
- pValidationList->UpdateDeleteTab(aCxt);
- }
- if ( pUnoBroadcaster )
- pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1*nSheets ) );
-
- for (auto & pTab : maTabs)
- if (pTab)
- pTab->UpdateDeleteTab(aCxt);
-
- maTabs.erase(maTabs.begin() + nTab, maTabs.begin() + nTab + nSheets);
- // UpdateBroadcastAreas must be called between UpdateDeleteTab,
- // which ends listening, and StartAllListeners, to not modify
- // areas that are to be inserted by starting listeners.
- UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,-1*nSheets);
- for (const auto& a : maTabs)
- {
- if (a)
- a->UpdateCompile();
- }
- // Excel-Filter deletes some Tables while loading, Listeners will
- // only be triggered after the loading is done.
- if ( !bInsertingFromOtherDoc )
- {
- StartAllListeners();
+ pDetOpList->DeleteOnTab( nTab + aTab );
+ DeleteAreaLinksOnTab( nTab + aTab );
+ }
- sc::SetFormulaDirtyContext aFormulaDirtyCxt;
- SetAllFormulasDirty(aFormulaDirtyCxt);
- }
+ if (pRangeName)
+ pRangeName->UpdateDeleteTab(aCxt);
+
+ // normal reference update
+
+ ScRange aRange( 0, 0, nTab, MaxCol(), MaxRow(), nTabCount - 1 );
+ xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1*nSheets );
+ xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1*nSheets );
+ pDBCollection->UpdateReference(
+ URM_INSDEL, 0,0,nTab, MaxCol(),MaxRow(),MAXTAB, 0,0,-1*nSheets );
+ if (pDPCollection)
+ pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,-1*nSheets );
+ if (pDetOpList)
+ pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,-1*nSheets );
+ UpdateChartRef( URM_INSDEL, 0,0,nTab, MaxCol(),MaxRow(),MAXTAB, 0,0,-1*nSheets );
+ UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,-1*nSheets );
+ if (pValidationList)
+ {
+ ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
+ pValidationList->UpdateDeleteTab(aCxt);
+ }
+ if ( pUnoBroadcaster )
+ pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1*nSheets ) );
+
+ for (auto & pTab : maTabs)
+ if (pTab)
+ pTab->UpdateDeleteTab(aCxt);
+
+ maTabs.erase(maTabs.begin() + nTab, maTabs.begin() + nTab + nSheets);
+ // UpdateBroadcastAreas must be called between UpdateDeleteTab,
+ // which ends listening, and StartAllListeners, to not modify
+ // areas that are to be inserted by starting listeners.
+ UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,-1*nSheets);
+ for (const auto& a : maTabs)
+ {
+ if (a)
+ a->UpdateCompile();
+ }
+ // Excel-Filter deletes some Tables while loading, Listeners will
+ // only be triggered after the loading is done.
+ if ( !bInsertingFromOtherDoc )
+ {
+ StartAllListeners();
- if (comphelper::LibreOfficeKit::isActive())
- {
- ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>(this->GetDocumentShell()->GetModel());
- SfxLokHelper::notifyDocumentSizeChangedAllViews(pModel);
- }
+ sc::SetFormulaDirtyContext aFormulaDirtyCxt;
+ SetAllFormulasDirty(aFormulaDirtyCxt);
+ }
- bValid = true;
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScModelObj* pModel = GetDocumentShell()->GetModel();
+ SfxLokHelper::notifyDocumentSizeChangedAllViews(pModel);
}
+
+ bValid = true;
}
}
return bValid;
@@ -853,41 +830,45 @@ bool ScDocument::RenameTab( SCTAB nTab, const OUString& rName, bool bExternalDoc
{
bool bValid = false;
SCTAB i;
- if (ValidTab(nTab))
+ if (HasTable(nTab))
{
- if (maTabs[nTab])
+ if ( bExternalDocument )
+ bValid = true; // composed name
+ else
+ bValid = ValidTabName(rName);
+ for (i = 0; i < GetTableCount() && bValid; i++)
{
- if ( bExternalDocument )
- bValid = true; // composed name
- else
- bValid = ValidTabName(rName);
- for (i=0; (i< static_cast<SCTAB>(maTabs.size())) && bValid; i++)
- if (maTabs[i] && (i != nTab))
- {
- OUString aOldName = maTabs[i]->GetName();
- bValid = !ScGlobal::GetpTransliteration()->isEqual( rName, aOldName );
- }
- if (bValid)
+ if (maTabs[i] && (i != nTab))
{
- // #i75258# update charts before renaming, so they can get their live data objects.
- // Once the charts are live, the sheet can be renamed without problems.
- if ( pChartListenerCollection )
- pChartListenerCollection->UpdateChartsContainingTab( nTab );
- maTabs[nTab]->SetName(rName);
-
- // If formulas refer to the renamed sheet, the TokenArray remains valid,
- // but the XML stream must be re-generated.
- for (const auto& a : maTabs)
+ OUString aOldName = maTabs[i]->GetName();
+ bValid = !ScGlobal::GetTransliteration().isEqual( rName, aOldName );
+ }
+ }
+ if (bValid)
+ {
+ // #i75258# update charts before renaming, so they can get their live data objects.
+ // Once the charts are live, the sheet can be renamed without problems.
+ if ( pChartListenerCollection )
+ pChartListenerCollection->UpdateChartsContainingTab( nTab );
+ maTabs[nTab]->SetName(rName);
+
+ // If formulas refer to the renamed sheet, the TokenArray remains valid,
+ // but the XML stream must be re-generated.
+ for (const auto& pTable : maTabs)
+ {
+ if (pTable)
{
- if (a)
- a->SetStreamValid( false );
+ pTable->SetStreamValid( false );
+ // tdf#156815 Reset solver settings so next time they're loaded they come with
+ // the updated sheet name
+ pTable->ResetSolverSettings();
}
+ }
- if (comphelper::LibreOfficeKit::isActive() && GetDrawLayer())
- {
- ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>(this->GetDocumentShell()->GetModel());
- SfxLokHelper::notifyDocumentSizeChangedAllViews(pModel);
- }
+ if (comphelper::LibreOfficeKit::isActive() && GetDrawLayer())
+ {
+ ScModelObj* pModel = GetDocumentShell()->GetModel();
+ SfxLokHelper::notifyDocumentSizeChangedAllViews(pModel);
}
}
}
@@ -899,32 +880,28 @@ bool ScDocument::RenameTab( SCTAB nTab, const OUString& rName, bool bExternalDoc
void ScDocument::SetVisible( SCTAB nTab, bool bVisible )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
- if (maTabs[nTab])
- maTabs[nTab]->SetVisible(bVisible);
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetVisible(bVisible);
}
bool ScDocument::IsVisible( SCTAB nTab ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
- if (maTabs[nTab])
- return maTabs[nTab]->IsVisible();
-
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->IsVisible();
return false;
}
bool ScDocument::IsStreamValid( SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->IsStreamValid();
-
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->IsStreamValid();
return false;
}
void ScDocument::SetStreamValid( SCTAB nTab, bool bSet, bool bIgnoreLock )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->SetStreamValid( bSet, bIgnoreLock );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetStreamValid( bSet, bIgnoreLock );
}
void ScDocument::LockStreamValid( bool bLock )
@@ -934,21 +911,30 @@ void ScDocument::LockStreamValid( bool bLock )
bool ScDocument::IsPendingRowHeights( SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->IsPendingRowHeights();
-
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->IsPendingRowHeights();
return false;
}
void ScDocument::SetPendingRowHeights( SCTAB nTab, bool bSet )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->SetPendingRowHeights( bSet );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetPendingRowHeights(bSet);
+}
+
+sal_uInt16 ScDocument::GetSheetOptimalMinRowHeight(SCTAB nTab) const
+{
+ const ScTable* pTab = FetchTable(nTab);
+ if (!pTab)
+ return ScGlobal::nStdRowHeight;
+
+ return pTab->GetOptimalMinRowHeight();
}
void ScDocument::SetLayoutRTL( SCTAB nTab, bool bRTL, ScObjectHandling eObjectHandling)
{
- if ( !(ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab]) )
+ ScTable* pTable = FetchTable(nTab);
+ if (!pTable)
return;
if ( bImportingXML )
@@ -957,12 +943,12 @@ void ScDocument::SetLayoutRTL( SCTAB nTab, bool bRTL, ScObjectHandling eObjectHa
// is applied in SetImportingXML(false). This is so the shapes can be loaded in
// normal LTR mode.
- maTabs[nTab]->SetLoadingRTL( bRTL );
+ pTable->SetLoadingRTL( bRTL );
return;
}
- maTabs[nTab]->SetLayoutRTL( bRTL ); // only sets the flag
- maTabs[nTab]->SetDrawPageSize(true, true, eObjectHandling);
+ pTable->SetLayoutRTL( bRTL ); // only sets the flag
+ pTable->SetDrawPageSize(true, true, eObjectHandling);
// objects are already repositioned via SetDrawPageSize, only writing mode is missing
if (!mpDrawLayer)
@@ -984,8 +970,8 @@ void ScDocument::SetLayoutRTL( SCTAB nTab, bool bRTL, ScObjectHandling eObjectHa
bool ScDocument::IsLayoutRTL( SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->IsLayoutRTL();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->IsLayoutRTL();
return false;
}
@@ -1008,9 +994,8 @@ bool ScDocument::IsNegativePage( SCTAB nTab ) const
bool ScDocument::GetCellArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
- if (maTabs[nTab])
- return maTabs[nTab]->GetCellArea( rEndCol, rEndRow );
+ if (HasTable(nTab))
+ return maTabs[nTab]->GetCellArea(rEndCol, rEndRow);
rEndCol = 0;
rEndRow = 0;
@@ -1019,9 +1004,8 @@ bool ScDocument::GetCellArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
bool ScDocument::GetTableArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow, bool bCalcHiddens) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
- if (maTabs[nTab])
- return maTabs[nTab]->GetTableArea( rEndCol, rEndRow, bCalcHiddens);
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetTableArea(rEndCol, rEndRow, bCalcHiddens);
rEndCol = 0;
rEndRow = 0;
@@ -1030,7 +1014,7 @@ bool ScDocument::GetTableArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow, bool
bool ScDocument::ShrinkToDataArea(SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB> (maTabs.size()) || !maTabs[nTab])
+ if (!HasTable(nTab))
return false;
SCCOL nCol1, nCol2;
@@ -1061,26 +1045,23 @@ bool ScDocument::ShrinkToDataArea(SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow
bool ScDocument::ShrinkToUsedDataArea( bool& o_bShrunk, SCTAB nTab, SCCOL& rStartCol,
SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly,
- bool bStickyTopRow, bool bStickyLeftCol, bool bConsiderCellNotes,
- bool bConsiderCellDrawObjects, bool bConsiderCellFormats ) const
+ bool bStickyTopRow, bool bStickyLeftCol, ScDataAreaExtras* pDataAreaExtras ) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB> (maTabs.size()) || !maTabs[nTab])
+ if (const ScTable* pTable = FetchTable(nTab))
{
- o_bShrunk = false;
- return false;
+ return pTable->ShrinkToUsedDataArea(
+ o_bShrunk, rStartCol, rStartRow, rEndCol, rEndRow, bColumnsOnly, bStickyTopRow,
+ bStickyLeftCol, pDataAreaExtras);
}
- return maTabs[nTab]->ShrinkToUsedDataArea(
- o_bShrunk, rStartCol, rStartRow, rEndCol, rEndRow, bColumnsOnly, bStickyTopRow,
- bStickyLeftCol, bConsiderCellNotes, bConsiderCellDrawObjects, bConsiderCellFormats);
+ o_bShrunk = false;
+ return false;
}
SCROW ScDocument::GetLastDataRow( SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCROW nLastRow ) const
{
- const ScTable* pTab = FetchTable(nTab);
- if (!pTab)
- return -1;
-
- return pTab->GetLastDataRow(nCol1, nCol2, nLastRow);
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetLastDataRow(nCol1, nCol2, nLastRow);
+ return -1;
}
// connected area
@@ -1088,8 +1069,15 @@ SCROW ScDocument::GetLastDataRow( SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCROW nL
void ScDocument::GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
SCCOL& rEndCol, SCROW& rEndRow, bool bIncludeOld, bool bOnlyDown ) const
{
+ if (const ScTable* pTable = FetchTable(nTab))
+ pTable->GetDataArea( rStartCol, rStartRow, rEndCol, rEndRow, bIncludeOld, bOnlyDown );
+}
+
+void ScDocument::GetBackColorArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
+ SCCOL& rEndCol, SCROW& rEndRow ) const
+{
if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->GetDataArea( rStartCol, rStartRow, rEndCol, rEndRow, bIncludeOld, bOnlyDown );
+ maTabs[nTab]->GetBackColorArea( rStartCol, rStartRow, rEndCol, rEndRow );
}
bool ScDocument::GetDataAreaSubrange(ScRange& rRange) const
@@ -1098,8 +1086,8 @@ bool ScDocument::GetDataAreaSubrange(ScRange& rRange) const
if (nTab != rRange.aEnd.Tab())
return true;
- if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetDataAreaSubrange(rRange);
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetDataAreaSubrange(rRange);
return true;
}
@@ -1107,9 +1095,8 @@ bool ScDocument::GetDataAreaSubrange(ScRange& rRange) const
void ScDocument::LimitChartArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
SCCOL& rEndCol, SCROW& rEndRow )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
- if (maTabs[nTab])
- maTabs[nTab]->LimitChartArea( rStartCol, rStartRow, rEndCol, rEndRow );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->LimitChartArea( rStartCol, rStartRow, rEndCol, rEndRow);
}
void ScDocument::LimitChartIfAll( ScRangeListRef& rRangeList )
@@ -1128,8 +1115,8 @@ void ScDocument::LimitChartIfAll( ScRangeListRef& rRangeList )
SCCOL nEndCol = aRange.aEnd.Col();
SCROW nEndRow = aRange.aEnd.Row();
SCTAB nTab = aRange.aStart.Tab();
- if ( nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->LimitChartArea(nStartCol, nStartRow, nEndCol, nEndRow);
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->LimitChartArea(nStartCol, nStartRow, nEndCol, nEndRow);
aRange.aStart.SetCol( nStartCol );
aRange.aStart.SetRow( nStartRow );
aRange.aEnd.SetCol( nEndCol );
@@ -1195,7 +1182,7 @@ bool ScDocument::CanInsertRow( const ScRange& rRange ) const
SCSIZE nSize = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
bool bTest = true;
- for (SCTAB i=nStartTab; i<=nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
+ for (SCTAB i = nStartTab; i <= nEndTab && bTest && i < GetTableCount(); i++)
if (maTabs[i])
bTest &= maTabs[i]->TestInsertRow( nStartCol, nEndCol, nStartRow, nSize );
@@ -1249,14 +1236,16 @@ bool ScDocument::InsertRow( SCCOL nStartCol, SCTAB nStartTab,
if ( pTabMark )
{
nStartTab = 0;
- nEndTab = static_cast<SCTAB>(maTabs.size()) -1;
+ nEndTab = GetTableCount() - 1;
}
bool bTest = true;
bool bRet = false;
bool bOldAutoCalc = GetAutoCalc();
SetAutoCalc( false ); // avoid multiple calculations
- for ( i = nStartTab; i <= nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
+ bool oldDelayedDeleteBroadcasters = IsDelayedDeletingBroadcasters();
+ EnableDelayDeletingBroadcasters( true );
+ for ( i = nStartTab; i <= nEndTab && bTest && i < GetTableCount(); i++)
if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
bTest &= maTabs[i]->TestInsertRow(nStartCol, nEndCol, nStartRow, nSize);
if (bTest)
@@ -1267,7 +1256,7 @@ bool ScDocument::InsertRow( SCCOL nStartCol, SCTAB nStartTab,
// handle chunks of consecutive selected sheets together
SCTAB nTabRangeStart = nStartTab;
SCTAB nTabRangeEnd = nEndTab;
- lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
+ lcl_GetFirstTabRange(nTabRangeStart, nTabRangeEnd, pTabMark, GetTableCount());
ScRange aShiftedRange(nStartCol, nStartRow, nTabRangeStart, nEndCol, MaxRow(), nTabRangeEnd);
sc::EndListeningContext aEndListenCxt(*this);
@@ -1285,9 +1274,9 @@ bool ScDocument::InsertRow( SCCOL nStartCol, SCTAB nStartTab,
UpdateBroadcastAreas(URM_INSDEL, aShiftedRange, 0, static_cast<SCROW>(nSize), 0);
}
- while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
+ while (lcl_GetNextTabRange(nTabRangeStart, nTabRangeEnd, pTabMark, GetTableCount()));
- lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
+ lcl_GetFirstTabRange(nTabRangeStart, nTabRangeEnd, pTabMark, GetTableCount());
sc::RefUpdateContext aCxt(*this);
aCxt.meMode = URM_INSDEL;
@@ -1299,20 +1288,25 @@ bool ScDocument::InsertRow( SCCOL nStartCol, SCTAB nStartTab,
aCxt.maRange.aEnd.SetTab(nTabRangeEnd);
UpdateReference(aCxt, pRefUndoDoc, false); // without drawing objects
}
- while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
+ while (lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, GetTableCount()));
// UpdateReference should have set "needs listening" flags to those
// whose references have been modified. We also need to set this flag
// to those that were in the groups that got split by shifting.
SetNeedsListeningGroups(aGroupPos);
- for (i=nStartTab; i<=nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
+ for (i=nStartTab; i<=nEndTab && i < GetTableCount(); i++)
+ {
if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
+ {
maTabs[i]->InsertRow( nStartCol, nEndCol, nStartRow, nSize );
+ maTabs[i]->CommentNotifyAddressChange(nStartCol, nStartRow, nEndCol, MaxRow());
+ }
+ }
// UpdateRef for drawing layer must be after inserting,
// when the new row heights are known.
- for (i=nStartTab; i<=nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
+ for (i=nStartTab; i<=nEndTab && i < GetTableCount(); i++)
if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
maTabs[i]->UpdateDrawRef( URM_INSDEL,
nStartCol, nStartRow, nStartTab, nEndCol, MaxRow(), nEndTab,
@@ -1343,6 +1337,7 @@ bool ScDocument::InsertRow( SCCOL nStartCol, SCTAB nStartTab,
}
bRet = true;
}
+ EnableDelayDeletingBroadcasters( oldDelayedDeleteBroadcasters );
SetAutoCalc( bOldAutoCalc );
if ( bRet && pChartListenerCollection )
pChartListenerCollection->UpdateDirtyCharts();
@@ -1369,7 +1364,7 @@ void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
if ( pTabMark )
{
nStartTab = 0;
- nEndTab = static_cast<SCTAB>(maTabs.size())-1;
+ nEndTab = GetTableCount() - 1;
}
sc::AutoCalcSwitch aACSwitch(*this, false); // avoid multiple calculations
@@ -1377,7 +1372,7 @@ void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
// handle chunks of consecutive selected sheets together
SCTAB nTabRangeStart = nStartTab;
SCTAB nTabRangeEnd = nEndTab;
- lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
+ lcl_GetFirstTabRange(nTabRangeStart, nTabRangeEnd, pTabMark, GetTableCount());
do
{
if ( ValidRow(nStartRow+nSize) )
@@ -1394,19 +1389,19 @@ void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
ScAddress( nStartCol, nStartRow, nTabRangeStart ),
ScAddress( nEndCol, MaxRow(), nTabRangeEnd ) ) );
}
- while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
+ while (lcl_GetNextTabRange(nTabRangeStart, nTabRangeEnd, pTabMark, GetTableCount()));
sc::RefUpdateContext aCxt(*this);
- const bool bLastRowIncluded = (static_cast<SCROW>(nStartRow + nSize) == GetSheetLimits().GetMaxRowCount() && ValidRow(nStartRow));
+ const bool bLastRowIncluded = (static_cast<SCROW>(nStartRow + nSize) == GetMaxRowCount() && ValidRow(nStartRow));
if ( ValidRow(nStartRow+nSize) || bLastRowIncluded )
{
- lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
+ lcl_GetFirstTabRange(nTabRangeStart, nTabRangeEnd, pTabMark, GetTableCount());
aCxt.meMode = URM_INSDEL;
aCxt.mnRowDelta = -static_cast<SCROW>(nSize);
if (bLastRowIncluded)
{
// Last row is included, shift a virtually non-existent row in.
- aCxt.maRange = ScRange( nStartCol, GetSheetLimits().GetMaxRowCount(), nTabRangeStart, nEndCol, GetSheetLimits().GetMaxRowCount(), nTabRangeEnd);
+ aCxt.maRange = ScRange( nStartCol, GetMaxRowCount(), nTabRangeStart, nEndCol, GetMaxRowCount(), nTabRangeEnd);
}
else
{
@@ -1416,7 +1411,7 @@ void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
{
UpdateReference(aCxt, pRefUndoDoc, true, false);
}
- while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
+ while (lcl_GetNextTabRange(nTabRangeStart, nTabRangeEnd, pTabMark, GetTableCount()));
}
if (pUndoOutline)
@@ -1426,9 +1421,14 @@ void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
// during row deletion.
std::vector<ScAddress> aGroupPos;
- for ( i = nStartTab; i <= nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
+ for ( i = nStartTab; i <= nEndTab && i < GetTableCount(); i++)
+ {
if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
+ {
maTabs[i]->DeleteRow(aCxt.maRegroupCols, nStartCol, nEndCol, nStartRow, nSize, pUndoOutline, &aGroupPos);
+ maTabs[i]->CommentNotifyAddressChange(nStartCol, nStartRow, nEndCol, MaxRow());
+ }
+ }
// Newly joined groups have some of their members still listening. We
// need to make sure none of them are listening.
@@ -1481,7 +1481,7 @@ bool ScDocument::CanInsertCol( const ScRange& rRange ) const
SCSIZE nSize = static_cast<SCSIZE>(nEndCol - nStartCol + 1);
bool bTest = true;
- for (SCTAB i=nStartTab; i<=nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
+ for (SCTAB i = nStartTab; i <= nEndTab && bTest && i < GetTableCount(); i++)
if (maTabs[i])
bTest &= maTabs[i]->TestInsertCol( nStartRow, nEndRow, nSize );
@@ -1500,14 +1500,16 @@ bool ScDocument::InsertCol( SCROW nStartRow, SCTAB nStartTab,
if ( pTabMark )
{
nStartTab = 0;
- nEndTab = static_cast<SCTAB>(maTabs.size())-1;
+ nEndTab = GetTableCount() - 1;
}
bool bTest = true;
bool bRet = false;
bool bOldAutoCalc = GetAutoCalc();
SetAutoCalc( false ); // avoid multiple calculations
- for ( i = nStartTab; i <= nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
+ bool oldDelayedDeleteBroadcasters = IsDelayedDeletingBroadcasters();
+ EnableDelayDeletingBroadcasters( true );
+ for ( i = nStartTab; i <= nEndTab && bTest && i < GetTableCount(); i++)
if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
bTest &= maTabs[i]->TestInsertCol( nStartRow, nEndRow, nSize );
if (bTest)
@@ -1515,16 +1517,16 @@ bool ScDocument::InsertCol( SCROW nStartRow, SCTAB nStartTab,
// handle chunks of consecutive selected sheets together
SCTAB nTabRangeStart = nStartTab;
SCTAB nTabRangeEnd = nEndTab;
- lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
+ lcl_GetFirstTabRange(nTabRangeStart, nTabRangeEnd, pTabMark, GetTableCount());
do
{
UpdateBroadcastAreas( URM_INSDEL, ScRange(
ScAddress( nStartCol, nStartRow, nTabRangeStart ),
ScAddress( MaxCol(), nEndRow, nTabRangeEnd )), static_cast<SCCOL>(nSize), 0, 0 );
}
- while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
+ while (lcl_GetNextTabRange(nTabRangeStart, nTabRangeEnd, pTabMark, GetTableCount()));
- lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
+ lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, GetTableCount());
sc::RefUpdateContext aCxt(*this);
aCxt.meMode = URM_INSDEL;
@@ -1534,9 +1536,9 @@ bool ScDocument::InsertCol( SCROW nStartRow, SCTAB nStartTab,
{
UpdateReference(aCxt, pRefUndoDoc, true, false);
}
- while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
+ while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, GetTableCount()));
- for (i=nStartTab; i<=nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
+ for (i = nStartTab; i <= nEndTab && i < GetTableCount(); i++)
if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
maTabs[i]->InsertCol(aCxt.maRegroupCols, nStartCol, nStartRow, nEndRow, nSize);
@@ -1552,7 +1554,10 @@ bool ScDocument::InsertCol( SCROW nStartRow, SCTAB nStartTab,
// At least all cells using range names pointing relative to the
// moved range must be recalculated, and all cells marked postponed
// dirty.
- std::for_each(maTabs.begin(), maTabs.end(), SetDirtyIfPostponedHandler());
+ {
+ ScBulkBroadcast aBulkBroadcast(GetBASM(), SfxHintId::ScDataChanged);
+ std::for_each(maTabs.begin(), maTabs.end(), SetDirtyIfPostponedHandler());
+ }
// Cells containing functions such as CELL, COLUMN or ROW may have
// changed their values on relocation. Broadcast them.
{
@@ -1562,6 +1567,7 @@ bool ScDocument::InsertCol( SCROW nStartRow, SCTAB nStartTab,
}
bRet = true;
}
+ EnableDelayDeletingBroadcasters( oldDelayedDeleteBroadcasters );
SetAutoCalc( bOldAutoCalc );
if ( bRet && pChartListenerCollection )
pChartListenerCollection->UpdateDirtyCharts();
@@ -1586,15 +1592,16 @@ void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTA
if ( pTabMark )
{
nStartTab = 0;
- nEndTab = static_cast<SCTAB>(maTabs.size())-1;
+ nEndTab = GetTableCount() - 1;
}
sc::AutoCalcSwitch aACSwitch(*this, false); // avoid multiple calculations
+ ScBulkBroadcast aBulkBroadcast(GetBASM(), SfxHintId::ScDataChanged);
// handle chunks of consecutive selected sheets together
SCTAB nTabRangeStart = nStartTab;
SCTAB nTabRangeEnd = nEndTab;
- lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
+ lcl_GetFirstTabRange(nTabRangeStart, nTabRangeEnd, pTabMark, GetTableCount());
do
{
if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
@@ -1611,19 +1618,19 @@ void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTA
ScAddress( nStartCol, nStartRow, nTabRangeStart ),
ScAddress( MaxCol(), nEndRow, nTabRangeEnd ) ) );
}
- while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
+ while (lcl_GetNextTabRange(nTabRangeStart, nTabRangeEnd, pTabMark, GetTableCount()));
sc::RefUpdateContext aCxt(*this);
- const bool bLastColIncluded = (nStartCol + nSize == MAXCOLCOUNT && ValidCol(nStartCol));
+ const bool bLastColIncluded = (static_cast<SCCOL>(nStartCol + nSize) == GetMaxColCount() && ValidCol(nStartCol));
if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) || bLastColIncluded )
{
- lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
+ lcl_GetFirstTabRange(nTabRangeStart, nTabRangeEnd, pTabMark, GetTableCount());
aCxt.meMode = URM_INSDEL;
aCxt.mnColDelta = -static_cast<SCCOL>(nSize);
if (bLastColIncluded)
{
// Last column is included, shift a virtually non-existent column in.
- aCxt.maRange = ScRange( MAXCOLCOUNT, nStartRow, nTabRangeStart, MAXCOLCOUNT, nEndRow, nTabRangeEnd);
+ aCxt.maRange = ScRange( GetMaxColCount(), nStartRow, nTabRangeStart, GetMaxColCount(), nEndRow, nTabRangeEnd);
}
else
{
@@ -1634,13 +1641,13 @@ void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTA
{
UpdateReference(aCxt, pRefUndoDoc, true, false);
}
- while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
+ while (lcl_GetNextTabRange(nTabRangeStart, nTabRangeEnd, pTabMark, GetTableCount()));
}
if (pUndoOutline)
*pUndoOutline = false;
- for (i = nStartTab; i <= nEndTab && i < static_cast<SCTAB>(maTabs.size()); ++i)
+ for (i = nStartTab; i <= nEndTab && i < GetTableCount(); ++i)
{
if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
maTabs[i]->DeleteCol(aCxt.maRegroupCols, nStartCol, nStartRow, nEndRow, nSize, pUndoOutline);
@@ -1752,16 +1759,15 @@ bool ScDocument::HasPartOfMerged( const ScRange& rRange )
formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScAddress& rPos )
{
SCTAB nTab = rPos.Tab();
- if (!TableExists(nTab))
- return formula::FormulaTokenRef();
-
- return maTabs[nTab]->ResolveStaticReference(rPos.Col(), rPos.Row());
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->ResolveStaticReference(rPos.Col(), rPos.Row());
+ return formula::FormulaTokenRef();
}
formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScRange& rRange )
{
SCTAB nTab = rRange.aStart.Tab();
- if (nTab != rRange.aEnd.Tab() || !TableExists(nTab))
+ if (nTab != rRange.aEnd.Tab() || !HasTable(nTab))
return formula::FormulaTokenRef();
return maTabs[nTab]->ResolveStaticReference(
@@ -1771,18 +1777,18 @@ formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScRange& rRan
formula::VectorRefArray ScDocument::FetchVectorRefArray( const ScAddress& rPos, SCROW nLength )
{
SCTAB nTab = rPos.Tab();
- if (!TableExists(nTab))
- return formula::VectorRefArray();
-
- return maTabs[nTab]->FetchVectorRefArray(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->FetchVectorRefArray(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
+ return formula::VectorRefArray();
}
#ifdef DBG_UTIL
void ScDocument::AssertNoInterpretNeeded( const ScAddress& rPos, SCROW nLength )
{
SCTAB nTab = rPos.Tab();
- assert(TableExists(nTab));
- return maTabs[nTab]->AssertNoInterpretNeeded(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
+ assert(HasTable(nTab));
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->AssertNoInterpretNeeded(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
}
#endif
@@ -1793,13 +1799,20 @@ void ScDocument::UnlockAdjustHeight()
--nAdjustHeightLock;
}
-bool ScDocument::HandleRefArrayForParallelism( const ScAddress& rPos, SCROW nLength, const ScFormulaCellGroupRef& mxGroup )
+bool ScDocument::HandleRefArrayForParallelism( const ScAddress& rPos, SCROW nLength, const ScFormulaCellGroupRef& mxGroup, ScAddress* pDirtiedAddress)
{
SCTAB nTab = rPos.Tab();
- if (!TableExists(nTab))
- return false;
-
- return maTabs[nTab]->HandleRefArrayForParallelism(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1, mxGroup);
+ if (ScTable* pTable = FetchTable(nTab))
+ {
+ bool bRet = pTable->HandleRefArrayForParallelism(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1, mxGroup, pDirtiedAddress);
+ if (!bRet && pDirtiedAddress && pDirtiedAddress->Row() != -1)
+ {
+ pDirtiedAddress->SetCol(rPos.Col());
+ pDirtiedAddress->SetTab(nTab);
+ }
+ return bRet;
+ }
+ return false;
}
bool ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
@@ -1883,7 +1896,7 @@ void ScDocument::DeleteArea(
// the area borders.
sc::EndListeningContext aCxt(*this);
ScRange aRange(nCol1, nRow1, 0, nCol2, nRow2, 0);
- for (SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); i++)
+ for (SCTAB i = 0; i < GetTableCount(); i++)
{
if (rMark.GetTableSelect(i))
{
@@ -1896,7 +1909,7 @@ void ScDocument::DeleteArea(
aCxt.purgeEmptyBroadcasters();
}
- for (SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); i++)
+ for (SCTAB i = 0; i < GetTableCount(); i++)
if (maTabs[i])
if ( rMark.GetTableSelect(i) || bIsUndo )
maTabs[i]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag, bBroadcast, pBroadcastSpans);
@@ -1915,7 +1928,7 @@ void ScDocument::DeleteArea(
return;
ScRange aRange(nCol1, nRow1, 0, nCol2, nRow2, 0);
- for (SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); i++)
+ for (SCTAB i = 0; i < GetTableCount(); i++)
{
if (rMark.GetTableSelect(i))
{
@@ -1932,11 +1945,11 @@ void ScDocument::DeleteAreaTab(SCCOL nCol1, SCROW nRow1,
{
PutInOrder( nCol1, nCol2 );
PutInOrder( nRow1, nRow2 );
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
+ if (ScTable* pTable = FetchTable(nTab))
{
bool bOldAutoCalc = GetAutoCalc();
SetAutoCalc( false ); // avoid multiple calculations
- maTabs[nTab]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
+ pTable->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
SetAutoCalc( bOldAutoCalc );
}
}
@@ -1962,14 +1975,14 @@ void ScDocument::InitUndoSelected(const ScDocument& rSrcDoc, const ScMarkData& r
if ( rTabSelection.GetTableSelect( nTab ) )
{
ScTableUniquePtr pTable(new ScTable(*this, nTab, OUString(), bColInfo, bRowInfo));
- if (nTab < static_cast<SCTAB>(maTabs.size()))
+ if (nTab < GetTableCount())
maTabs[nTab] = std::move(pTable);
else
maTabs.push_back(std::move(pTable));
}
else
{
- if (nTab < static_cast<SCTAB>(maTabs.size()))
+ if (nTab < GetTableCount())
maTabs[nTab]=nullptr;
else
maTabs.push_back(nullptr);
@@ -1998,7 +2011,7 @@ void ScDocument::InitUndo( const ScDocument& rSrcDoc, SCTAB nTab1, SCTAB nTab2,
if (rSrcDoc.mpShell->GetMedium())
maFileURL = rSrcDoc.mpShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::ToIUri);
- if ( nTab2 >= static_cast<SCTAB>(maTabs.size()))
+ if (nTab2 >= GetTableCount())
maTabs.resize(nTab2 + 1);
for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
{
@@ -2014,7 +2027,7 @@ void ScDocument::AddUndoTab( SCTAB nTab1, SCTAB nTab2, bool bColInfo, bool bRowI
return;
}
- if (nTab2 >= static_cast<SCTAB>(maTabs.size()))
+ if (nTab2 >= GetTableCount())
{
maTabs.resize(nTab2+1);
}
@@ -2075,7 +2088,7 @@ void ScDocument::UndoToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
CopyToDocument(0, 0, 0, MaxCol(), MaxRow(), nTab1-1, InsertDeleteFlags::FORMULA, false, rDestDoc);
sc::CopyToDocContext aCxt(rDestDoc);
- assert( nTab2 < static_cast<SCTAB>(maTabs.size()) && nTab2 < static_cast<SCTAB>(rDestDoc.maTabs.size()));
+ assert(nTab2 < GetTableCount() && nTab2 < rDestDoc.GetTableCount());
for (SCTAB i = nTab1; i <= nTab2; i++)
{
if (maTabs[i] && rDestDoc.maTabs[i])
@@ -2098,11 +2111,13 @@ void ScDocument::CopyToDocument(const ScRange& rRange,
rDestDoc.aDocName = aDocName;
sc::AutoCalcSwitch aACSwitch(rDestDoc, false); // avoid multiple calculations
+ ScBulkBroadcast aBulkBroadcast(rDestDoc.GetBASM(), SfxHintId::ScDataChanged);
+ sc::DelayDeletingBroadcasters delayDeletingBroadcasters(*this);
sc::CopyToDocContext aCxt(rDestDoc);
aCxt.setStartListening(false);
- SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), rDestDoc.maTabs.size()));
+ SCTAB nMinSizeBothTabs = std::min(GetTableCount(), rDestDoc.GetTableCount());
for (SCTAB i = aNewRange.aStart.Tab(); i <= aNewRange.aEnd.Tab() && i < nMinSizeBothTabs; i++)
{
ScTable* pTab = FetchTable(i);
@@ -2133,7 +2148,7 @@ void ScDocument::UndoToDocument(const ScRange& rRange,
if (nTab1 > 0)
CopyToDocument(0, 0, 0, MaxCol(), MaxRow(), nTab1-1, InsertDeleteFlags::FORMULA, false, rDestDoc);
- SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), rDestDoc.maTabs.size()));
+ SCTAB nMinSizeBothTabs = std::min(GetTableCount(), rDestDoc.GetTableCount());
for (SCTAB i = nTab1; i <= nTab2 && i < nMinSizeBothTabs; i++)
{
if (maTabs[i] && rDestDoc.maTabs[i])
@@ -2142,8 +2157,8 @@ void ScDocument::UndoToDocument(const ScRange& rRange,
nFlags, bOnlyMarked, rDestDoc.maTabs[i].get());
}
- if (nTab2 < static_cast<SCTAB>(maTabs.size()))
- CopyToDocument(0, 0 , nTab2+1, MaxCol(), MaxRow(), maTabs.size(), InsertDeleteFlags::FORMULA, false, rDestDoc);
+ if (nTab2 < GetTableCount())
+ CopyToDocument(0, 0 , nTab2+1, MaxCol(), MaxRow(), GetTableCount(), InsertDeleteFlags::FORMULA, false, rDestDoc);
}
void ScDocument::CopyToClip(const ScClipParam& rClipParam,
@@ -2188,28 +2203,34 @@ void ScDocument::CopyToClip(const ScClipParam& rClipParam,
pClipDoc->aDocName = aDocName;
pClipDoc->SetClipParam(rClipParam);
ScRange aClipRange = rClipParam.getWholeRange();
- SCTAB nEndTab = static_cast<SCTAB>(maTabs.size());
+ SCTAB nEndTab = GetTableCount();
pClipDoc->ResetClip(this, pMarks);
sc::CopyToClipContext aCxt(*pClipDoc, bKeepScenarioFlags);
CopyRangeNamesToClip(pClipDoc, aClipRange, pMarks);
+ // 1. Copy selected cells
for (SCTAB i = 0; i < nEndTab; ++i)
{
- if (!maTabs[i] || i >= static_cast<SCTAB>(pClipDoc->maTabs.size()) || !pClipDoc->maTabs[i])
+ if (!maTabs[i] || i >= pClipDoc->GetTableCount() || !pClipDoc->maTabs[i])
continue;
if ( pMarks && !pMarks->GetTableSelect(i) )
continue;
maTabs[i]->CopyToClip(aCxt, rClipParam.maRanges, pClipDoc->maTabs[i].get());
+ }
- if (mpDrawLayer && bIncludeObjects)
+ // 2. Copy drawing objects in the selection. Do in after the first "copy cells" pass, because
+ // the embedded objects (charts) could reference cells from tabs not (yet) copied; doing it now
+ // allows to know what is already copied, to not overwrite attributes of already copied data.
+ if (mpDrawLayer && bIncludeObjects)
+ {
+ for (SCTAB i = 0; i < nEndTab; ++i)
{
- // also copy drawing objects
- tools::Rectangle aObjRect = GetMMRect(
- aClipRange.aStart.Col(), aClipRange.aStart.Row(), aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i);
+ tools::Rectangle aObjRect = GetMMRect(aClipRange.aStart.Col(), aClipRange.aStart.Row(),
+ aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i);
mpDrawLayer->CopyToClip(pClipDoc, i, aObjRect);
}
}
@@ -2220,8 +2241,8 @@ void ScDocument::CopyToClip(const ScClipParam& rClipParam,
void ScDocument::CopyStaticToDocument(const ScRange& rSrcRange, SCTAB nDestTab, ScDocument& rDestDoc)
{
- ScTable* pSrcTab = rSrcRange.aStart.Tab() < static_cast<SCTAB>(maTabs.size()) ? maTabs[rSrcRange.aStart.Tab()].get() : nullptr;
- ScTable* pDestTab = nDestTab < static_cast<SCTAB>(rDestDoc.maTabs.size()) ? rDestDoc.maTabs[nDestTab].get() : nullptr;
+ ScTable* pSrcTab = rSrcRange.aStart.Tab() < GetTableCount() ? maTabs[rSrcRange.aStart.Tab()].get() : nullptr;
+ ScTable* pDestTab = nDestTab < rDestDoc.GetTableCount() ? rDestDoc.maTabs[nDestTab].get() : nullptr;
if (!pSrcTab || !pDestTab)
return;
@@ -2236,7 +2257,7 @@ void ScDocument::CopyStaticToDocument(const ScRange& rSrcRange, SCTAB nDestTab,
void ScDocument::CopyCellToDocument( const ScAddress& rSrcPos, const ScAddress& rDestPos, ScDocument& rDestDoc )
{
- if (!TableExists(rSrcPos.Tab()) || !rDestDoc.TableExists(rDestPos.Tab()))
+ if (!HasTable(rSrcPos.Tab()) || !rDestDoc.HasTable(rDestPos.Tab()))
return;
ScTable& rSrcTab = *maTabs[rSrcPos.Tab()];
@@ -2292,7 +2313,7 @@ void ScDocument::CopyTabToClip(SCCOL nCol1, SCROW nRow1,
pClipDoc->ResetClip( this, nTab );
sc::CopyToClipContext aCxt(*pClipDoc, false);
- if (nTab < static_cast<SCTAB>(maTabs.size()) && nTab < static_cast<SCTAB>(pClipDoc->maTabs.size()))
+ if (nTab < GetTableCount() && nTab < pClipDoc->GetTableCount())
if (maTabs[nTab] && pClipDoc->maTabs[nTab])
maTabs[nTab]->CopyToClip(aCxt, nCol1, nRow1, nCol2, nRow2, pClipDoc->maTabs[nTab].get());
@@ -2370,7 +2391,7 @@ void ScDocument::TransposeClip(ScDocument* pTransClip, InsertDeleteFlags nFlags,
nRowCount += nRowCountNonFiltered; // for next iteration
}
- for (SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); i++)
+ for (SCTAB i = 0; i < GetTableCount(); i++)
{
if (maTabs[i])
{
@@ -2388,13 +2409,14 @@ void ScDocument::TransposeClip(ScDocument* pTransClip, InsertDeleteFlags nFlags,
// (mpDrawLayer in the original clipboard document is set only if there
// are drawing objects to copy)
+ // ToDo: Loop over blocks of non-filtered rows in case of filtered rows exist.
pTransClip->InitDrawLayer();
- tools::Rectangle aSourceRect = GetMMRect( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
- aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i );
- tools::Rectangle aDestRect = pTransClip->GetMMRect( 0, 0,
- static_cast<SCCOL>(aClipRange.aEnd.Row() - aClipRange.aStart.Row()),
- static_cast<SCROW>(aClipRange.aEnd.Col() - aClipRange.aStart.Col()), i );
- pTransClip->mpDrawLayer->CopyFromClip( mpDrawLayer.get(), i, aSourceRect, ScAddress(0,0,i), aDestRect );
+ ScAddress aTransposedEnd(
+ static_cast<SCCOL>(aClipRange.aEnd.Row() - aClipRange.aStart.Row() + aClipRange.aStart.Col()),
+ static_cast<SCROW>(aClipRange.aEnd.Col() - aClipRange.aStart.Col() + aClipRange.aStart.Row()), i);
+ ScRange aDestRange(aClipRange.aStart, aTransposedEnd);
+ ScAddress aDestStart = aClipRange.aStart;
+ pTransClip->mpDrawLayer->CopyFromClip(mpDrawLayer.get(), i, aClipRange, aDestStart, aDestRange, true);
}
}
}
@@ -2436,7 +2458,7 @@ void ScDocument::CopyRangeNamesToClip(ScDocument* pClipDoc, const ScRange& rClip
return;
sc::UpdatedRangeNames aUsedNames; // indexes of named ranges that are used in the copied cells
- SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), pClipDoc->maTabs.size()));
+ SCTAB nMinSizeBothTabs = std::min(GetTableCount(), pClipDoc->GetTableCount());
for (SCTAB i = 0; i < nMinSizeBothTabs; ++i)
if (maTabs[i] && pClipDoc->maTabs[i])
if ( !pMarks || pMarks->GetTableSelect(i) )
@@ -2505,22 +2527,16 @@ void ScDocument::DumpColumnStorage( SCTAB nTab, SCCOL nCol ) const
}
#endif
-#if DEBUG_AREA_BROADCASTER
-void ScDocument::DumpAreaBroadcasters() const
+bool ScDocument::HasTable(SCTAB nTab) const
{
- if (pBASM)
- pBASM->Dump();
-}
-#endif
-
-bool ScDocument::TableExists( SCTAB nTab ) const
-{
- return ValidTab(nTab) && o3tl::make_unsigned(nTab) < maTabs.size() && maTabs[nTab];
+ return ValidTab(nTab)
+ && nTab < GetTableCount()
+ && maTabs[nTab];
}
ScTable* ScDocument::FetchTable( SCTAB nTab )
{
- if (!TableExists(nTab))
+ if (!HasTable(nTab))
return nullptr;
return maTabs[nTab].get();
@@ -2528,22 +2544,33 @@ ScTable* ScDocument::FetchTable( SCTAB nTab )
const ScTable* ScDocument::FetchTable( SCTAB nTab ) const
{
- if (!TableExists(nTab))
+ if (!HasTable(nTab))
return nullptr;
return maTabs[nTab].get();
}
-ScColumnsRange ScDocument::GetColumnsRange( SCTAB nTab, SCCOL nColBegin, SCCOL nColEnd) const
+ScColumnsRange ScDocument::GetWritableColumnsRange( SCTAB nTab, SCCOL nColBegin, SCCOL nColEnd)
{
- if (!TableExists(nTab))
- {
- std::vector<std::unique_ptr<ScColumn, o3tl::default_delete<ScColumn>>> aEmptyVector;
- return ScColumnsRange(ScColumnsRange::Iterator(aEmptyVector.begin()),
- ScColumnsRange::Iterator(aEmptyVector.end()));
- }
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->GetWritableColumnsRange(nColBegin, nColEnd);
+
+ SAL_WARN("sc", "GetWritableColumnsRange() called for non-existent table");
+ return ScColumnsRange(-1, -1);
+}
- return maTabs[nTab]->GetColumnsRange(nColBegin, nColEnd);
+ScColumnsRange ScDocument::GetAllocatedColumnsRange( SCTAB nTab, SCCOL nColBegin, SCCOL nColEnd) const
+{
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetAllocatedColumnsRange(nColBegin, nColEnd);
+ return ScColumnsRange(-1, -1);
+}
+
+ScColumnsRange ScDocument::GetColumnsRange( SCTAB nTab, SCCOL nColBegin, SCCOL nColEnd) const
+{
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetColumnsRange(nColBegin, nColEnd);
+ return ScColumnsRange(-1, -1);
}
void ScDocument::MergeNumberFormatter(const ScDocument& rSrcDoc)
@@ -2585,6 +2612,14 @@ bool ScDocument::IsClipboardSource() const
mxPoolHelper->GetDocPool() == pClipDoc->mxPoolHelper->GetDocPool();
}
+void ScDocument::StartListeningFromClip(
+ sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt,
+ SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
+{
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->StartListeningFormulaCells(rStartCxt, rEndCxt, nCol1, nRow1, nCol2, nRow2);
+}
+
void ScDocument::StartListeningFromClip( SCCOL nCol1, SCROW nRow1,
SCCOL nCol2, SCROW nRow2,
const ScMarkData& rMark, InsertDeleteFlags nInsFlag )
@@ -2597,14 +2632,8 @@ void ScDocument::StartListeningFromClip( SCCOL nCol1, SCROW nRow1,
sc::StartListeningContext aStartCxt(*this, pSet);
sc::EndListeningContext aEndCxt(*this, pSet, nullptr);
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
- for (const auto& rTab : rMark)
- {
- if (rTab >= nMax)
- break;
- if (maTabs[rTab])
- maTabs[rTab]->StartListeningFormulaCells(aStartCxt, aEndCxt, nCol1, nRow1, nCol2, nRow2);
- }
+ for (SCTAB nTab : rMark)
+ StartListeningFromClip(aStartCxt, aEndCxt, nTab, nCol1, nRow1, nCol2, nRow2);
}
void ScDocument::SetDirtyFromClip(
@@ -2613,7 +2642,7 @@ void ScDocument::SetDirtyFromClip(
{
if (nInsFlag & InsertDeleteFlags::CONTENTS)
{
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -2626,10 +2655,9 @@ void ScDocument::SetDirtyFromClip(
bool ScDocument::InitColumnBlockPosition( sc::ColumnBlockPosition& rBlockPos, SCTAB nTab, SCCOL nCol )
{
- if (!TableExists(nTab))
- return false;
-
- return maTabs[nTab]->InitColumnBlockPosition(rBlockPos, nCol);
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->InitColumnBlockPosition(rBlockPos, nCol);
+ return false;
}
void ScDocument::CopyBlockFromClip(
@@ -2639,7 +2667,7 @@ void ScDocument::CopyBlockFromClip(
TableContainer& rClipTabs = rCxt.getClipDoc()->maTabs;
SCTAB nTabEnd = rCxt.getTabEnd();
SCTAB nClipTab = 0;
- for (SCTAB i = rCxt.getTabStart(); i <= nTabEnd && i < static_cast<SCTAB>(maTabs.size()); i++)
+ for (SCTAB i = rCxt.getTabStart(); i <= nTabEnd && i < GetTableCount(); i++)
{
if (maTabs[i] && rMark.GetTableSelect(i) )
{
@@ -2660,12 +2688,10 @@ void ScDocument::CopyBlockFromClip(
// For GetMMRect, the row heights in the target document must already be valid
// (copied in an extra step before pasting, or updated after pasting cells, but
// before pasting objects).
-
- tools::Rectangle aSourceRect = rCxt.getClipDoc()->GetMMRect(
- nCol1-nDx, nRow1-nDy, nCol2-nDx, nRow2-nDy, nClipTab );
- tools::Rectangle aDestRect = GetMMRect( nCol1, nRow1, nCol2, nRow2, i );
- mpDrawLayer->CopyFromClip(rCxt.getClipDoc()->mpDrawLayer.get(), nClipTab, aSourceRect,
- ScAddress( nCol1, nRow1, i ), aDestRect );
+ ScRange aSourceRange(nCol1 - nDx, nRow1 - nDy, nClipTab, nCol2 - nDx, nRow2 - nDy, nClipTab);
+ ScRange aDestRange(nCol1, nRow1, i, nCol2, nRow2, i);
+ mpDrawLayer->CopyFromClip(rCxt.getClipDoc()->mpDrawLayer.get(), nClipTab, aSourceRange,
+ ScAddress( nCol1, nRow1, i ), aDestRange);
}
}
@@ -2676,7 +2702,7 @@ void ScDocument::CopyBlockFromClip(
return;
nClipTab = 0;
- for (SCTAB i = rCxt.getTabStart(); i <= nTabEnd && i < static_cast<SCTAB>(maTabs.size()); i++)
+ for (SCTAB i = rCxt.getTabStart(); i <= nTabEnd && i < GetTableCount(); i++)
{
if (maTabs[i] && rMark.GetTableSelect(i) )
{
@@ -2813,11 +2839,11 @@ public:
}
-void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMark,
- InsertDeleteFlags nInsFlag,
- ScDocument* pRefUndoDoc, ScDocument* pClipDoc, bool bResetCut,
- bool bAsLink, bool bIncludeFiltered, bool bSkipAttrForEmpty,
- const ScRangeList * pDestRanges )
+void ScDocument::CopyFromClip(
+ const ScRange& rDestRange, const ScMarkData& rMark, InsertDeleteFlags nInsFlag,
+ ScDocument* pRefUndoDoc, ScDocument* pClipDoc, bool bResetCut,
+ bool bAsLink, bool bIncludeFiltered, bool bSkipEmptyCells,
+ const ScRangeList * pDestRanges )
{
if (bIsClip)
return;
@@ -2843,7 +2869,7 @@ void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMar
SCCOL nXw = 0;
SCROW nYw = 0;
ScRange aClipRange = pClipDoc->GetClipParam().getWholeRange();
- for (SCTAB nTab = 0; nTab < static_cast<SCTAB>(pClipDoc->maTabs.size()); nTab++) // find largest merge overlap
+ for (SCTAB nTab = 0; nTab < pClipDoc->GetTableCount(); nTab++) // find largest merge overlap
if (pClipDoc->maTabs[nTab]) // all sheets of the clipboard content
{
SCCOL nThisEndX = aClipRange.aEnd.Col();
@@ -2876,13 +2902,14 @@ void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMar
InsertDeleteFlags nDelFlag = InsertDeleteFlags::NONE;
if ( (nInsFlag & (InsertDeleteFlags::CONTENTS | InsertDeleteFlags::ADDNOTES)) == (InsertDeleteFlags::NOTE | InsertDeleteFlags::ADDNOTES) )
nDelFlag |= InsertDeleteFlags::NOTE;
- else if ( nInsFlag & InsertDeleteFlags::CONTENTS )
- nDelFlag |= InsertDeleteFlags::CONTENTS;
+ // tdf#141440 - do not delete notes when pasting contents (see InsertDeleteFlags::CONTENTS)
+ else if ( nInsFlag & (InsertDeleteFlags::CONTENTS & ~InsertDeleteFlags::NOTE) )
+ nDelFlag |= InsertDeleteFlags::CONTENTS & ~InsertDeleteFlags::NOTE;
if (nInsFlag & InsertDeleteFlags::ATTRIB)
nDelFlag |= InsertDeleteFlags::ATTRIB;
- sc::CopyFromClipContext aCxt(*this, pRefUndoDoc, pClipDoc, nInsFlag, bAsLink, bSkipAttrForEmpty);
+ sc::CopyFromClipContext aCxt(*this, pRefUndoDoc, pClipDoc, nInsFlag, bAsLink, bSkipEmptyCells);
std::pair<SCTAB,SCTAB> aTabRanges = getMarkedTableRange(maTabs, rMark);
aCxt.setTabRange(aTabRanges.first, aTabRanges.second);
aCxt.setDeleteFlag(nDelFlag);
@@ -2909,14 +2936,8 @@ void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMar
SCCOL nCol2 = rRange.aEnd.Col();
SCROW nRow2 = rRange.aEnd.Row();
- if (bSkipAttrForEmpty)
- {
- // Delete cells in the destination only if their corresponding clip cells are not empty.
- aCxt.setDestRange(nCol1, nRow1, nCol2, nRow2);
- DeleteBeforeCopyFromClip(aCxt, rMark, aBroadcastSpans);
- }
- else
- DeleteArea(nCol1, nRow1, nCol2, nRow2, rMark, nDelFlag, false, &aBroadcastSpans);
+ aCxt.setDestRange(nCol1, nRow1, nCol2, nRow2);
+ DeleteBeforeCopyFromClip(aCxt, rMark, aBroadcastSpans); // <- this removes existing formula listeners
if (CopyOneCellFromClip(aCxt, nCol1, nRow1, nCol2, nRow2))
continue;
@@ -3012,8 +3033,14 @@ void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMar
bInsertingFromOtherDoc = false;
+ if (nInsFlag & InsertDeleteFlags::CONTENTS)
+ {
+ for (SCTAB nTab : rMark)
+ aCxt.setListeningFormulaSpans(nTab, nAllCol1, nAllRow1, nAllCol2, nAllRow2);
+ }
+
// Create Listener after everything has been inserted
- StartListeningFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
+ aCxt.startListeningFormulas();
{
ScBulkBroadcast aBulkBroadcast( GetBASM(), SfxHintId::ScDataChanged);
@@ -3047,8 +3074,7 @@ void ScDocument::CopyMultiRangeFromClip(const ScAddress& rDestPos, const ScMarkD
sc::AutoCalcSwitch aACSwitch(*this, false); // turn of auto calc temporarily.
NumFmtMergeHandler aNumFmtMergeHdl(*this, *pClipDoc);
- ScRange aDestRange;
- rMark.GetMarkArea(aDestRange);
+ const ScRange& aDestRange = rMark.GetMarkArea();
bInsertingFromOtherDoc = true; // No Broadcast/Listener created at Insert
@@ -3186,7 +3212,7 @@ void ScDocument::GetClipArea(SCCOL& nClipX, SCROW& nClipY, bool bIncludeFiltered
// count non-filtered rows
// count on first used table in clipboard
SCTAB nCountTab = 0;
- while ( nCountTab < static_cast<SCTAB>(maTabs.size()) && !maTabs[nCountTab] )
+ while (nCountTab < GetTableCount() && !maTabs[nCountTab])
++nCountTab;
SCROW nResult = CountNonFilteredRows(nStartRow, nEndRow, nCountTab);
@@ -3219,19 +3245,23 @@ bool ScDocument::HasClipFilteredRows()
{
// count on first used table in clipboard
SCTAB nCountTab = 0;
- while ( nCountTab < static_cast<SCTAB>(maTabs.size()) && !maTabs[nCountTab] )
+ while (nCountTab < GetTableCount() && !maTabs[nCountTab])
++nCountTab;
ScRangeList& rClipRanges = GetClipParam().maRanges;
if ( rClipRanges.empty() )
return false;
- for ( size_t i = 0, n = rClipRanges.size(); i < n; ++i )
+ if (maTabs.size() > 0)
{
- ScRange & rRange = rClipRanges[ i ];
- bool bAnswer = maTabs[nCountTab]->HasFilteredRows(rRange.aStart.Row(), rRange.aEnd.Row());
- if (bAnswer)
- return true;
+ for (size_t i = 0, n = rClipRanges.size(); i < n; ++i)
+ {
+ ScRange& rRange = rClipRanges[i];
+ bool bAnswer
+ = maTabs[nCountTab]->HasFilteredRows(rRange.aStart.Row(), rRange.aEnd.Row());
+ if (bAnswer)
+ return true;
+ }
}
return false;
}
@@ -3242,7 +3272,7 @@ void ScDocument::MixDocument( const ScRange& rRange, ScPasteFunc nFunction, bool
SCTAB nTab1 = rRange.aStart.Tab();
SCTAB nTab2 = rRange.aEnd.Tab();
sc::MixDocContext aCxt(*this);
- SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), rSrcDoc.maTabs.size()));
+ SCTAB nMinSizeBothTabs = std::min(GetTableCount(), rSrcDoc.GetTableCount());
for (SCTAB i = nTab1; i <= nTab2 && i < nMinSizeBothTabs; i++)
{
ScTable* pTab = FetchTable(i);
@@ -3266,7 +3296,7 @@ void ScDocument::FillTab( const ScRange& rSrcArea, const ScMarkData& rMark,
SCTAB nSrcTab = rSrcArea.aStart.Tab();
- if (ValidTab(nSrcTab) && nSrcTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nSrcTab])
+ if (ScTable* pSourceTable = FetchTable(nSrcTab))
{
SCCOL nStartCol = rSrcArea.aStart.Col();
SCROW nStartRow = rSrcArea.aStart.Row();
@@ -3281,7 +3311,7 @@ void ScDocument::FillTab( const ScRange& rSrcArea, const ScMarkData& rMark,
sc::CopyToDocContext aCxt(*this);
sc::MixDocContext aMixDocCxt(*this);
- SCTAB nCount = static_cast<SCTAB>(maTabs.size());
+ SCTAB nCount = GetTableCount();
for (const SCTAB& i : rMark)
{
if (i >= nCount)
@@ -3306,7 +3336,7 @@ void ScDocument::FillTab( const ScRange& rSrcArea, const ScMarkData& rMark,
/*bGlobalNamesToLocal*/false, /*bCopyCaptions*/true );
}
maTabs[i]->DeleteArea( nStartCol,nStartRow, nEndCol,nEndRow, nDelFlags);
- maTabs[nSrcTab]->CopyToTable(aCxt, nStartCol,nStartRow, nEndCol,nEndRow,
+ pSourceTable->CopyToTable(aCxt, nStartCol,nStartRow, nEndCol,nEndRow,
nFlags, false, maTabs[i].get(), nullptr, bAsLink,
/*bColRowFlags*/true, /*bGlobalNamesToLocal*/false, /*bCopyCaptions*/true );
@@ -3332,7 +3362,7 @@ void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
if (nDelFlags & InsertDeleteFlags::CONTENTS)
nDelFlags |= InsertDeleteFlags::CONTENTS; // Either all contents or delete nothing!
- if (ValidTab(nSrcTab) && nSrcTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nSrcTab])
+ if (ScTable* pSourceTable = FetchTable(nSrcTab))
{
ScDocumentUniquePtr pMixDoc;
bool bDoMix = ( bSkipEmpty || nFunction != ScPasteFunc::NONE ) && ( nFlags & InsertDeleteFlags::CONTENTS );
@@ -3340,8 +3370,7 @@ void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
bool bOldAutoCalc = GetAutoCalc();
SetAutoCalc( false ); // avoid multiple calculations
- ScRange aArea;
- rMark.GetMultiMarkArea( aArea );
+ const ScRange& aArea = rMark.GetMultiMarkArea();
SCCOL nStartCol = aArea.aStart.Col();
SCROW nStartRow = aArea.aStart.Row();
SCCOL nEndCol = aArea.aEnd.Col();
@@ -3349,7 +3378,7 @@ void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
sc::CopyToDocContext aCxt(*this);
sc::MixDocContext aMixDocCxt(*this);
- SCTAB nCount = static_cast<SCTAB>(maTabs.size());
+ SCTAB nCount = GetTableCount();
for (const SCTAB& i : rMark)
{
if (i >= nCount)
@@ -3374,7 +3403,7 @@ void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
}
maTabs[i]->DeleteSelection( nDelFlags, rMark );
- maTabs[nSrcTab]->CopyToTable(aCxt, nStartCol,nStartRow, nEndCol,nEndRow,
+ pSourceTable->CopyToTable(aCxt, nStartCol,nStartRow, nEndCol,nEndRow,
nFlags, true, maTabs[i].get(), &rMark, bAsLink,
/*bColRowFlags*/true, /*bGlobalNamesToLocal*/false, /*bCopyCaptions*/true );
@@ -3424,66 +3453,57 @@ bool ScDocument::SetString(
bool ScDocument::SetEditText( const ScAddress& rPos, std::unique_ptr<EditTextObject> pEditText )
{
- if (!TableExists(rPos.Tab()))
- {
- return false;
- }
-
- return maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), std::move(pEditText));
+ if (ScTable* pTable = FetchTable(rPos.Tab()))
+ return pTable->SetEditText(rPos.Col(), rPos.Row(), std::move(pEditText));
+ return false;
}
void ScDocument::SetEditText( const ScAddress& rPos, const EditTextObject& rEditText, const SfxItemPool* pEditPool )
{
- if (!TableExists(rPos.Tab()))
- return;
-
- maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), rEditText, pEditPool);
+ if (ScTable* pTable = FetchTable(rPos.Tab()))
+ pTable->SetEditText(rPos.Col(), rPos.Row(), rEditText, pEditPool);
}
void ScDocument::SetEditText( const ScAddress& rPos, const OUString& rStr )
{
- if (!TableExists(rPos.Tab()))
- return;
-
- ScFieldEditEngine& rEngine = GetEditEngine();
- rEngine.SetTextCurrentDefaults(rStr);
- maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), rEngine.CreateTextObject());
+ if (ScTable* pTable = FetchTable(rPos.Tab()))
+ {
+ ScFieldEditEngine& rEngine = GetEditEngine();
+ rEngine.SetTextCurrentDefaults(rStr);
+ pTable->SetEditText(rPos.Col(), rPos.Row(), rEngine.CreateTextObject());
+ }
}
SCROW ScDocument::GetFirstEditTextRow( const ScRange& rRange ) const
{
- const ScTable* pTab = FetchTable(rRange.aStart.Tab());
- if (!pTab)
- return -1;
-
- return pTab->GetFirstEditTextRow(rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
+ if (const ScTable* pTable = FetchTable(rRange.aStart.Tab()))
+ return pTable->GetFirstEditTextRow(rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
+ return -1;
}
void ScDocument::SetTextCell( const ScAddress& rPos, const OUString& rStr )
{
- if (!TableExists(rPos.Tab()))
- return;
-
- if (ScStringUtil::isMultiline(rStr))
- {
- ScFieldEditEngine& rEngine = GetEditEngine();
- rEngine.SetTextCurrentDefaults(rStr);
- maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), rEngine.CreateTextObject());
- }
- else
+ if (ScTable* pTable = FetchTable(rPos.Tab()))
{
- ScSetStringParam aParam;
- aParam.setTextInput();
- maTabs[rPos.Tab()]->SetString(rPos.Col(), rPos.Row(), rPos.Tab(), rStr, &aParam);
+ if (ScStringUtil::isMultiline(rStr))
+ {
+ ScFieldEditEngine& rEngine = GetEditEngine();
+ rEngine.SetTextCurrentDefaults(rStr);
+ pTable->SetEditText(rPos.Col(), rPos.Row(), rEngine.CreateTextObject());
+ }
+ else
+ {
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ pTable->SetString(rPos.Col(), rPos.Row(), rPos.Tab(), rStr, &aParam);
+ }
}
}
void ScDocument::SetEmptyCell( const ScAddress& rPos )
{
- if (!TableExists(rPos.Tab()))
- return;
-
- maTabs[rPos.Tab()]->SetEmptyCell(rPos.Col(), rPos.Row());
+ if (ScTable* pTable = FetchTable(rPos.Tab()))
+ pTable->SetEmptyCell(rPos.Col(), rPos.Row());
}
void ScDocument::SetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rVal )
@@ -3514,42 +3534,32 @@ void ScDocument::SetValue( const ScAddress& rPos, double fVal )
pTab->SetValue(rPos.Col(), rPos.Row(), fVal);
}
-OUString ScDocument::GetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScInterpreterContext* pContext ) const
+OUString ScDocument::GetString( SCCOL nCol, SCROW nRow, SCTAB nTab, ScInterpreterContext* pContext ) const
{
- if (TableExists(nTab))
- {
- OUString aStr;
- maTabs[nTab]->GetString(nCol, nRow, aStr, pContext);
- return aStr;
- }
- else
- return EMPTY_OUSTRING;
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetString(nCol, nRow, pContext);
+ return OUString();
}
-OUString ScDocument::GetString( const ScAddress& rPos, const ScInterpreterContext* pContext ) const
+OUString ScDocument::GetString( const ScAddress& rPos, ScInterpreterContext* pContext ) const
{
- if (!TableExists(rPos.Tab()))
- return EMPTY_OUSTRING;
-
- OUString aStr;
- maTabs[rPos.Tab()]->GetString(rPos.Col(), rPos.Row(), aStr, pContext);
- return aStr;
+ if (const ScTable* pTable = FetchTable(rPos.Tab()))
+ return pTable->GetString(rPos.Col(), rPos.Row(), pContext);
+ return OUString();
}
double* ScDocument::GetValueCell( const ScAddress& rPos )
{
- if (!TableExists(rPos.Tab()))
- return nullptr;
-
- return maTabs[rPos.Tab()]->GetValueCell(rPos.Col(), rPos.Row());
+ if (ScTable* pTable = FetchTable(rPos.Tab()))
+ return pTable->GetValueCell(rPos.Col(), rPos.Row());
+ return nullptr;
}
svl::SharedString ScDocument::GetSharedString( const ScAddress& rPos ) const
{
- if (!TableExists(rPos.Tab()))
- return svl::SharedString();
-
- return maTabs[rPos.Tab()]->GetSharedString(rPos.Col(), rPos.Row());
+ if (const ScTable* pTable = FetchTable(rPos.Tab()))
+ return pTable->GetSharedString(rPos.Col(), rPos.Row());
+ return svl::SharedString();
}
std::shared_ptr<sc::FormulaGroupContext>& ScDocument::GetFormulaGroupContext()
@@ -3568,12 +3578,12 @@ void ScDocument::DiscardFormulaGroupContext()
mpFormulaGroupCxt.reset();
}
-void ScDocument::GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rString )
+OUString ScDocument::GetInputString(SCCOL nCol, SCROW nRow, SCTAB nTab, bool bForceSystemLocale ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->GetInputString( nCol, nRow, rString );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetInputString(nCol, nRow, bForceSystemLocale);
else
- rString.clear();
+ return OUString();
}
FormulaError ScDocument::GetStringForFormula( const ScAddress& rPos, OUString& rString )
@@ -3585,14 +3595,14 @@ FormulaError ScDocument::GetStringForFormula( const ScAddress& rPos, OUString& r
ScRefCellValue aCell(*this, rPos);
if (aCell.isEmpty())
{
- rString = EMPTY_OUSTRING;
+ rString.clear();
return FormulaError::NONE;
}
FormulaError nErr = FormulaError::NONE;
OUString aStr;
SvNumberFormatter* pFormatter = GetFormatTable();
- switch (aCell.meType)
+ switch (aCell.getType())
{
case CELLTYPE_STRING:
case CELLTYPE_EDIT:
@@ -3600,7 +3610,7 @@ FormulaError ScDocument::GetStringForFormula( const ScAddress& rPos, OUString& r
break;
case CELLTYPE_FORMULA:
{
- ScFormulaCell* pFCell = aCell.mpFormula;
+ ScFormulaCell* pFCell = aCell.getFormula();
nErr = pFCell->GetErrCode();
if (pFCell->IsValue())
{
@@ -3616,7 +3626,7 @@ FormulaError ScDocument::GetStringForFormula( const ScAddress& rPos, OUString& r
break;
case CELLTYPE_VALUE:
{
- double fVal = aCell.mfValue;
+ double fVal = aCell.getDouble();
sal_uInt32 nIndex = pFormatter->GetStandardFormat(
SvNumFormatType::NUMBER,
ScGlobal::eLnge);
@@ -3631,54 +3641,39 @@ FormulaError ScDocument::GetStringForFormula( const ScAddress& rPos, OUString& r
return nErr;
}
-void ScDocument::GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, double& rValue ) const
-{
- if (TableExists(nTab))
- rValue = maTabs[nTab]->GetValue( nCol, nRow );
- else
- rValue = 0.0;
-}
-
const EditTextObject* ScDocument::GetEditText( const ScAddress& rPos ) const
{
SCTAB nTab = rPos.Tab();
- if (!TableExists(nTab))
- return nullptr;
-
- return maTabs[nTab]->GetEditText(rPos.Col(), rPos.Row());
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetEditText(rPos.Col(), rPos.Row());
+ return nullptr;
}
void ScDocument::RemoveEditTextCharAttribs( const ScAddress& rPos, const ScPatternAttr& rAttr )
{
- if (!TableExists(rPos.Tab()))
- return;
-
- return maTabs[rPos.Tab()]->RemoveEditTextCharAttribs(rPos.Col(), rPos.Row(), rAttr);
+ if (ScTable* pTable = FetchTable(rPos.Tab()))
+ return pTable->RemoveEditTextCharAttribs(rPos.Col(), rPos.Row(), rAttr);
}
double ScDocument::GetValue( const ScAddress& rPos ) const
{
SCTAB nTab = rPos.Tab();
- if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetValue(rPos.Col(), rPos.Row());
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetValue(rPos.Col(), rPos.Row());
return 0.0;
}
double ScDocument::GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
{
- ScAddress aAdr(nCol, nRow, nTab); return GetValue(aAdr);
+ ScAddress aAdr(nCol, nRow, nTab);
+ return GetValue(aAdr);
}
-void ScDocument::GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab,
- sal_uInt32& rFormat ) const
+sal_uInt32 ScDocument::GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
- if (maTabs[nTab])
- {
- rFormat = maTabs[nTab]->GetNumberFormat( nCol, nRow );
- return ;
- }
- rFormat = 0;
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetNumberFormat(nCol, nRow);
+ return 0;
}
sal_uInt32 ScDocument::GetNumberFormat( const ScRange& rRange ) const
@@ -3687,12 +3682,12 @@ sal_uInt32 ScDocument::GetNumberFormat( const ScRange& rRange ) const
SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
- if (!TableExists(nTab1) || !TableExists(nTab2))
+ if (!HasTable(nTab1) || !HasTable(nTab2))
return 0;
sal_uInt32 nFormat = 0;
bool bFirstItem = true;
- for (SCTAB nTab = nTab1; nTab <= nTab2 && nTab < static_cast<SCTAB>(maTabs.size()) ; ++nTab)
+ for (SCTAB nTab = nTab1; nTab <= nTab2 && nTab < GetTableCount() ; ++nTab)
for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
{
sal_uInt32 nThisFormat = maTabs[nTab]->GetNumberFormat(nCol, nRow1, nRow2);
@@ -3711,30 +3706,27 @@ sal_uInt32 ScDocument::GetNumberFormat( const ScRange& rRange ) const
sal_uInt32 ScDocument::GetNumberFormat( const ScInterpreterContext& rContext, const ScAddress& rPos ) const
{
SCTAB nTab = rPos.Tab();
- if (!TableExists(nTab))
- return 0;
-
- return maTabs[nTab]->GetNumberFormat( rContext, rPos );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetNumberFormat( rContext, rPos );
+ return 0;
}
void ScDocument::SetNumberFormat( const ScAddress& rPos, sal_uInt32 nNumberFormat )
{
assert(!IsThreadedGroupCalcInProgress());
SCTAB nTab = rPos.Tab();
- if (!TableExists(nTab))
- return;
-
- maTabs[nTab]->SetNumberFormat(rPos.Col(), rPos.Row(), nNumberFormat);
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetNumberFormat(rPos.Col(), rPos.Row(), nNumberFormat);
}
void ScDocument::GetNumberFormatInfo( const ScInterpreterContext& rContext, SvNumFormatType& nType, sal_uInt32& nIndex,
const ScAddress& rPos ) const
{
SCTAB nTab = rPos.Tab();
- if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
+ if (nTab < GetTableCount() && maTabs[nTab])
{
nIndex = maTabs[nTab]->GetNumberFormat( rContext, rPos );
- nType = rContext.GetNumberFormatType( nIndex );
+ nType = rContext.NFGetType(nIndex);
}
else
{
@@ -3743,63 +3735,55 @@ void ScDocument::GetNumberFormatInfo( const ScInterpreterContext& rContext, SvNu
}
}
-void ScDocument::GetFormula( SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rFormula ) const
+OUString ScDocument::GetFormula( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->GetFormula( nCol, nRow, rFormula );
- else
- rFormula.clear();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetFormula(nCol, nRow);
+
+ return OUString();
}
const ScFormulaCell* ScDocument::GetFormulaCell( const ScAddress& rPos ) const
{
- if (!TableExists(rPos.Tab()))
- return nullptr;
-
- return maTabs[rPos.Tab()]->GetFormulaCell(rPos.Col(), rPos.Row());
+ if (const ScTable* pTable = FetchTable(rPos.Tab()))
+ return pTable->GetFormulaCell(rPos.Col(), rPos.Row());
+ return nullptr;
}
ScFormulaCell* ScDocument::GetFormulaCell( const ScAddress& rPos )
{
- if (!TableExists(rPos.Tab()))
- return nullptr;
-
- return maTabs[rPos.Tab()]->GetFormulaCell(rPos.Col(), rPos.Row());
+ if (ScTable* pTable = FetchTable(rPos.Tab()))
+ return pTable->GetFormulaCell(rPos.Col(), rPos.Row());
+ return nullptr;
}
CellType ScDocument::GetCellType( const ScAddress& rPos ) const
{
SCTAB nTab = rPos.Tab();
- if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetCellType( rPos );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetCellType(rPos);
return CELLTYPE_NONE;
}
-void ScDocument::GetCellType( SCCOL nCol, SCROW nRow, SCTAB nTab,
- CellType& rCellType ) const
+CellType ScDocument::GetCellType( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- rCellType = maTabs[nTab]->GetCellType( nCol, nRow );
- else
- rCellType = CELLTYPE_NONE;
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetCellType( nCol, nRow );
+ return CELLTYPE_NONE;
}
bool ScDocument::HasStringData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab]
- && nCol < maTabs[nTab]->GetAllocatedColumnsCount())
- return maTabs[nTab]->HasStringData( nCol, nRow );
- else
- return false;
+ if (const ScTable* pTable = FetchTable(nTab) ; pTable && nCol < pTable->GetAllocatedColumnsCount())
+ return pTable->HasStringData(nCol, nRow);
+ return false;
}
bool ScDocument::HasValueData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab]
- && nCol < maTabs[nTab]->GetAllocatedColumnsCount())
- return maTabs[nTab]->HasValueData( nCol, nRow );
- else
- return false;
+ if (const ScTable* pTable = FetchTable(nTab) ; pTable && nCol < pTable->GetAllocatedColumnsCount())
+ return pTable->HasValueData( nCol, nRow );
+ return false;
}
bool ScDocument::HasValueData( const ScAddress& rPos ) const
@@ -3818,10 +3802,11 @@ bool ScDocument::HasStringCells( const ScRange& rRange ) const
SCROW nEndRow = rRange.aEnd.Row();
SCTAB nEndTab = rRange.aEnd.Tab();
- for ( SCTAB nTab=nStartTab; nTab<=nEndTab && nTab < static_cast<SCTAB>(maTabs.size()); nTab++ )
+ for (SCTAB nTab = nStartTab; nTab <= nEndTab && nTab < GetTableCount(); nTab++)
+ {
if ( maTabs[nTab] && maTabs[nTab]->HasStringCells( nStartCol, nStartRow, nEndCol, nEndRow ) )
return true;
-
+ }
return false;
}
@@ -3892,7 +3877,7 @@ void ScDocument::SetDirty( const ScRange& rRange, bool bIncludeEmptyCells )
{ // scope for bulk broadcast
ScBulkBroadcast aBulkBroadcast( GetBASM(), SfxHintId::ScDataChanged);
SCTAB nTab2 = rRange.aEnd.Tab();
- for (SCTAB i=rRange.aStart.Tab(); i<=nTab2 && i < static_cast<SCTAB>(maTabs.size()); i++)
+ for (SCTAB i = rRange.aStart.Tab(); i <= nTab2 && i < GetTableCount(); i++)
if (maTabs[i]) maTabs[i]->SetDirty( rRange,
(bIncludeEmptyCells ? ScColumn::BROADCAST_BROADCASTERS : ScColumn::BROADCAST_DATA_POSITIONS));
@@ -3911,7 +3896,7 @@ void ScDocument::SetTableOpDirty( const ScRange& rRange )
bool bOldAutoCalc = GetAutoCalc();
bAutoCalc = false; // no multiple recalculation
SCTAB nTab2 = rRange.aEnd.Tab();
- for (SCTAB i=rRange.aStart.Tab(); i<=nTab2 && i < static_cast<SCTAB>(maTabs.size()); i++)
+ for (SCTAB i = rRange.aStart.Tab(); i <= nTab2 && i < GetTableCount(); i++)
if (maTabs[i]) maTabs[i]->SetTableOpDirty( rRange );
SetAutoCalc( bOldAutoCalc );
}
@@ -3941,6 +3926,28 @@ void ScDocument::InterpretDirtyCells( const ScRangeList& rRanges )
mpFormulaGroupCxt.reset();
}
+bool ScDocument::InterpretCellsIfNeeded( const ScRangeList& rRanges )
+{
+ bool allInterpreted = true;
+ for (size_t nPos=0, nRangeCount = rRanges.size(); nPos < nRangeCount; nPos++)
+ {
+ const ScRange& rRange = rRanges[nPos];
+ for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab)
+ {
+ ScTable* pTab = FetchTable(nTab);
+ if (!pTab)
+ break;
+
+ if( !pTab->InterpretCellsIfNeeded(
+ rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row()))
+ {
+ allInterpreted = false;
+ }
+ }
+ }
+ return allInterpreted;
+}
+
void ScDocument::AddTableOpFormulaCell( ScFormulaCell* pCell )
{
if (m_TableOpList.empty())
@@ -4042,12 +4049,9 @@ bool ScDocument::CompileErrorCells(FormulaError nErrCode)
{
bool bCompiled = false;
sc::CompileFormulaContext aCxt(*this);
- for (const auto& a : maTabs)
+ for (const auto& pTab : maTabs)
{
- if (!a)
- continue;
-
- if (a->CompileErrorCells(aCxt, nErrCode))
+ if (pTab && pTab->CompileErrorCells(aCxt, nErrCode))
bCompiled = true;
}
@@ -4062,15 +4066,15 @@ void ScDocument::CalcAfterLoad( bool bStartListening )
bCalcingAfterLoad = true;
sc::CompileFormulaContext aCxt(*this);
{
- for (const auto& a : maTabs)
+ for (const auto& pTable : maTabs)
{
- if (a)
- a->CalcAfterLoad(aCxt, bStartListening);
+ if (pTable)
+ pTable->CalcAfterLoad(aCxt, bStartListening);
}
- for (const auto& a : maTabs)
+ for (const auto& pTable : maTabs)
{
- if (a)
- a->SetDirtyAfterLoad();
+ if (pTable)
+ pTable->SetDirtyAfterLoad();
}
}
bCalcingAfterLoad = false;
@@ -4094,14 +4098,14 @@ void ScDocument::CalcAfterLoad( bool bStartListening )
FormulaError ScDocument::GetErrCode( const ScAddress& rPos ) const
{
SCTAB nTab = rPos.Tab();
- if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetErrCode( rPos );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetErrCode( rPos );
return FormulaError::NONE;
}
void ScDocument::ResetChanged( const ScRange& rRange )
{
- SCTAB nTabSize = static_cast<SCTAB>(maTabs.size());
+ SCTAB nTabSize = GetTableCount();
SCTAB nTab1 = rRange.aStart.Tab();
SCTAB nTab2 = rRange.aEnd.Tab();
for (SCTAB nTab = nTab1; nTab1 <= nTab2 && nTab < nTabSize; ++nTab)
@@ -4113,99 +4117,96 @@ void ScDocument::ResetChanged( const ScRange& rRange )
void ScDocument::SetColWidth( SCCOL nCol, SCTAB nTab, sal_uInt16 nNewWidth )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->SetColWidth( nCol, nNewWidth );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetColWidth(nCol, nNewWidth);
}
void ScDocument::SetColWidthOnly( SCCOL nCol, SCTAB nTab, sal_uInt16 nNewWidth )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->SetColWidthOnly( nCol, nNewWidth );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetColWidthOnly(nCol, nNewWidth);
}
void ScDocument::SetRowHeight( SCROW nRow, SCTAB nTab, sal_uInt16 nNewHeight )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->SetRowHeight( nRow, nNewHeight );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetRowHeight(nRow, nNewHeight);
}
void ScDocument::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->SetRowHeightRange
- ( nStartRow, nEndRow, nNewHeight, 1.0, true );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetRowHeightRange(nStartRow, nEndRow, nNewHeight, 1.0, true);
}
void ScDocument::SetRowHeightOnly( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->SetRowHeightOnly( nStartRow, nEndRow, nNewHeight );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetRowHeightOnly( nStartRow, nEndRow, nNewHeight );
}
void ScDocument::SetManualHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bManual )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->SetManualHeight( nStartRow, nEndRow, bManual );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetManualHeight( nStartRow, nEndRow, bManual );
}
sal_uInt16 ScDocument::GetColWidth( SCCOL nCol, SCTAB nTab, bool bHiddenAsZero ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetColWidth( nCol, bHiddenAsZero );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetColWidth( nCol, bHiddenAsZero );
OSL_FAIL("wrong table number");
return 0;
}
-sal_uLong ScDocument::GetColWidth( SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab ) const
+tools::Long ScDocument::GetColWidth( SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab ) const
{
- const ScTable* pTab = FetchTable(nTab);
- if (!pTab)
- return 0;
-
- return pTab->GetColWidth(nStartCol, nEndCol);
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetColWidth(nStartCol, nEndCol);
+ return 0;
}
sal_uInt16 ScDocument::GetOriginalWidth( SCCOL nCol, SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetOriginalWidth( nCol );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetOriginalWidth( nCol );
OSL_FAIL("wrong table number");
return 0;
}
sal_uInt16 ScDocument::GetCommonWidth( SCCOL nEndCol, SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetCommonWidth( nEndCol );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetCommonWidth( nEndCol );
OSL_FAIL("Wrong table number");
return 0;
}
sal_uInt16 ScDocument::GetOriginalHeight( SCROW nRow, SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetOriginalHeight( nRow );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetOriginalHeight( nRow );
OSL_FAIL("Wrong table number");
return 0;
}
sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, bool bHiddenAsZero ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetRowHeight( nRow, nullptr, nullptr, bHiddenAsZero );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetRowHeight( nRow, nullptr, nullptr, bHiddenAsZero );
OSL_FAIL("Wrong sheet number");
return 0;
}
-sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, SCROW* pStartRow, SCROW* pEndRow ) const
+sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, SCROW* pStartRow, SCROW* pEndRow, bool bHiddenAsZero ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetRowHeight( nRow, pStartRow, pEndRow );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetRowHeight( nRow, pStartRow, pEndRow, bHiddenAsZero );
OSL_FAIL("Wrong sheet number");
return 0;
}
-sal_uLong ScDocument::GetRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bHiddenAsZero ) const
+tools::Long ScDocument::GetRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bHiddenAsZero ) const
{
if (nStartRow == nEndRow)
return GetRowHeight( nStartRow, nTab, bHiddenAsZero ); // faster for a single row
@@ -4214,31 +4215,31 @@ sal_uLong ScDocument::GetRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab,
if (nStartRow > nEndRow)
return 0;
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetRowHeight( nStartRow, nEndRow, bHiddenAsZero );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetRowHeight( nStartRow, nEndRow, bHiddenAsZero );
OSL_FAIL("wrong sheet number");
return 0;
}
-SCROW ScDocument::GetRowForHeight( SCTAB nTab, sal_uLong nHeight ) const
+SCROW ScDocument::GetRowForHeight( SCTAB nTab, tools::Long nHeight ) const
{
return maTabs[nTab]->GetRowForHeight(nHeight);
}
-sal_uLong ScDocument::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow,
- SCTAB nTab, double fScale, const sal_uLong* pnMaxHeight ) const
+tools::Long ScDocument::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow,
+ SCTAB nTab, double fScale ) const
{
// faster for a single row
if (nStartRow == nEndRow)
- return static_cast<sal_uLong>(GetRowHeight( nStartRow, nTab) * fScale);
+ return static_cast<tools::Long>(GetRowHeight( nStartRow, nTab) * fScale);
// check bounds because this method replaces former for(i=start;i<=end;++i) loops
if (nStartRow > nEndRow)
return 0;
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetScaledRowHeight( nStartRow, nEndRow, fScale, pnMaxHeight );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetScaledRowHeight( nStartRow, nEndRow, fScale);
OSL_FAIL("wrong sheet number");
return 0;
@@ -4246,24 +4247,24 @@ sal_uLong ScDocument::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow,
SCROW ScDocument::GetHiddenRowCount( SCROW nRow, SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetHiddenRowCount( nRow );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetHiddenRowCount( nRow );
OSL_FAIL("wrong table number");
return 0;
}
-sal_uLong ScDocument::GetColOffset( SCCOL nCol, SCTAB nTab, bool bHiddenAsZero ) const
+tools::Long ScDocument::GetColOffset( SCCOL nCol, SCTAB nTab, bool bHiddenAsZero ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetColOffset( nCol, bHiddenAsZero );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetColOffset( nCol, bHiddenAsZero );
OSL_FAIL("wrong table number");
return 0;
}
-sal_uLong ScDocument::GetRowOffset( SCROW nRow, SCTAB nTab, bool bHiddenAsZero ) const
+tools::Long ScDocument::GetRowOffset( SCROW nRow, SCTAB nTab, bool bHiddenAsZero ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetRowOffset( nRow, bHiddenAsZero );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetRowOffset( nRow, bHiddenAsZero );
OSL_FAIL("wrong table number");
return 0;
}
@@ -4274,9 +4275,9 @@ sal_uInt16 ScDocument::GetOptimalColWidth( SCCOL nCol, SCTAB nTab, OutputDevice*
bool bFormula, const ScMarkData* pMarkData,
const ScColWidthParam* pParam )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetOptimalColWidth( nCol, pDev, nPPTX, nPPTY,
- rZoomX, rZoomY, bFormula, pMarkData, pParam );
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->GetOptimalColWidth(nCol, pDev, nPPTX, nPPTY, rZoomX,
+ rZoomY, bFormula, pMarkData, pParam);
OSL_FAIL("wrong table number");
return 0;
}
@@ -4287,35 +4288,34 @@ tools::Long ScDocument::GetNeededSize( SCCOL nCol, SCROW nRow, SCTAB nTab,
const Fraction& rZoomX, const Fraction& rZoomY,
bool bWidth, bool bTotalSize, bool bInPrintTwips )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetNeededSize
- ( nCol, nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, bTotalSize, bInPrintTwips );
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->GetNeededSize(nCol, nRow, pDev, nPPTX, nPPTY,
+ rZoomX, rZoomY, bWidth, bTotalSize,
+ bInPrintTwips);
OSL_FAIL("wrong table number");
return 0;
}
bool ScDocument::SetOptimalHeight( sc::RowHeightContext& rCxt, SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bApi )
{
- ScTable* pTab = FetchTable(nTab);
- if (!pTab)
- return false;
-
- return pTab->SetOptimalHeight(rCxt, nStartRow, nEndRow, bApi);
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->SetOptimalHeight(rCxt, nStartRow, nEndRow, bApi);
+ return false;
}
void ScDocument::UpdateAllRowHeights( sc::RowHeightContext& rCxt, const ScMarkData* pTabMark )
{
// one progress across all (selected) sheets
- sal_uLong nCellCount = 0;
- for ( SCTAB nTab=0; nTab< static_cast<SCTAB>(maTabs.size()); nTab++ )
+ sal_uInt64 nCellCount = 0;
+ for (SCTAB nTab = 0; nTab < GetTableCount(); nTab++)
if ( maTabs[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
nCellCount += maTabs[nTab]->GetWeightedCount();
ScProgress aProgress( GetDocumentShell(), ScResId(STR_PROGRESS_HEIGHTING), nCellCount, true );
- sal_uLong nProgressStart = 0;
- for ( SCTAB nTab=0; nTab< static_cast<SCTAB>(maTabs.size()); nTab++ )
+ sal_uInt64 nProgressStart = 0;
+ for (SCTAB nTab = 0; nTab < GetTableCount(); nTab++)
if ( maTabs[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
{
maTabs[nTab]->SetOptimalHeightOnly(rCxt, 0, MaxRow(), &aProgress, nProgressStart);
@@ -4328,327 +4328,298 @@ void ScDocument::UpdateAllRowHeights( sc::RowHeightContext& rCxt, const ScMarkDa
void ScDocument::ShowCol(SCCOL nCol, SCTAB nTab, bool bShow)
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->ShowCol( nCol, bShow );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->ShowCol(nCol, bShow);
}
void ScDocument::ShowRow(SCROW nRow, SCTAB nTab, bool bShow)
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->ShowRow( nRow, bShow );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->ShowRow(nRow, bShow);
}
void ScDocument::ShowRows(SCROW nRow1, SCROW nRow2, SCTAB nTab, bool bShow)
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->ShowRows( nRow1, nRow2, bShow );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->ShowRows( nRow1, nRow2, bShow );
}
void ScDocument::SetRowFlags( SCROW nRow, SCTAB nTab, CRFlags nNewFlags )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->SetRowFlags( nRow, nNewFlags );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetRowFlags( nRow, nNewFlags );
}
void ScDocument::SetRowFlags( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, CRFlags nNewFlags )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->SetRowFlags( nStartRow, nEndRow, nNewFlags );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetRowFlags( nStartRow, nEndRow, nNewFlags );
}
CRFlags ScDocument::GetColFlags( SCCOL nCol, SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetColFlags( nCol );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetColFlags( nCol );
OSL_FAIL("wrong table number");
return CRFlags::NONE;
}
CRFlags ScDocument::GetRowFlags( SCROW nRow, SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetRowFlags( nRow );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetRowFlags( nRow );
OSL_FAIL("wrong table number");
return CRFlags::NONE;
}
void ScDocument::GetAllRowBreaks(set<SCROW>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return;
- maTabs[nTab]->GetAllRowBreaks(rBreaks, bPage, bManual);
+ if (const ScTable* pTable = FetchTable(nTab))
+ pTable->GetAllRowBreaks(rBreaks, bPage, bManual);
}
void ScDocument::GetAllColBreaks(set<SCCOL>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
{
- if (!ValidTab(nTab) || !maTabs[nTab])
- return;
-
- maTabs[nTab]->GetAllColBreaks(rBreaks, bPage, bManual);
+ if (const ScTable* pTable = FetchTable(nTab))
+ pTable->GetAllColBreaks(rBreaks, bPage, bManual);
}
ScBreakType ScDocument::HasRowBreak(SCROW nRow, SCTAB nTab) const
{
ScBreakType nType = ScBreakType::NONE;
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidRow(nRow))
- return nType;
-
- if (maTabs[nTab]->HasRowPageBreak(nRow))
- nType |= ScBreakType::Page;
-
- if (maTabs[nTab]->HasRowManualBreak(nRow))
- nType |= ScBreakType::Manual;
+ if (const ScTable* pTable = FetchTable(nTab); pTable && ValidRow(nRow))
+ {
+ if (pTable->HasRowPageBreak(nRow))
+ nType |= ScBreakType::Page;
+ if (pTable->HasRowManualBreak(nRow))
+ nType |= ScBreakType::Manual;
+ }
return nType;
}
ScBreakType ScDocument::HasColBreak(SCCOL nCol, SCTAB nTab) const
{
ScBreakType nType = ScBreakType::NONE;
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidCol(nCol))
- return nType;
-
- if (maTabs[nTab]->HasColPageBreak(nCol))
- nType |= ScBreakType::Page;
- if (maTabs[nTab]->HasColManualBreak(nCol))
- nType |= ScBreakType::Manual;
+ if (const ScTable* pTable = FetchTable(nTab); pTable && ValidCol(nCol))
+ {
+ if (pTable->HasColPageBreak(nCol))
+ nType |= ScBreakType::Page;
+ if (pTable->HasColManualBreak(nCol))
+ nType |= ScBreakType::Manual;
+ }
return nType;
}
void ScDocument::SetRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidRow(nRow))
- return;
-
- maTabs[nTab]->SetRowBreak(nRow, bPage, bManual);
+ if (ScTable* pTable = FetchTable(nTab); pTable && ValidRow(nRow))
+ pTable->SetRowBreak(nRow, bPage, bManual);
}
void ScDocument::SetColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidCol(nCol))
- return;
-
- maTabs[nTab]->SetColBreak(nCol, bPage, bManual);
+ if (ScTable* pTable = FetchTable(nTab); pTable && ValidCol(nCol))
+ pTable->SetColBreak(nCol, bPage, bManual);
}
void ScDocument::RemoveRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidRow(nRow))
- return;
-
- maTabs[nTab]->RemoveRowBreak(nRow, bPage, bManual);
+ if (ScTable* pTable = FetchTable(nTab); pTable && ValidRow(nRow))
+ pTable->RemoveRowBreak(nRow, bPage, bManual);
}
void ScDocument::RemoveColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidCol(nCol))
- return;
-
- maTabs[nTab]->RemoveColBreak(nCol, bPage, bManual);
+ if (ScTable* pTable = FetchTable(nTab); pTable && ValidCol(nCol))
+ pTable->RemoveColBreak(nCol, bPage, bManual);
}
Sequence<TablePageBreakData> ScDocument::GetRowBreakData(SCTAB nTab) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return Sequence<TablePageBreakData>();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetRowBreakData();
- return maTabs[nTab]->GetRowBreakData();
+ return Sequence<TablePageBreakData>();
}
bool ScDocument::RowHidden(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return false;
-
- return maTabs[nTab]->RowHidden(nRow, pFirstRow, pLastRow);
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->RowHidden(nRow, pFirstRow, pLastRow);
+ return false;
}
bool ScDocument::HasHiddenRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return false;
-
- return maTabs[nTab]->HasHiddenRows(nStartRow, nEndRow);
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->HasHiddenRows(nStartRow, nEndRow);
+ return false;
}
bool ScDocument::ColHidden(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- {
- if (pFirstCol)
- *pFirstCol = nCol;
- if (pLastCol)
- *pLastCol = nCol;
- return false;
- }
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->ColHidden(nCol, pFirstCol, pLastCol);
- return maTabs[nTab]->ColHidden(nCol, pFirstCol, pLastCol);
+ if (pFirstCol)
+ *pFirstCol = nCol;
+ if (pLastCol)
+ *pLastCol = nCol;
+ return false;
}
void ScDocument::SetRowHidden(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bHidden)
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return;
-
- maTabs[nTab]->SetRowHidden(nStartRow, nEndRow, bHidden);
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetRowHidden(nStartRow, nEndRow, bHidden);
}
void ScDocument::SetColHidden(SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bHidden)
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return;
-
- maTabs[nTab]->SetColHidden(nStartCol, nEndCol, bHidden);
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetColHidden(nStartCol, nEndCol, bHidden);
}
SCROW ScDocument::FirstVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return ::std::numeric_limits<SCROW>::max();
-
- return maTabs[nTab]->FirstVisibleRow(nStartRow, nEndRow);
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->FirstVisibleRow(nStartRow, nEndRow);
+ return 0;
}
SCROW ScDocument::LastVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return ::std::numeric_limits<SCROW>::max();
-
- return maTabs[nTab]->LastVisibleRow(nStartRow, nEndRow);
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->LastVisibleRow(nStartRow, nEndRow);
+ return ::std::numeric_limits<SCROW>::max();
}
SCROW ScDocument::CountVisibleRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return 0;
-
- return maTabs[nTab]->CountVisibleRows(nStartRow, nEndRow);
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->CountVisibleRows(nStartRow, nEndRow);
+ return 0;
}
bool ScDocument::RowFiltered(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return false;
-
- return maTabs[nTab]->RowFiltered(nRow, pFirstRow, pLastRow);
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->RowFiltered(nRow, pFirstRow, pLastRow);
+ return false;
}
bool ScDocument::HasFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return false;
-
- return maTabs[nTab]->HasFilteredRows(nStartRow, nEndRow);
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->HasFilteredRows(nStartRow, nEndRow);
+ return false;
}
bool ScDocument::ColFiltered(SCCOL nCol, SCTAB nTab) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return false;
-
- return maTabs[nTab]->ColFiltered(nCol);
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->ColFiltered(nCol);
+ return false;
}
void ScDocument::SetRowFiltered(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bFiltered)
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return;
-
- maTabs[nTab]->SetRowFiltered(nStartRow, nEndRow, bFiltered);
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetRowFiltered(nStartRow, nEndRow, bFiltered);
}
SCROW ScDocument::FirstNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return ::std::numeric_limits<SCROW>::max();
-
- return maTabs[nTab]->FirstNonFilteredRow(nStartRow, nEndRow);
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->FirstNonFilteredRow(nStartRow, nEndRow);
+ return std::numeric_limits<SCROW>::max();
}
SCROW ScDocument::LastNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return ::std::numeric_limits<SCROW>::max();
-
- return maTabs[nTab]->LastNonFilteredRow(nStartRow, nEndRow);
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->LastNonFilteredRow(nStartRow, nEndRow);
+ return std::numeric_limits<SCROW>::max();
}
SCROW ScDocument::CountNonFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return 0;
-
- return maTabs[nTab]->CountNonFilteredRows(nStartRow, nEndRow);
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->CountNonFilteredRows(nStartRow, nEndRow);
+ return 0;
}
bool ScDocument::IsManualRowHeight(SCROW nRow, SCTAB nTab) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
- return false;
-
- return maTabs[nTab]->IsManualRowHeight(nRow);
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->IsManualRowHeight(nRow);
+ return false;
}
void ScDocument::SyncColRowFlags()
{
- for (const auto& a : maTabs)
+ for (const auto& pTable : maTabs)
{
- if (a)
- a->SyncColRowFlags();
+ if (pTable)
+ pTable->SyncColRowFlags();
}
}
SCROW ScDocument::GetLastFlaggedRow( SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetLastFlaggedRow();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetLastFlaggedRow();
return 0;
}
-SCCOL ScDocument::GetLastChangedCol( SCTAB nTab ) const
+SCCOL ScDocument::GetLastChangedColFlagsWidth( SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetLastChangedCol();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetLastChangedColFlagsWidth();
return 0;
}
-SCROW ScDocument::GetLastChangedRow( SCTAB nTab ) const
+SCROW ScDocument::GetLastChangedRowFlagsWidth( SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetLastChangedRow();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetLastChangedRowFlagsWidth();
return 0;
}
-SCCOL ScDocument::GetNextDifferentChangedCol( SCTAB nTab, SCCOL nStart) const
+SCCOL ScDocument::GetNextDifferentChangedColFlagsWidth( SCTAB nTab, SCCOL nStart) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
+ if (const ScTable* pTable = FetchTable(nTab))
{
- CRFlags nStartFlags = maTabs[nTab]->GetColFlags(nStart);
- sal_uInt16 nStartWidth = maTabs[nTab]->GetOriginalWidth(nStart);
- for (SCCOL nCol : maTabs[nTab]->GetColumnsRange( nStart + 1, MaxCol()))
+ CRFlags nStartFlags = pTable->GetColFlags(nStart);
+ sal_uInt16 nStartWidth = pTable->GetOriginalWidth(nStart);
+ for (SCCOL nCol : pTable->GetColumnsRange( nStart + 1, MaxCol()))
{
- if (((nStartFlags & CRFlags::ManualBreak) != (maTabs[nTab]->GetColFlags(nCol) & CRFlags::ManualBreak)) ||
- (nStartWidth != maTabs[nTab]->GetOriginalWidth(nCol)) ||
- ((nStartFlags & CRFlags::Hidden) != (maTabs[nTab]->GetColFlags(nCol) & CRFlags::Hidden)) )
+ if (((nStartFlags & CRFlags::ManualBreak) != (pTable->GetColFlags(nCol) & CRFlags::ManualBreak)) ||
+ (nStartWidth != pTable->GetOriginalWidth(nCol)) ||
+ ((nStartFlags & CRFlags::Hidden) != (pTable->GetColFlags(nCol) & CRFlags::Hidden)) )
+ {
return nCol;
+ }
}
return MaxCol()+1;
}
return 0;
}
-SCROW ScDocument::GetNextDifferentChangedRow( SCTAB nTab, SCROW nStart) const
+SCROW ScDocument::GetNextDifferentChangedRowFlagsWidth( SCTAB nTab, SCROW nStart) const
{
- if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
+ const ScTable* pTable = FetchTable(nTab);
+ if (!pTable)
return 0;
- const ScBitMaskCompressedArray<SCROW, CRFlags>* pRowFlagsArray = maTabs[nTab]->GetRowFlagsArray();
+ const ScBitMaskCompressedArray<SCROW, CRFlags>* pRowFlagsArray = pTable->GetRowFlagsArray();
if (!pRowFlagsArray)
return 0;
- if (!maTabs[nTab]->mpRowHeights || !maTabs[nTab]->mpHiddenRows)
+ if (!pTable->mpRowHeights || !pTable->mpHiddenRows)
return 0;
size_t nIndex; // ignored
@@ -4659,17 +4630,17 @@ SCROW ScDocument::GetNextDifferentChangedRow( SCTAB nTab, SCROW nStart) const
bool bHidden;
sal_uInt16 nHeight;
CRFlags nStartFlags = nFlags = pRowFlagsArray->GetValue( nStart, nIndex, nFlagsEndRow);
- bool bStartHidden = bHidden = maTabs[nTab]->RowHidden( nStart, nullptr, &nHiddenEndRow);
- sal_uInt16 nStartHeight = nHeight = maTabs[nTab]->GetRowHeight( nStart, nullptr, &nHeightEndRow, false);
+ bool bStartHidden = bHidden = pTable->RowHidden( nStart, nullptr, &nHiddenEndRow);
+ sal_uInt16 nStartHeight = nHeight = pTable->GetRowHeight( nStart, nullptr, &nHeightEndRow, false);
SCROW nRow;
while ((nRow = std::min( nHiddenEndRow, std::min( nFlagsEndRow, nHeightEndRow)) + 1) <= MaxRow())
{
if (nFlagsEndRow < nRow)
nFlags = pRowFlagsArray->GetValue( nRow, nIndex, nFlagsEndRow);
if (nHiddenEndRow < nRow)
- bHidden = maTabs[nTab]->RowHidden( nRow, nullptr, &nHiddenEndRow);
+ bHidden = pTable->RowHidden( nRow, nullptr, &nHiddenEndRow);
if (nHeightEndRow < nRow)
- nHeight = maTabs[nTab]->GetRowHeight( nRow, nullptr, &nHeightEndRow, false);
+ nHeight = pTable->GetRowHeight( nRow, nullptr, &nHeightEndRow, false);
if (((nStartFlags & CRFlags::ManualBreak) != (nFlags & CRFlags::ManualBreak)) ||
((nStartFlags & CRFlags::ManualSize) != (nFlags & CRFlags::ManualSize)) ||
@@ -4692,62 +4663,57 @@ void ScDocument::GetColDefault( SCTAB nTab, SCCOL nCol, SCROW nLastRow, SCROW& n
if (nEndRow >= nLastRow)
return;
- ScDefaultAttrSet aSet;
- ScDefaultAttrSet::iterator aItr = aSet.end();
+ ScDefaultAttrMap aMap;
while (pAttr)
{
- ScDefaultAttr aAttr(pAttr);
- aItr = aSet.find(aAttr);
- if (aItr == aSet.end())
+ auto aItr = aMap.find(pAttr);
+ if (aItr == aMap.end())
{
+ ScDefaultAttr aAttr;
aAttr.nCount = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
aAttr.nFirst = nStartRow;
- aSet.insert(aAttr);
+ aMap.insert({ pAttr, aAttr});
}
else
{
- aAttr.nCount = aItr->nCount + static_cast<SCSIZE>(nEndRow - nStartRow + 1);
- aAttr.nFirst = aItr->nFirst;
- aSet.erase(aItr);
- aSet.insert(aAttr);
+ aItr->second.nCount += static_cast<SCSIZE>(nEndRow - nStartRow + 1);
}
pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
}
- ScDefaultAttrSet::iterator aDefaultItr = aSet.begin();
- aItr = aDefaultItr;
+ auto aDefaultItr = aMap.begin();
+ auto aItr = aDefaultItr;
++aItr;
- while (aItr != aSet.end())
+ while (aItr != aMap.end())
{
// for entries with equal count, use the one with the lowest start row,
// don't use the random order of pointer comparisons
- if ( aItr->nCount > aDefaultItr->nCount ||
- ( aItr->nCount == aDefaultItr->nCount && aItr->nFirst < aDefaultItr->nFirst ) )
+ if ( aItr->second.nCount > aDefaultItr->second.nCount ||
+ ( aItr->second.nCount == aDefaultItr->second.nCount && aItr->second.nFirst < aDefaultItr->second.nFirst ) )
aDefaultItr = aItr;
++aItr;
}
- nDefault = aDefaultItr->nFirst;
+ nDefault = aDefaultItr->second.nFirst;
}
void ScDocument::StripHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->StripHidden( rX1, rY1, rX2, rY2 );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->StripHidden( rX1, rY1, rX2, rY2 );
}
void ScDocument::ExtendHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
{
- if ( ValidTab(nTab) && maTabs[nTab] )
- maTabs[nTab]->ExtendHidden( rX1, rY1, rX2, rY2 );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->ExtendHidden( rX1, rY1, rX2, rY2 );
}
// Attribute ----------------------------------------------------------
const SfxPoolItem* ScDocument::GetAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] &&
- nCol < maTabs[nTab]->GetAllocatedColumnsCount())
+ if (const ScTable* pTable = FetchTable(nTab))
{
- const SfxPoolItem* pTemp = maTabs[nTab]->GetAttr( nCol, nRow, nWhich );
+ const SfxPoolItem* pTemp = pTable->GetAttr( nCol, nRow, nWhich );
if (pTemp)
return pTemp;
else
@@ -4755,7 +4721,22 @@ const SfxPoolItem* ScDocument::GetAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, sal_
OSL_FAIL( "Attribute Null" );
}
}
- return &mxPoolHelper->GetDocPool()->GetDefaultItem( nWhich );
+ return &mxPoolHelper->GetDocPool()->GetUserOrPoolDefaultItem( nWhich );
+}
+
+const SfxPoolItem* ScDocument::GetAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich, SCROW& nStartRow, SCROW& nEndRow ) const
+{
+ if (const ScTable* pTable = FetchTable(nTab))
+ {
+ const SfxPoolItem* pTemp = pTable->GetAttr( nCol, nRow, nWhich, nStartRow, nEndRow );
+ if (pTemp)
+ return pTemp;
+ else
+ {
+ OSL_FAIL( "Attribute Null" );
+ }
+ }
+ return &mxPoolHelper->GetDocPool()->GetUserOrPoolDefaultItem( nWhich );
}
const SfxPoolItem* ScDocument::GetAttr( const ScAddress& rPos, sal_uInt16 nWhich ) const
@@ -4765,36 +4746,36 @@ const SfxPoolItem* ScDocument::GetAttr( const ScAddress& rPos, sal_uInt16 nWhich
const ScPatternAttr* ScDocument::GetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
{
- if (TableExists(nTab))
- return maTabs[nTab]->GetPattern( nCol, nRow );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetPattern( nCol, nRow );
return nullptr;
}
const ScPatternAttr* ScDocument::GetPattern( const ScAddress& rPos ) const
{
- if (TableExists(rPos.Tab()))
- return maTabs[rPos.Tab()]->GetPattern(rPos.Col(), rPos.Row());
+ if (const ScTable* pTable = FetchTable(rPos.Tab()))
+ return pTable->GetPattern(rPos.Col(), rPos.Row());
return nullptr;
}
const ScPatternAttr* ScDocument::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetMostUsedPattern( nCol, nStartRow, nEndRow );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetMostUsedPattern(nCol, nStartRow, nEndRow);
return nullptr;
}
void ScDocument::ApplyAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, const SfxPoolItem& rAttr )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->ApplyAttr( nCol, nRow, rAttr );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->ApplyAttr( nCol, nRow, rAttr );
}
void ScDocument::ApplyPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->ApplyPattern( nCol, nRow, rAttr );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->ApplyPattern(nCol, nRow, rAttr);
}
void ScDocument::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow,
@@ -4804,7 +4785,7 @@ void ScDocument::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow,
ScEditDataArray* pDataArray,
bool* const pIsChanged )
{
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -4817,15 +4798,14 @@ void ScDocument::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow,
void ScDocument::ApplyPatternAreaTab( SCCOL nStartCol, SCROW nStartRow,
SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScPatternAttr& rAttr )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
- if (maTabs[nTab])
- maTabs[nTab]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->ApplyPatternArea(nStartCol, nStartRow, nEndCol, nEndRow, rAttr);
}
void ScDocument::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
const ScMarkData& rMark, const ScPatternAttr& rPattern, SvNumFormatType nNewType )
{
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -4837,31 +4817,20 @@ void ScDocument::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
void ScDocument::AddCondFormatData( const ScRangeList& rRange, SCTAB nTab, sal_uInt32 nIndex )
{
- if(o3tl::make_unsigned(nTab) >= maTabs.size())
- return;
-
- if(!maTabs[nTab])
- return;
-
- maTabs[nTab]->AddCondFormatData(rRange, nIndex);
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->AddCondFormatData(rRange, nIndex);
}
void ScDocument::RemoveCondFormatData( const ScRangeList& rRange, SCTAB nTab, sal_uInt32 nIndex )
{
- if(o3tl::make_unsigned(nTab) >= maTabs.size())
- return;
-
- if(!maTabs[nTab])
- return;
-
- maTabs[nTab]->RemoveCondFormatData(rRange, nIndex);
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->RemoveCondFormatData(rRange, nIndex);
}
void ScDocument::ApplyStyle( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScStyleSheet& rStyle)
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
- if (maTabs[nTab])
- maTabs[nTab]->ApplyStyle( nCol, nRow, &rStyle );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->ApplyStyle(nCol, nRow, &rStyle);
}
void ScDocument::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow,
@@ -4869,7 +4838,7 @@ void ScDocument::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow,
const ScMarkData& rMark,
const ScStyleSheet& rStyle)
{
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -4882,9 +4851,8 @@ void ScDocument::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow,
void ScDocument::ApplyStyleAreaTab( SCCOL nStartCol, SCROW nStartRow,
SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScStyleSheet& rStyle)
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
- if (maTabs[nTab])
- maTabs[nTab]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
}
void ScDocument::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
@@ -4892,14 +4860,13 @@ void ScDocument::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkDat
// ApplySelectionStyle needs multi mark
if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
{
- ScRange aRange;
- rMark.GetMarkArea( aRange );
+ const ScRange& aRange = rMark.GetMarkArea();
ApplyStyleArea( aRange.aStart.Col(), aRange.aStart.Row(),
aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rStyle );
}
else
{
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -4916,7 +4883,7 @@ void ScDocument::ApplySelectionLineStyle( const ScMarkData& rMark,
if ( bColorOnly && !pLine )
return;
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -4928,10 +4895,9 @@ void ScDocument::ApplySelectionLineStyle( const ScMarkData& rMark,
const ScStyleSheet* ScDocument::GetStyle( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetStyle(nCol, nRow);
- else
- return nullptr;
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetStyle(nCol, nRow);
+ return nullptr;
}
const ScStyleSheet* ScDocument::GetSelectionStyle( const ScMarkData& rMark ) const
@@ -4944,7 +4910,7 @@ const ScStyleSheet* ScDocument::GetSelectionStyle( const ScMarkData& rMark ) con
if ( rMark.IsMultiMarked() )
{
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -4964,9 +4930,8 @@ const ScStyleSheet* ScDocument::GetSelectionStyle( const ScMarkData& rMark ) con
}
if ( rMark.IsMarked() )
{
- ScRange aRange;
- rMark.GetMarkArea( aRange );
- for (SCTAB i=aRange.aStart.Tab(); i<=aRange.aEnd.Tab() && bEqual && i < static_cast<SCTAB>(maTabs.size()); i++)
+ const ScRange& aRange = rMark.GetMarkArea();
+ for (SCTAB i = aRange.aStart.Tab(); i <= aRange.aEnd.Tab() && bEqual && i < GetTableCount(); i++)
if (maTabs[i] && rMark.GetTableSelect(i))
{
pNewStyle = maTabs[i]->GetAreaStyle( bFound,
@@ -4989,17 +4954,12 @@ void ScDocument::StyleSheetChanged( const SfxStyleSheetBase* pStyleSheet, bool b
double nPPTX, double nPPTY,
const Fraction& rZoomX, const Fraction& rZoomY )
{
- for (const auto& a : maTabs)
+ for (const auto& rTab : maTabs)
{
- if (a)
- a->StyleSheetChanged
- ( pStyleSheet, bRemoved, pDev, nPPTX, nPPTY, rZoomX, rZoomY );
- }
-
- if ( pStyleSheet && pStyleSheet->GetName() == ScResId(STR_STYLENAME_STANDARD) )
- {
- // update attributes for all note objects
- ScDetectiveFunc::UpdateAllComments( *this );
+ if (rTab)
+ {
+ rTab->StyleSheetChanged(pStyleSheet, bRemoved, pDev, nPPTX, nPPTY, rZoomX, rZoomY);
+ }
}
}
@@ -5021,9 +4981,9 @@ bool ScDocument::IsStyleSheetUsed( const ScStyleSheet& rStyle ) const
bool bIsUsed = false;
- for (const auto& a : maTabs)
+ for (const auto& pTable : maTabs)
{
- if (a && a->IsStyleSheetUsed( rStyle ) )
+ if (pTable && pTable->IsStyleSheetUsed(rStyle))
bIsUsed = true;
}
@@ -5038,9 +4998,8 @@ bool ScDocument::IsStyleSheetUsed( const ScStyleSheet& rStyle ) const
bool ScDocument::ApplyFlagsTab( SCCOL nStartCol, SCROW nStartRow,
SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, ScMF nFlags )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
- if (maTabs[nTab])
- return maTabs[nTab]->ApplyFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->ApplyFlags(nStartCol, nStartRow, nEndCol, nEndRow, nFlags);
OSL_FAIL("ApplyFlags: wrong table");
return false;
@@ -5049,34 +5008,29 @@ bool ScDocument::ApplyFlagsTab( SCCOL nStartCol, SCROW nStartRow,
bool ScDocument::RemoveFlagsTab( SCCOL nStartCol, SCROW nStartRow,
SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, ScMF nFlags )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
- if (maTabs[nTab])
- return maTabs[nTab]->RemoveFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->RemoveFlags(nStartCol, nStartRow, nEndCol, nEndRow, nFlags);
OSL_FAIL("RemoveFlags: wrong table");
return false;
}
-const ScPatternAttr* ScDocument::SetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, std::unique_ptr<ScPatternAttr> pAttr )
+void ScDocument::SetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const CellAttributeHolder& rHolder )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
- if (maTabs[nTab])
- return maTabs[nTab]->SetPattern( nCol, nRow, std::move(pAttr) );
- return nullptr;
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetPattern(nCol, nRow, rHolder);
}
-void ScDocument::SetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr )
+void ScDocument::SetPattern( const ScAddress& rPos, const CellAttributeHolder& rHolder )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
- if (maTabs[nTab])
- maTabs[nTab]->SetPattern( nCol, nRow, rAttr );
+ SetPattern(rPos.Col(), rPos.Row(), rPos.Tab(), rHolder);
}
void ScDocument::SetPattern( const ScAddress& rPos, const ScPatternAttr& rAttr )
{
SCTAB nTab = rPos.Tab();
- if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->SetPattern( rPos, rAttr );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetPattern(rPos, rAttr);
}
std::unique_ptr<ScPatternAttr> ScDocument::CreateSelectionPattern( const ScMarkData& rMark, bool bDeep )
@@ -5085,7 +5039,7 @@ std::unique_ptr<ScPatternAttr> ScDocument::CreateSelectionPattern( const ScMarkD
if ( rMark.IsMultiMarked() ) // multi selection
{
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -5096,9 +5050,8 @@ std::unique_ptr<ScPatternAttr> ScDocument::CreateSelectionPattern( const ScMarkD
}
if ( rMark.IsMarked() ) // single selection
{
- ScRange aRange;
- rMark.GetMarkArea(aRange);
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ const ScRange& aRange = rMark.GetMarkArea();
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -5113,14 +5066,14 @@ std::unique_ptr<ScPatternAttr> ScDocument::CreateSelectionPattern( const ScMarkD
OSL_ENSURE( aState.pItemSet, "SelectionPattern Null" );
if (aState.pItemSet)
{
- std::unique_ptr<ScPatternAttr> pPattern(new ScPatternAttr( std::move(aState.pItemSet) ));
+ std::unique_ptr<ScPatternAttr> pPattern(new ScPatternAttr(getCellAttributeHelper(), &aState.pItemSet.value()));
if (aState.mbValidPatternId)
- pPattern->SetKey(aState.mnPatternId);
+ pPattern->SetPAKey(aState.mnPatternId);
return pPattern;
}
else
- return std::unique_ptr<ScPatternAttr>(new ScPatternAttr( GetPool() )); // empty
+ return std::unique_ptr<ScPatternAttr>(new ScPatternAttr(getCellAttributeHelper())); // empty
}
const ScPatternAttr* ScDocument::GetSelectionPattern( const ScMarkData& rMark )
@@ -5158,7 +5111,7 @@ void ScDocument::GetSelectionFrame( const ScMarkData& rMark,
const ScRange & rRange = aRangeList[ nRangeIdx ];
bMultipleRows = ( bMultipleRows || ( rRange.aStart.Row() != rRange.aEnd.Row() ) );
bMultipleCols = ( bMultipleCols || ( rRange.aStart.Col() != rRange.aEnd.Col() ) );
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -5175,11 +5128,10 @@ void ScDocument::GetSelectionFrame( const ScMarkData& rMark,
}
else if( rMark.IsMarked() )
{
- ScRange aRange;
- rMark.GetMarkArea(aRange);
+ const ScRange& aRange = rMark.GetMarkArea();
rLineInner.EnableHor( aRange.aStart.Row() != aRange.aEnd.Row() );
rLineInner.EnableVer( aRange.aStart.Col() != aRange.aEnd.Col() );
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -5202,18 +5154,17 @@ void ScDocument::GetSelectionFrame( const ScMarkData& rMark,
rLineInner.SetValid( SvxBoxInfoItemValidFlags::VERT, ( aFlags.nVert != SC_LINE_DONTCARE ) );
}
-bool ScDocument::HasAttrib( SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
- SCCOL nCol2, SCROW nRow2, SCTAB nTab2, HasAttrFlags nMask ) const
+static HasAttrFlags OptimizeHasAttrib( HasAttrFlags nMask, const ScDocumentPool* pPool )
{
if ( nMask & HasAttrFlags::Rotate )
{
// Is attribute used in document?
// (as in fillinfo)
- ScDocumentPool* pPool = mxPoolHelper->GetDocPool();
-
bool bAnyItem = false;
- for (const SfxPoolItem* pItem : pPool->GetItemSurrogates(ATTR_ROTATE_VALUE))
+ ItemSurrogates aSurrogates;
+ pPool->GetItemSurrogates(aSurrogates, ATTR_ROTATE_VALUE);
+ for (const SfxPoolItem* pItem : aSurrogates)
{
// 90 or 270 degrees is former SvxOrientationItem - only look for other values
// (see ScPatternAttr::GetCellOrientation)
@@ -5227,12 +5178,18 @@ bool ScDocument::HasAttrib( SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
if (!bAnyItem)
nMask &= ~HasAttrFlags::Rotate;
}
+ return nMask;
+}
+
+bool ScDocument::HasAttrib( SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2, HasAttrFlags nMask ) const
+{
+ nMask = OptimizeHasAttrib( nMask, mxPoolHelper->GetDocPool());
if (nMask == HasAttrFlags::NONE)
return false;
- bool bFound = false;
- for (SCTAB i=nTab1; i<=nTab2 && !bFound && i < static_cast<SCTAB>(maTabs.size()); i++)
+ for (SCTAB i = nTab1; i <= nTab2 && i < GetTableCount(); i++)
if (maTabs[i])
{
if ( nMask & HasAttrFlags::RightOrCenter )
@@ -5242,14 +5199,46 @@ bool ScDocument::HasAttrib( SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
// That way, ScAttrArray::HasAttrib doesn't have to handle RTL sheets.
if ( IsLayoutRTL(i) )
- bFound = true;
+ return true;
}
- if ( !bFound )
- bFound = maTabs[i]->HasAttrib( nCol1, nRow1, nCol2, nRow2, nMask );
+ if( maTabs[i]->HasAttrib( nCol1, nRow1, nCol2, nRow2, nMask ))
+ return true;
}
- return bFound;
+ return false;
+}
+
+bool ScDocument::HasAttrib( SCCOL nCol, SCROW nRow, SCTAB nTab, HasAttrFlags nMask, SCROW* nStartRow, SCROW* nEndRow ) const
+{
+ nMask = OptimizeHasAttrib( nMask, mxPoolHelper->GetDocPool());
+
+ if (nMask == HasAttrFlags::NONE || nTab >= GetTableCount())
+ {
+ if( nStartRow )
+ *nStartRow = 0;
+ if( nEndRow )
+ *nEndRow = MaxRow();
+ return false;
+ }
+
+ if ( nMask & HasAttrFlags::RightOrCenter )
+ {
+ // On a RTL sheet, don't start to look for the default left value
+ // (which is then logically right), instead always assume true.
+ // That way, ScAttrArray::HasAttrib doesn't have to handle RTL sheets.
+
+ if ( IsLayoutRTL(nTab) )
+ {
+ if( nStartRow )
+ *nStartRow = 0;
+ if( nEndRow )
+ *nEndRow = MaxRow();
+ return true;
+ }
+ }
+
+ return maTabs[nTab]->HasAttrib( nCol, nRow, nMask, nStartRow, nEndRow );
}
bool ScDocument::HasAttrib( const ScRange& rRange, HasAttrFlags nMask ) const
@@ -5262,12 +5251,12 @@ bool ScDocument::HasAttrib( const ScRange& rRange, HasAttrFlags nMask ) const
void ScDocument::FindMaxRotCol( SCTAB nTab, RowInfo* pRowInfo, SCSIZE nArrCount,
SCCOL nX1, SCCOL nX2 ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->FindMaxRotCol( pRowInfo, nArrCount, nX1, nX2 );
- else
+ if (HasTable(nTab))
{
- OSL_FAIL("FindMaxRotCol: wrong table");
+ maTabs[nTab]->FindMaxRotCol(pRowInfo, nArrCount, nX1, nX2);
+ return;
}
+ OSL_FAIL("FindMaxRotCol: wrong table");
}
void ScDocument::GetBorderLines( SCCOL nCol, SCROW nRow, SCTAB nTab,
@@ -5319,21 +5308,19 @@ void ScDocument::GetBorderLines( SCCOL nCol, SCROW nRow, SCTAB nTab,
*ppBottom = pBottomLine;
}
-bool ScDocument::IsBlockEmpty( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
- SCCOL nEndCol, SCROW nEndRow, bool bIgnoreNotes ) const
+bool ScDocument::IsBlockEmpty(SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
- if (maTabs[nTab])
- return maTabs[nTab]->IsBlockEmpty( nStartCol, nStartRow, nEndCol, nEndRow, bIgnoreNotes );
-
+ if (HasTable(nTab))
+ return maTabs[nTab]->IsBlockEmpty(nStartCol, nStartRow, nEndCol, nEndRow);
OSL_FAIL("wrong table number");
return false;
}
void ScDocument::LockTable(SCTAB nTab)
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->LockTable();
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->LockTable();
else
{
OSL_FAIL("wrong table number");
@@ -5342,8 +5329,8 @@ void ScDocument::LockTable(SCTAB nTab)
void ScDocument::UnlockTable(SCTAB nTab)
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->UnlockTable();
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->UnlockTable();
else
{
OSL_FAIL("wrong table number");
@@ -5363,10 +5350,9 @@ bool ScDocument::IsBlockEditable( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
return false;
}
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
- if (maTabs[nTab])
- return maTabs[nTab]->IsBlockEditable( nStartCol, nStartRow, nEndCol,
- nEndRow, pOnlyNotBecauseOfMatrix, bNoMatrixAtAll );
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->IsBlockEditable(nStartCol, nStartRow, nEndCol, nEndRow,
+ pOnlyNotBecauseOfMatrix, bNoMatrixAtAll);
OSL_FAIL("wrong table number");
if ( pOnlyNotBecauseOfMatrix )
@@ -5385,12 +5371,11 @@ bool ScDocument::IsSelectionEditable( const ScMarkData& rMark,
return false;
}
- ScRange aRange;
- rMark.GetMarkArea(aRange);
+ const ScRange& aRange = rMark.GetMarkArea();
bool bOk = true;
bool bMatrix = ( pOnlyNotBecauseOfMatrix != nullptr );
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -5435,7 +5420,7 @@ bool ScDocument::HasSelectedBlockMatrixFragment( SCCOL nStartCol, SCROW nStartRo
const ScMarkData& rMark ) const
{
bool bOk = true;
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -5506,7 +5491,7 @@ void ScDocument::ExtendOverlapped( SCCOL& rStartCol, SCROW& rStartRow,
{
if ( ValidColRow(rStartCol,rStartRow) && ValidColRow(nEndCol,nEndRow) && ValidTab(nTab) )
{
- if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
+ if (const ScTable* pTable = FetchTable(nTab))
{
SCCOL nCol;
SCCOL nOldCol = rStartCol;
@@ -5517,25 +5502,26 @@ void ScDocument::ExtendOverlapped( SCCOL& rStartCol, SCROW& rStartRow,
//TODO: pass on ?
- ScAttrArray* pAttrArray = maTabs[nTab]->aCol[nOldCol].pAttrArray.get();
+ const ScAttrArray& pAttrArray = pTable->GetColumnData(nOldCol).AttrArray();
SCSIZE nIndex;
- if ( pAttrArray->Count() )
- pAttrArray->Search( nOldRow, nIndex );
+ if ( pAttrArray.Count() )
+ pAttrArray.Search( nOldRow, nIndex );
else
nIndex = 0;
SCROW nAttrPos = nOldRow;
while (nAttrPos<=nEndRow)
{
- OSL_ENSURE( nIndex < pAttrArray->Count(), "Wrong index in AttrArray" );
+ OSL_ENSURE( nIndex < pAttrArray.Count(), "Wrong index in AttrArray" );
bool bHorOverlapped;
- if ( pAttrArray->Count() )
- bHorOverlapped = pAttrArray->mvData[nIndex].pPattern->GetItem(ATTR_MERGE_FLAG).IsHorOverlapped();
+ if ( pAttrArray.Count() )
+ bHorOverlapped = pAttrArray.mvData[nIndex].getScPatternAttr()->GetItem(ATTR_MERGE_FLAG).IsHorOverlapped();
else
- bHorOverlapped = GetDefPattern()->GetItem(ATTR_MERGE_FLAG).IsHorOverlapped();
+ bHorOverlapped = getCellAttributeHelper().getDefaultCellAttribute().GetItem(ATTR_MERGE_FLAG).IsHorOverlapped();
+
if ( bHorOverlapped )
{
- SCROW nEndRowSeg = (pAttrArray->Count()) ? pAttrArray->mvData[nIndex].nEndRow : MaxRow();
+ SCROW nEndRowSeg = (pAttrArray.Count()) ? pAttrArray.mvData[nIndex].nEndRow : MaxRow();
SCROW nLoopEndRow = std::min( nEndRow, nEndRowSeg );
for (SCROW nAttrRow = nAttrPos; nAttrRow <= nLoopEndRow; nAttrRow++)
{
@@ -5547,9 +5533,9 @@ void ScDocument::ExtendOverlapped( SCCOL& rStartCol, SCROW& rStartRow,
rStartCol = nTempCol;
}
}
- if ( pAttrArray->Count() )
+ if ( pAttrArray.Count() )
{
- nAttrPos = pAttrArray->mvData[nIndex].nEndRow + 1;
+ nAttrPos = pAttrArray.mvData[nIndex].nEndRow + 1;
++nIndex;
}
else
@@ -5572,7 +5558,7 @@ void ScDocument::ExtendMergeSel( SCCOL nStartCol, SCROW nStartRow,
SCCOL nOldEndCol = rEndCol;
SCROW nOldEndRow = rEndRow;
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -5598,8 +5584,8 @@ bool ScDocument::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
bool bFound = false;
if ( ValidColRow(nStartCol,nStartRow) && ValidColRow(rEndCol,rEndRow) && ValidTab(nTab) )
{
- if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- bFound = maTabs[nTab]->ExtendMerge( nStartCol, nStartRow, rEndCol, rEndRow, bRefresh );
+ if (ScTable* pTable = FetchTable(nTab))
+ bFound = pTable->ExtendMerge( nStartCol, nStartRow, rEndCol, rEndRow, bRefresh );
if (bRefresh)
RefreshAutoFilter( nStartCol, nStartRow, rEndCol, rEndRow, nTab );
@@ -5621,7 +5607,7 @@ bool ScDocument::ExtendMerge( ScRange& rRange, bool bRefresh )
SCROW nEndRow = rRange.aEnd.Row();
PutInOrder( nStartTab, nEndTab );
- for (SCTAB nTab = nStartTab; nTab <= nEndTab && nTab < static_cast<SCTAB>(maTabs.size()); nTab++ )
+ for (SCTAB nTab = nStartTab; nTab <= nEndTab && nTab < GetTableCount(); nTab++ )
{
SCCOL nExtendCol = rRange.aEnd.Col();
SCROW nExtendRow = rRange.aEnd.Row();
@@ -5675,7 +5661,7 @@ void ScDocument::ExtendOverlapped( ScRange& rRange ) const
SCROW nStartRow = rRange.aStart.Row();
PutInOrder( nStartTab, nEndTab );
- for (SCTAB nTab = nStartTab; nTab <= nEndTab && nTab < static_cast<SCTAB>(maTabs.size()); nTab++ )
+ for (SCTAB nTab = nStartTab; nTab <= nEndTab && nTab < GetTableCount(); nTab++ )
{
SCCOL nExtendCol = rRange.aStart.Col();
SCROW nExtendRow = rRange.aStart.Row();
@@ -5726,10 +5712,10 @@ bool ScDocument::RefreshAutoFilter( SCCOL nStartCol, SCROW nStartRow,
}
}
}
- if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- pData = maTabs[nTab]->GetAnonymousDBData();
+ if (ScTable* pTable = FetchTable(nTab))
+ pData = pTable->GetAnonymousDBData();
else
- pData=nullptr;
+ pData = nullptr;
if (pData && pData->HasAutoFilter())
{
pData->GetArea( nDBTab, nDBStartCol,nDBStartRow, nDBEndCol,nDBEndRow );
@@ -5764,9 +5750,11 @@ bool ScDocument::IsHorOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
}
}
-bool ScDocument::IsVerOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+bool ScDocument::IsVerOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab, SCROW* nStartRow, SCROW* nEndRow ) const
{
- const ScMergeFlagAttr* pAttr = GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
+ SCROW dummy;
+ const ScMergeFlagAttr* pAttr = GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG,
+ nStartRow ? *nStartRow : dummy, nEndRow ? *nEndRow : dummy );
if (pAttr)
return pAttr->IsVerOverlapped();
else
@@ -5783,7 +5771,7 @@ void ScDocument::ApplySelectionFrame( const ScMarkData& rMark,
ScRangeList aRangeList;
rMark.FillRangeListWithMarks( &aRangeList, false );
size_t nRangeCount = aRangeList.size();
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -5890,7 +5878,7 @@ void ScDocument::ApplyFrameAreaTab(const ScRange& rRange,
{
SCTAB nStartTab = rRange.aStart.Tab();
SCTAB nEndTab = rRange.aStart.Tab();
- for (SCTAB nTab=nStartTab; nTab<=nEndTab && nTab < static_cast<SCTAB>(maTabs.size()); nTab++)
+ for (SCTAB nTab = nStartTab; nTab <= nEndTab && nTab < GetTableCount(); nTab++)
if (maTabs[nTab])
maTabs[nTab]->ApplyBlockFrame(rLineOuter, &rLineInner,
rRange.aStart.Col(), rRange.aStart.Row(),
@@ -5912,28 +5900,27 @@ void ScDocument::ApplySelectionPattern( const ScPatternAttr& rAttr, const ScMark
// ApplySelectionCache needs multi mark
if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
{
- ScRange aRange;
- rMark.GetMarkArea( aRange );
+ const ScRange& aRange = rMark.GetMarkArea();
ApplyPatternArea( aRange.aStart.Col(), aRange.aStart.Row(),
aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rAttr, pDataArray, pIsChanged );
}
else
{
- SfxItemPoolCache aCache( mxPoolHelper->GetDocPool(), pSet );
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ ScItemPoolCache aCache( getCellAttributeHelper(), *pSet );
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
break;
if (maTabs[rTab])
- maTabs[rTab]->ApplySelectionCache( &aCache, rMark, pDataArray, pIsChanged );
+ maTabs[rTab]->ApplySelectionCache( aCache, rMark, pDataArray, pIsChanged );
}
}
}
void ScDocument::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark )
{
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -5945,7 +5932,7 @@ void ScDocument::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark
void ScDocument::ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark )
{
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -5977,7 +5964,7 @@ void ScDocument::DeleteSelection( InsertDeleteFlags nDelFlag, const ScMarkData&
aCxt.purgeEmptyBroadcasters();
}
- SCTAB nMax = static_cast<SCTAB>(maTabs.size());
+ SCTAB nMax = GetTableCount();
for (const auto& rTab : rMark)
{
if (rTab >= nMax)
@@ -6016,7 +6003,7 @@ void ScDocument::DeleteSelection( InsertDeleteFlags nDelFlag, const ScMarkData&
void ScDocument::DeleteSelectionTab(
SCTAB nTab, InsertDeleteFlags nDelFlag, const ScMarkData& rMark )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
+ if (ScTable* pTable = FetchTable(nTab))
{
sc::AutoCalcSwitch aACSwitch(*this, false);
@@ -6044,7 +6031,7 @@ void ScDocument::DeleteSelectionTab(
aCxt.purgeEmptyBroadcasters();
}
- maTabs[nTab]->DeleteSelection(nDelFlag, rMark);
+ pTable->DeleteSelection(nDelFlag, rMark);
if (bDelContent)
{
@@ -6079,19 +6066,21 @@ void ScDocument::DeleteSelectionTab(
}
}
-ScPatternAttr* ScDocument::GetDefPattern() const
+ScDocumentPool* ScDocument::GetPool()
{
- return const_cast<ScPatternAttr*>(&mxPoolHelper->GetDocPool()->GetDefaultItem(ATTR_PATTERN));
+ return mxPoolHelper ? mxPoolHelper->GetDocPool() : nullptr;
}
-ScDocumentPool* ScDocument::GetPool()
+ScStyleSheetPool* ScDocument::GetStyleSheetPool() const
{
- return mxPoolHelper->GetDocPool();
+ return mxPoolHelper ? mxPoolHelper->GetStylePool() : nullptr;
}
-ScStyleSheetPool* ScDocument::GetStyleSheetPool() const
+bool ScDocument::IsEmptyData(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, SCTAB nTab) const
{
- return mxPoolHelper->GetStylePool();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->IsEmptyData(nStartCol, nStartRow, nEndCol, nEndRow);
+ return true;
}
SCSIZE ScDocument::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
@@ -6100,21 +6089,15 @@ SCSIZE ScDocument::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCTAB
PutInOrder(nStartCol, nEndCol);
PutInOrder(nStartRow, nEndRow);
PutInOrder(nStartTab, nEndTab);
- if (ValidTab(nStartTab) && nStartTab < static_cast<SCTAB>(maTabs.size()))
- {
- if (maTabs[nStartTab])
- return maTabs[nStartTab]->GetEmptyLinesInBlock(nStartCol, nStartRow, nEndCol, nEndRow, eDir);
- else
- return 0;
- }
- else
- return 0;
+ if (ScTable* pTable = FetchTable(nStartTab))
+ return pTable->GetEmptyLinesInBlock(nStartCol, nStartRow, nEndCol, nEndRow, eDir);
+ return 0;
}
void ScDocument::FindAreaPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, ScMoveDirection eDirection ) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->FindAreaPos( rCol, rRow, eDirection );
+ if (const ScTable* pTable = FetchTable(nTab))
+ pTable->FindAreaPos(rCol, rRow, eDirection);
}
void ScDocument::GetNextPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCCOL nMovX, SCROW nMovY,
@@ -6126,41 +6109,15 @@ void ScDocument::GetNextPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCCOL nMovX,
aCopyMark.SetMarking(false);
aCopyMark.MarkToMulti();
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->GetNextPos( rCol, rRow, nMovX, nMovY, bMarked, bUnprotected, aCopyMark, nTabStartCol );
+ if (const ScTable* pTable = FetchTable(nTab))
+ pTable->GetNextPos(rCol, rRow, nMovX, nMovY, bMarked, bUnprotected, aCopyMark, nTabStartCol);
}
// Data operations
-void ScDocument::UpdStlShtPtrsFrmNms()
+sal_uInt64 ScDocument::GetCellCount() const
{
- ScDocumentPool* pPool = mxPoolHelper->GetDocPool();
-
- for (const SfxPoolItem* pItem : pPool->GetItemSurrogates(ATTR_PATTERN))
- {
- auto pPattern = const_cast<ScPatternAttr*>(dynamic_cast<const ScPatternAttr*>(pItem));
- if (pPattern)
- pPattern->UpdateStyleSheet(*this);
- }
- const_cast<ScPatternAttr&>(pPool->GetDefaultItem(ATTR_PATTERN)).UpdateStyleSheet(*this);
-}
-
-void ScDocument::StylesToNames()
-{
- ScDocumentPool* pPool = mxPoolHelper->GetDocPool();
-
- for (const SfxPoolItem* pItem : pPool->GetItemSurrogates(ATTR_PATTERN))
- {
- auto pPattern = const_cast<ScPatternAttr*>(dynamic_cast<const ScPatternAttr*>(pItem));
- if (pPattern)
- pPattern->StyleToName();
- }
- const_cast<ScPatternAttr&>(pPool->GetDefaultItem(ATTR_PATTERN)).StyleToName();
-}
-
-sal_uLong ScDocument::GetCellCount() const
-{
- sal_uLong nCellCount = 0;
+ sal_uInt64 nCellCount = 0;
for (const auto& a : maTabs)
{
@@ -6171,9 +6128,9 @@ sal_uLong ScDocument::GetCellCount() const
return nCellCount;
}
-sal_uLong ScDocument::GetFormulaGroupCount() const
+sal_uInt64 ScDocument::GetFormulaGroupCount() const
{
- sal_uLong nFormulaGroupCount = 0;
+ sal_uInt64 nFormulaGroupCount = 0;
ScFormulaGroupIterator aIter( *const_cast<ScDocument*>(this) );
for ( sc::FormulaGroupEntry* ptr = aIter.first(); ptr; ptr = aIter.next())
@@ -6184,9 +6141,9 @@ sal_uLong ScDocument::GetFormulaGroupCount() const
return nFormulaGroupCount;
}
-sal_uLong ScDocument::GetCodeCount() const
+sal_uInt64 ScDocument::GetCodeCount() const
{
- sal_uLong nCodeCount = 0;
+ sal_uInt64 nCodeCount = 0;
for (const auto& a : maTabs)
{
@@ -6199,34 +6156,33 @@ sal_uLong ScDocument::GetCodeCount() const
void ScDocument::PageStyleModified( SCTAB nTab, const OUString& rNewName )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->PageStyleModified( rNewName );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->PageStyleModified( rNewName );
}
void ScDocument::SetPageStyle( SCTAB nTab, const OUString& rName )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->SetPageStyle( rName );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetPageStyle( rName );
}
OUString ScDocument::GetPageStyle( SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetPageStyle();
-
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetPageStyle();
return OUString();
}
void ScDocument::SetPageSize( SCTAB nTab, const Size& rSize )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->SetPageSize( rSize );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetPageSize( rSize );
}
Size ScDocument::GetPageSize( SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->GetPageSize();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetPageSize();
OSL_FAIL("invalid tab");
return Size();
@@ -6234,32 +6190,32 @@ Size ScDocument::GetPageSize( SCTAB nTab ) const
void ScDocument::SetRepeatArea( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->SetRepeatArea( nStartCol, nEndCol, nStartRow, nEndRow );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetRepeatArea( nStartCol, nEndCol, nStartRow, nEndRow );
}
void ScDocument::InvalidatePageBreaks(SCTAB nTab)
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->InvalidatePageBreaks();
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->InvalidatePageBreaks();
}
void ScDocument::UpdatePageBreaks( SCTAB nTab, const ScRange* pUserArea )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->UpdatePageBreaks( pUserArea );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->UpdatePageBreaks( pUserArea );
}
void ScDocument::RemoveManualBreaks( SCTAB nTab )
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->RemoveManualBreaks();
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->RemoveManualBreaks();
}
bool ScDocument::HasManualBreaks( SCTAB nTab ) const
{
- if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- return maTabs[nTab]->HasManualBreaks();
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->HasManualBreaks();
OSL_FAIL("invalid tab");
return false;
@@ -6291,74 +6247,79 @@ bool ScDocument::HasPrintRange()
bool ScDocument::IsPrintEntireSheet( SCTAB nTab ) const
{
- return (ValidTab(nTab) ) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->IsPrintEntireSheet();
+ const ScTable* pTable = FetchTable(nTab);
+ return (pTable && pTable->IsPrintEntireSheet());
}
sal_uInt16 ScDocument::GetPrintRangeCount( SCTAB nTab )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetPrintRangeCount();
-
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->GetPrintRangeCount();
return 0;
}
const ScRange* ScDocument::GetPrintRange( SCTAB nTab, sal_uInt16 nPos )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetPrintRange(nPos);
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->GetPrintRange(nPos);
return nullptr;
}
-const ScRange* ScDocument::GetRepeatColRange( SCTAB nTab )
+std::optional<ScRange> ScDocument::GetRepeatColRange( SCTAB nTab )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetRepeatColRange();
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->GetRepeatColRange();
- return nullptr;
+ return std::nullopt;
}
-const ScRange* ScDocument::GetRepeatRowRange( SCTAB nTab )
+std::optional<ScRange> ScDocument::GetRepeatRowRange( SCTAB nTab )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetRepeatRowRange();
-
- return nullptr;
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->GetRepeatRowRange();
+ return std::nullopt;
}
void ScDocument::ClearPrintRanges( SCTAB nTab )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->ClearPrintRanges();
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->ClearPrintRanges();
+}
+
+void ScDocument::ClearPrintNamedRanges( SCTAB nTab )
+{
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->ClearPrintNamedRanges();
}
void ScDocument::AddPrintRange( SCTAB nTab, const ScRange& rNew )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->AddPrintRange( rNew );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->AddPrintRange(rNew);
}
void ScDocument::SetPrintEntireSheet( SCTAB nTab )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->SetPrintEntireSheet();
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetPrintEntireSheet();
}
-void ScDocument::SetRepeatColRange( SCTAB nTab, std::unique_ptr<ScRange> pNew )
+void ScDocument::SetRepeatColRange( SCTAB nTab, std::optional<ScRange> oNew )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->SetRepeatColRange( std::move(pNew) );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetRepeatColRange(std::move(oNew));
}
-void ScDocument::SetRepeatRowRange( SCTAB nTab, std::unique_ptr<ScRange> pNew )
+void ScDocument::SetRepeatRowRange( SCTAB nTab, std::optional<ScRange> oNew )
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->SetRepeatRowRange( std::move(pNew) );
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetRepeatRowRange(std::move(oNew));
}
std::unique_ptr<ScPrintRangeSaver> ScDocument::CreatePrintRangeSaver() const
{
- const SCTAB nCount = static_cast<SCTAB>(maTabs.size());
+ const SCTAB nCount = GetTableCount();
std::unique_ptr<ScPrintRangeSaver> pNew(new ScPrintRangeSaver( nCount ));
for (SCTAB i=0; i<nCount; i++)
if (maTabs[i])
@@ -6369,7 +6330,7 @@ std::unique_ptr<ScPrintRangeSaver> ScDocument::CreatePrintRangeSaver() const
void ScDocument::RestorePrintRanges( const ScPrintRangeSaver& rSaver )
{
const SCTAB nCount = rSaver.GetTabCount();
- const SCTAB maxIndex = std::min(nCount, static_cast<SCTAB>(maTabs.size()));
+ const SCTAB maxIndex = std::min(nCount, GetTableCount());
for (SCTAB i=0; i<maxIndex; i++)
if (maTabs[i])
maTabs[i]->RestorePrintRanges( rSaver.GetTabData(i) );
@@ -6380,7 +6341,7 @@ bool ScDocument::NeedPageResetAfterTab( SCTAB nTab ) const
// The page number count restarts at a sheet, if another template is set at
// the preceding one (only compare names) and if a pagenumber is specified (not 0)
- if ( nTab + 1 < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab+1] )
+ if (nTab + 1 < GetTableCount() && maTabs[nTab] && maTabs[nTab+1])
{
const OUString & rNew = maTabs[nTab+1]->GetPageStyle();
if ( rNew != maTabs[nTab]->GetPageStyle() )
@@ -6399,14 +6360,14 @@ bool ScDocument::NeedPageResetAfterTab( SCTAB nTab ) const
return false; // otherwise not
}
-SfxUndoManager* ScDocument::GetUndoManager()
+ScUndoManager* ScDocument::GetUndoManager()
{
if (!mpUndoManager)
{
// to support enhanced text edit for draw objects, use an SdrUndoManager
ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
- SdrUndoManager* pUndoManager = new SdrUndoManager;
+ ScUndoManager* pUndoManager = new ScUndoManager;
pUndoManager->SetDocShell(GetDocumentShell());
mpUndoManager = pUndoManager;
}
@@ -6416,7 +6377,7 @@ SfxUndoManager* ScDocument::GetUndoManager()
ScRowBreakIterator* ScDocument::GetRowBreakIterator(SCTAB nTab) const
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
+ if (HasTable(nTab))
return new ScRowBreakIterator(maTabs[nTab]->maRowPageBreaks);
return nullptr;
}
@@ -6471,26 +6432,24 @@ void ScDocument::SetSubTotalCellsDirty(const ScRange& rDirtyRange)
sal_uInt16 ScDocument::GetTextWidth( const ScAddress& rPos ) const
{
SCTAB nTab = rPos.Tab();
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetTextWidth(rPos.Col(), rPos.Row());
-
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetTextWidth(rPos.Col(), rPos.Row());
return 0;
}
SvtScriptType ScDocument::GetScriptType( const ScAddress& rPos ) const
{
SCTAB nTab = rPos.Tab();
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- return maTabs[nTab]->GetScriptType(rPos.Col(), rPos.Row());
-
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetScriptType(rPos.Col(), rPos.Row());
return SvtScriptType::NONE;
}
void ScDocument::SetScriptType( const ScAddress& rPos, SvtScriptType nType )
{
SCTAB nTab = rPos.Tab();
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->SetScriptType(rPos.Col(), rPos.Row(), nType);
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->SetScriptType(rPos.Col(), rPos.Row(), nType);
}
void ScDocument::EnableUndo( bool bVal )
@@ -6531,6 +6490,99 @@ bool ScDocument::IsInVBAMode() const
return false;
}
+// Sparklines
+std::shared_ptr<sc::Sparkline> ScDocument::GetSparkline(ScAddress const& rPosition)
+{
+ SCTAB nTab = rPosition.Tab();
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->GetSparkline(rPosition.Col(), rPosition.Row());
+ return std::shared_ptr<sc::Sparkline>();
+}
+
+bool ScDocument::HasSparkline(ScAddress const & rPosition)
+{
+ return bool(GetSparkline(rPosition));
+}
+
+sc::Sparkline* ScDocument::CreateSparkline(ScAddress const& rPosition, std::shared_ptr<sc::SparklineGroup> const& pSparklineGroup)
+{
+ SCTAB nTab = rPosition.Tab();
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->CreateSparkline(rPosition.Col(), rPosition.Row(), pSparklineGroup);
+ return nullptr;
+}
+
+bool ScDocument::DeleteSparkline(ScAddress const & rPosition)
+{
+ SCTAB nTab = rPosition.Tab();
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->DeleteSparkline(rPosition.Col(), rPosition.Row());
+ return false;
+}
+
+sc::SparklineList* ScDocument::GetSparklineList(SCTAB nTab)
+{
+ if (ScTable* pTable = FetchTable(nTab))
+ return &pTable->GetSparklineList();
+ return nullptr;
+}
+
+bool ScDocument::HasOneSparklineGroup(ScRange const& rRange)
+{
+ std::shared_ptr<sc::SparklineGroup> pSparklineGroup;
+ return GetSparklineGroupInRange(rRange, pSparklineGroup);
+}
+
+bool ScDocument::GetSparklineGroupInRange(ScRange const& rRange, std::shared_ptr<sc::SparklineGroup>& rGroup)
+{
+ std::shared_ptr<sc::SparklineGroup> pFoundGroup;
+ SCTAB nTab = rRange.aStart.Tab();
+
+ for (SCCOL nX = rRange.aStart.Col(); nX <= rRange.aEnd.Col(); nX++)
+ {
+ for (SCROW nY = rRange.aStart.Row(); nY <= rRange.aEnd.Row(); nY++)
+ {
+ auto pSparkline = GetSparkline(ScAddress(nX, nY, nTab));
+ if (!pSparkline)
+ {
+ return false;
+ }
+ else if (!pFoundGroup)
+ {
+ pFoundGroup = pSparkline->getSparklineGroup();
+ }
+ else if (pFoundGroup != pSparkline->getSparklineGroup())
+ {
+ return false;
+ }
+ }
+ }
+
+ rGroup = pFoundGroup;
+ return true;
+}
+
+std::shared_ptr<sc::SparklineGroup> ScDocument::SearchSparklineGroup(tools::Guid const& rGuid)
+{
+ for (auto const& rTable : maTabs)
+ {
+ if (!rTable)
+ continue;
+
+ auto& rSparklineList = rTable->GetSparklineList();
+
+ for (auto const& pSparklineGroup : rSparklineList.getSparklineGroups())
+ {
+ if (pSparklineGroup->getID() == rGuid)
+ return pSparklineGroup;
+ }
+ }
+
+ return std::shared_ptr<sc::SparklineGroup>();
+}
+
+// Notes
+
ScPostIt* ScDocument::GetNote(const ScAddress& rPos)
{
return GetNote(rPos.Col(), rPos.Row(), rPos.Tab());
@@ -6538,12 +6590,9 @@ ScPostIt* ScDocument::GetNote(const ScAddress& rPos)
ScPostIt* ScDocument::GetNote(SCCOL nCol, SCROW nRow, SCTAB nTab)
{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) &&
- nCol < maTabs[nTab]->GetAllocatedColumnsCount())
- return maTabs[nTab]->aCol[nCol].GetCellNote(nRow);
- else
- return nullptr;
-
+ if (ScTable* pTable = FetchTable(nTab))
+ return pTable->GetNote(nCol, nRow);
+ return nullptr;
}
void ScDocument::SetNote(const ScAddress& rPos, std::unique_ptr<ScPostIt> pNote)
@@ -6553,7 +6602,16 @@ void ScDocument::SetNote(const ScAddress& rPos, std::unique_ptr<ScPostIt> pNote)
void ScDocument::SetNote(SCCOL nCol, SCROW nRow, SCTAB nTab, std::unique_ptr<ScPostIt> pNote)
{
- return maTabs[nTab]->CreateColumnIfNotExists(nCol).SetCellNote(nRow, std::move(pNote));
+ if (ScTable* pTable = FetchTable(nTab))
+ {
+ pTable->SetNote(nCol, nRow, std::move(pNote));
+
+ if (ScDocShell* pDocSh = GetDocumentShell())
+ {
+ HelperNotifyChanges::NotifyIfChangesListeners(
+ *pDocSh, ScRange(nCol, nRow, nTab), "note");
+ }
+ }
}
bool ScDocument::HasNote(const ScAddress& rPos) const
@@ -6579,15 +6637,14 @@ bool ScDocument::HasNote(SCCOL nCol, SCROW nRow, SCTAB nTab) const
bool ScDocument::HasNote(SCTAB nTab, SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow) const
{
- const ScTable* pTab = FetchTable(nTab);
- if (!pTab)
- return false;
-
- nStartCol = pTab->ClampToAllocatedColumns(nStartCol);
- nEndCol = pTab->ClampToAllocatedColumns(nEndCol);
- for (SCCOL nCol = nStartCol; nCol < nEndCol; ++nCol)
- if (pTab->aCol[nCol].HasCellNote(nStartRow, nEndRow))
- return true;
+ if (const ScTable* pTable = FetchTable(nTab))
+ {
+ nStartCol = pTable->ClampToAllocatedColumns(nStartCol);
+ nEndCol = pTable->ClampToAllocatedColumns(nEndCol);
+ for (SCCOL nCol = nStartCol; nCol < nEndCol; ++nCol)
+ if (pTable->aCol[nCol].HasCellNote(nStartRow, nEndRow))
+ return true;
+ }
return false;
}
@@ -6596,24 +6653,25 @@ bool ScDocument::HasColNotes(SCCOL nCol, SCTAB nTab) const
if (!ValidCol(nCol))
return false;
- const ScTable* pTab = FetchTable(nTab);
- if (!pTab)
- return false;
+ if (const ScTable* pTable = FetchTable(nTab))
+ {
+ if (nCol >= pTable->GetAllocatedColumnsCount())
+ return false;
+
+ return pTable->aCol[nCol].HasCellNotes();
+ }
- return pTab->aCol[nCol].HasCellNotes();
+ return false;
}
bool ScDocument::HasTabNotes(SCTAB nTab) const
{
- const ScTable* pTab = FetchTable(nTab);
-
- if ( !pTab )
- return false;
-
- for (SCCOL nCol=0, nColSize = pTab->aCol.size(); nCol < nColSize; ++nCol)
- if ( HasColNotes(nCol, nTab) )
- return true;
-
+ if (const ScTable* pTable = FetchTable(nTab))
+ {
+ for (SCCOL nCol=0, nColSize = pTable->aCol.size(); nCol < nColSize; ++nCol)
+ if ( HasColNotes(nCol, nTab) )
+ return true;
+ }
return false;
}
@@ -6629,11 +6687,9 @@ bool ScDocument::HasNotes() const
std::unique_ptr<ScPostIt> ScDocument::ReleaseNote(const ScAddress& rPos)
{
- ScTable* pTab = FetchTable(rPos.Tab());
- if (!pTab)
- return nullptr;
-
- return pTab->ReleaseNote(rPos.Col(), rPos.Row());
+ if (ScTable* pTable = FetchTable(rPos.Tab()))
+ return pTable->ReleaseNote(rPos.Col(), rPos.Row());
+ return nullptr;
}
ScPostIt* ScDocument::GetOrCreateNote(const ScAddress& rPos)
@@ -6643,6 +6699,7 @@ ScPostIt* ScDocument::GetOrCreateNote(const ScAddress& rPos)
else
return CreateNote(rPos);
}
+
ScPostIt* ScDocument::CreateNote(const ScAddress& rPos)
{
ScPostIt* pPostIt = new ScPostIt(*this, rPos);
@@ -6652,19 +6709,17 @@ ScPostIt* ScDocument::CreateNote(const ScAddress& rPos)
size_t ScDocument::GetNoteCount( SCTAB nTab, SCCOL nCol ) const
{
- const ScTable* pTab = FetchTable(nTab);
- if (!pTab)
- return 0;
-
- return pTab->GetNoteCount(nCol);
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetNoteCount(nCol);
+ return 0;
}
void ScDocument::CreateAllNoteCaptions()
{
- for (const auto& a : maTabs)
+ for (const auto& pTable : maTabs)
{
- if (a)
- a->CreateAllNoteCaptions();
+ if (pTable)
+ pTable->CreateAllNoteCaptions();
}
}
@@ -6677,11 +6732,8 @@ void ScDocument::ForgetNoteCaptions( const ScRangeList& rRanges, bool bPreserveD
const ScAddress& e = rRange.aEnd;
for (SCTAB nTab = s.Tab(); nTab <= e.Tab(); ++nTab)
{
- ScTable* pTab = FetchTable(nTab);
- if (!pTab)
- continue;
-
- pTab->ForgetNoteCaptions(s.Col(), s.Row(), e.Col(), e.Row(), bPreserveData);
+ if (ScTable* pTable = FetchTable(nTab))
+ pTable->ForgetNoteCaptions(s.Col(), s.Row(), e.Col(), e.Row(), bPreserveData);
}
}
}
@@ -6723,7 +6775,7 @@ ScAddress ScDocument::GetNotePosition( size_t nIndex ) const
{
for (size_t nTab = 0; nTab < maTabs.size(); ++nTab)
{
- for (SCCOL nCol : GetColumnsRange(nTab, 0, MaxCol()))
+ for (SCCOL nCol : GetAllocatedColumnsRange(nTab, 0, MaxCol()))
{
size_t nColNoteCount = GetNoteCount(nTab, nCol);
if (!nColNoteCount)
@@ -6750,7 +6802,7 @@ ScAddress ScDocument::GetNotePosition( size_t nIndex ) const
ScAddress ScDocument::GetNotePosition( size_t nIndex, SCTAB nTab ) const
{
- for (SCCOL nCol : GetColumnsRange(nTab, 0, MaxCol()))
+ for (SCCOL nCol : GetAllocatedColumnsRange(nTab, 0, MaxCol()))
{
size_t nColNoteCount = GetNoteCount(nTab, nCol);
if (!nColNoteCount)
@@ -6776,31 +6828,24 @@ ScAddress ScDocument::GetNotePosition( size_t nIndex, SCTAB nTab ) const
SCROW ScDocument::GetNotePosition( SCTAB nTab, SCCOL nCol, size_t nIndex ) const
{
- const ScTable* pTab = FetchTable(nTab);
- if (!pTab)
- return -1;
-
- return pTab->GetNotePosition(nCol, nIndex);
+ if (const ScTable* pTable = FetchTable(nTab))
+ return pTable->GetNotePosition(nCol, nIndex);
+ return -1;
}
void ScDocument::GetAllNoteEntries( std::vector<sc::NoteEntry>& rNotes ) const
{
- for (const auto & pTab : maTabs)
+ for (const auto & pTable : maTabs)
{
- if (!pTab)
- continue;
-
- pTab->GetAllNoteEntries(rNotes);
+ if (pTable)
+ pTable->GetAllNoteEntries(rNotes);
}
}
void ScDocument::GetAllNoteEntries( SCTAB nTab, std::vector<sc::NoteEntry>& rNotes ) const
{
- const ScTable* pTab = FetchTable(nTab);
- if (!pTab)
- return;
-
- return pTab->GetAllNoteEntries( rNotes );
+ if (const ScTable* pTable = FetchTable(nTab))
+ pTable->GetAllNoteEntries(rNotes);
}
void ScDocument::GetNotesInRange( const ScRangeList& rRangeList, std::vector<sc::NoteEntry>& rNotes ) const
@@ -6810,6 +6855,8 @@ void ScDocument::GetNotesInRange( const ScRangeList& rRangeList, std::vector<sc:
const ScRange & rRange = rRangeList[i];
for( SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab )
{
+ if (!maTabs[nTab])
+ continue;
maTabs[nTab]->GetNotesInRange( rRange, rNotes );
}
}
@@ -6817,7 +6864,8 @@ void ScDocument::GetNotesInRange( const ScRangeList& rRangeList, std::vector<sc:
void ScDocument::GetUnprotectedCells( ScRangeList& rRangeList, SCTAB nTab ) const
{
- maTabs[nTab]->GetUnprotectedCells( rRangeList );
+ if (const ScTable* pTable = FetchTable(nTab))
+ pTable->GetUnprotectedCells(rRangeList);
}
bool ScDocument::ContainsNotesInRange( const ScRangeList& rRangeList ) const
@@ -6827,6 +6875,8 @@ bool ScDocument::ContainsNotesInRange( const ScRangeList& rRangeList ) const
const ScRange & rRange = rRangeList[i];
for( SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab )
{
+ if (!maTabs[nTab])
+ continue;
bool bContainsNote = maTabs[nTab]->ContainsNotesInRange( rRange );
if(bContainsNote)
return true;
@@ -6875,6 +6925,7 @@ void ScDocument::MergeContextBackIntoNonThreadedContext(ScInterpreterContext& th
std::make_move_iterator(threadedContext.maDelayedSetNumberFormat.begin()),
std::make_move_iterator(threadedContext.maDelayedSetNumberFormat.end()));
// lookup cache is now only in pooled ScInterpreterContext's
+ threadedContext.MergeDefaultFormatKeys(*GetFormatTable());
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx
index 81f2fe11bc83..a2d1ae67b919 100644
--- a/sc/source/core/data/document10.cxx
+++ b/sc/source/core/data/document10.cxx
@@ -22,10 +22,12 @@
#include <refupdatecontext.hxx>
#include <sal/log.hxx>
-#include <editeng/colritem.hxx>
+#include <svx/DocumentColorHelper.hxx>
#include <scitems.hxx>
#include <datamapper.hxx>
#include <docsh.hxx>
+#include <bcaslot.hxx>
+#include <broadcast.hxx>
// Add totally brand-new methods to this source file.
@@ -125,16 +127,20 @@ bool ScDocument::CopyOneCellFromClip(
if ((rCxt.getInsertFlag() & (InsertDeleteFlags::NOTE | InsertDeleteFlags::ADDNOTES)) != InsertDeleteFlags::NONE)
rCxt.setSingleCellNote(nColOffset, pClipDoc->GetNote(aSrcPos));
- ScColumn& rSrcCol = pSrcTab->aCol[aSrcPos.Col()];
+ 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.
- rSrcCol.UpdateScriptTypes(aSrcPos.Row(), aSrcPos.Row());
- rCxt.setSingleCell(aSrcPos, rSrcCol);
+ 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 < static_cast<SCTAB>(maTabs.size()); ++i)
+ for (SCTAB i = rCxt.getTabStart(); i <= nTabEnd && i < GetTableCount(); ++i)
{
maTabs[i]->CopyOneCellFromClip(rCxt, nCol1, nRow1, nCol2, nRow2, aClipRange.aStart.Row(), pSrcTab);
}
@@ -182,17 +188,10 @@ std::set<Color> ScDocument::GetDocColors()
{
std::set<Color> aDocColors;
ScDocumentPool *pPool = GetPool();
- const sal_uInt16 pAttribs[] = {ATTR_BACKGROUND, ATTR_FONT_COLOR};
- for (sal_uInt16 nAttrib : pAttribs)
- {
- for (const SfxPoolItem* pItem : pPool->GetItemSurrogates(nAttrib))
- {
- const SvxColorItem *pColorItem = static_cast<const SvxColorItem*>(pItem);
- Color aColor( pColorItem->GetValue() );
- if (COL_AUTO != aColor)
- aDocColors.insert(aColor);
- }
- }
+
+ svx::DocumentColorHelper::queryColors<SvxBrushItem>(ATTR_BACKGROUND, pPool, aDocColors);
+ svx::DocumentColorHelper::queryColors<SvxColorItem>(ATTR_FONT_COLOR, pPool, aDocColors);
+
return aDocColors;
}
@@ -242,7 +241,7 @@ void ScDocument::SwapNonEmpty( sc::TableValues& rValues )
aEndCxt.purgeEmptyBroadcasters();
}
-void ScDocument::PreprocessAllRangeNamesUpdate( const std::map<OUString, std::unique_ptr<ScRangeName>>& rRangeMap )
+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
@@ -262,9 +261,7 @@ void ScDocument::PreprocessAllRangeNamesUpdate( const std::map<OUString, std::un
if (itNewTab == rRangeMap.end())
continue;
- const ScRangeName* pNewRangeNames = itNewTab->second.get();
- if (!pNewRangeNames)
- continue;
+ const ScRangeName& rNewRangeNames = itNewTab->second;
for (const auto& rEntry : *pOldRangeNames)
{
@@ -272,7 +269,7 @@ void ScDocument::PreprocessAllRangeNamesUpdate( const std::map<OUString, std::un
if (!pOldData)
continue;
- const ScRangeData* pNewData = pNewRangeNames->findByIndex( pOldData->GetIndex());
+ const ScRangeData* pNewData = rNewRangeNames.findByIndex( pOldData->GetIndex());
if (pNewData)
pOldData->SetNewName( pNewData->GetName());
}
@@ -328,6 +325,10 @@ void ScDocument::SharePooledResources( const ScDocument* pSrcDoc )
ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
mxPoolHelper = pSrcDoc->mxPoolHelper;
mpCellStringPool = pSrcDoc->mpCellStringPool;
+
+ // force lazy creation/existence in source document *before* sharing
+ pSrcDoc->getCellAttributeHelper();
+ mpCellAttributeHelper = pSrcDoc->mpCellAttributeHelper;
}
void ScDocument::UpdateScriptTypes( const ScAddress& rPos, SCCOL nColSize, SCROW nRowSize )
@@ -390,7 +391,7 @@ void ScDocument::DelayFormulaGrouping( bool delay )
void ScDocument::AddDelayedFormulaGroupingCell( const ScFormulaCell* cell )
{
- if( !pDelayedFormulaGrouping->In( cell->aPos ))
+ if( !pDelayedFormulaGrouping->Contains( cell->aPos ))
pDelayedFormulaGrouping->ExtendTo( cell->aPos );
}
@@ -442,6 +443,19 @@ bool ScDocument::CanDelayStartListeningFormulaCells( ScColumn* column, SCROW row
return true;
}
+void ScDocument::EnableDelayDeletingBroadcasters( bool set )
+{
+ if( bDelayedDeletingBroadcasters == set )
+ return;
+ bDelayedDeletingBroadcasters = set;
+ if( !bDelayedDeletingBroadcasters )
+ {
+ for (auto& rxTab : maTabs)
+ if (rxTab)
+ rxTab->DeleteEmptyBroadcasters();
+ }
+}
+
bool ScDocument::HasFormulaCell( const ScRange& rRange ) const
{
if (!rRange.IsValid())
@@ -935,7 +949,7 @@ bool ScDocument::CopyAdjustRangeName( SCTAB& rSheet, sal_uInt16& rIndex, ScRange
if (rpRangeData && !rNewDoc.IsClipOrUndo())
{
- ScDocShell* pDocSh = static_cast<ScDocShell*>(rNewDoc.GetDocumentShell());
+ ScDocShell* pDocSh = rNewDoc.GetDocumentShell();
if (pDocSh)
pDocSh->SetAreasChangedNeedBroadcast();
}
@@ -963,18 +977,18 @@ bool ScDocument::IsEditActionAllowed(
[this, &eAction, &nStart, &nEnd](const SCTAB& rTab) { return IsEditActionAllowed(eAction, rTab, nStart, nEnd); });
}
-std::unique_ptr<sc::ColumnIterator> ScDocument::GetColumnIterator( SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const
+std::optional<sc::ColumnIterator> ScDocument::GetColumnIterator( SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const
{
const ScTable* pTab = FetchTable(nTab);
if (!pTab)
- return std::unique_ptr<sc::ColumnIterator>();
+ return {};
return pTab->GetColumnIterator(nCol, nRow1, nRow2);
}
void ScDocument::CreateColumnIfNotExists( SCTAB nTab, SCCOL nCol )
{
- const ScTable* pTab = FetchTable(nTab);
+ ScTable* pTab = FetchTable(nTab);
if (!pTab)
return;
@@ -1028,7 +1042,7 @@ OString ScDocument::dumpSheetGeomData(SCTAB nTab, bool bColumns, SheetGeomType e
{
ScTable* pTab = FetchTable(nTab);
if (!pTab)
- return "";
+ return ""_ostr;
return pTab->dumpSheetGeomData(bColumns, eGeomType);
}
@@ -1068,4 +1082,35 @@ bool ScDocument::SetLOKFreezeRow(SCROW nFreezeRow, SCTAB nTab)
return pTab->SetLOKFreezeRow(nFreezeRow);
}
+std::set<SCCOL> ScDocument::QueryColumnsWithFormulaCells( SCTAB nTab ) const
+{
+ const ScTable* pTab = FetchTable(nTab);
+ if (!pTab)
+ return std::set<SCCOL>{};
+
+ return pTab->QueryColumnsWithFormulaCells();
+}
+
+void ScDocument::CheckIntegrity( SCTAB nTab ) const
+{
+ const ScTable* pTab = FetchTable(nTab);
+ if (!pTab)
+ return;
+
+ pTab->CheckIntegrity();
+}
+
+sc::BroadcasterState ScDocument::GetBroadcasterState() const
+{
+ sc::BroadcasterState aState;
+
+ for (const auto& xTab : maTabs)
+ xTab->CollectBroadcasterState(aState);
+
+ if (pBASM)
+ pBASM->CollectBroadcasterState(aState);
+
+ return aState;
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/documentimport.cxx b/sc/source/core/data/documentimport.cxx
index 2dbc61c03938..b2e823c4a511 100644
--- a/sc/source/core/data/documentimport.cxx
+++ b/sc/source/core/data/documentimport.cxx
@@ -28,7 +28,7 @@
#include <o3tl/safeint.hxx>
#include <svl/sharedstringpool.hxx>
#include <svl/languageoptions.hxx>
-#include <unotools/configmgr.hxx>
+#include <comphelper/configuration.hxx>
#include <unordered_map>
namespace {
@@ -53,13 +53,16 @@ struct ScDocumentImportImpl
sc::StartListeningContext maListenCxt;
std::vector<sc::TableColumnBlockPositionSet> maBlockPosSet;
SvtScriptType mnDefaultScriptNumeric;
+ bool mbFuzzing;
std::vector<TabAttr> maTabAttrs;
std::unordered_map<sal_uInt32, bool> maIsLatinScriptMap;
explicit ScDocumentImportImpl(ScDocument& rDoc) :
mrDoc(rDoc),
maListenCxt(rDoc),
- mnDefaultScriptNumeric(SvtScriptType::UNKNOWN) {}
+ mnDefaultScriptNumeric(SvtScriptType::UNKNOWN),
+ mbFuzzing(comphelper::IsFuzzing())
+ {}
bool isValid( size_t nTab, size_t nCol )
{
@@ -96,6 +99,15 @@ struct ScDocumentImportImpl
return rTab.getBlockPosition(nCol);
}
+ void invalidateBlockPositionSet(SCTAB nTab)
+ {
+ if (o3tl::make_unsigned(nTab) >= maBlockPosSet.size())
+ return;
+
+ sc::TableColumnBlockPositionSet& rTab = maBlockPosSet[nTab];
+ rTab.invalidate();
+ }
+
void initForSheets()
{
size_t n = mrDoc.GetTableCount();
@@ -183,6 +195,11 @@ void ScDocumentImport::setOriginDate(sal_uInt16 nYear, sal_uInt16 nMonth, sal_uI
mpImpl->mrDoc.pDocOptions->SetDate(nDay, nMonth, nYear);
}
+void ScDocumentImport::invalidateBlockPositionSet(SCTAB nTab)
+{
+ mpImpl->invalidateBlockPositionSet(nTab);
+}
+
void ScDocumentImport::setAutoInput(const ScAddress& rPos, const OUString& rStr, const ScSetStringParam* pStringParam)
{
ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
@@ -203,26 +220,24 @@ void ScDocumentImport::setAutoInput(const ScAddress& rPos, const OUString& rStr,
aCell, rPos.Row(), rPos.Tab(), rStr, mpImpl->mrDoc.GetAddressConvention(), pStringParam);
sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
- switch (aCell.meType)
+ switch (aCell.getType())
{
case CELLTYPE_STRING:
// string is copied.
- pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), *aCell.mpString);
+ pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), *aCell.getSharedString());
break;
case CELLTYPE_EDIT:
// Cell takes the ownership of the text object.
- pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), aCell.mpEditText);
- aCell.mpEditText = nullptr;
+ pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), aCell.releaseEditText());
break;
case CELLTYPE_VALUE:
- pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), aCell.mfValue);
+ pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), aCell.getDouble());
break;
case CELLTYPE_FORMULA:
if (!pStringParam)
- mpImpl->mrDoc.CheckLinkFormulaNeedingCheck( *aCell.mpFormula->GetCode());
+ mpImpl->mrDoc.CheckLinkFormulaNeedingCheck( *aCell.getFormula()->GetCode());
// This formula cell instance is directly placed in the document without copying.
- pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), aCell.mpFormula);
- aCell.mpFormula = nullptr;
+ pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), aCell.releaseFormula());
break;
default:
pBlockPos->miCellPos = rCells.set_empty(pBlockPos->miCellPos, rPos.Row(), rPos.Row());
@@ -370,6 +385,14 @@ void ScDocumentImport::setFormulaCell(const ScAddress& rPos, ScFormulaCell* pCel
mpImpl->mrDoc.CheckLinkFormulaNeedingCheck( *pCell->GetCode());
sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
+
+ sc::CellStoreType::position_type aPos = rCells.position(rPos.Row());
+ if (aPos.first != rCells.end() && aPos.first->type == sc::element_type_formula)
+ {
+ ScFormulaCell* p = sc::formula_block::at(*aPos.first->data, aPos.second);
+ sc::SharedFormulaUtil::unshareFormulaCell(aPos, *p);
+ }
+
pBlockPos->miCellPos =
rCells.set(pBlockPos->miCellPos, rPos.Row(), pCell);
}
@@ -388,7 +411,7 @@ void ScDocumentImport::setMatrixCells(
if (!pBlockPos)
return;
- if (utl::ConfigManager::IsFuzzing()) //just too slow
+ if (comphelper::IsFuzzing()) //just too slow
return;
sc::CellStoreType& rCells = pTab->aCol[rBasePos.Col()].maCells;
@@ -424,8 +447,8 @@ void ScDocumentImport::setMatrixCells(
// Reference in each cell must point to the origin cell relative to the current cell.
aRefData.SetAddress(mpImpl->mrDoc.GetSheetLimits(), rBasePos, aPos);
*t->GetSingleRef() = aRefData;
- std::unique_ptr<ScTokenArray> pTokArr(aArr.Clone());
- pCell = new ScFormulaCell(mpImpl->mrDoc, aPos, *pTokArr, eGram, ScMatrixMode::Reference);
+ ScTokenArray aTokArr(aArr.CloneValue());
+ pCell = new ScFormulaCell(mpImpl->mrDoc, aPos, aTokArr, eGram, ScMatrixMode::Reference);
pBlockPos->miCellPos =
rCells.set(pBlockPos->miCellPos, aPos.Row(), pCell);
}
@@ -444,8 +467,8 @@ void ScDocumentImport::setMatrixCells(
aPos.SetRow(nRow);
aRefData.SetAddress(mpImpl->mrDoc.GetSheetLimits(), rBasePos, aPos);
*t->GetSingleRef() = aRefData;
- std::unique_ptr<ScTokenArray> pTokArr(aArr.Clone());
- pCell = new ScFormulaCell(mpImpl->mrDoc, aPos, *pTokArr, eGram, ScMatrixMode::Reference);
+ ScTokenArray aTokArr(aArr.CloneValue());
+ pCell = new ScFormulaCell(mpImpl->mrDoc, aPos, aTokArr, eGram, ScMatrixMode::Reference);
pBlockPos->miCellPos =
rColCells.set(pBlockPos->miCellPos, aPos.Row(), pCell);
}
@@ -466,19 +489,18 @@ void ScDocumentImport::setTableOpCells(const ScRange& rRange, const ScTabOpParam
ScDocument& rDoc = mpImpl->mrDoc;
ScRefAddress aRef;
- OUStringBuffer aFormulaBuf;
- aFormulaBuf.append('=');
- aFormulaBuf.append(ScCompiler::GetNativeSymbol(ocTableOp));
- aFormulaBuf.append(ScCompiler::GetNativeSymbol(ocOpen));
+ OUStringBuffer aFormulaBuf("="
+ + ScCompiler::GetNativeSymbol(ocTableOp)
+ + ScCompiler::GetNativeSymbol(ocOpen));
OUString aSep = ScCompiler::GetNativeSymbol(ocSep);
if (rParam.meMode == ScTabOpParam::Column) // column only
{
aRef.Set(rParam.aRefFormulaCell.GetAddress(), true, false, false);
- aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
- aFormulaBuf.append(aSep);
- aFormulaBuf.append(rParam.aRefColCell.GetRefString(rDoc, nTab));
- aFormulaBuf.append(aSep);
+ aFormulaBuf.append(aRef.GetRefString(rDoc, nTab)
+ + aSep
+ + rParam.aRefColCell.GetRefString(rDoc, nTab)
+ + aSep);
aRef.Set(nCol1, nRow1, nTab, false, true, true);
aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
nCol1++;
@@ -488,10 +510,10 @@ void ScDocumentImport::setTableOpCells(const ScRange& rRange, const ScTabOpParam
else if (rParam.meMode == ScTabOpParam::Row) // row only
{
aRef.Set(rParam.aRefFormulaCell.GetAddress(), false, true, false);
- aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
- aFormulaBuf.append(aSep);
- aFormulaBuf.append(rParam.aRefRowCell.GetRefString(rDoc, nTab));
- aFormulaBuf.append(aSep);
+ aFormulaBuf.append(aRef.GetRefString(rDoc, nTab)
+ + aSep
+ + rParam.aRefRowCell.GetRefString(rDoc, nTab)
+ + aSep);
aRef.Set(nCol1, nRow1, nTab, true, false, true);
aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
++nRow1;
@@ -500,15 +522,15 @@ void ScDocumentImport::setTableOpCells(const ScRange& rRange, const ScTabOpParam
}
else // both
{
- aFormulaBuf.append(rParam.aRefFormulaCell.GetRefString(rDoc, nTab));
- aFormulaBuf.append(aSep);
- aFormulaBuf.append(rParam.aRefColCell.GetRefString(rDoc, nTab));
- aFormulaBuf.append(aSep);
+ aFormulaBuf.append(rParam.aRefFormulaCell.GetRefString(rDoc, nTab)
+ + aSep
+ + rParam.aRefColCell.GetRefString(rDoc, nTab)
+ + aSep);
aRef.Set(nCol1, nRow1 + 1, nTab, false, true, true);
- aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
- aFormulaBuf.append(aSep);
- aFormulaBuf.append(rParam.aRefRowCell.GetRefString(rDoc, nTab));
- aFormulaBuf.append(aSep);
+ aFormulaBuf.append(aRef.GetRefString(rDoc, nTab)
+ + aSep
+ + rParam.aRefRowCell.GetRefString(rDoc, nTab)
+ + aSep);
aRef.Set(nCol1 + 1, nRow1, nTab, true, false, true);
aFormulaBuf.append(aRef.GetRefString(rDoc, nTab));
++nCol1;
@@ -555,18 +577,18 @@ void ScDocumentImport::fillDownCells(const ScAddress& rPos, SCROW nFillSize)
sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
ScRefCellValue aRefCell = pTab->aCol[rPos.Col()].GetCellValue(*pBlockPos, rPos.Row());
- switch (aRefCell.meType)
+ switch (aRefCell.getType())
{
case CELLTYPE_VALUE:
{
- std::vector<double> aCopied(nFillSize, aRefCell.mfValue);
+ std::vector<double> aCopied(nFillSize, aRefCell.getDouble());
pBlockPos->miCellPos = rCells.set(
pBlockPos->miCellPos, rPos.Row()+1, aCopied.begin(), aCopied.end());
break;
}
case CELLTYPE_STRING:
{
- std::vector<svl::SharedString> aCopied(nFillSize, *aRefCell.mpString);
+ std::vector<svl::SharedString> aCopied(nFillSize, *aRefCell.getSharedString());
pBlockPos->miCellPos = rCells.set(
pBlockPos->miCellPos, rPos.Row()+1, aCopied.begin(), aCopied.end());
break;
@@ -576,21 +598,20 @@ void ScDocumentImport::fillDownCells(const ScAddress& rPos, SCROW nFillSize)
}
}
-void ScDocumentImport::setAttrEntries( SCTAB nTab, SCCOL nCol, Attrs&& rAttrs )
+void ScDocumentImport::setAttrEntries( SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, Attrs&& rAttrs )
{
ScTable* pTab = mpImpl->mrDoc.FetchTable(nTab);
if (!pTab)
return;
- ScColumn* pCol = pTab->FetchColumn(nCol);
- if (!pCol)
- return;
-
- ColAttr* pColAttr = mpImpl->getColAttr(nTab, nCol);
- if (pColAttr)
- pColAttr->mbLatinNumFmtOnly = rAttrs.mbLatinNumFmtOnly;
+ for(SCCOL nCol = nColStart; nCol <= nColEnd; ++nCol )
+ {
+ ColAttr* pColAttr = mpImpl->getColAttr(nTab, nCol);
+ if (pColAttr)
+ pColAttr->mbLatinNumFmtOnly = rAttrs.mbLatinNumFmtOnly;
+ }
- pCol->pAttrArray->SetAttrEntries(std::move(rAttrs.mvData));
+ pTab->SetAttrEntries( nColStart, nColEnd, std::move( rAttrs.mvData ));
}
void ScDocumentImport::setRowsVisible(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, bool bVisible)
@@ -708,6 +729,9 @@ public:
if (node.type != sc::element_type_formula)
return;
+ if (mrDocImpl.mbFuzzing) // skip listening when fuzzing
+ return;
+
// Have all formula cells start listening to the document.
ScFormulaCell** pp = &sc::formula_block::at(*node.data, 0);
ScFormulaCell** ppEnd = pp + node.size;
diff --git a/sc/source/core/data/dpcache.cxx b/sc/source/core/data/dpcache.cxx
index f1c32e376091..efc331ed8bdd 100644
--- a/sc/source/core/data/dpcache.cxx
+++ b/sc/source/core/data/dpcache.cxx
@@ -38,6 +38,7 @@
#include <unotools/textsearch.hxx>
#include <unotools/localedatawrapper.hxx>
#include <unotools/collatorwrapper.hxx>
+#include <svl/numformat.hxx>
#include <svl/zforlist.hxx>
#include <o3tl/safeint.hxx>
#include <osl/diagnose.h>
@@ -71,7 +72,7 @@ ScDPCache::Field::Field() : mnNumFormat(0) {}
ScDPCache::ScDPCache(ScDocument& rDoc) :
mrDoc( rDoc ),
mnColumnCount ( 0 ),
- maEmptyRows(0, rDoc.GetSheetLimits().GetMaxRowCount(), true),
+ maEmptyRows(0, rDoc.GetMaxRowCount(), true),
mnDataSize(-1),
mnRowCount(0),
mbDisposing(false)
@@ -333,7 +334,7 @@ typedef std::unordered_set<OUString> LabelSet;
void normalizeAddLabel(const OUString& rLabel, std::vector<OUString>& rLabels, LabelSet& rExistingNames)
{
- const OUString aLabelLower = ScGlobal::getCharClassPtr()->lowercase(rLabel);
+ const OUString aLabelLower = ScGlobal::getCharClass().lowercase(rLabel);
sal_Int32 nSuffix = 1;
OUString aNewLabel = rLabel;
OUString aNewLabelLower = aLabelLower;
@@ -355,9 +356,11 @@ void normalizeAddLabel(const OUString& rLabel, std::vector<OUString>& rLabels, L
std::vector<OUString> normalizeLabels(const std::vector<InitColumnData>& rColData)
{
- std::vector<OUString> aLabels(1u, ScResId(STR_PIVOT_DATA));
+ std::vector<OUString> aLabels;
+ aLabels.reserve(rColData.size() + 1);
LabelSet aExistingNames;
+ normalizeAddLabel(ScResId(STR_PIVOT_DATA), aLabels, aExistingNames);
for (const InitColumnData& rCol : rColData)
normalizeAddLabel(rCol.maLabel, aLabels, aExistingNames);
@@ -367,10 +370,11 @@ std::vector<OUString> normalizeLabels(const std::vector<InitColumnData>& rColDat
std::vector<OUString> normalizeLabels(const ScDPCache::DBConnector& rDB, const sal_Int32 nLabelCount)
{
- std::vector<OUString> aLabels(1u, ScResId(STR_PIVOT_DATA));
+ std::vector<OUString> aLabels;
aLabels.reserve(nLabelCount + 1);
LabelSet aExistingNames;
+ normalizeAddLabel(ScResId(STR_PIVOT_DATA), aLabels, aExistingNames);
for (sal_Int32 nCol = 0; nCol < nLabelCount; ++nCol)
{
@@ -391,7 +395,7 @@ void initColumnFromDoc( InitDocData& rDocData, InitColumnData &rColData )
SCROW nEndRow = rDocData.mnEndRow;
bool bTailEmptyRows = rDocData.mbTailEmptyRows;
- std::unique_ptr<sc::ColumnIterator> pIter =
+ std::optional<sc::ColumnIterator> pIter =
rDoc.GetColumnIterator(nDocTab, nCol, nStartRow, nEndRow);
assert(pIter);
assert(pIter->hasCell());
@@ -654,8 +658,8 @@ bool ScDPCache::InitFromDataBase(DBConnector& rDB)
if (!aData.IsEmpty())
{
maEmptyRows.insert_back(nRow, nRow+1, false);
- SvNumberFormatter* pFormatter = mrDoc.GetFormatTable();
- rField.mnNumFormat = pFormatter ? pFormatter->GetStandardFormat(nFormatType) : 0;
+ ScInterpreterContext& rContext = mrDoc.GetNonThreadedContext();
+ rField.mnNumFormat = rContext.NFGetStandardFormat(nFormatType);
}
++nRow;
@@ -693,10 +697,8 @@ bool ScDPCache::ValidQuery( SCROW nRow, const ScQueryParam &rParam) const
std::vector<bool> aPassed(nEntryCount, false);
tools::Long nPos = -1;
- CollatorWrapper* pCollator = (rParam.bCaseSens ? ScGlobal::GetCaseCollator() :
- ScGlobal::GetCollator() );
- ::utl::TransliterationWrapper* pTransliteration = (rParam.bCaseSens ?
- ScGlobal::GetCaseTransliteration() : ScGlobal::GetpTransliteration());
+ CollatorWrapper& rCollator = ScGlobal::GetCollator(rParam.bCaseSens);
+ ::utl::TransliterationWrapper& rTransliteration = ScGlobal::GetTransliteration(rParam.bCaseSens);
for (size_t i = 0; i < nEntryCount && rParam.GetEntry(i).bDoQuery; ++i)
{
@@ -785,7 +787,7 @@ bool ScDPCache::ValidQuery( SCROW nRow, const ScQueryParam &rParam) const
{
// TODO: Use shared string for fast equality check.
OUString aStr = rEntry.GetQueryItem().maString.getString();
- bOk = pTransliteration->isEqual(aCellStr, aStr);
+ bOk = rTransliteration.isEqual(aCellStr, aStr);
bool bHasStar = false;
sal_Int32 nIndex;
if (( nIndex = aStr.indexOf('*') ) != -1)
@@ -810,10 +812,10 @@ bool ScDPCache::ValidQuery( SCROW nRow, const ScQueryParam &rParam) const
{
OUString aQueryStr = rEntry.GetQueryItem().maString.getString();
css::uno::Sequence< sal_Int32 > xOff;
- const LanguageType nLang = ScGlobal::xSysLocale->GetLanguageTag().getLanguageType();
- OUString aCell = pTransliteration->transliterate(
+ const LanguageType nLang = ScGlobal::oSysLocale->GetLanguageTag().getLanguageType();
+ OUString aCell = rTransliteration.transliterate(
aCellStr, nLang, 0, aCellStr.getLength(), &xOff);
- OUString aQuer = pTransliteration->transliterate(
+ OUString aQuer = rTransliteration.transliterate(
aQueryStr, nLang, 0, aQueryStr.getLength(), &xOff);
bOk = (aCell.indexOf( aQuer ) != -1);
}
@@ -822,7 +824,7 @@ bool ScDPCache::ValidQuery( SCROW nRow, const ScQueryParam &rParam) const
}
else
{ // use collator here because data was probably sorted
- sal_Int32 nCompare = pCollator->compareString(
+ sal_Int32 nCompare = rCollator.compareString(
aCellStr, rEntry.GetQueryItem().maString.getString());
switch (rEntry.eOp)
{
@@ -1066,11 +1068,8 @@ bool ScDPCache::IsDateDimension( tools::Long nDim ) const
if (nDim >= mnColumnCount)
return false;
- SvNumberFormatter* pFormatter = mrDoc.GetFormatTable();
- if (!pFormatter)
- return false;
-
- SvNumFormatType eType = pFormatter->GetType(maFields[nDim]->mnNumFormat);
+ ScInterpreterContext& rContext = mrDoc.GetNonThreadedContext();
+ SvNumFormatType eType = rContext.NFGetType(maFields[nDim]->mnNumFormat);
return (eType == SvNumFormatType::DATE) || (eType == SvNumFormatType::DATETIME);
}
@@ -1161,22 +1160,22 @@ SCROW ScDPCache::GetIdByItemData(tools::Long nDim, const ScDPItemData& rItem) co
}
// static
-sal_uInt32 ScDPCache::GetLocaleIndependentFormat( SvNumberFormatter& rFormatter, sal_uInt32 nNumFormat )
+sal_uInt32 ScDPCache::GetLocaleIndependentFormat(ScInterpreterContext& rContext, sal_uInt32 nNumFormat)
{
// For a date or date+time format use ISO format so it works across locales
// and can be matched against string based item queries. For time use 24h
// format. All others use General format, no currency, percent, ...
// Use en-US locale for all.
- switch (rFormatter.GetType( nNumFormat))
+ switch (rContext.NFGetType(nNumFormat))
{
case SvNumFormatType::DATE:
- return rFormatter.GetFormatIndex( NF_DATE_ISO_YYYYMMDD, LANGUAGE_ENGLISH_US);
+ return rContext.NFGetFormatIndex( NF_DATE_ISO_YYYYMMDD, LANGUAGE_ENGLISH_US);
case SvNumFormatType::TIME:
- return rFormatter.GetFormatIndex( NF_TIME_HHMMSS, LANGUAGE_ENGLISH_US);
+ return rContext.NFGetFormatIndex( NF_TIME_HHMMSS, LANGUAGE_ENGLISH_US);
case SvNumFormatType::DATETIME:
- return rFormatter.GetFormatIndex( NF_DATETIME_ISO_YYYYMMDD_HHMMSS, LANGUAGE_ENGLISH_US);
+ return rContext.NFGetFormatIndex( NF_DATETIME_ISO_YYYYMMDD_HHMMSS, LANGUAGE_ENGLISH_US);
default:
- return rFormatter.GetFormatIndex( NF_NUMBER_STANDARD, LANGUAGE_ENGLISH_US);
+ return rContext.NFGetFormatIndex( NF_NUMBER_STANDARD, LANGUAGE_ENGLISH_US);
}
}
@@ -1188,15 +1187,15 @@ OUString ScDPCache::GetLocaleIndependentFormattedNumberString( double fValue )
// static
OUString ScDPCache::GetLocaleIndependentFormattedString( double fValue,
- SvNumberFormatter& rFormatter, sal_uInt32 nNumFormat )
+ ScInterpreterContext& rContext, sal_uInt32 nNumFormat )
{
- nNumFormat = GetLocaleIndependentFormat( rFormatter, nNumFormat);
+ nNumFormat = GetLocaleIndependentFormat( rContext, nNumFormat);
if ((nNumFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
return GetLocaleIndependentFormattedNumberString( fValue);
OUString aStr;
const Color* pColor = nullptr;
- rFormatter.GetOutputString( fValue, nNumFormat, aStr, &pColor);
+ rContext.NFGetOutputString( fValue, nNumFormat, aStr, &pColor);
return aStr;
}
@@ -1209,21 +1208,15 @@ OUString ScDPCache::GetFormattedString(tools::Long nDim, const ScDPItemData& rIt
if (eType == ScDPItemData::Value)
{
// Format value using the stored number format.
- SvNumberFormatter* pFormatter = mrDoc.GetFormatTable();
- if (pFormatter)
- {
- sal_uInt32 nNumFormat = GetNumberFormat(nDim);
- if (bLocaleIndependent)
- return GetLocaleIndependentFormattedString( rItem.GetValue(), *pFormatter, nNumFormat);
-
- OUString aStr;
- const Color* pColor = nullptr;
- pFormatter->GetOutputString(rItem.GetValue(), nNumFormat, aStr, &pColor);
- return aStr;
- }
-
- // Last resort...
- return GetLocaleIndependentFormattedNumberString( rItem.GetValue());
+ ScInterpreterContext& rContext = mrDoc.GetNonThreadedContext();
+ sal_uInt32 nNumFormat = GetNumberFormat(nDim);
+ if (bLocaleIndependent)
+ return GetLocaleIndependentFormattedString( rItem.GetValue(), rContext, nNumFormat);
+
+ OUString aStr;
+ const Color* pColor = nullptr;
+ rContext.NFGetOutputString(rItem.GetValue(), nNumFormat, aStr, &pColor);
+ return aStr;
}
if (eType == ScDPItemData::GroupValue)
@@ -1247,16 +1240,16 @@ OUString ScDPCache::GetFormattedString(tools::Long nDim, const ScDPItemData& rIt
if (!p)
return rItem.GetString();
- sal_Unicode cDecSep = ScGlobal::getLocaleDataPtr()->getNumDecimalSep()[0];
+ sal_Unicode cDecSep = ScGlobal::getLocaleData().getNumDecimalSep()[0];
return ScDPUtil::getNumGroupName(fVal, p->maInfo, cDecSep, mrDoc.GetFormatTable());
}
return rItem.GetString();
}
-SvNumberFormatter* ScDPCache::GetNumberFormatter() const
+ScInterpreterContext& ScDPCache::GetInterpreterContext() const
{
- return mrDoc.GetFormatTable();
+ return mrDoc.GetNonThreadedContext();
}
tools::Long ScDPCache::AppendGroupField()
diff --git a/sc/source/core/data/dpdimsave.cxx b/sc/source/core/data/dpdimsave.cxx
index fa9b2ded7d78..63811dc1f713 100644
--- a/sc/source/core/data/dpdimsave.cxx
+++ b/sc/source/core/data/dpdimsave.cxx
@@ -26,18 +26,19 @@
#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
-#include <svl/zforlist.hxx>
+#include <svl/numformat.hxx>
#include <osl/diagnose.h>
#include <rtl/math.hxx>
#include <algorithm>
#include <globstr.hrc>
#include <scresid.hxx>
+#include <utility>
using namespace com::sun::star;
-ScDPSaveGroupItem::ScDPSaveGroupItem( const OUString& rName ) :
- aGroupName(rName) {}
+ScDPSaveGroupItem::ScDPSaveGroupItem( OUString aName ) :
+ aGroupName(std::move(aName)) {}
ScDPSaveGroupItem::~ScDPSaveGroupItem() {}
@@ -49,9 +50,7 @@ void ScDPSaveGroupItem::AddElement( const OUString& rName )
void ScDPSaveGroupItem::AddElementsFromGroup( const ScDPSaveGroupItem& rGroup )
{
// add all elements of the other group (used for nested grouping)
-
- for ( const auto& rElement : rGroup.aElements )
- aElements.push_back( rElement );
+ aElements.insert( aElements.end(), rGroup.aElements.begin(), rGroup.aElements.end() );
}
bool ScDPSaveGroupItem::RemoveElement( const OUString& rName )
@@ -125,16 +124,16 @@ void ScDPSaveGroupItem::AddToData(ScDPGroupDimension& rDataDim) const
rDataDim.AddItem(aGroup);
}
-ScDPSaveGroupDimension::ScDPSaveGroupDimension( const OUString& rSource, const OUString& rName ) :
- aSourceDim( rSource ),
- aGroupDimName( rName ),
+ScDPSaveGroupDimension::ScDPSaveGroupDimension( OUString aSource, OUString aName ) :
+ aSourceDim(std::move( aSource )),
+ aGroupDimName(std::move( aName )),
nDatePart( 0 )
{
}
-ScDPSaveGroupDimension::ScDPSaveGroupDimension( const OUString& rSource, const OUString& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
- aSourceDim( rSource ),
- aGroupDimName( rName ),
+ScDPSaveGroupDimension::ScDPSaveGroupDimension( OUString aSource, OUString aName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
+ aSourceDim(std::move( aSource )),
+ aGroupDimName(std::move( aName )),
aDateInfo( rDateInfo ),
nDatePart( nPart )
{
@@ -392,15 +391,15 @@ void ScDPSaveGroupDimension::AddToCache(ScDPCache& rCache) const
}
}
-ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const OUString& rName, const ScDPNumGroupInfo& rInfo ) :
- aDimensionName( rName ),
+ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( OUString aName, const ScDPNumGroupInfo& rInfo ) :
+ aDimensionName(std::move( aName )),
aGroupInfo( rInfo ),
nDatePart( 0 )
{
}
-ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const OUString& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
- aDimensionName( rName ),
+ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( OUString aName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
+ aDimensionName(std::move( aName )),
aDateInfo( rDateInfo ),
nDatePart( nPart )
{
@@ -539,14 +538,14 @@ namespace {
struct ScDPSaveGroupDimNameFunc
{
OUString maDimName;
- explicit ScDPSaveGroupDimNameFunc( const OUString& rDimName ) : maDimName( rDimName ) {}
+ explicit ScDPSaveGroupDimNameFunc( OUString aDimName ) : maDimName(std::move( aDimName )) {}
bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetGroupDimName() == maDimName; }
};
struct ScDPSaveGroupSourceNameFunc
{
OUString maSrcDimName;
- explicit ScDPSaveGroupSourceNameFunc( const OUString& rSrcDimName ) : maSrcDimName( rSrcDimName ) {}
+ explicit ScDPSaveGroupSourceNameFunc( OUString aSrcDimName ) : maSrcDimName(std::move( aSrcDimName )) {}
bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetSourceDimName() == maSrcDimName; }
};
@@ -758,7 +757,7 @@ OUString ScDPDimensionSaveData::CreateGroupDimName(
namespace
{
- const char* aDatePartIds[] =
+ const TranslateId aDatePartIds[] =
{
STR_DPFIELD_GROUP_BY_SECONDS,
STR_DPFIELD_GROUP_BY_MINUTES,
diff --git a/sc/source/core/data/dpfilteredcache.cxx b/sc/source/core/data/dpfilteredcache.cxx
index 16e11c183b83..b47fc43aeb8c 100644
--- a/sc/source/core/data/dpfilteredcache.cxx
+++ b/sc/source/core/data/dpfilteredcache.cxx
@@ -41,9 +41,7 @@ bool ScDPFilteredCache::SingleFilter::match(const ScDPItemData& rCellData) const
std::vector<ScDPItemData> ScDPFilteredCache::SingleFilter::getMatchValues() const
{
- std::vector<ScDPItemData> aValues;
- aValues.push_back(maItem);
- return aValues;
+ return { maItem };
}
ScDPFilteredCache::GroupFilter::GroupFilter()
@@ -305,12 +303,13 @@ void ScDPFilteredCache::filterTable(const vector<Criterion>& rCriteria, Sequence
// Header first.
Sequence<Any> headerRow(nColSize);
+ auto pRow = headerRow.getArray();
for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
{
OUString str = getFieldName( nCol);
Any any;
any <<= str;
- headerRow[nCol] = any;
+ pRow[nCol] = any;
}
tableData.push_back(headerRow);
@@ -330,6 +329,7 @@ void ScDPFilteredCache::filterTable(const vector<Criterion>& rCriteria, Sequence
// Insert this row into table.
Sequence<Any> row(nColSize);
+ pRow = row.getArray();
for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
{
Any any;
@@ -342,7 +342,7 @@ void ScDPFilteredCache::filterTable(const vector<Criterion>& rCriteria, Sequence
OUString string (pData->GetString() );
any <<= string;
}
- row[nCol] = any;
+ pRow[nCol] = any;
}
tableData.push_back(row);
}
@@ -350,8 +350,9 @@ void ScDPFilteredCache::filterTable(const vector<Criterion>& rCriteria, Sequence
// convert vector to Sequence
sal_Int32 nTabSize = static_cast<sal_Int32>(tableData.size());
rTabData.realloc(nTabSize);
+ auto pTabData = rTabData.getArray();
for (sal_Int32 i = 0; i < nTabSize; ++i)
- rTabData[i] = tableData[i];
+ pTabData[i] = tableData[i];
}
void ScDPFilteredCache::clear()
diff --git a/sc/source/core/data/dpgroup.cxx b/sc/source/core/data/dpgroup.cxx
index b2b5b4681306..336388a36daf 100644
--- a/sc/source/core/data/dpgroup.cxx
+++ b/sc/source/core/data/dpgroup.cxx
@@ -26,11 +26,13 @@
#include <osl/diagnose.h>
#include <rtl/math.hxx>
+#include <svl/numformat.hxx>
#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
#include <unordered_map>
#include <unordered_set>
+#include <utility>
#include <vector>
#include <algorithm>
@@ -48,7 +50,7 @@ namespace {
class ScDPGroupNumFilter : public ScDPFilteredCache::FilterBase
{
public:
- ScDPGroupNumFilter(const std::vector<ScDPItemData>& rValues, const ScDPNumGroupInfo& rInfo);
+ ScDPGroupNumFilter(std::vector<ScDPItemData>&& rValues, const ScDPNumGroupInfo& rInfo);
virtual bool match(const ScDPItemData &rCellData) const override;
virtual std::vector<ScDPItemData> getMatchValues() const override;
@@ -59,8 +61,8 @@ private:
}
-ScDPGroupNumFilter::ScDPGroupNumFilter(const std::vector<ScDPItemData>& rValues, const ScDPNumGroupInfo& rInfo) :
- maValues(rValues), maNumInfo(rInfo) {}
+ScDPGroupNumFilter::ScDPGroupNumFilter( std::vector<ScDPItemData>&& rValues, const ScDPNumGroupInfo& rInfo) :
+ maValues(std::move(rValues)), maNumInfo(rInfo) {}
bool ScDPGroupNumFilter::match(const ScDPItemData& rCellData) const
{
@@ -109,7 +111,7 @@ class ScDPGroupDateFilter : public ScDPFilteredCache::FilterBase
{
public:
ScDPGroupDateFilter(
- const std::vector<ScDPItemData>& rValues, const Date& rNullDate, const ScDPNumGroupInfo& rNumInfo);
+ std::vector<ScDPItemData>&& rValues, const Date& rNullDate, const ScDPNumGroupInfo& rNumInfo);
virtual bool match(const ScDPItemData & rCellData) const override;
virtual std::vector<ScDPItemData> getMatchValues() const override;
@@ -123,8 +125,8 @@ private:
}
ScDPGroupDateFilter::ScDPGroupDateFilter(
- const std::vector<ScDPItemData>& rValues, const Date& rNullDate, const ScDPNumGroupInfo& rNumInfo) :
- maValues(rValues),
+ std::vector<ScDPItemData>&& rValues, const Date& rNullDate, const ScDPNumGroupInfo& rNumInfo) :
+ maValues(std::move(rValues)),
maNullDate(rNullDate),
maNumInfo(rNumInfo)
{
@@ -329,10 +331,10 @@ void ScDPGroupItem::FillGroupFilter( ScDPFilteredCache::GroupFilter& rFilter ) c
rFilter.addMatchItem(rElement);
}
-ScDPGroupDimension::ScDPGroupDimension( tools::Long nSource, const OUString& rNewName ) :
+ScDPGroupDimension::ScDPGroupDimension( tools::Long nSource, OUString aNewName ) :
nSourceDim( nSource ),
nGroupDim( -1 ),
- aGroupName( rNewName ),
+ aGroupName(std::move( aNewName )),
mbDateDimension(false)
{
}
@@ -678,13 +680,13 @@ void ScDPGroupTableData::ModifyFilterCriteria(vector<ScDPFilteredCache::Criterio
// grouped by dates.
aCri.mpFilter =
std::make_shared<ScDPGroupDateFilter>(
- aMatchValues, pDoc->GetFormatTable()->GetNullDate(), *pNumInfo);
+ std::move(aMatchValues), pDoc->GetFormatTable()->GetNullDate(), *pNumInfo);
}
else
{
// This dimension is grouped by numeric ranges.
aCri.mpFilter =
- std::make_shared<ScDPGroupNumFilter>(aMatchValues, *pNumInfo);
+ std::make_shared<ScDPGroupNumFilter>(std::move(aMatchValues), *pNumInfo);
}
aNewCriteria.push_back(aCri);
@@ -711,7 +713,7 @@ void ScDPGroupTableData::ModifyFilterCriteria(vector<ScDPFilteredCache::Criterio
aCri.mnFieldIndex = nSrcDim; // use the source dimension, not the group dimension.
aCri.mpFilter =
std::make_shared<ScDPGroupDateFilter>(
- aMatchValues, pDoc->GetFormatTable()->GetNullDate(), *pNumInfo);
+ std::move(aMatchValues), pDoc->GetFormatTable()->GetNullDate(), *pNumInfo);
aNewCriteria.push_back(aCri);
}
@@ -746,18 +748,16 @@ void ScDPGroupTableData::ModifyFilterCriteria(vector<ScDPFilteredCache::Criterio
rCriteria.swap(aNewCriteria);
}
-void ScDPGroupTableData::FilterCacheTable(const vector<ScDPFilteredCache::Criterion>& rCriteria, const std::unordered_set<sal_Int32>& rCatDims)
+void ScDPGroupTableData::FilterCacheTable(std::vector<ScDPFilteredCache::Criterion>&& rCriteria, std::unordered_set<sal_Int32>&& rCatDims)
{
- vector<ScDPFilteredCache::Criterion> aNewCriteria(rCriteria);
- ModifyFilterCriteria(aNewCriteria);
- pSourceData->FilterCacheTable(aNewCriteria, rCatDims);
+ ModifyFilterCriteria(rCriteria);
+ pSourceData->FilterCacheTable(std::move(rCriteria), std::move(rCatDims));
}
-void ScDPGroupTableData::GetDrillDownData(const vector<ScDPFilteredCache::Criterion>& rCriteria, const std::unordered_set<sal_Int32>& rCatDims, Sequence< Sequence<Any> >& rData)
+void ScDPGroupTableData::GetDrillDownData(std::vector<ScDPFilteredCache::Criterion>&& rCriteria, std::unordered_set<sal_Int32>&&rCatDims, Sequence< Sequence<Any> >& rData)
{
- vector<ScDPFilteredCache::Criterion> aNewCriteria(rCriteria);
- ModifyFilterCriteria(aNewCriteria);
- pSourceData->GetDrillDownData(aNewCriteria, rCatDims, rData);
+ ModifyFilterCriteria(rCriteria);
+ pSourceData->GetDrillDownData(std::move(rCriteria), std::move(rCatDims), rData);
}
void ScDPGroupTableData::CalcResults(CalcInfo& rInfo, bool bAutoShow)
diff --git a/sc/source/core/data/dpitemdata.cxx b/sc/source/core/data/dpitemdata.cxx
index f6d2e9812f9e..e4efe75ee935 100644
--- a/sc/source/core/data/dpitemdata.cxx
+++ b/sc/source/core/data/dpitemdata.cxx
@@ -64,7 +64,7 @@ sal_Int32 ScDPItemData::Compare(const ScDPItemData& rA, const ScDPItemData& rB)
// strings may be interned.
return 0;
- return ScGlobal::GetCollator()->compareString(rA.GetString(), rB.GetString());
+ return ScGlobal::GetCollator().compareString(rA.GetString(), rB.GetString());
default:
;
}
@@ -167,14 +167,14 @@ void ScDPItemData::SetRangeStart(double fVal)
void ScDPItemData::SetRangeFirst()
{
DisposeString();
- rtl::math::setInf(&mfValue, true);
+ mfValue = -std::numeric_limits<double>::infinity();
meType = RangeStart;
}
void ScDPItemData::SetRangeLast()
{
DisposeString();
- rtl::math::setInf(&mfValue, false);
+ mfValue = std::numeric_limits<double>::infinity();
meType = RangeStart;
}
@@ -205,7 +205,7 @@ bool ScDPItemData::IsCaseInsEqual(const ScDPItemData& r) const
// Fast equality check for interned strings.
return true;
- return ScGlobal::GetpTransliteration()->isEqual(GetString(), r.GetString());
+ return ScGlobal::GetTransliteration().isEqual(GetString(), r.GetString());
}
bool ScDPItemData::operator== (const ScDPItemData& r) const
diff --git a/sc/source/core/data/dpobject.cxx b/sc/source/core/data/dpobject.cxx
index d60b41d143e8..d80acccb55c4 100644
--- a/sc/source/core/data/dpobject.cxx
+++ b/sc/source/core/data/dpobject.cxx
@@ -68,14 +68,15 @@
#include <comphelper/processfactory.hxx>
#include <comphelper/string.hxx>
#include <comphelper/types.hxx>
+#include <o3tl/safeint.hxx>
#include <sal/macros.h>
-#include <rtl/math.hxx>
-#include <tools/diagnose_ex.h>
+#include <svl/numformat.hxx>
+#include <comphelper/diagnose_ex.hxx>
#include <svl/zforlist.hxx>
+#include <utility>
#include <vcl/svapp.hxx>
#include <vcl/weld.hxx>
-#include <utility>
#include <vector>
#include <memory>
#include <algorithm>
@@ -94,13 +95,13 @@ using ::com::sun::star::sheet::DataPilotTablePositionData;
using ::com::sun::star::sheet::XDimensionsSupplier;
using ::com::sun::star::beans::XPropertySet;
-#define SC_SERVICE_ROWSET "com.sun.star.sdb.RowSet"
+constexpr OUStringLiteral SC_SERVICE_ROWSET = u"com.sun.star.sdb.RowSet";
-#define SC_DBPROP_DATASOURCENAME "DataSourceName"
-#define SC_DBPROP_COMMAND "Command"
-#define SC_DBPROP_COMMANDTYPE "CommandType"
+constexpr OUStringLiteral SC_DBPROP_DATASOURCENAME = u"DataSourceName";
+constexpr OUStringLiteral SC_DBPROP_COMMAND = u"Command";
+constexpr OUStringLiteral SC_DBPROP_COMMANDTYPE = u"CommandType";
-#define SCDPSOURCE_SERVICE "com.sun.star.sheet.DataPilotSource"
+constexpr OUString SCDPSOURCE_SERVICE = u"com.sun.star.sheet.DataPilotSource"_ustr;
namespace {
@@ -119,7 +120,7 @@ class DBConnector : public ScDPCache::DBConnector
Date maNullDate;
public:
- DBConnector(ScDPCache& rCache, const uno::Reference<sdbc::XRowSet>& xRowSet, const Date& rNullDate);
+ DBConnector(ScDPCache& rCache, uno::Reference<sdbc::XRowSet> xRowSet, const Date& rNullDate);
bool isValid() const;
@@ -131,8 +132,8 @@ public:
virtual void finish() override;
};
-DBConnector::DBConnector(ScDPCache& rCache, const uno::Reference<sdbc::XRowSet>& xRowSet, const Date& rNullDate) :
- mrCache(rCache), mxRowSet(xRowSet), maNullDate(rNullDate)
+DBConnector::DBConnector(ScDPCache& rCache, uno::Reference<sdbc::XRowSet> xRowSet, const Date& rNullDate) :
+ mrCache(rCache), mxRowSet(std::move(xRowSet)), maNullDate(rNullDate)
{
Reference<sdbc::XResultSetMetaDataSupplier> xMetaSupp(mxRowSet, UNO_QUERY);
if (xMetaSupp.is())
@@ -289,13 +290,13 @@ static sheet::DataPilotFieldOrientation lcl_GetDataGetOrientation( const uno::Re
}
ScDPServiceDesc::ScDPServiceDesc(
- const OUString& rServ, const OUString& rSrc, const OUString& rNam,
- const OUString& rUser, const OUString& rPass ) :
- aServiceName( rServ ),
- aParSource( rSrc ),
- aParName( rNam ),
- aParUser( rUser ),
- aParPass( rPass ) {}
+ OUString aServ, OUString aSrc, OUString aNam,
+ OUString aUser, OUString aPass ) :
+ aServiceName(std::move( aServ )),
+ aParSource(std::move( aSrc )),
+ aParName(std::move( aNam )),
+ aParUser(std::move( aUser )),
+ aParPass(std::move( aPass )) {}
bool ScDPServiceDesc::operator== ( const ScDPServiceDesc& rOther ) const
{
@@ -306,37 +307,37 @@ bool ScDPServiceDesc::operator== ( const ScDPServiceDesc& rOther ) const
aParPass == rOther.aParPass;
}
-ScDPObject::ScDPObject( ScDocument* pD ) :
- pDoc( pD ),
- nHeaderRows( 0 ),
- mbHeaderLayout(false),
- bAllowMove(false),
- bSettingsChanged(false),
- mbEnableGetPivotData(true)
+ScDPObject::ScDPObject(ScDocument* pDocument)
+ : mpDocument(pDocument)
+ , mnHeaderRows(0)
+ , mbHeaderLayout(false)
+ , mbAllowMove(false)
+ , mbSettingsChanged(false)
+ , mbEnableGetPivotData(true)
{
}
-ScDPObject::ScDPObject(const ScDPObject& r) :
- pDoc( r.pDoc ),
- aTableName( r.aTableName ),
- aTableTag( r.aTableTag ),
- aOutRange( r.aOutRange ),
- maInteropGrabBag(r.maInteropGrabBag),
- nHeaderRows( r.nHeaderRows ),
- mbHeaderLayout( r.mbHeaderLayout ),
- bAllowMove(false),
- bSettingsChanged(false),
- mbEnableGetPivotData(r.mbEnableGetPivotData)
+ScDPObject::ScDPObject(const ScDPObject& rOther)
+ : mpDocument(rOther.mpDocument)
+ , maTableName(rOther.maTableName)
+ , maTableTag(rOther.maTableTag)
+ , maOutputRange(rOther.maOutputRange)
+ , maInteropGrabBag(rOther.maInteropGrabBag)
+ , mnHeaderRows(rOther.mnHeaderRows)
+ , mbHeaderLayout(rOther.mbHeaderLayout)
+ , mbAllowMove(false)
+ , mbSettingsChanged(false)
+ , mbEnableGetPivotData(rOther.mbEnableGetPivotData)
{
- if (r.pSaveData)
- pSaveData.reset( new ScDPSaveData(*r.pSaveData) );
- if (r.pSheetDesc)
- pSheetDesc.reset( new ScSheetSourceDesc(*r.pSheetDesc) );
- if (r.pImpDesc)
- pImpDesc.reset( new ScImportSourceDesc(*r.pImpDesc) );
- if (r.pServDesc)
- pServDesc.reset( new ScDPServiceDesc(*r.pServDesc) );
- // xSource (and pOutput) is not copied
+ if (rOther.mpSaveData)
+ mpSaveData.reset(new ScDPSaveData(*rOther.mpSaveData));
+ if (rOther.mpSheetDescription)
+ mpSheetDescription.reset(new ScSheetSourceDesc(*rOther.mpSheetDescription));
+ if (rOther.mpImportDescription)
+ mpImportDescription.reset(new ScImportSourceDesc(*rOther.mpImportDescription));
+ if (rOther.mpServiceDescription)
+ mpServiceDescription.reset(new ScDPServiceDesc(*rOther.mpServiceDescription));
+ // mxSource (and mpOutput) is not copied
}
ScDPObject::~ScDPObject()
@@ -344,31 +345,31 @@ ScDPObject::~ScDPObject()
Clear();
}
-ScDPObject& ScDPObject::operator= (const ScDPObject& r)
+ScDPObject& ScDPObject::operator= (const ScDPObject& rOther)
{
- if (this != &r)
+ if (this != &rOther)
{
Clear();
- pDoc = r.pDoc;
- aTableName = r.aTableName;
- aTableTag = r.aTableTag;
- aOutRange = r.aOutRange;
- maInteropGrabBag = r.maInteropGrabBag;
- nHeaderRows = r.nHeaderRows;
- mbHeaderLayout = r.mbHeaderLayout;
- bAllowMove = false;
- bSettingsChanged = false;
- mbEnableGetPivotData = r.mbEnableGetPivotData;
-
- if (r.pSaveData)
- pSaveData.reset( new ScDPSaveData(*r.pSaveData) );
- if (r.pSheetDesc)
- pSheetDesc.reset( new ScSheetSourceDesc(*r.pSheetDesc) );
- if (r.pImpDesc)
- pImpDesc.reset( new ScImportSourceDesc(*r.pImpDesc) );
- if (r.pServDesc)
- pServDesc.reset( new ScDPServiceDesc(*r.pServDesc) );
+ mpDocument = rOther.mpDocument;
+ maTableName = rOther.maTableName;
+ maTableTag = rOther.maTableTag;
+ maOutputRange = rOther.maOutputRange;
+ maInteropGrabBag = rOther.maInteropGrabBag;
+ mnHeaderRows = rOther.mnHeaderRows;
+ mbHeaderLayout =rOther.mbHeaderLayout;
+ mbAllowMove = false;
+ mbSettingsChanged = false;
+ mbEnableGetPivotData = rOther.mbEnableGetPivotData;
+
+ if (rOther.mpSaveData)
+ mpSaveData.reset(new ScDPSaveData(*rOther.mpSaveData));
+ if (rOther.mpSheetDescription)
+ mpSheetDescription.reset(new ScSheetSourceDesc(*rOther.mpSheetDescription));
+ if (rOther.mpImportDescription)
+ mpImportDescription.reset(new ScImportSourceDesc(*rOther.mpImportDescription));
+ if (rOther.mpServiceDescription)
+ mpServiceDescription.reset(new ScDPServiceDesc(*rOther.mpServiceDescription));
}
return *this;
}
@@ -380,14 +381,14 @@ void ScDPObject::EnableGetPivotData(bool b)
void ScDPObject::SetAllowMove(bool bSet)
{
- bAllowMove = bSet;
+ mbAllowMove = bSet;
}
void ScDPObject::SetSaveData(const ScDPSaveData& rData)
{
- if ( pSaveData.get() != &rData ) // API implementation modifies the original SaveData object
+ if (mpSaveData.get() != &rData) // API implementation modifies the original SaveData object
{
- pSaveData.reset( new ScDPSaveData( rData ) );
+ mpSaveData.reset(new ScDPSaveData(rData));
}
InvalidateData(); // re-init source from SaveData
@@ -400,157 +401,161 @@ void ScDPObject::SetHeaderLayout (bool bUseGrid)
void ScDPObject::SetOutRange(const ScRange& rRange)
{
- aOutRange = rRange;
+ maOutputRange = rRange;
- if ( pOutput )
- pOutput->SetPosition( rRange.aStart );
+ if (mpOutput)
+ mpOutput->SetPosition( rRange.aStart );
}
const ScRange& ScDPObject::GetOutRange() const
{
- return aOutRange;
+ return maOutputRange;
}
void ScDPObject::SetSheetDesc(const ScSheetSourceDesc& rDesc)
{
- if ( pSheetDesc && rDesc == *pSheetDesc )
- return; // nothing to do
+ if (mpSheetDescription && rDesc == *mpSheetDescription)
+ return; // nothing to do
- pImpDesc.reset();
- pServDesc.reset();
+ mpImportDescription.reset();
+ mpServiceDescription.reset();
- pSheetDesc.reset( new ScSheetSourceDesc(rDesc) );
+ mpSheetDescription.reset( new ScSheetSourceDesc(rDesc) );
// make valid QueryParam
- const ScRange& rSrcRange = pSheetDesc->GetSourceRange();
- ScQueryParam aParam = pSheetDesc->GetQueryParam();
+ const ScRange& rSrcRange = mpSheetDescription->GetSourceRange();
+ ScQueryParam aParam = mpSheetDescription->GetQueryParam();
aParam.nCol1 = rSrcRange.aStart.Col();
aParam.nRow1 = rSrcRange.aStart.Row();
aParam.nCol2 = rSrcRange.aEnd.Col();
aParam.nRow2 = rSrcRange.aEnd.Row();
aParam.bHasHeader = true;
- pSheetDesc->SetQueryParam(aParam);
+ mpSheetDescription->SetQueryParam(aParam);
- ClearTableData(); // new source must be created
+ ClearTableData(); // new source must be created
}
void ScDPObject::SetImportDesc(const ScImportSourceDesc& rDesc)
{
- if ( pImpDesc && rDesc == *pImpDesc )
- return; // nothing to do
+ if (mpImportDescription && rDesc == *mpImportDescription)
+ return; // nothing to do
- pSheetDesc.reset();
- pServDesc.reset();
+ mpSheetDescription.reset();
+ mpServiceDescription.reset();
- pImpDesc.reset( new ScImportSourceDesc(rDesc) );
+ mpImportDescription.reset(new ScImportSourceDesc(rDesc));
- ClearTableData(); // new source must be created
+ ClearTableData(); // new source must be created
}
void ScDPObject::SetServiceData(const ScDPServiceDesc& rDesc)
{
- if ( pServDesc && rDesc == *pServDesc )
- return; // nothing to do
+ if (mpServiceDescription && rDesc == *mpServiceDescription)
+ return; // nothing to do
- pSheetDesc.reset();
- pImpDesc.reset();
+ mpSheetDescription.reset();
+ mpImportDescription.reset();
- pServDesc.reset( new ScDPServiceDesc(rDesc) );
+ mpServiceDescription.reset(new ScDPServiceDesc(rDesc));
ClearTableData(); // new source must be created
}
void ScDPObject::WriteSourceDataTo( ScDPObject& rDest ) const
{
- if ( pSheetDesc )
- rDest.SetSheetDesc( *pSheetDesc );
- else if ( pImpDesc )
- rDest.SetImportDesc( *pImpDesc );
- else if ( pServDesc )
- rDest.SetServiceData( *pServDesc );
+ if (mpSheetDescription)
+ rDest.SetSheetDesc(*mpSheetDescription);
+ else if (mpImportDescription)
+ rDest.SetImportDesc(*mpImportDescription);
+ else if (mpServiceDescription)
+ rDest.SetServiceData(*mpServiceDescription);
// name/tag are not source data, but needed along with source data
- rDest.aTableName = aTableName;
- rDest.aTableTag = aTableTag;
+ rDest.maTableName = maTableName;
+ rDest.maTableTag = maTableTag;
}
void ScDPObject::WriteTempDataTo( ScDPObject& rDest ) const
{
- rDest.nHeaderRows = nHeaderRows;
+ rDest.mnHeaderRows = mnHeaderRows;
}
bool ScDPObject::IsSheetData() const
{
- return ( pSheetDesc != nullptr );
+ return mpSheetDescription != nullptr;
}
void ScDPObject::SetName(const OUString& rNew)
{
- aTableName = rNew;
+ maTableName = rNew;
}
void ScDPObject::SetTag(const OUString& rNew)
{
- aTableTag = rNew;
+ maTableTag = rNew;
}
bool ScDPObject::IsDataDescriptionCell(const ScAddress& rPos)
{
- if (!pSaveData)
+ if (!mpSaveData)
return false;
- tools::Long nDataDimCount = pSaveData->GetDataDimensionCount();
+ tools::Long nDataDimCount = mpSaveData->GetDataDimensionCount();
if (nDataDimCount != 1)
// There has to be exactly one data dimension for the description to
// appear at top-left corner.
return false;
CreateOutput();
- ScRange aTabRange = pOutput->GetOutputRange(sheet::DataPilotOutputRangeType::TABLE);
+ ScRange aTabRange = mpOutput->GetOutputRange(sheet::DataPilotOutputRangeType::TABLE);
return (rPos == aTabRange.aStart);
}
uno::Reference<sheet::XDimensionsSupplier> const & ScDPObject::GetSource()
{
CreateObjects();
- return xSource;
+ return mxSource;
}
void ScDPObject::CreateOutput()
{
CreateObjects();
- if (pOutput)
+ if (mpOutput)
return;
- bool bFilterButton = IsSheetData() && pSaveData && pSaveData->GetFilterButton();
- pOutput.reset( new ScDPOutput( pDoc, xSource, aOutRange.aStart, bFilterButton ) );
- pOutput->SetHeaderLayout ( mbHeaderLayout );
+ bool bFilterButton = IsSheetData() && mpSaveData && mpSaveData->GetFilterButton();
+ bool bExpandCollapse = mpSaveData ? mpSaveData->GetExpandCollapse() : false;
+
+ mpOutput.reset(new ScDPOutput(mpDocument, mxSource, maOutputRange.aStart, bFilterButton, bExpandCollapse, *this));
+ mpOutput->SetHeaderLayout(mbHeaderLayout);
+ if (mpSaveData->hasFormats())
+ mpOutput->setFormats(mpSaveData->getFormats());
- sal_Int32 nOldRows = nHeaderRows;
- nHeaderRows = pOutput->GetHeaderRows();
+ sal_Int32 nOldRows = mnHeaderRows;
+ mnHeaderRows = mpOutput->GetHeaderRows();
- if ( !(bAllowMove && nHeaderRows != nOldRows) )
+ if (!(mbAllowMove && mnHeaderRows != nOldRows))
return;
- sal_Int32 nDiff = nOldRows - nHeaderRows;
+ sal_Int32 nDiff = nOldRows - mnHeaderRows;
if ( nOldRows == 0 )
--nDiff;
- if ( nHeaderRows == 0 )
+ if (mnHeaderRows == 0)
++nDiff;
- sal_Int32 nNewRow = aOutRange.aStart.Row() + nDiff;
+ sal_Int32 nNewRow = maOutputRange.aStart.Row() + nDiff;
if ( nNewRow < 0 )
nNewRow = 0;
- ScAddress aStart( aOutRange.aStart );
+ ScAddress aStart(maOutputRange.aStart);
aStart.SetRow(nNewRow);
- pOutput->SetPosition( aStart );
+ mpOutput->SetPosition( aStart );
- //TODO: modify aOutRange?
+ //TODO: modify maOutputRange?
- bAllowMove = false; // use only once
+ mbAllowMove = false; // use only once
}
namespace {
@@ -679,25 +684,25 @@ ScDPTableData* ScDPObject::GetTableData()
if (!mpTableData)
{
shared_ptr<ScDPTableData> pData;
- const ScDPDimensionSaveData* pDimData = pSaveData ? pSaveData->GetExistingDimensionData() : nullptr;
+ const ScDPDimensionSaveData* pDimData = mpSaveData ? mpSaveData->GetExistingDimensionData() : nullptr;
- if ( pImpDesc )
+ if (mpImportDescription)
{
// database data
- const ScDPCache* pCache = pImpDesc->CreateCache(pDimData);
+ const ScDPCache* pCache = mpImportDescription->CreateCache(pDimData);
if (pCache)
{
pCache->AddReference(this);
- pData = std::make_shared<ScDatabaseDPData>(pDoc, *pCache);
+ pData = std::make_shared<ScDatabaseDPData>(mpDocument, *pCache);
}
}
else
{
// cell data
- if (!pSheetDesc)
+ if (!mpSheetDescription)
{
OSL_FAIL("no source descriptor");
- pSheetDesc.reset( new ScSheetSourceDesc(pDoc) ); // dummy defaults
+ mpSheetDescription.reset(new ScSheetSourceDesc(mpDocument)); // dummy defaults
}
{
@@ -705,11 +710,11 @@ ScDPTableData* ScDPObject::GetTableData()
// GETPIVOTDATA called onto itself from within the source
// range.
DisableGetPivotData aSwitch(*this, mbEnableGetPivotData);
- const ScDPCache* pCache = pSheetDesc->CreateCache(pDimData);
+ const ScDPCache* pCache = mpSheetDescription->CreateCache(pDimData);
if (pCache)
{
pCache->AddReference(this);
- pData = std::make_shared<ScSheetDPData>(pDoc, *pSheetDesc, *pCache);
+ pData = std::make_shared<ScSheetDPData>(mpDocument, *mpSheetDescription, *pCache);
}
}
}
@@ -717,7 +722,7 @@ ScDPTableData* ScDPObject::GetTableData()
// grouping (for cell or database data)
if (pData && pDimData)
{
- auto pGroupData = std::make_shared<ScDPGroupTableData>(pData, pDoc);
+ auto pGroupData = std::make_shared<ScDPGroupTableData>(pData, mpDocument);
pDimData->WriteToData(*pGroupData);
pData = pGroupData;
}
@@ -730,39 +735,39 @@ ScDPTableData* ScDPObject::GetTableData()
void ScDPObject::CreateObjects()
{
- if (!xSource.is())
+ if (!mxSource.is())
{
- pOutput.reset(); // not valid when xSource is changed
+ mpOutput.reset(); // not valid when mxSource is changed
- if ( pServDesc )
+ if (mpServiceDescription)
{
- xSource = CreateSource( *pServDesc );
+ mxSource = CreateSource(*mpServiceDescription);
}
- if ( !xSource.is() ) // database or sheet data, or error in CreateSource
+ if (!mxSource.is()) // database or sheet data, or error in CreateSource
{
- OSL_ENSURE( !pServDesc, "DPSource could not be created" );
+ OSL_ENSURE(!mpServiceDescription, "DPSource could not be created");
ScDPTableData* pData = GetTableData();
if (pData)
{
- if (pSaveData)
+ if (mpSaveData)
// Make sure to transfer these flags to the table data
// since they may have changed.
- pData->SetEmptyFlags(pSaveData->GetIgnoreEmptyRows(), pSaveData->GetRepeatIfEmpty());
+ pData->SetEmptyFlags(mpSaveData->GetIgnoreEmptyRows(), mpSaveData->GetRepeatIfEmpty());
pData->ReloadCacheTable();
- xSource = new ScDPSource( pData );
+ mxSource = new ScDPSource( pData );
}
}
- if (pSaveData)
- pSaveData->WriteToSource( xSource );
+ if (mpSaveData)
+ mpSaveData->WriteToSource(mxSource);
}
- else if (bSettingsChanged)
+ else if (mbSettingsChanged)
{
- pOutput.reset(); // not valid when xSource is changed
+ mpOutput.reset(); // not valid when mxSource is changed
- uno::Reference<util::XRefreshable> xRef( xSource, uno::UNO_QUERY );
+ uno::Reference<util::XRefreshable> xRef(mxSource, uno::UNO_QUERY);
if (xRef.is())
{
try
@@ -775,24 +780,24 @@ void ScDPObject::CreateObjects()
}
}
- if (pSaveData)
- pSaveData->WriteToSource( xSource );
+ if (mpSaveData)
+ mpSaveData->WriteToSource(mxSource);
}
- bSettingsChanged = false;
+ mbSettingsChanged = false;
}
void ScDPObject::InvalidateData()
{
- bSettingsChanged = true;
+ mbSettingsChanged = true;
}
void ScDPObject::Clear()
{
- pOutput.reset();
- pSaveData.reset();
- pSheetDesc.reset();
- pImpDesc.reset();
- pServDesc.reset();
+ mpOutput.reset();
+ mpSaveData.reset();
+ mpSheetDescription.reset();
+ mpImportDescription.reset();
+ mpServiceDescription.reset();
ClearTableData();
maInteropGrabBag.clear();
}
@@ -814,11 +819,11 @@ void ScDPObject::ReloadGroupTableData()
// Table data not built yet. No need to reload the group data.
return;
- if (!pSaveData)
+ if (!mpSaveData)
// How could it not have the save data... but whatever.
return;
- const ScDPDimensionSaveData* pDimData = pSaveData->GetExistingDimensionData();
+ const ScDPDimensionSaveData* pDimData = mpSaveData->GetExistingDimensionData();
if (!pDimData || !pDimData->HasGroupDimensions())
{
// No group dimensions exist. Check if it currently has group
@@ -838,24 +843,24 @@ void ScDPObject::ReloadGroupTableData()
// This is already a group table data. Salvage the source data and
// re-create a new group data.
const shared_ptr<ScDPTableData>& pSource = pData->GetSourceTableData();
- auto pGroupData = std::make_shared<ScDPGroupTableData>(pSource, pDoc);
+ auto pGroupData = std::make_shared<ScDPGroupTableData>(pSource, mpDocument);
pDimData->WriteToData(*pGroupData);
mpTableData = pGroupData;
}
else
{
// This is a source data. Create a group data based on it.
- auto pGroupData = std::make_shared<ScDPGroupTableData>(mpTableData, pDoc);
+ auto pGroupData = std::make_shared<ScDPGroupTableData>(mpTableData, mpDocument);
pDimData->WriteToData(*pGroupData);
mpTableData = pGroupData;
}
- bSettingsChanged = true;
+ mbSettingsChanged = true;
}
void ScDPObject::ClearSource()
{
- Reference< XComponent > xObjectComp( xSource, UNO_QUERY );
+ uno::Reference<XComponent> xObjectComp(mxSource, UNO_QUERY);
if (xObjectComp.is())
{
try
@@ -867,62 +872,62 @@ void ScDPObject::ClearSource()
DBG_UNHANDLED_EXCEPTION("sc.core");
}
}
- xSource = nullptr;
+ mxSource = nullptr;
}
ScRange ScDPObject::GetNewOutputRange( bool& rOverflow )
{
- CreateOutput(); // create xSource and pOutput if not already done
+ CreateOutput(); // create mxSource and mpOutput if not already done
- rOverflow = pOutput->HasError(); // range overflow or exception from source
+ rOverflow = mpOutput->HasError(); // range overflow or exception from source
if ( rOverflow )
- return ScRange( aOutRange.aStart );
+ return ScRange(maOutputRange.aStart);
else
{
- // don't store the result in aOutRange, because nothing has been output yet
- return pOutput->GetOutputRange();
+ // don't store the result in maOutputRange, because nothing has been output yet
+ return mpOutput->GetOutputRange();
}
}
void ScDPObject::Output( const ScAddress& rPos )
{
// clear old output area
- pDoc->DeleteAreaTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
- aOutRange.aEnd.Col(), aOutRange.aEnd.Row(),
- aOutRange.aStart.Tab(), InsertDeleteFlags::ALL );
- pDoc->RemoveFlagsTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
- aOutRange.aEnd.Col(), aOutRange.aEnd.Row(),
- aOutRange.aStart.Tab(), ScMF::Auto );
+ mpDocument->DeleteAreaTab(maOutputRange.aStart.Col(), maOutputRange.aStart.Row(),
+ maOutputRange.aEnd.Col(), maOutputRange.aEnd.Row(),
+ maOutputRange.aStart.Tab(), InsertDeleteFlags::ALL );
+ mpDocument->RemoveFlagsTab( maOutputRange.aStart.Col(), maOutputRange.aStart.Row(),
+ maOutputRange.aEnd.Col(), maOutputRange.aEnd.Row(),
+ maOutputRange.aStart.Tab(), ScMF::Auto );
- CreateOutput(); // create xSource and pOutput if not already done
+ CreateOutput(); // create mxSource and mpOutput if not already done
- pOutput->SetPosition( rPos );
+ mpOutput->SetPosition( rPos );
- pOutput->Output();
+ mpOutput->Output();
- // aOutRange is always the range that was last output to the document
- aOutRange = pOutput->GetOutputRange();
- const ScAddress& s = aOutRange.aStart;
- const ScAddress& e = aOutRange.aEnd;
- pDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), ScMF::DpTable);
+ // maOutputRange is always the range that was last output to the document
+ maOutputRange = mpOutput->GetOutputRange();
+ const ScAddress& s = maOutputRange.aStart;
+ const ScAddress& e = maOutputRange.aEnd;
+ mpDocument->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), ScMF::DpTable);
}
ScRange ScDPObject::GetOutputRangeByType( sal_Int32 nType )
{
CreateOutput();
- if (pOutput->HasError())
- return ScRange(aOutRange.aStart);
+ if (mpOutput->HasError())
+ return ScRange(maOutputRange.aStart);
- return pOutput->GetOutputRange(nType);
+ return mpOutput->GetOutputRange(nType);
}
ScRange ScDPObject::GetOutputRangeByType( sal_Int32 nType ) const
{
- if (!pOutput || pOutput->HasError())
+ if (!mpOutput || mpOutput->HasError())
return ScRange(ScAddress::INITIALIZE_INVALID);
- return pOutput->GetOutputRange(nType);
+ return mpOutput->GetOutputRange(nType);
}
static bool lcl_HasButton( const ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
@@ -932,52 +937,52 @@ static bool lcl_HasButton( const ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB
void ScDPObject::RefreshAfterLoad()
{
- // apply drop-down attribute, initialize nHeaderRows, without accessing the source
+ // apply drop-down attribute, initialize mnHeaderRows, without accessing the source
// (button attribute must be present)
// simple test: block of button cells at the top, followed by an empty cell
- SCCOL nFirstCol = aOutRange.aStart.Col();
- SCROW nFirstRow = aOutRange.aStart.Row();
- SCTAB nTab = aOutRange.aStart.Tab();
+ SCCOL nFirstCol = maOutputRange.aStart.Col();
+ SCROW nFirstRow = maOutputRange.aStart.Row();
+ SCTAB nTab = maOutputRange.aStart.Tab();
SCROW nInitial = 0;
- SCROW nOutRows = aOutRange.aEnd.Row() + 1 - aOutRange.aStart.Row();
- while ( nInitial + 1 < nOutRows && lcl_HasButton( pDoc, nFirstCol, nFirstRow + nInitial, nTab ) )
+ SCROW nOutRows = maOutputRange.aEnd.Row() + 1 - maOutputRange.aStart.Row();
+ while (nInitial + 1 < nOutRows && lcl_HasButton(mpDocument, nFirstCol, nFirstRow + nInitial, nTab))
++nInitial;
if ( nInitial + 1 < nOutRows &&
- pDoc->IsBlockEmpty( nTab, nFirstCol, nFirstRow + nInitial, nFirstCol, nFirstRow + nInitial ) &&
- aOutRange.aEnd.Col() > nFirstCol )
+ mpDocument->IsBlockEmpty( nFirstCol, nFirstRow + nInitial, nFirstCol, nFirstRow + nInitial, nTab ) &&
+ maOutputRange.aEnd.Col() > nFirstCol )
{
- nHeaderRows = nInitial;
+ mnHeaderRows = nInitial;
}
else
- nHeaderRows = 0; // nothing found, no drop-down lists
+ mnHeaderRows = 0; // nothing found, no drop-down lists
}
void ScDPObject::BuildAllDimensionMembers()
{
- if (!pSaveData)
+ if (!mpSaveData)
return;
// #i111857# don't always create empty mpTableData for external service.
- if (pServDesc)
+ if (mpServiceDescription)
return;
ScDPTableData* pTableData = GetTableData();
if(pTableData)
- pSaveData->BuildAllDimensionMembers(pTableData);
+ mpSaveData->BuildAllDimensionMembers(pTableData);
}
bool ScDPObject::SyncAllDimensionMembers()
{
- if (!pSaveData)
+ if (!mpSaveData)
return false;
// #i111857# don't always create empty mpTableData for external service.
- // Ideally, xSource should be used instead of mpTableData.
- if (pServDesc)
+ // Ideally, mxSource should be used instead of mpTableData.
+ if (mpServiceDescription)
return false;
ScDPTableData* pData = GetTableData();
@@ -987,9 +992,9 @@ bool ScDPObject::SyncAllDimensionMembers()
return false;
// Refresh the cache wrapper since the cache may have changed.
- pData->SetEmptyFlags(pSaveData->GetIgnoreEmptyRows(), pSaveData->GetRepeatIfEmpty());
+ pData->SetEmptyFlags(mpSaveData->GetIgnoreEmptyRows(), mpSaveData->GetRepeatIfEmpty());
pData->ReloadCacheTable();
- pSaveData->SyncAllDimensionMembers(pData);
+ mpSaveData->SyncAllDimensionMembers(pData);
return true;
}
@@ -1001,8 +1006,9 @@ bool ScDPObject::GetMemberNames( sal_Int32 nDim, Sequence<OUString>& rNames )
size_t n = aMembers.size();
rNames.realloc(n);
+ auto pNames = rNames.getArray();
for (size_t i = 0; i < n; ++i)
- rNames[i] = aMembers[i].maName;
+ pNames[i] = aMembers[i].maName;
return true;
}
@@ -1020,7 +1026,16 @@ bool ScDPObject::GetMembers( sal_Int32 nDim, sal_Int32 nHier, vector<ScDPLabelDa
for (sal_Int32 i = 0; i < nCount; ++i)
{
- Reference<container::XNamed> xMember(xMembersIA->getByIndex(i), UNO_QUERY);
+ Reference<container::XNamed> xMember;
+ try
+ {
+ xMember = Reference<container::XNamed>(xMembersIA->getByIndex(i), UNO_QUERY);
+ }
+ catch (const container::NoSuchElementException&)
+ {
+ TOOLS_WARN_EXCEPTION("sc", "ScNameToIndexAccess getByIndex failed");
+ }
+
ScDPLabelData::Member aMem;
if (xMember.is())
@@ -1047,15 +1062,15 @@ void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode,
{
// Output area
- SCCOL nCol1 = aOutRange.aStart.Col();
- SCROW nRow1 = aOutRange.aStart.Row();
- SCTAB nTab1 = aOutRange.aStart.Tab();
- SCCOL nCol2 = aOutRange.aEnd.Col();
- SCROW nRow2 = aOutRange.aEnd.Row();
- SCTAB nTab2 = aOutRange.aEnd.Tab();
+ SCCOL nCol1 = maOutputRange.aStart.Col();
+ SCROW nRow1 = maOutputRange.aStart.Row();
+ SCTAB nTab1 = maOutputRange.aStart.Tab();
+ SCCOL nCol2 = maOutputRange.aEnd.Col();
+ SCROW nRow2 = maOutputRange.aEnd.Row();
+ SCTAB nTab2 = maOutputRange.aEnd.Tab();
ScRefUpdateRes eRes =
- ScRefUpdate::Update( pDoc, eUpdateRefMode,
+ ScRefUpdate::Update(mpDocument, eUpdateRefMode,
rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
@@ -1064,15 +1079,15 @@ void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode,
// sheet source data
- if ( !pSheetDesc )
+ if (!mpSheetDescription)
return;
- const OUString& rRangeName = pSheetDesc->GetRangeName();
+ const OUString& rRangeName = mpSheetDescription->GetRangeName();
if (!rRangeName.isEmpty())
// Source range is a named range. No need to update.
return;
- const ScRange& rSrcRange = pSheetDesc->GetSourceRange();
+ const ScRange& rSrcRange = mpSheetDescription->GetSourceRange();
nCol1 = rSrcRange.aStart.Col();
nRow1 = rSrcRange.aStart.Row();
nTab1 = rSrcRange.aStart.Tab();
@@ -1080,17 +1095,17 @@ void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode,
nRow2 = rSrcRange.aEnd.Row();
nTab2 = rSrcRange.aEnd.Tab();
- eRes = ScRefUpdate::Update( pDoc, eUpdateRefMode,
+ eRes = ScRefUpdate::Update(mpDocument, eUpdateRefMode,
rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
if ( eRes == UR_NOTHING )
return;
- SCCOL nDiffX = nCol1 - pSheetDesc->GetSourceRange().aStart.Col();
- SCROW nDiffY = nRow1 - pSheetDesc->GetSourceRange().aStart.Row();
+ SCCOL nDiffX = nCol1 - mpSheetDescription->GetSourceRange().aStart.Col();
+ SCROW nDiffY = nRow1 - mpSheetDescription->GetSourceRange().aStart.Row();
- ScQueryParam aParam = pSheetDesc->GetQueryParam();
+ ScQueryParam aParam = mpSheetDescription->GetQueryParam();
aParam.nCol1 = sal::static_int_cast<SCCOL>( aParam.nCol1 + nDiffX );
aParam.nCol2 = sal::static_int_cast<SCCOL>( aParam.nCol2 + nDiffX );
aParam.nRow1 += nDiffY; //TODO: used?
@@ -1100,21 +1115,21 @@ void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode,
if (aParam.GetEntry(i).bDoQuery)
aParam.GetEntry(i).nField += nDiffX;
- pSheetDesc->SetQueryParam(aParam);
- pSheetDesc->SetSourceRange(ScRange(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2));
+ mpSheetDescription->SetQueryParam(aParam);
+ mpSheetDescription->SetSourceRange(ScRange(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2));
}
-bool ScDPObject::RefsEqual( const ScDPObject& r ) const
+bool ScDPObject::RefsEqual( const ScDPObject& rOther) const
{
- if ( aOutRange != r.aOutRange )
+ if (maOutputRange != rOther.maOutputRange)
return false;
- if ( pSheetDesc && r.pSheetDesc )
+ if (mpSheetDescription && rOther.mpSheetDescription)
{
- if ( pSheetDesc->GetSourceRange() != r.pSheetDesc->GetSourceRange() )
+ if (mpSheetDescription->GetSourceRange() != rOther.mpSheetDescription->GetSourceRange())
return false;
}
- else if ( pSheetDesc || r.pSheetDesc )
+ else if (mpSheetDescription || rOther.mpSheetDescription)
{
OSL_FAIL("RefsEqual: SheetDesc set at only one object");
return false;
@@ -1123,17 +1138,17 @@ bool ScDPObject::RefsEqual( const ScDPObject& r ) const
return true;
}
-void ScDPObject::WriteRefsTo( ScDPObject& r ) const
+void ScDPObject::WriteRefsTo(ScDPObject& rObject) const
{
- r.SetOutRange( aOutRange );
- if ( pSheetDesc )
- r.SetSheetDesc( *pSheetDesc );
+ rObject.SetOutRange(maOutputRange);
+ if (mpSheetDescription)
+ rObject.SetSheetDesc(*mpSheetDescription);
}
void ScDPObject::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData)
{
CreateOutput();
- pOutput->GetPositionData(rPos, rPosData);
+ mpOutput->GetPositionData(rPos, rPosData);
}
bool ScDPObject::GetDataFieldPositionData(
@@ -1142,13 +1157,14 @@ bool ScDPObject::GetDataFieldPositionData(
CreateOutput();
vector<sheet::DataPilotFieldFilter> aFilters;
- if (!pOutput->GetDataResultPositionData(aFilters, rPos))
+ if (!mpOutput->GetDataResultPositionData(aFilters, rPos))
return false;
sal_Int32 n = static_cast<sal_Int32>(aFilters.size());
rFilters.realloc(n);
+ auto pFilters = rFilters.getArray();
for (sal_Int32 i = 0; i < n; ++i)
- rFilters[i] = aFilters[i];
+ pFilters[i] = aFilters[i];
return true;
}
@@ -1157,7 +1173,7 @@ void ScDPObject::GetDrillDownData(const ScAddress& rPos, Sequence< Sequence<Any>
{
CreateOutput();
- Reference<sheet::XDrillDownDataSupplier> xDrillDownData(xSource, UNO_QUERY);
+ uno::Reference<sheet::XDrillDownDataSupplier> xDrillDownData(mxSource, UNO_QUERY);
if (!xDrillDownData.is())
return;
@@ -1170,10 +1186,10 @@ void ScDPObject::GetDrillDownData(const ScAddress& rPos, Sequence< Sequence<Any>
bool ScDPObject::IsDimNameInUse(std::u16string_view rName) const
{
- if (!xSource.is())
+ if (!mxSource.is())
return false;
- Reference<container::XNameAccess> xDims = xSource->getDimensions();
+ Reference<container::XNameAccess> xDims = mxSource->getDimensions();
const Sequence<OUString> aDimNames = xDims->getElementNames();
for (const OUString& rDimName : aDimNames)
{
@@ -1197,9 +1213,9 @@ OUString ScDPObject::GetDimName( tools::Long nDim, bool& rIsDataLayout, sal_Int3
rIsDataLayout = false;
OUString aRet;
- if ( xSource.is() )
+ if (mxSource.is())
{
- uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XNameAccess> xDimsName = mxSource->getDimensions();
uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
tools::Long nDimCount = xDims->getCount();
if ( nDim < nDimCount )
@@ -1244,9 +1260,9 @@ OUString ScDPObject::GetDimName( tools::Long nDim, bool& rIsDataLayout, sal_Int3
bool ScDPObject::IsDuplicated( tools::Long nDim )
{
bool bDuplicated = false;
- if ( xSource.is() )
+ if (mxSource.is())
{
- uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XNameAccess> xDimsName = mxSource->getDimensions();
uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
tools::Long nDimCount = xDims->getCount();
if ( nDim < nDimCount )
@@ -1273,11 +1289,11 @@ bool ScDPObject::IsDuplicated( tools::Long nDim )
tools::Long ScDPObject::GetDimCount()
{
tools::Long nRet = 0;
- if ( xSource.is() )
+ if (mxSource.is())
{
try
{
- uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XNameAccess> xDimsName = mxSource->getDimensions();
if ( xDimsName.is() )
nRet = xDimsName->getElementNames().getLength();
}
@@ -1290,14 +1306,14 @@ tools::Long ScDPObject::GetDimCount()
void ScDPObject::GetHeaderPositionData(const ScAddress& rPos, DataPilotTableHeaderData& rData)
{
- CreateOutput(); // create xSource and pOutput if not already done
+ CreateOutput(); // create mxSource and mpOutput if not already done
// Reset member values to invalid state.
rData.Dimension = rData.Hierarchy = rData.Level = -1;
rData.Flags = 0;
DataPilotTablePositionData aPosData;
- pOutput->GetPositionData(rPos, aPosData);
+ mpOutput->GetPositionData(rPos, aPosData);
const sal_Int32 nPosType = aPosData.PositionType;
if (nPosType == css::sheet::DataPilotTablePositionType::COLUMN_HEADER || nPosType == css::sheet::DataPilotTablePositionType::ROW_HEADER)
aPosData.PositionData >>= rData;
@@ -1309,22 +1325,22 @@ class FindByName
{
OUString maName; // must be all uppercase.
public:
- explicit FindByName(const OUString& rName) : maName(rName) {}
+ explicit FindByName(OUString aName) : maName(std::move(aName)) {}
bool operator() (const ScDPSaveDimension* pDim) const
{
// Layout name takes precedence.
const std::optional<OUString> & pLayoutName = pDim->GetLayoutName();
- if (pLayoutName && ScGlobal::getCharClassPtr()->uppercase(*pLayoutName) == maName)
+ if (pLayoutName && ScGlobal::getCharClass().uppercase(*pLayoutName) == maName)
return true;
ScGeneralFunction eGenFunc = pDim->GetFunction();
ScSubTotalFunc eFunc = ScDPUtil::toSubTotalFunc(eGenFunc);
OUString aSrcName = ScDPUtil::getSourceDimensionName(pDim->GetName());
OUString aFuncName = ScDPUtil::getDisplayedMeasureName(aSrcName, eFunc);
- if (maName == ScGlobal::getCharClassPtr()->uppercase(aFuncName))
+ if (maName == ScGlobal::getCharClass().uppercase(aFuncName))
return true;
- return maName == ScGlobal::getCharClassPtr()->uppercase(aSrcName);
+ return maName == ScGlobal::getCharClass().uppercase(aSrcName);
}
};
@@ -1339,11 +1355,13 @@ public:
{
size_t nRank1 = mrDimOrder.size();
size_t nRank2 = mrDimOrder.size();
- ScDPSaveData::DimOrderType::const_iterator it1 = mrDimOrder.find(r1.FieldName);
+ ScDPSaveData::DimOrderType::const_iterator it1 = mrDimOrder.find(
+ ScGlobal::getCharClass().uppercase(r1.FieldName));
if (it1 != mrDimOrder.end())
nRank1 = it1->second;
- ScDPSaveData::DimOrderType::const_iterator it2 = mrDimOrder.find(r2.FieldName);
+ ScDPSaveData::DimOrderType::const_iterator it2 = mrDimOrder.find(
+ ScGlobal::getCharClass().uppercase(r2.FieldName));
if (it2 != mrDimOrder.end())
nRank2 = it2->second;
@@ -1355,74 +1373,80 @@ public:
double ScDPObject::GetPivotData(const OUString& rDataFieldName, std::vector<sheet::DataPilotFieldFilter>& rFilters)
{
- double fRet;
- rtl::math::setNan(&fRet);
if (!mbEnableGetPivotData)
- return fRet;
+ return std::numeric_limits<double>::quiet_NaN();
CreateObjects();
std::vector<const ScDPSaveDimension*> aDataDims;
- pSaveData->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_DATA, aDataDims);
+ mpSaveData->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_DATA, aDataDims);
if (aDataDims.empty())
- return fRet;
+ return std::numeric_limits<double>::quiet_NaN();
std::vector<const ScDPSaveDimension*>::iterator it = std::find_if(
aDataDims.begin(), aDataDims.end(),
- FindByName(ScGlobal::getCharClassPtr()->uppercase(rDataFieldName)));
+ FindByName(ScGlobal::getCharClass().uppercase(rDataFieldName)));
if (it == aDataDims.end())
- return fRet;
+ return std::numeric_limits<double>::quiet_NaN();
size_t nDataIndex = std::distance(aDataDims.begin(), it);
- uno::Reference<sheet::XDataPilotResults> xDPResults(xSource, uno::UNO_QUERY);
+ uno::Reference<sheet::XDataPilotResults> xDPResults(mxSource, uno::UNO_QUERY);
if (!xDPResults.is())
- return fRet;
+ return std::numeric_limits<double>::quiet_NaN();
// Dimensions must be sorted in order of appearance, and row dimensions
// must come before column dimensions.
- std::sort(rFilters.begin(), rFilters.end(), LessByDimOrder(pSaveData->GetDimensionSortOrder()));
+ std::sort(rFilters.begin(), rFilters.end(), LessByDimOrder(mpSaveData->GetDimensionSortOrder()));
size_t n = rFilters.size();
uno::Sequence<sheet::DataPilotFieldFilter> aFilters(n);
+ auto aFiltersRange = asNonConstRange(aFilters);
for (size_t i = 0; i < n; ++i)
- aFilters[i] = rFilters[i];
+ aFiltersRange[i] = rFilters[i];
uno::Sequence<double> aRes = xDPResults->getFilteredResults(aFilters);
- if (static_cast<sal_Int32>(nDataIndex) >= aRes.getLength())
- return fRet;
+ if (nDataIndex >= o3tl::make_unsigned(aRes.getLength()))
+ return std::numeric_limits<double>::quiet_NaN();
return aRes[nDataIndex];
}
bool ScDPObject::IsFilterButton( const ScAddress& rPos )
{
- CreateOutput(); // create xSource and pOutput if not already done
+ CreateOutput(); // create mxSource and mpOutput if not already done
- return pOutput->IsFilterButton( rPos );
+ return mpOutput->IsFilterButton( rPos );
}
tools::Long ScDPObject::GetHeaderDim( const ScAddress& rPos, sheet::DataPilotFieldOrientation& rOrient )
{
- CreateOutput(); // create xSource and pOutput if not already done
+ CreateOutput(); // create mxSource and mpOutput if not already done
- return pOutput->GetHeaderDim( rPos, rOrient );
+ return mpOutput->GetHeaderDim( rPos, rOrient );
}
bool ScDPObject::GetHeaderDrag( const ScAddress& rPos, bool bMouseLeft, bool bMouseTop, tools::Long nDragDim,
tools::Rectangle& rPosRect, sheet::DataPilotFieldOrientation& rOrient, tools::Long& rDimPos )
{
- CreateOutput(); // create xSource and pOutput if not already done
+ CreateOutput();// create mxSource and mpOutput if not already done
- return pOutput->GetHeaderDrag( rPos, bMouseLeft, bMouseTop, nDragDim, rPosRect, rOrient, rDimPos );
+ return mpOutput->GetHeaderDrag( rPos, bMouseLeft, bMouseTop, nDragDim, rPosRect, rOrient, rDimPos );
}
void ScDPObject::GetMemberResultNames(ScDPUniqueStringSet& rNames, tools::Long nDimension)
{
- CreateOutput(); // create xSource and pOutput if not already done
+ CreateOutput();// create mxSource and mpOutput if not already done
+
+ mpOutput->GetMemberResultNames(rNames, nDimension); // used only with table data -> level not needed
+}
- pOutput->GetMemberResultNames(rNames, nDimension); // used only with table data -> level not needed
+OUString ScDPObject::GetFormattedString(ScDPTableData* pTableData, tools::Long nDimension, const double fValue)
+{
+ ScDPItemData aItemData;
+ aItemData.SetValue(fValue);
+ return pTableData->GetFormattedString(nDimension, aItemData, false);
}
OUString ScDPObject::GetFormattedString(std::u16string_view rDimName, const double fValue)
@@ -1437,15 +1461,14 @@ OUString ScDPObject::GetFormattedString(std::u16string_view rDimName, const doub
if(rDimName == pTableData->getDimensionName(nDim))
break;
}
- ScDPItemData aItemData;
- aItemData.SetValue(fValue);
- return GetTableData()->GetFormattedString(nDim, aItemData, false);
+
+ return GetFormattedString(pTableData, nDim, fValue);
}
namespace {
-bool dequote( const OUString& rSource, sal_Int32 nStartPos, sal_Int32& rEndPos, OUString& rResult )
+bool dequote( std::u16string_view rSource, sal_Int32 nStartPos, sal_Int32& rEndPos, OUString& rResult )
{
// nStartPos has to point to opening quote
@@ -1455,7 +1478,7 @@ bool dequote( const OUString& rSource, sal_Int32 nStartPos, sal_Int32& rEndPos,
{
OUStringBuffer aBuffer;
sal_Int32 nPos = nStartPos + 1;
- const sal_Int32 nLen = rSource.getLength();
+ const sal_Int32 nLen = rSource.size();
while ( nPos < nLen )
{
@@ -1493,7 +1516,7 @@ struct ScGetPivotDataFunctionEntry
sal_Int16 eFunc;
};
-bool parseFunction( const OUString& rList, sal_Int32 nStartPos, sal_Int32& rEndPos, sal_Int16& rFunc )
+bool parseFunction( std::u16string_view rList, sal_Int32 nStartPos, sal_Int32& rEndPos, sal_Int16& rFunc )
{
static const ScGetPivotDataFunctionEntry aFunctions[] =
{
@@ -1515,7 +1538,7 @@ bool parseFunction( const OUString& rList, sal_Int32 nStartPos, sal_Int32& rEndP
{ "StdDevp", sheet::GeneralFunction2::STDEVP }
};
- const sal_Int32 nListLen = rList.getLength();
+ const sal_Int32 nListLen = rList.size();
while (nStartPos < nListLen && rList[nStartPos] == ' ')
++nStartPos;
@@ -1527,10 +1550,10 @@ bool parseFunction( const OUString& rList, sal_Int32 nStartPos, sal_Int32& rEndP
bParsed = dequote( rList, nStartPos, nFuncEnd, aFuncStr );
else
{
- nFuncEnd = rList.indexOf(']', nStartPos);
+ nFuncEnd = rList.find(']', nStartPos);
if (nFuncEnd >= 0)
{
- aFuncStr = rList.copy(nStartPos, nFuncEnd - nStartPos);
+ aFuncStr = rList.substr(nStartPos, nFuncEnd - nStartPos);
bParsed = true;
}
}
@@ -1557,10 +1580,10 @@ bool parseFunction( const OUString& rList, sal_Int32 nStartPos, sal_Int32& rEndP
return bFound;
}
-bool extractAtStart( const OUString& rList, sal_Int32& rMatched, bool bAllowBracket, sal_Int16* pFunc,
+bool extractAtStart( std::u16string_view rList, sal_Int32& rMatched, bool bAllowBracket, sal_Int16* pFunc,
OUString& rDequoted )
{
- sal_Int32 nMatchList = 0;
+ size_t nMatchList = 0;
sal_Unicode cFirst = rList[0];
bool bParsed = false;
if ( cFirst == '\'' || cFirst == '[' )
@@ -1577,7 +1600,7 @@ bool extractAtStart( const OUString& rList, sal_Int32& rMatched, bool bAllowBrac
// skip spaces after the opening bracket
sal_Int32 nStartPos = 1;
- const sal_Int32 nListLen = rList.getLength();
+ const sal_Int32 nListLen = rList.size();
while (nStartPos < nListLen && rList[nStartPos] == ' ')
++nStartPos;
@@ -1608,11 +1631,11 @@ bool extractAtStart( const OUString& rList, sal_Int32& rMatched, bool bAllowBrac
{
// implicit quoting to the closing bracket
- sal_Int32 nClosePos = rList.indexOf(']', nStartPos);
+ sal_Int32 nClosePos = rList.find(']', nStartPos);
if (nClosePos >= 0)
{
sal_Int32 nNameEnd = nClosePos;
- sal_Int32 nSemiPos = rList.indexOf(';', nStartPos);
+ sal_Int32 nSemiPos = rList.find(';', nStartPos);
if (nSemiPos >= 0 && nSemiPos < nClosePos && pFunc)
{
sal_Int32 nFuncEnd = 0;
@@ -1620,7 +1643,7 @@ bool extractAtStart( const OUString& rList, sal_Int32& rMatched, bool bAllowBrac
nNameEnd = nSemiPos;
}
- aDequoted = rList.copy(nStartPos, nNameEnd - nStartPos);
+ aDequoted = rList.substr(nStartPos, nNameEnd - nStartPos);
// spaces before the closing bracket or semicolon
aDequoted = comphelper::string::stripEnd(aDequoted, ' ');
nQuoteEnd = nClosePos + 1;
@@ -1641,7 +1664,7 @@ bool extractAtStart( const OUString& rList, sal_Int32& rMatched, bool bAllowBrac
// look for following space or end of string
bool bValid = false;
- if ( sal::static_int_cast<sal_Int32>(nMatchList) >= rList.getLength() )
+ if ( nMatchList >= rList.size() )
bValid = true;
else
{
@@ -1671,7 +1694,7 @@ bool isAtStart(
{
OUString aDequoted;
bool bParsed = extractAtStart( rList, rMatched, bAllowBracket, pFunc, aDequoted);
- if ( bParsed && ScGlobal::GetpTransliteration()->isEqual( aDequoted, rSearch ) )
+ if ( bParsed && ScGlobal::GetTransliteration().isEqual( aDequoted, rSearch ) )
{
nMatchList = rMatched; // match count in the list string, including quotes
nMatchSearch = rSearch.getLength();
@@ -1680,7 +1703,7 @@ bool isAtStart(
else
{
// otherwise look for search string at the start of rList
- ScGlobal::GetpTransliteration()->equals(
+ ScGlobal::GetTransliteration().equals(
rList, 0, rList.getLength(), nMatchList, rSearch, 0, rSearch.getLength(), nMatchSearch);
}
@@ -1717,7 +1740,7 @@ bool ScDPObject::ParseFilters(
{
// parse the string rFilterList into parameters for GetPivotData
- CreateObjects(); // create xSource if not already done
+ CreateObjects(); // create mxSource if not already done
std::vector<OUString> aDataNames; // data fields (source name)
std::vector<OUString> aGivenNames; // data fields (compound name)
@@ -1727,7 +1750,7 @@ bool ScDPObject::ParseFilters(
// get all the field and item names
- uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XNameAccess> xDimsName = mxSource->getDimensions();
uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
sal_Int32 nDimCount = xIntDims->getCount();
for ( sal_Int32 nDim = 0; nDim<nDimCount; nDim++ )
@@ -1875,16 +1898,13 @@ bool ScDPObject::ParseFilters(
OUString aQueryValue = aQueryValueName;
if (mpTableData)
{
- SvNumberFormatter* pFormatter = mpTableData->GetCacheTable().getCache().GetNumberFormatter();
- if (pFormatter)
- {
- // Parse possible number from aQueryValueName and format
- // locale independent as aQueryValue.
- sal_uInt32 nNumFormat = 0;
- double fValue;
- if (pFormatter->IsNumberFormat( aQueryValueName, nNumFormat, fValue))
- aQueryValue = ScDPCache::GetLocaleIndependentFormattedString( fValue, *pFormatter, nNumFormat);
- }
+ ScInterpreterContext& rContext = mpTableData->GetCacheTable().getCache().GetInterpreterContext();
+ // Parse possible number from aQueryValueName and format
+ // locale independent as aQueryValue.
+ sal_uInt32 nNumFormat = 0;
+ double fValue;
+ if (rContext.NFIsNumberFormat(aQueryValueName, nNumFormat, fValue))
+ aQueryValue = ScDPCache::GetLocaleIndependentFormattedString(fValue, rContext, nNumFormat);
}
for ( SCSIZE nField=0; nField<nFieldCount; nField++ )
@@ -1905,10 +1925,10 @@ bool ScDPObject::ParseFilters(
if (bHasQuery)
{
// First check given value name against both.
- bThisItemFound = ScGlobal::GetpTransliteration()->isEqual(
+ bThisItemFound = ScGlobal::GetTransliteration().isEqual(
aQueryValueName, pItemNamesArr[nItem]);
if (!bThisItemFound && pItemValuesArr[nItem] != pItemNamesArr[nItem])
- bThisItemFound = ScGlobal::GetpTransliteration()->isEqual(
+ bThisItemFound = ScGlobal::GetTransliteration().isEqual(
aQueryValueName, pItemValuesArr[nItem]);
if (!bThisItemFound && aQueryValueName != aQueryValue)
{
@@ -1916,10 +1936,10 @@ bool ScDPObject::ParseFilters(
// against both.
/* TODO: or check only value string against
* value string, not against the value name? */
- bThisItemFound = ScGlobal::GetpTransliteration()->isEqual(
+ bThisItemFound = ScGlobal::GetTransliteration().isEqual(
aQueryValue, pItemNamesArr[nItem]);
if (!bThisItemFound && pItemValuesArr[nItem] != pItemNamesArr[nItem])
- bThisItemFound = ScGlobal::GetpTransliteration()->isEqual(
+ bThisItemFound = ScGlobal::GetTransliteration().isEqual(
aQueryValue, pItemValuesArr[nItem]);
}
}
@@ -1985,12 +2005,12 @@ bool ScDPObject::ParseFilters(
void ScDPObject::ToggleDetails(const DataPilotTableHeaderData& rElemDesc, ScDPObject* pDestObj)
{
- CreateObjects(); // create xSource if not already done
+ CreateObjects(); // create mxSource if not already done
// find dimension name
uno::Reference<container::XNamed> xDim;
- uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XNameAccess> xDimsName = mxSource->getDimensions();
uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
tools::Long nIntCount = xIntDims->getCount();
if ( rElemDesc.Dimension < nIntCount )
@@ -2072,7 +2092,7 @@ void ScDPObject::ToggleDetails(const DataPilotTableHeaderData& rElemDesc, ScDPOb
//TODO: use Hierarchy and Level in SaveData !!!!
// modify pDestObj if set, this object otherwise
- ScDPSaveData* pModifyData = pDestObj ? ( pDestObj->pSaveData.get() ) : pSaveData.get();
+ ScDPSaveData* pModifyData = pDestObj ? ( pDestObj->mpSaveData.get() ) : mpSaveData.get();
OSL_ENSURE( pModifyData, "no data?" );
if ( pModifyData )
{
@@ -2284,27 +2304,27 @@ static void lcl_FillOldFields( ScPivotFieldVector& rFields,
void ScDPObject::FillOldParam(ScPivotParam& rParam) const
{
- const_cast<ScDPObject*>(this)->CreateObjects(); // xSource is needed for field numbers
+ const_cast<ScDPObject*>(this)->CreateObjects(); // mxSource is needed for field numbers
- if (!xSource.is())
+ if (!mxSource.is())
return;
- rParam.nCol = aOutRange.aStart.Col();
- rParam.nRow = aOutRange.aStart.Row();
- rParam.nTab = aOutRange.aStart.Tab();
+ rParam.nCol = maOutputRange.aStart.Col();
+ rParam.nRow = maOutputRange.aStart.Row();
+ rParam.nTab = maOutputRange.aStart.Tab();
// ppLabelArr / nLabels is not changed
- bool bAddData = ( lcl_GetDataGetOrientation( xSource ) == sheet::DataPilotFieldOrientation_HIDDEN );
+ bool bAddData = lcl_GetDataGetOrientation(mxSource) == sheet::DataPilotFieldOrientation_HIDDEN;
lcl_FillOldFields(
- rParam.maPageFields, xSource, sheet::DataPilotFieldOrientation_PAGE, false);
+ rParam.maPageFields, mxSource, sheet::DataPilotFieldOrientation_PAGE, false);
lcl_FillOldFields(
- rParam.maColFields, xSource, sheet::DataPilotFieldOrientation_COLUMN, bAddData);
+ rParam.maColFields, mxSource, sheet::DataPilotFieldOrientation_COLUMN, bAddData);
lcl_FillOldFields(
- rParam.maRowFields, xSource, sheet::DataPilotFieldOrientation_ROW, false);
+ rParam.maRowFields, mxSource, sheet::DataPilotFieldOrientation_ROW, false);
lcl_FillOldFields(
- rParam.maDataFields, xSource, sheet::DataPilotFieldOrientation_DATA, false);
+ rParam.maDataFields, mxSource, sheet::DataPilotFieldOrientation_DATA, false);
- uno::Reference<beans::XPropertySet> xProp( xSource, uno::UNO_QUERY );
+ uno::Reference<beans::XPropertySet> xProp(mxSource, uno::UNO_QUERY);
if (!xProp.is())
return;
@@ -2435,10 +2455,10 @@ void ScDPObject::FillLabelDataForDimension(
void ScDPObject::FillLabelData(sal_Int32 nDim, ScDPLabelData& rLabels)
{
CreateObjects();
- if (!xSource.is())
+ if (!mxSource.is())
return;
- uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XNameAccess> xDimsName = mxSource->getDimensions();
uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
sal_Int32 nDimCount = xDims->getCount();
if (nDimCount <= 0 || nDim >= nDimCount)
@@ -2452,10 +2472,10 @@ void ScDPObject::FillLabelData(ScPivotParam& rParam)
rParam.maLabelArray.clear();
CreateObjects();
- if (!xSource.is())
+ if (!mxSource.is())
return;
- uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XNameAccess> xDimsName = mxSource->getDimensions();
uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
sal_Int32 nDimCount = xDims->getCount();
if (nDimCount <= 0)
@@ -2469,6 +2489,34 @@ void ScDPObject::FillLabelData(ScPivotParam& rParam)
}
}
+void ScDPObject::GetFieldIdsNames(sheet::DataPilotFieldOrientation nOrient, std::vector<tools::Long>& rIndices,
+ std::vector<OUString>& rNames)
+{
+ CreateObjects();
+ if (!mxSource.is())
+ return;
+
+ uno::Reference<container::XNameAccess> xDimsName = mxSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
+ tools::Long nDimCount = xDims->getCount();
+ for (tools::Long nDim = 0; nDim < nDimCount; ++nDim)
+ {
+ uno::Reference<uno::XInterface> xIntDim(xDims->getByIndex(nDim), uno::UNO_QUERY);
+ uno::Reference<container::XNamed> xDimName(xIntDim, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xDimProp(xIntDim, uno::UNO_QUERY);
+
+ sheet::DataPilotFieldOrientation nDimOrient = ScUnoHelpFunctions::GetEnumProperty(
+ xDimProp, SC_UNO_DP_ORIENTATION,
+ sheet::DataPilotFieldOrientation_HIDDEN );
+
+ if ( xDimProp.is() && nDimOrient == nOrient)
+ {
+ rIndices.push_back(nDim);
+ rNames.push_back(xDimName->getName());
+ }
+ }
+}
+
bool ScDPObject::GetHierarchiesNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xHiers )
{
bool bRet = false;
@@ -2679,7 +2727,7 @@ void ScDPObject::ConvertOrientation(
nSubTotalFuncs.push_back( ScDataPilotConversion::FirstFunc( static_cast<PivotFunc>(nMask) ) );
nMask *= 2;
}
- pDim->SetSubTotals( nSubTotalFuncs );
+ pDim->SetSubTotals( std::move(nSubTotalFuncs) );
// ShowEmpty was implicit in old tables,
// must be set for data layout dimension (not accessible in dialog)
@@ -2853,8 +2901,8 @@ uno::Reference<sheet::XDimensionsSupplier> ScDPObject::CreateSource( const ScDPS
void ScDPObject::Dump() const
{
- if (pSaveData)
- pSaveData->Dump();
+ if (mpSaveData)
+ mpSaveData->Dump();
if (mpTableData)
mpTableData->Dump();
@@ -3157,8 +3205,8 @@ bool ScDPCollection::NameCaches::remove(const ScDPCache* p)
return false;
}
-ScDPCollection::DBType::DBType(sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand) :
- mnSdbType(nSdbType), maDBName(rDBName), maCommand(rCommand) {}
+ScDPCollection::DBType::DBType(sal_Int32 nSdbType, OUString aDBName, OUString aCommand) :
+ mnSdbType(nSdbType), maDBName(std::move(aDBName)), maCommand(std::move(aCommand)) {}
bool ScDPCollection::DBType::less::operator() (const DBType& left, const DBType& right) const
{
@@ -3232,7 +3280,7 @@ uno::Reference<sdbc::XRowSet> ScDPCollection::DBCaches::createRowSet(
OSL_ENSURE( xRowProp.is(), "can't get RowSet" );
if (!xRowProp.is())
{
- xRowSet.set(nullptr);
+ xRowSet.clear();
return xRowSet;
}
@@ -3268,7 +3316,7 @@ uno::Reference<sdbc::XRowSet> ScDPCollection::DBCaches::createRowSet(
TOOLS_WARN_EXCEPTION( "sc", "Unexpected exception in database");
}
- xRowSet.set(nullptr);
+ xRowSet.clear();
return xRowSet;
}
@@ -3367,7 +3415,7 @@ public:
}
-const char* ScDPCollection::ReloadCache(const ScDPObject* pDPObj, o3tl::sorted_vector<ScDPObject*>& rRefs)
+TranslateId ScDPCollection::ReloadCache(const ScDPObject* pDPObj, o3tl::sorted_vector<ScDPObject*>& rRefs)
{
if (!pDPObj)
return STR_ERR_DATAPILOTSOURCE;
@@ -3379,7 +3427,7 @@ const char* ScDPCollection::ReloadCache(const ScDPObject* pDPObj, o3tl::sorted_v
if (!pDesc)
return STR_ERR_DATAPILOTSOURCE;
- const char* pErrId = pDesc->CheckSourceRange();
+ TranslateId pErrId = pDesc->CheckSourceRange();
if (pErrId)
return pErrId;
@@ -3428,7 +3476,7 @@ const char* ScDPCollection::ReloadCache(const ScDPObject* pDPObj, o3tl::sorted_v
GetAllTables(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, rRefs);
}
}
- return nullptr;
+ return {};
}
bool ScDPCollection::ReloadGroupsInCache(const ScDPObject* pDPObj, o3tl::sorted_vector<ScDPObject*>& rRefs)
@@ -3586,7 +3634,7 @@ bool ScDPCollection::GetReferenceGroups(const ScDPObject& rDPObj, const ScDPDime
void ScDPCollection::DeleteOnTab( SCTAB nTab )
{
- maTables.erase( std::remove_if(maTables.begin(), maTables.end(), MatchByTable(nTab)), maTables.end());
+ std::erase_if(maTables, MatchByTable(nTab));
}
void ScDPCollection::UpdateReference( UpdateRefMode eUpdateRefMode,
@@ -3605,17 +3653,17 @@ void ScDPCollection::CopyToTab( SCTAB nOld, SCTAB nNew )
for (const auto& rxTable : maTables)
{
const ScDPObject& rObj = *rxTable;
- ScRange aOutRange = rObj.GetOutRange();
- if (aOutRange.aStart.Tab() != nOld)
+ ScRange maOutputRange = rObj.GetOutRange();
+ if (maOutputRange.aStart.Tab() != nOld)
continue;
- ScAddress& s = aOutRange.aStart;
- ScAddress& e = aOutRange.aEnd;
- s.SetTab(nNew);
- e.SetTab(nNew);
+ ScAddress& start = maOutputRange.aStart;
+ ScAddress& end = maOutputRange.aEnd;
+ start.SetTab(nNew);
+ end.SetTab(nNew);
ScDPObject* pNew = new ScDPObject(rObj);
- pNew->SetOutRange(aOutRange);
- mrDoc.ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), ScMF::DpTable);
+ pNew->SetOutRange(maOutputRange);
+ mrDoc.ApplyFlagsTab(start.Col(), start.Row(), end.Col(), end.Row(), start.Tab(), ScMF::DpTable);
aAdded.push_back(std::unique_ptr<ScDPObject>(pNew));
}
@@ -3724,7 +3772,7 @@ void ScDPCollection::FreeTable(const ScDPObject* pDPObject)
return pCurrent.get() == pDPObject;
};
- maTables.erase(std::remove_if(maTables.begin(), maTables.end(), funcRemoveCondition), maTables.end());
+ std::erase_if(maTables, funcRemoveCondition);
}
ScDPObject* ScDPCollection::InsertNewTable(std::unique_ptr<ScDPObject> pDPObj)
diff --git a/sc/source/core/data/dpoutput.cxx b/sc/source/core/data/dpoutput.cxx
index fe54b7c1086c..1b20d6fc3a56 100644
--- a/sc/source/core/data/dpoutput.cxx
+++ b/sc/source/core/data/dpoutput.cxx
@@ -18,6 +18,8 @@
*/
#include <scitems.hxx>
+
+#include <comphelper/sequence.hxx>
#include <editeng/borderline.hxx>
#include <editeng/boxitem.hxx>
#include <editeng/wghtitem.hxx>
@@ -27,6 +29,7 @@
#include <svl/itemset.hxx>
#include <dpoutput.hxx>
+#include <dpobject.hxx>
#include <document.hxx>
#include <attrib.hxx>
#include <formula/errorcodes.hxx>
@@ -39,6 +42,7 @@
#include <strings.hrc>
#include <stringutil.hxx>
#include <dputil.hxx>
+#include <pivot/DPOutLevelData.hxx>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
@@ -57,9 +61,14 @@
#include <com/sun/star/sheet/XLevelsSupplier.hpp>
#include <com/sun/star/sheet/XMembersAccess.hpp>
#include <com/sun/star/sheet/XMembersSupplier.hpp>
+#include <com/sun/star/sheet/DataPilotFieldLayoutInfo.hpp>
+#include <com/sun/star/sheet/DataPilotFieldLayoutMode.hpp>
+#include <limits>
#include <string_view>
+#include <utility>
#include <vector>
+#include <iostream>
using namespace com::sun::star;
using ::std::vector;
@@ -75,43 +84,17 @@ using ::com::sun::star::sheet::DataPilotTableResultData;
#define SC_DP_FRAME_COLOR Color(0,0,0) //( 0x20, 0x40, 0x68 )
-struct ScDPOutLevelData
+namespace
+{
+struct ScDPOutLevelDataComparator
{
- tools::Long mnDim;
- tools::Long mnHier;
- tools::Long mnLevel;
- tools::Long mnDimPos;
- sal_uInt32 mnSrcNumFmt; /// Prevailing number format used in the source data.
- uno::Sequence<sheet::MemberResult> maResult;
- OUString maName; /// Name is the internal field name.
- OUString maCaption; /// Caption is the name visible in the output table.
- bool mbHasHiddenMember:1;
- bool mbDataLayout:1;
- bool mbPageDim:1;
-
- ScDPOutLevelData(tools::Long nDim, tools::Long nHier, tools::Long nLevel, tools::Long nDimPos, sal_uInt32 nSrcNumFmt, const uno::Sequence<sheet::MemberResult> &aResult,
- const OUString &aName, const OUString &aCaption, bool bHasHiddenMember, bool bDataLayout, bool bPageDim) :
- mnDim(nDim), mnHier(nHier), mnLevel(nLevel), mnDimPos(nDimPos), mnSrcNumFmt(nSrcNumFmt), maResult(aResult),
- maName(aName), maCaption(aCaption), mbHasHiddenMember(bHasHiddenMember), mbDataLayout(bDataLayout),
- mbPageDim(bPageDim)
+ bool operator()(const ScDPOutLevelData & rA, const ScDPOutLevelData & rB)
{
+ return rA.mnDimPos<rB.mnDimPos || ( rA.mnDimPos==rB.mnDimPos && rA.mnHier<rB.mnHier ) ||
+ ( rA.mnDimPos==rB.mnDimPos && rA.mnHier==rB.mnHier && rA.mnLevel<rB.mnLevel );
}
-
- // bug (73840) in uno::Sequence - copy and then assign doesn't work!
};
-
-
-
-namespace {
- struct ScDPOutLevelDataComparator
- {
- bool operator()(const ScDPOutLevelData & rA, const ScDPOutLevelData & rB)
- {
- return rA.mnDimPos<rB.mnDimPos || ( rA.mnDimPos==rB.mnDimPos && rA.mnHier<rB.mnHier ) ||
- ( rA.mnDimPos==rB.mnDimPos && rA.mnHier==rB.mnHier && rA.mnLevel<rB.mnLevel );
- }
- };
-
+} // end anonymous namespace
class ScDPOutputImpl
{
@@ -281,9 +264,12 @@ void ScDPOutputImpl::OutputBlockFrame ( SCCOL nStartCol, SCROW nStartRow, SCCOL
}
+namespace
+{
+
void lcl_SetStyleById(ScDocument* pDoc, SCTAB nTab,
SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
- const char* pStrId)
+ TranslateId pStrId)
{
if ( nCol1 > nCol2 || nRow1 > nRow2 )
{
@@ -302,12 +288,12 @@ void lcl_SetStyleById(ScDocument* pDoc, SCTAB nTab,
SfxStyleSearchBits::UserDefined ) );
pStyle->SetParent( ScResId(STR_STYLENAME_STANDARD) );
SfxItemSet& rSet = pStyle->GetItemSet();
- if (strcmp(pStrId, STR_PIVOT_STYLENAME_RESULT) == 0 || strcmp(pStrId, STR_PIVOT_STYLENAME_TITLE) == 0){
+ if (pStrId == STR_PIVOT_STYLENAME_RESULT || pStrId == STR_PIVOT_STYLENAME_TITLE){
rSet.Put( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) );
rSet.Put( SvxWeightItem( WEIGHT_BOLD, ATTR_CJK_FONT_WEIGHT ) );
rSet.Put( SvxWeightItem( WEIGHT_BOLD, ATTR_CTL_FONT_WEIGHT ) );
}
- if (strcmp(pStrId, STR_PIVOT_STYLENAME_CATEGORY) == 0 || strcmp(pStrId, STR_PIVOT_STYLENAME_TITLE) == 0)
+ if (pStrId == STR_PIVOT_STYLENAME_CATEGORY || pStrId == STR_PIVOT_STYLENAME_TITLE)
rSet.Put( SvxHorJustifyItem( SvxCellHorJustify::Left, ATTR_HOR_JUSTIFY ) );
}
@@ -486,48 +472,50 @@ uno::Sequence<sheet::MemberResult> getVisiblePageMembersAsResults( const uno::Re
if (bVisible)
{
/* TODO: any numeric value to obtain? */
- double fValue;
- rtl::math::setNan(&fValue);
- aRes.emplace_back(rName, aCaption, 0, fValue);
+ aRes.emplace_back(rName, aCaption, 0, std::numeric_limits<double>::quiet_NaN());
}
}
- if (aNames.getLength() == static_cast<sal_Int32>(aRes.size()))
+ if (o3tl::make_unsigned(aNames.getLength()) == aRes.size())
// All members are visible. Return empty result.
return uno::Sequence<sheet::MemberResult>();
- return ScUnoHelpFunctions::VectorToSequence(aRes);
+ return comphelper::containerToSequence(aRes);
}
-}
-
-ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference<sheet::XDimensionsSupplier>& xSrc,
- const ScAddress& rPos, bool bFilter ) :
- pDoc( pD ),
- xSource( xSrc ),
- aStartPos( rPos ),
- nColFmtCount( 0 ),
- nRowFmtCount( 0 ),
- nSingleNumFmt( 0 ),
- nColCount(0),
- nRowCount(0),
- nHeaderSize(0),
- bDoFilter(bFilter),
- bResultsError(false),
- bSizesValid(false),
- bSizeOverflow(false),
- mbHeaderLayout(false)
+} // end anonymous namespace
+
+ScDPOutput::ScDPOutput(ScDocument* pDocument, uno::Reference<sheet::XDimensionsSupplier> xSource,
+ const ScAddress& rPosition, bool bFilter, bool bExpandCollapse, ScDPObject& rObject)
+ : mpDocument(pDocument)
+ , maFormatOutput(rObject)
+ , mxSource(std::move(xSource))
+ , maStartPos(rPosition)
+ , mnColFormatCount(0)
+ , mnRowFormatCount(0)
+ , mnSingleNumberFormat(0)
+ , mnRowDims(0)
+ , mnColCount(0)
+ , mnRowCount(0)
+ , mnHeaderSize(0)
+ , mbDoFilter(bFilter)
+ , mbResultsError(false)
+ , mbSizesValid(false)
+ , mbSizeOverflow(false)
+ , mbHeaderLayout(false)
+ , mbHasCompactRowField(false)
+ , mbExpandCollapse(bExpandCollapse)
{
- nTabStartCol = nMemberStartCol = nDataStartCol = nTabEndCol = 0;
- nTabStartRow = nMemberStartRow = nDataStartRow = nTabEndRow = 0;
+ mnTabStartCol = mnMemberStartCol = mnDataStartCol = mnTabEndCol = 0;
+ mnTabStartRow = mnMemberStartRow = mnDataStartRow = mnTabEndRow = 0;
- uno::Reference<sheet::XDataPilotResults> xResult( xSource, uno::UNO_QUERY );
- if ( xSource.is() && xResult.is() )
+ uno::Reference<sheet::XDataPilotResults> xResult(mxSource, uno::UNO_QUERY);
+ if (mxSource.is() && xResult.is())
{
// get dimension results:
uno::Reference<container::XIndexAccess> xDims =
- new ScNameToIndexAccess( xSource->getDimensions() );
+ new ScNameToIndexAccess(mxSource->getDimensions());
tools::Long nDimCount = xDims->getCount();
for (tools::Long nDim=0; nDim<nDimCount; nDim++)
{
@@ -590,30 +578,45 @@ ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference<sheet::XDimensionsS
uno::Sequence<sheet::MemberResult> aResult = xLevRes->getResults();
if (!lcl_MemberEmpty(aResult))
{
- ScDPOutLevelData tmp(nDim, nHierarchy, nLev, nDimPos, nNumFmt, aResult, aName,
- aCaption, bHasHiddenMember, bIsDataLayout, false);
- pColFields.push_back(tmp);
+ mpColFields.emplace_back(nDim, nHierarchy, nLev, nDimPos, nNumFmt, aResult, aName,
+ aCaption, bHasHiddenMember, bIsDataLayout, false);
}
}
break;
case sheet::DataPilotFieldOrientation_ROW:
{
uno::Sequence<sheet::MemberResult> aResult = xLevRes->getResults();
- if (!lcl_MemberEmpty(aResult))
+ ++mnRowDims;
+ // We want only to remove the DATA column if it is empty
+ // and not any other empty columns (to still show the
+ // header columns)
+ bool bSkip = lcl_MemberEmpty(aResult) && bIsDataLayout;
+ if (!bSkip)
{
- ScDPOutLevelData tmp(nDim, nHierarchy, nLev, nDimPos, nNumFmt, aResult, aName,
- aCaption, bHasHiddenMember, bIsDataLayout, false);
- pRowFields.push_back(tmp);
+ bool bFieldCompact = false;
+ try
+ {
+ sheet::DataPilotFieldLayoutInfo aLayoutInfo;
+ xPropSet->getPropertyValue( SC_UNO_DP_LAYOUT ) >>= aLayoutInfo;
+ bFieldCompact = (aLayoutInfo.LayoutMode == sheet::DataPilotFieldLayoutMode::COMPACT_LAYOUT);
+ }
+ catch (uno::Exception&)
+ {
+ }
+ mpRowFields.emplace_back(nDim, nHierarchy, nLev, nDimPos, nNumFmt, aResult, aName,
+ aCaption, bHasHiddenMember, bIsDataLayout, false);
+ maRowCompactFlags.push_back(bFieldCompact);
+ mbHasCompactRowField |= bFieldCompact;
}
+
}
break;
case sheet::DataPilotFieldOrientation_PAGE:
{
uno::Sequence<sheet::MemberResult> aResult = getVisiblePageMembersAsResults(xLevel);
// no check on results for page fields
- ScDPOutLevelData tmp(nDim, nHierarchy, nLev, nDimPos, nNumFmt, aResult, aName,
- aCaption, bHasHiddenMember, false, true);
- pPageFields.push_back(tmp);
+ mpPageFields.emplace_back(nDim, nHierarchy, nLev, nDimPos, nNumFmt, aResult, aName,
+ aCaption, bHasHiddenMember, false, true);
}
break;
default:
@@ -627,9 +630,9 @@ ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference<sheet::XDimensionsS
{
OSL_ENSURE( nLevCount == 1, "data layout: multiple levels?" );
if ( eDimOrient == sheet::DataPilotFieldOrientation_COLUMN )
- lcl_FillNumberFormats( pColNumFmt, nColFmtCount, xLevRes, xDims );
+ lcl_FillNumberFormats(mpColNumberFormat, mnColFormatCount, xLevRes, xDims);
else if ( eDimOrient == sheet::DataPilotFieldOrientation_ROW )
- lcl_FillNumberFormats( pRowNumFmt, nRowFmtCount, xLevRes, xDims );
+ lcl_FillNumberFormats(mpRowNumberFormat, mnRowFormatCount, xLevRes, xDims);
}
}
}
@@ -640,29 +643,29 @@ ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference<sheet::XDimensionsS
// data layout dimension is hidden (allowed if there is only one data dimension)
// -> use the number format from the first data dimension for all results
- nSingleNumFmt = lcl_GetFirstNumberFormat( xDims );
+ mnSingleNumberFormat = lcl_GetFirstNumberFormat( xDims );
}
}
}
- std::sort(pColFields.begin(), pColFields.end(), ScDPOutLevelDataComparator());
- std::sort(pRowFields.begin(), pRowFields.end(), ScDPOutLevelDataComparator());
- std::sort(pPageFields.begin(), pPageFields.end(), ScDPOutLevelDataComparator());
+ std::sort(mpColFields.begin(), mpColFields.end(), ScDPOutLevelDataComparator());
+ std::sort(mpRowFields.begin(), mpRowFields.end(), ScDPOutLevelDataComparator());
+ std::sort(mpPageFields.begin(), mpPageFields.end(), ScDPOutLevelDataComparator());
// get data results:
try
{
- aData = xResult->getResults();
+ maData = xResult->getResults();
}
catch (const uno::RuntimeException&)
{
- bResultsError = true;
+ mbResultsError = true;
}
}
// get "DataDescription" property (may be missing in external sources)
- uno::Reference<beans::XPropertySet> xSrcProp( xSource, uno::UNO_QUERY );
+ uno::Reference<beans::XPropertySet> xSrcProp(mxSource, uno::UNO_QUERY);
if ( !xSrcProp.is() )
return;
@@ -671,7 +674,7 @@ ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference<sheet::XDimensionsS
uno::Any aAny = xSrcProp->getPropertyValue( SC_UNO_DP_DATADESC );
OUString aUStr;
aAny >>= aUStr;
- aDataDescription = aUStr;
+ maDataDescription = aUStr;
}
catch(const uno::Exception&)
{
@@ -682,10 +685,10 @@ ScDPOutput::~ScDPOutput()
{
}
-void ScDPOutput::SetPosition( const ScAddress& rPos )
+void ScDPOutput::SetPosition(const ScAddress& rPosition)
{
- aStartPos = rPos;
- bSizesValid = bSizeOverflow = false;
+ maStartPos = rPosition;
+ mbSizesValid = mbSizeOverflow = false;
}
void ScDPOutput::DataCell( SCCOL nCol, SCROW nRow, SCTAB nTab, const sheet::DataResult& rData )
@@ -693,49 +696,49 @@ void ScDPOutput::DataCell( SCCOL nCol, SCROW nRow, SCTAB nTab, const sheet::Data
tools::Long nFlags = rData.Flags;
if ( nFlags & sheet::DataResultFlags::ERROR )
{
- pDoc->SetError( nCol, nRow, nTab, FormulaError::NoValue );
+ mpDocument->SetError( nCol, nRow, nTab, FormulaError::NoValue );
}
else if ( nFlags & sheet::DataResultFlags::HASDATA )
{
- pDoc->SetValue( nCol, nRow, nTab, rData.Value );
+ mpDocument->SetValue( nCol, nRow, nTab, rData.Value );
// use number formats from source
- OSL_ENSURE( bSizesValid, "DataCell: !bSizesValid" );
+ OSL_ENSURE(mbSizesValid, "DataCell: !bSizesValid");
sal_uInt32 nFormat = 0;
bool bApplyFormat = false;
- if ( pColNumFmt )
+ if (mpColNumberFormat)
{
- if ( nCol >= nDataStartCol )
+ if (nCol >= mnDataStartCol)
{
- tools::Long nIndex = nCol - nDataStartCol;
- if ( nIndex < nColFmtCount )
+ tools::Long nIndex = nCol - mnDataStartCol;
+ if (nIndex < mnColFormatCount)
{
- nFormat = pColNumFmt[nIndex];
+ nFormat = mpColNumberFormat[nIndex];
bApplyFormat = true;
}
}
}
- else if ( pRowNumFmt )
+ else if (mpRowNumberFormat)
{
- if ( nRow >= nDataStartRow )
+ if (nRow >= mnDataStartRow)
{
- tools::Long nIndex = nRow - nDataStartRow;
- if ( nIndex < nRowFmtCount )
+ tools::Long nIndex = nRow - mnDataStartRow;
+ if (nIndex < mnRowFormatCount)
{
- nFormat = pRowNumFmt[nIndex];
+ nFormat = mpRowNumberFormat[nIndex];
bApplyFormat = true;
}
}
}
- else if ( nSingleNumFmt != 0 )
+ else if (mnSingleNumberFormat != 0)
{
- nFormat = nSingleNumFmt; // single format is used everywhere
+ nFormat = mnSingleNumberFormat; // single format is used everywhere
bApplyFormat = true;
}
if (bApplyFormat)
- pDoc->ApplyAttr(nCol, nRow, nTab, SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat));
+ mpDocument->ApplyAttr(nCol, nRow, nTab, SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat));
}
// SubTotal formatting is controlled by headers
}
@@ -750,7 +753,7 @@ void ScDPOutput::HeaderCell( SCCOL nCol, SCROW nRow, SCTAB nTab,
bool bNumeric = (nFlags & sheet::MemberResultFlags::NUMERIC) != 0;
if (bNumeric && std::isfinite( rData.Value))
{
- pDoc->SetValue( nCol, nRow, nTab, rData.Value);
+ mpDocument->SetValue( nCol, nRow, nTab, rData.Value);
}
else
{
@@ -760,36 +763,52 @@ void ScDPOutput::HeaderCell( SCCOL nCol, SCROW nRow, SCTAB nTab,
else
aParam.setTextInput();
- pDoc->SetString(nCol, nRow, nTab, rData.Caption, &aParam);
+ mpDocument->SetString(nCol, nRow, nTab, rData.Caption, &aParam);
}
}
if ( !(nFlags & sheet::MemberResultFlags::SUBTOTAL) )
return;
- ScDPOutputImpl outputimp( pDoc, nTab,
- nTabStartCol, nTabStartRow,
- nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow );
+ ScDPOutputImpl outputimp(mpDocument, nTab,
+ mnTabStartCol, mnTabStartRow,
+ mnDataStartCol, mnDataStartRow, mnTabEndCol, mnTabEndRow);
//TODO: limit frames to horizontal or vertical?
if (bColHeader)
{
- outputimp.OutputBlockFrame( nCol,nMemberStartRow+static_cast<SCROW>(nLevel), nCol,nDataStartRow-1 );
+ outputimp.OutputBlockFrame(nCol, mnMemberStartRow+static_cast<SCROW>(nLevel), nCol, mnDataStartRow - 1);
- lcl_SetStyleById( pDoc,nTab, nCol,nMemberStartRow+static_cast<SCROW>(nLevel), nCol,nDataStartRow-1,
- STR_PIVOT_STYLENAME_TITLE );
- lcl_SetStyleById( pDoc,nTab, nCol,nDataStartRow, nCol,nTabEndRow,
- STR_PIVOT_STYLENAME_RESULT );
+ lcl_SetStyleById(mpDocument, nTab, nCol, mnMemberStartRow + static_cast<SCROW>(nLevel), nCol, mnDataStartRow - 1, STR_PIVOT_STYLENAME_TITLE);
+ lcl_SetStyleById(mpDocument, nTab, nCol, mnDataStartRow, nCol, mnTabEndRow, STR_PIVOT_STYLENAME_RESULT );
}
else
{
- outputimp.OutputBlockFrame( nMemberStartCol+static_cast<SCCOL>(nLevel),nRow, nDataStartCol-1,nRow );
- lcl_SetStyleById( pDoc,nTab, nMemberStartCol+static_cast<SCCOL>(nLevel),nRow, nDataStartCol-1,nRow,
- STR_PIVOT_STYLENAME_TITLE );
- lcl_SetStyleById( pDoc,nTab, nDataStartCol,nRow, nTabEndCol,nRow,
- STR_PIVOT_STYLENAME_RESULT );
+ outputimp.OutputBlockFrame(mnMemberStartCol + static_cast<SCCOL>(nLevel), nRow, mnDataStartCol - 1, nRow);
+ lcl_SetStyleById(mpDocument, nTab, mnMemberStartCol + static_cast<SCCOL>(nLevel), nRow, mnDataStartCol - 1, nRow, STR_PIVOT_STYLENAME_TITLE);
+ lcl_SetStyleById(mpDocument, nTab, mnDataStartCol, nRow, mnTabEndCol, nRow, STR_PIVOT_STYLENAME_RESULT);
}
}
+void ScDPOutput::MultiFieldCell(SCCOL nCol, SCROW nRow, SCTAB nTab, bool bRowField)
+{
+ mpDocument->SetString(nCol, nRow, nTab, ScResId(bRowField ? STR_PIVOT_ROW_LABELS : STR_PIVOT_COL_LABELS));
+
+ ScMF nMergeFlag = ScMF::Button;
+ for (auto& rData : mpRowFields)
+ {
+ if (rData.mbHasHiddenMember)
+ {
+ nMergeFlag |= ScMF::HiddenMember;
+ break;
+ }
+ }
+
+ nMergeFlag |= ScMF::ButtonPopup2;
+
+ mpDocument->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, nMergeFlag);
+ lcl_SetStyleById(mpDocument, nTab, nCol, nRow, nCol, nRow, STR_PIVOT_STYLENAME_FIELDNAME);
+}
+
void ScDPOutput::FieldCell(
SCCOL nCol, SCROW nRow, SCTAB nTab, const ScDPOutLevelData& rData, bool bInTable)
{
@@ -798,10 +817,10 @@ void ScDPOutput::FieldCell(
aParam.mbDetectNumberFormat = false;
aParam.meSetTextNumFormat = ScSetStringParam::Always;
aParam.mbHandleApostrophe = false;
- pDoc->SetString(nCol, nRow, nTab, rData.maCaption, &aParam);
+ mpDocument->SetString(nCol, nRow, nTab, rData.maCaption, &aParam);
if (bInTable)
- lcl_SetFrame( pDoc,nTab, nCol,nRow, nCol,nRow, 20 );
+ lcl_SetFrame(mpDocument, nTab, nCol,nRow, nCol,nRow, 20);
// For field button drawing
ScMF nMergeFlag = ScMF::NONE;
@@ -811,18 +830,18 @@ void ScDPOutput::FieldCell(
if (rData.mbPageDim)
{
nMergeFlag |= ScMF::ButtonPopup;
- pDoc->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, ScMF::Button);
- pDoc->ApplyFlagsTab(nCol+1, nRow, nCol+1, nRow, nTab, nMergeFlag);
+ mpDocument->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, ScMF::Button);
+ mpDocument->ApplyFlagsTab(nCol+1, nRow, nCol+1, nRow, nTab, nMergeFlag);
}
else
{
nMergeFlag |= ScMF::Button;
if (!rData.mbDataLayout)
nMergeFlag |= ScMF::ButtonPopup;
- pDoc->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, nMergeFlag);
+ mpDocument->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, nMergeFlag);
}
- lcl_SetStyleById( pDoc,nTab, nCol,nRow, nCol,nRow, STR_PIVOT_STYLENAME_FIELDNAME );
+ lcl_SetStyleById(mpDocument, nTab, nCol,nRow, nCol,nRow, STR_PIVOT_STYLENAME_FIELDNAME);
}
static void lcl_DoFilterButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
@@ -831,57 +850,73 @@ static void lcl_DoFilterButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB
pDoc->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, ScMF::Button);
}
+SCCOL ScDPOutput::GetColumnsForRowFields() const
+{
+ if (!mbHasCompactRowField)
+ return static_cast<SCCOL>(mpRowFields.size());
+
+ SCCOL nNum = 0;
+ for (const auto bCompact: maRowCompactFlags)
+ if (!bCompact)
+ ++nNum;
+
+ if (maRowCompactFlags.back())
+ ++nNum;
+
+ return nNum;
+}
+
void ScDPOutput::CalcSizes()
{
- if (bSizesValid)
+ if (mbSizesValid)
return;
// get column size of data from first row
//TODO: allow different sizes (and clear following areas) ???
- nRowCount = aData.getLength();
- const uno::Sequence<sheet::DataResult>* pRowAry = aData.getConstArray();
- nColCount = nRowCount ? ( pRowAry[0].getLength() ) : 0;
+ mnRowCount = maData.getLength();
+ const uno::Sequence<sheet::DataResult>* pRowAry = maData.getConstArray();
+ mnColCount = mnRowCount ? ( pRowAry[0].getLength() ) : 0;
- nHeaderSize = 1;
- if (GetHeaderLayout() && pColFields.empty())
+ mnHeaderSize = 1;
+ if (GetHeaderLayout() && mpColFields.empty())
// Insert an extra header row only when there is no column field.
- nHeaderSize = 2;
+ mnHeaderSize = 2;
// calculate output positions and sizes
tools::Long nPageSize = 0; // use page fields!
- if ( bDoFilter || !pPageFields.empty() )
+ if (mbDoFilter || !mpPageFields.empty())
{
- nPageSize += pPageFields.size() + 1; // plus one empty row
- if ( bDoFilter )
+ nPageSize += mpPageFields.size() + 1; // plus one empty row
+ if (mbDoFilter)
++nPageSize; // filter button above the page fields
}
- if ( aStartPos.Col() + static_cast<tools::Long>(pRowFields.size()) + nColCount - 1 > MAXCOL ||
- aStartPos.Row() + nPageSize + nHeaderSize + pColFields.size() + nRowCount > MAXROW )
+ if (maStartPos.Col() + static_cast<tools::Long>(mpRowFields.size()) + mnColCount - 1 > mpDocument->MaxCol() ||
+ maStartPos.Row() + nPageSize + mnHeaderSize + static_cast<tools::Long>(mpColFields.size()) + mnRowCount > mpDocument->MaxRow())
{
- bSizeOverflow = true;
+ mbSizeOverflow = true;
}
- nTabStartCol = aStartPos.Col();
- nTabStartRow = aStartPos.Row() + static_cast<SCROW>(nPageSize); // below page fields
- nMemberStartCol = nTabStartCol;
- nMemberStartRow = nTabStartRow + static_cast<SCROW>(nHeaderSize);
- nDataStartCol = nMemberStartCol + static_cast<SCCOL>(pRowFields.size());
- nDataStartRow = nMemberStartRow + static_cast<SCROW>(pColFields.size());
- if ( nColCount > 0 )
- nTabEndCol = nDataStartCol + static_cast<SCCOL>(nColCount) - 1;
+ mnTabStartCol = maStartPos.Col();
+ mnTabStartRow = maStartPos.Row() + static_cast<SCROW>(nPageSize); // below page fields
+ mnMemberStartCol = mnTabStartCol;
+ mnMemberStartRow = mnTabStartRow + static_cast<SCROW>(mnHeaderSize);
+ mnDataStartCol = mnMemberStartCol + GetColumnsForRowFields();
+ mnDataStartRow = mnMemberStartRow + static_cast<SCROW>(mpColFields.size());
+ if (mnColCount > 0)
+ mnTabEndCol = mnDataStartCol + static_cast<SCCOL>(mnColCount) - 1;
else
- nTabEndCol = nDataStartCol; // single column will remain empty
+ mnTabEndCol = mnDataStartCol; // single column will remain empty
// if page fields are involved, include the page selection cells
- if ( !pPageFields.empty() && nTabEndCol < nTabStartCol + 1 )
- nTabEndCol = nTabStartCol + 1;
- if ( nRowCount > 0 )
- nTabEndRow = nDataStartRow + static_cast<SCROW>(nRowCount) - 1;
+ if (!mpPageFields.empty() && mnTabEndCol < mnTabStartCol + 1)
+ mnTabEndCol = mnTabStartCol + 1;
+ if (mnRowCount > 0)
+ mnTabEndRow = mnDataStartRow + static_cast<SCROW>(mnRowCount) - 1;
else
- nTabEndRow = nDataStartRow; // single row will remain empty
- bSizesValid = true;
+ mnTabEndRow = mnDataStartRow; // single row will remain empty
+ mbSizesValid = true;
}
sal_Int32 ScDPOutput::GetPositionType(const ScAddress& rPos)
@@ -891,21 +926,21 @@ sal_Int32 ScDPOutput::GetPositionType(const ScAddress& rPos)
SCCOL nCol = rPos.Col();
SCROW nRow = rPos.Row();
SCTAB nTab = rPos.Tab();
- if ( nTab != aStartPos.Tab() )
+ if ( nTab != maStartPos.Tab() )
return DataPilotTablePositionType::NOT_IN_TABLE;
CalcSizes();
// Make sure the cursor is within the table.
- if (nCol < nTabStartCol || nRow < nTabStartRow || nCol > nTabEndCol || nRow > nTabEndRow)
+ if (nCol < mnTabStartCol || nRow < mnTabStartRow || nCol > mnTabEndCol || nRow > mnTabEndRow)
return DataPilotTablePositionType::NOT_IN_TABLE;
// test for result data area.
- if (nCol >= nDataStartCol && nCol <= nTabEndCol && nRow >= nDataStartRow && nRow <= nTabEndRow)
+ if (nCol >= mnDataStartCol && nCol <= mnTabEndCol && nRow >= mnDataStartRow && nRow <= mnTabEndRow)
return DataPilotTablePositionType::RESULT;
- bool bInColHeader = (nRow >= nTabStartRow && nRow < nDataStartRow);
- bool bInRowHeader = (nCol >= nTabStartCol && nCol < nDataStartCol);
+ bool bInColHeader = (nRow >= mnTabStartRow && nRow < mnDataStartRow);
+ bool bInRowHeader = (nCol >= mnTabStartCol && nCol < mnDataStartCol);
if (bInColHeader && bInRowHeader)
// probably in that ugly little box at the upper-left corner of the table.
@@ -913,7 +948,7 @@ sal_Int32 ScDPOutput::GetPositionType(const ScAddress& rPos)
if (bInColHeader)
{
- if (nRow == nTabStartRow)
+ if (nRow == mnTabStartRow)
// first row in the column header area is always used for column
// field buttons.
return DataPilotTablePositionType::OTHER;
@@ -927,37 +962,18 @@ sal_Int32 ScDPOutput::GetPositionType(const ScAddress& rPos)
return DataPilotTablePositionType::OTHER;
}
-void ScDPOutput::Output()
+void ScDPOutput::outputPageFields(SCTAB nTab)
{
- SCTAB nTab = aStartPos.Tab();
- const uno::Sequence<sheet::DataResult>* pRowAry = aData.getConstArray();
-
- // calculate output positions and sizes
-
- CalcSizes();
- if ( bSizeOverflow || bResultsError ) // does output area exceed sheet limits?
- return; // nothing
-
- // clear whole (new) output area
- // when modifying table, clear old area !
- //TODO: include InsertDeleteFlags::OBJECTS ???
- pDoc->DeleteAreaTab( aStartPos.Col(), aStartPos.Row(), nTabEndCol, nTabEndRow, nTab, InsertDeleteFlags::ALL );
-
- if ( bDoFilter )
- lcl_DoFilterButton( pDoc, aStartPos.Col(), aStartPos.Row(), nTab );
-
- // output page fields:
-
- for (size_t nField=0; nField<pPageFields.size(); ++nField)
+ for (size_t nField = 0; nField < mpPageFields.size(); ++nField)
{
- SCCOL nHdrCol = aStartPos.Col();
- SCROW nHdrRow = aStartPos.Row() + nField + ( bDoFilter ? 1 : 0 );
+ SCCOL nHeaderCol = maStartPos.Col();
+ SCROW nHeaderRow = maStartPos.Row() + nField + (mbDoFilter ? 1 : 0);
// draw without frame for consistency with filter button:
- FieldCell(nHdrCol, nHdrRow, nTab, pPageFields[nField], false);
- SCCOL nFldCol = nHdrCol + 1;
+ FieldCell(nHeaderCol, nHeaderRow, nTab, mpPageFields[nField], false);
+ SCCOL nFieldCol = nHeaderCol + 1;
OUString aPageValue = ScResId(SCSTR_ALL);
- const uno::Sequence<sheet::MemberResult>& rRes = pPageFields[nField].maResult;
+ const uno::Sequence<sheet::MemberResult>& rRes = mpPageFields[nField].maResult;
sal_Int32 n = rRes.getLength();
if (n == 1)
{
@@ -967,159 +983,267 @@ void ScDPOutput::Output()
aPageValue = rRes[0].Caption;
}
else if (n > 1)
+ {
aPageValue = ScResId(SCSTR_MULTIPLE);
+ }
ScSetStringParam aParam;
aParam.setTextInput();
- pDoc->SetString(nFldCol, nHdrRow, nTab, aPageValue, &aParam);
+ mpDocument->SetString(nFieldCol, nHeaderRow, nTab, aPageValue, &aParam);
- lcl_SetFrame( pDoc,nTab, nFldCol,nHdrRow, nFldCol,nHdrRow, 20 );
+ lcl_SetFrame(mpDocument, nTab, nFieldCol, nHeaderRow, nFieldCol, nHeaderRow, 20);
}
+}
- // data description
- // (may get overwritten by first row field)
+void ScDPOutput::outputColumnHeaders(SCTAB nTab, ScDPOutputImpl& rOutputImpl)
+{
+ size_t nNumColFields = mpColFields.size();
- if (aDataDescription.isEmpty())
+ for (size_t nField = 0; nField < nNumColFields; nField++)
{
- //TODO: use default string ("result") ?
- }
- pDoc->SetString(nTabStartCol, nTabStartRow, nTab, aDataDescription);
+ SCCOL nHeaderCol = mnDataStartCol + SCCOL(nField); //TODO: check for overflow
- // set STR_PIVOT_STYLENAME_INNER for whole data area (subtotals are overwritten)
+ if (!mbHasCompactRowField || nNumColFields == 1)
+ FieldCell(nHeaderCol, mnTabStartRow, nTab, mpColFields[nField], true);
+ else if (!nField)
+ MultiFieldCell(nHeaderCol, mnTabStartRow, nTab, false /* bRowField */);
- if ( nDataStartRow > nTabStartRow )
- lcl_SetStyleById( pDoc, nTab, nTabStartCol, nTabStartRow, nTabEndCol, nDataStartRow-1,
- STR_PIVOT_STYLENAME_TOP );
- lcl_SetStyleById( pDoc, nTab, nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow,
- STR_PIVOT_STYLENAME_INNER );
-
- // output column headers:
- ScDPOutputImpl outputimp( pDoc, nTab,
- nTabStartCol, nTabStartRow,
- nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow );
- for (size_t nField=0; nField<pColFields.size(); nField++)
- {
- SCCOL nHdrCol = nDataStartCol + static_cast<SCCOL>(nField); //TODO: check for overflow
- FieldCell(nHdrCol, nTabStartRow, nTab, pColFields[nField], true);
+ SCROW nRowPos = mnMemberStartRow + SCROW(nField); //TODO: check for overflow
+ const uno::Sequence<sheet::MemberResult> rMemberSequence = mpColFields[nField].maResult;
+ const sheet::MemberResult* pMemberArray = rMemberSequence.getConstArray();
+ tools::Long nThisColCount = rMemberSequence.getLength();
+ OSL_ENSURE(nThisColCount == mnColCount, "count mismatch"); //TODO: ???
- SCROW nRowPos = nMemberStartRow + static_cast<SCROW>(nField); //TODO: check for overflow
- const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nField].maResult;
- const sheet::MemberResult* pArray = rSequence.getConstArray();
- tools::Long nThisColCount = rSequence.getLength();
- OSL_ENSURE( nThisColCount == nColCount, "count mismatch" ); //TODO: ???
- for (tools::Long nCol=0; nCol<nThisColCount; nCol++)
+ for (tools::Long nColumn = 0; nColumn < nThisColCount; nColumn++)
{
- SCCOL nColPos = nDataStartCol + static_cast<SCCOL>(nCol); //TODO: check for overflow
- HeaderCell( nColPos, nRowPos, nTab, pArray[nCol], true, nField );
- if ( ( pArray[nCol].Flags & sheet::MemberResultFlags::HASMEMBER ) &&
- !( pArray[nCol].Flags & sheet::MemberResultFlags::SUBTOTAL ) )
+ sheet::MemberResult const& rMember = rMemberSequence[nColumn];
+
+ SCCOL nColPos = mnDataStartCol + SCCOL(nColumn); //TODO: check for overflow
+
+ HeaderCell(nColPos, nRowPos, nTab, rMember, true, nField);
+
+ if ((rMember.Flags & sheet::MemberResultFlags::HASMEMBER) &&
+ !(rMember.Flags & sheet::MemberResultFlags::SUBTOTAL))
{
- tools::Long nEnd = nCol;
- while ( nEnd+1 < nThisColCount && ( pArray[nEnd+1].Flags & sheet::MemberResultFlags::CONTINUE ) )
+ // Check the number of columns this spreads
+ tools::Long nEnd = nColumn;
+ while (nEnd + 1 < nThisColCount && (pMemberArray[nEnd + 1].Flags & sheet::MemberResultFlags::CONTINUE))
++nEnd;
- SCCOL nEndColPos = nDataStartCol + static_cast<SCCOL>(nEnd); //TODO: check for overflow
- if ( nField+1 < pColFields.size())
+
+ SCCOL nEndColPos = mnDataStartCol + SCCOL(nEnd); //TODO: check for overflow
+ if (nField + 1 < mpColFields.size())
{
- if ( nField == pColFields.size() - 2 )
+ if (nField == mpColFields.size() - 2)
{
- outputimp.AddCol( nColPos );
- if ( nColPos + 1 == nEndColPos )
- outputimp.OutputBlockFrame( nColPos,nRowPos, nEndColPos,nRowPos+1, true );
+ rOutputImpl.AddCol( nColPos );
+ if (nColPos + 1 == nEndColPos)
+ rOutputImpl.OutputBlockFrame(nColPos, nRowPos, nEndColPos, nRowPos + 1, true);
}
else
- outputimp.OutputBlockFrame( nColPos,nRowPos, nEndColPos,nRowPos );
+ rOutputImpl.OutputBlockFrame(nColPos, nRowPos, nEndColPos, nRowPos);
- lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nEndColPos,nDataStartRow-1, STR_PIVOT_STYLENAME_CATEGORY );
+ lcl_SetStyleById(mpDocument, nTab, nColPos, nRowPos, nEndColPos, mnDataStartRow - 1, STR_PIVOT_STYLENAME_CATEGORY);
}
else
- lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nColPos,nDataStartRow-1, STR_PIVOT_STYLENAME_CATEGORY );
+ {
+ lcl_SetStyleById(mpDocument, nTab, nColPos, nRowPos, nColPos, mnDataStartRow - 1, STR_PIVOT_STYLENAME_CATEGORY);
+ }
+ }
+ else if (rMember.Flags & sheet::MemberResultFlags::SUBTOTAL)
+ {
+ rOutputImpl.AddCol(nColPos);
}
- else if ( pArray[nCol].Flags & sheet::MemberResultFlags::SUBTOTAL )
- outputimp.AddCol( nColPos );
+
+ // Resolve formats
+ maFormatOutput.insertFieldMember(nField, mpColFields[nField], nColumn, rMember, nColPos, nRowPos, sc::FormatResultDirection::COLUMN);
// Apply the same number format as in data source.
- pDoc->ApplyAttr(nColPos, nRowPos, nTab, SfxUInt32Item(ATTR_VALUE_FORMAT, pColFields[nField].mnSrcNumFmt));
+ mpDocument->ApplyAttr(nColPos, nRowPos, nTab, SfxUInt32Item(ATTR_VALUE_FORMAT, mpColFields[nField].mnSrcNumFmt));
}
- if ( nField== 0 && pColFields.size() == 1 )
- outputimp.OutputBlockFrame( nDataStartCol,nTabStartRow, nTabEndCol,nRowPos-1 );
+ if (nField == 0 && mpColFields.size() == 1)
+ rOutputImpl.OutputBlockFrame(mnDataStartCol, mnTabStartRow, mnTabEndCol, nRowPos - 1);
}
+}
- // output row headers:
+void ScDPOutput::outputRowHeader(SCTAB nTab, ScDPOutputImpl& rOutputImpl)
+{
std::vector<bool> vbSetBorder;
- vbSetBorder.resize( nTabEndRow - nDataStartRow + 1, false );
- for (size_t nField=0; nField<pRowFields.size(); nField++)
+ vbSetBorder.resize(mnTabEndRow - mnDataStartRow + 1, false);
+ size_t nFieldColOffset = 0;
+ size_t nFieldIndentLevel = 0; // To calculate indent level for fields packed in a column.
+ size_t nNumRowFields = mpRowFields.size();
+ for (size_t nField = 0; nField < nNumRowFields; nField++)
{
- SCCOL nHdrCol = nTabStartCol + static_cast<SCCOL>(nField); //TODO: check for overflow
- SCROW nHdrRow = nDataStartRow - 1;
- FieldCell(nHdrCol, nHdrRow, nTab, pRowFields[nField], true);
-
- SCCOL nColPos = nMemberStartCol + static_cast<SCCOL>(nField); //TODO: check for overflow
- const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nField].maResult;
- const sheet::MemberResult* pArray = rSequence.getConstArray();
- sal_Int32 nThisRowCount = rSequence.getLength();
- OSL_ENSURE( nThisRowCount == nRowCount, "count mismatch" ); //TODO: ???
- for (sal_Int32 nRow=0; nRow<nThisRowCount; nRow++)
+ const bool bCompactField = maRowCompactFlags[nField];
+ SCCOL nHdrCol = mnTabStartCol + SCCOL(nField); //TODO: check for overflow
+ SCROW nHdrRow = mnDataStartRow - 1;
+ if (!mbHasCompactRowField || nNumRowFields == 1)
+ FieldCell(nHdrCol, nHdrRow, nTab, mpRowFields[nField], true);
+ else if (!nField)
+ MultiFieldCell(nHdrCol, nHdrRow, nTab, true /* bRowField */);
+
+ SCCOL nColPos = mnMemberStartCol + SCCOL(nFieldColOffset); //TODO: check for overflow
+ const uno::Sequence<sheet::MemberResult> rMemberSequence = mpRowFields[nField].maResult;
+ const sheet::MemberResult* pMemberArray = rMemberSequence.getConstArray();
+ sal_Int32 nThisRowCount = rMemberSequence.getLength();
+ OSL_ENSURE(nThisRowCount == mnRowCount, "count mismatch"); //TODO: ???
+ for (sal_Int32 nRow = 0; nRow < nThisRowCount; nRow++)
{
- SCROW nRowPos = nDataStartRow + static_cast<SCROW>(nRow); //TODO: check for overflow
- HeaderCell( nColPos, nRowPos, nTab, pArray[nRow], false, nField );
- if ( ( pArray[nRow].Flags & sheet::MemberResultFlags::HASMEMBER ) &&
- !( pArray[nRow].Flags & sheet::MemberResultFlags::SUBTOTAL ) )
+ sheet::MemberResult const& rMember = rMemberSequence[nRow];
+ const sheet::MemberResult& rData = rMember;
+ const bool bHasMember = rData.Flags & sheet::MemberResultFlags::HASMEMBER;
+ const bool bSubtotal = rData.Flags & sheet::MemberResultFlags::SUBTOTAL;
+ SCROW nRowPos = mnDataStartRow + SCROW(nRow); //TODO: check for overflow
+ HeaderCell( nColPos, nRowPos, nTab, rData, false, nFieldColOffset );
+ if (bHasMember && !bSubtotal)
{
- if ( nField+1 < pRowFields.size() )
+ if (nField + 1 < mpRowFields.size())
{
tools::Long nEnd = nRow;
- while ( nEnd+1 < nThisRowCount && ( pArray[nEnd+1].Flags & sheet::MemberResultFlags::CONTINUE ) )
+ while (nEnd + 1 < nThisRowCount && (pMemberArray[nEnd + 1].Flags & sheet::MemberResultFlags::CONTINUE))
+ {
++nEnd;
- SCROW nEndRowPos = nDataStartRow + static_cast<SCROW>(nEnd); //TODO: check for overflow
- outputimp.AddRow( nRowPos );
- if ( !vbSetBorder[ nRow ] )
+ }
+ SCROW nEndRowPos = mnDataStartRow + SCROW(nEnd); //TODO: check for overflow
+ rOutputImpl.AddRow(nRowPos);
+ if (!vbSetBorder[nRow] )
{
- outputimp.OutputBlockFrame( nColPos, nRowPos, nTabEndCol, nEndRowPos );
- vbSetBorder[ nRow ] = true;
+ rOutputImpl.OutputBlockFrame(nColPos, nRowPos, mnTabEndCol, nEndRowPos);
+ vbSetBorder[nRow] = true;
}
- outputimp.OutputBlockFrame( nColPos, nRowPos, nColPos, nEndRowPos );
+ rOutputImpl.OutputBlockFrame(nColPos, nRowPos, nColPos, nEndRowPos);
- if ( nField == pRowFields.size() - 2 )
- outputimp.OutputBlockFrame( nColPos+1, nRowPos, nColPos+1, nEndRowPos );
+ if (nField == mpRowFields.size() - 2)
+ rOutputImpl.OutputBlockFrame(nColPos + 1, nRowPos, nColPos + 1, nEndRowPos);
- lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nDataStartCol-1,nEndRowPos, STR_PIVOT_STYLENAME_CATEGORY );
+ lcl_SetStyleById(mpDocument, nTab, nColPos, nRowPos, mnDataStartCol - 1, nEndRowPos, STR_PIVOT_STYLENAME_CATEGORY);
}
else
- lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nDataStartCol-1,nRowPos, STR_PIVOT_STYLENAME_CATEGORY );
+ {
+ lcl_SetStyleById(mpDocument, nTab, nColPos, nRowPos, mnDataStartCol - 1, nRowPos, STR_PIVOT_STYLENAME_CATEGORY);
+ }
+
+ // Set flags for collapse/expand buttons and indent field header text
+ {
+ bool bLast = mnRowDims == (nField + 1);
+ size_t nMinIndentLevel = mbExpandCollapse ? 1 : 0;
+ tools::Long nIndent = o3tl::convert(13 * (bLast ? nFieldIndentLevel : nMinIndentLevel + nFieldIndentLevel), o3tl::Length::px, o3tl::Length::twip);
+ bool bHasContinue = !bLast && nRow + 1 < nThisRowCount && (pMemberArray[nRow + 1].Flags & sheet::MemberResultFlags::CONTINUE);
+ if (nIndent)
+ mpDocument->ApplyAttr(nColPos, nRowPos, nTab, ScIndentItem(nIndent));
+ if (mbExpandCollapse && !bLast)
+ {
+ mpDocument->ApplyFlagsTab(nColPos, nRowPos, nColPos, nRowPos, nTab,
+ bHasContinue ? ScMF::DpCollapse : ScMF::DpExpand);
+ }
+ }
}
- else if ( pArray[nRow].Flags & sheet::MemberResultFlags::SUBTOTAL )
- outputimp.AddRow( nRowPos );
+ else if (bSubtotal)
+ {
+ rOutputImpl.AddRow(nRowPos);
+ }
+
+ // Resolve formats
+ maFormatOutput.insertFieldMember(nField, mpRowFields[nField], nRow, rMember, nColPos, nRowPos, sc::FormatResultDirection::ROW);
// Apply the same number format as in data source.
- pDoc->ApplyAttr(nColPos, nRowPos, nTab, SfxUInt32Item(ATTR_VALUE_FORMAT, pRowFields[nField].mnSrcNumFmt));
+ mpDocument->ApplyAttr(nColPos, nRowPos, nTab, SfxUInt32Item(ATTR_VALUE_FORMAT, mpRowFields[nField].mnSrcNumFmt));
}
- }
- if (nColCount == 1 && nRowCount > 0 && pColFields.empty())
- {
- // the table contains exactly one data field and no column fields.
- // Display data description at top right corner.
- ScSetStringParam aParam;
- aParam.setTextInput();
- pDoc->SetString(nDataStartCol, nDataStartRow-1, nTab, aDataDescription, &aParam);
+ if (!bCompactField)
+ {
+ // Next field should be placed in next column only if current field has a non-compact layout.
+ ++nFieldColOffset;
+ nFieldIndentLevel = 0; // Reset indent level.
+ }
+ else
+ {
+ ++nFieldIndentLevel;
+ }
}
+}
- // output data results:
+void ScDPOutput::outputDataResults(SCTAB nTab)
+{
+ const uno::Sequence<sheet::DataResult>* pRowAry = maData.getConstArray();
- for (sal_Int32 nRow=0; nRow<nRowCount; nRow++)
+ for (sal_Int32 nRow = 0; nRow < mnRowCount; nRow++)
{
- SCROW nRowPos = nDataStartRow + static_cast<SCROW>(nRow); //TODO: check for overflow
+ SCROW nRowPos = mnDataStartRow + SCROW(nRow); //TODO: check for overflow
const sheet::DataResult* pColAry = pRowAry[nRow].getConstArray();
sal_Int32 nThisColCount = pRowAry[nRow].getLength();
- OSL_ENSURE( nThisColCount == nColCount, "count mismatch" ); //TODO: ???
- for (sal_Int32 nCol=0; nCol<nThisColCount; nCol++)
+ OSL_ENSURE(nThisColCount == mnColCount, "count mismatch"); //TODO: ???
+ for (sal_Int32 nCol = 0; nCol < nThisColCount; nCol++)
{
- SCCOL nColPos = nDataStartCol + static_cast<SCCOL>(nCol); //TODO: check for overflow
- DataCell( nColPos, nRowPos, nTab, pColAry[nCol] );
+ SCCOL nColPos = mnDataStartCol + SCCOL(nCol); //TODO: check for overflow
+ DataCell(nColPos, nRowPos, nTab, pColAry[nCol]);
}
}
- outputimp.OutputDataArea();
+ maFormatOutput.apply(*mpDocument);
+}
+
+void ScDPOutput::Output()
+{
+ SCTAB nTab = maStartPos.Tab();
+
+ // calculate output positions and sizes
+ CalcSizes();
+
+ if (mbSizeOverflow || mbResultsError) // does output area exceed sheet limits?
+ return; // nothing
+
+ // Prepare format output
+ bool bColumnFieldIsDataOnly = mnColCount == 1 && mnRowCount > 0 && mpColFields.empty();
+ maFormatOutput.prepare(nTab, mpColFields, mpRowFields, bColumnFieldIsDataOnly);
+
+ // clear whole (new) output area
+ // when modifying table, clear old area !
+ //TODO: include InsertDeleteFlags::OBJECTS ???
+ mpDocument->DeleteAreaTab(maStartPos.Col(), maStartPos.Row(), mnTabEndCol, mnTabEndRow, nTab, InsertDeleteFlags::ALL );
+
+ if (mbDoFilter)
+ lcl_DoFilterButton(mpDocument, maStartPos.Col(), maStartPos.Row(), nTab);
+
+ outputPageFields(nTab);
+
+ // data description
+ // (may get overwritten by first row field)
+
+ if (maDataDescription.isEmpty())
+ {
+ //TODO: use default string ("result") ?
+ }
+ mpDocument->SetString(mnTabStartCol, mnTabStartRow, nTab, maDataDescription);
+
+ // set STR_PIVOT_STYLENAME_INNER for whole data area (subtotals are overwritten)
+
+ if (mnDataStartRow > mnTabStartRow)
+ lcl_SetStyleById(mpDocument, nTab, mnTabStartCol, mnTabStartRow, mnTabEndCol, mnDataStartRow - 1, STR_PIVOT_STYLENAME_TOP);
+ lcl_SetStyleById(mpDocument, nTab, mnDataStartCol, mnDataStartRow, mnTabEndCol, mnTabEndRow, STR_PIVOT_STYLENAME_INNER);
+
+ ScDPOutputImpl aOutputImpl(mpDocument, nTab, mnTabStartCol, mnTabStartRow,
+ mnDataStartCol, mnDataStartRow, mnTabEndCol, mnTabEndRow);
+
+ outputColumnHeaders(nTab, aOutputImpl);
+
+ outputRowHeader(nTab, aOutputImpl);
+
+ if (bColumnFieldIsDataOnly)
+ {
+ // the table contains exactly one data field and no column fields.
+ // Display data description at top right corner.
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ SCCOL nCol = mnDataStartCol;
+ SCCOL nRow = mnDataStartRow - 1;
+ mpDocument->SetString(nCol, nRow, nTab, maDataDescription, &aParam);
+ maFormatOutput.insertEmptyDataColumn(nCol, nRow);
+ }
+
+ outputDataResults(nTab);
+
+ aOutputImpl.OutputDataArea();
}
ScRange ScDPOutput::GetOutputRange( sal_Int32 nRegionType )
@@ -1128,30 +1252,30 @@ ScRange ScDPOutput::GetOutputRange( sal_Int32 nRegionType )
CalcSizes();
- SCTAB nTab = aStartPos.Tab();
+ SCTAB nTab = maStartPos.Tab();
switch (nRegionType)
{
case DataPilotOutputRangeType::RESULT:
- return ScRange(nDataStartCol, nDataStartRow, nTab, nTabEndCol, nTabEndRow, nTab);
+ return ScRange(mnDataStartCol, mnDataStartRow, nTab, mnTabEndCol, mnTabEndRow, nTab);
case DataPilotOutputRangeType::TABLE:
- return ScRange(aStartPos.Col(), nTabStartRow, nTab, nTabEndCol, nTabEndRow, nTab);
+ return ScRange(maStartPos.Col(), mnTabStartRow, nTab, mnTabEndCol, mnTabEndRow, nTab);
default:
OSL_ENSURE(nRegionType == DataPilotOutputRangeType::WHOLE, "ScDPOutput::GetOutputRange: unknown region type");
break;
}
- return ScRange(aStartPos.Col(), aStartPos.Row(), nTab, nTabEndCol, nTabEndRow, nTab);
+ return ScRange(maStartPos.Col(), maStartPos.Row(), nTab, mnTabEndCol, mnTabEndRow, nTab);
}
bool ScDPOutput::HasError()
{
CalcSizes();
- return bSizeOverflow || bResultsError;
+ return mbSizeOverflow || mbResultsError;
}
sal_Int32 ScDPOutput::GetHeaderRows() const
{
- return pPageFields.size() + ( bDoFilter ? 1 : 0 );
+ return mpPageFields.size() + (mbDoFilter ? 1 : 0);
}
namespace
@@ -1175,8 +1299,8 @@ void ScDPOutput::GetMemberResultNames(ScDPUniqueStringSet& rNames, tools::Long n
auto lFindDimension = [nDimension](const ScDPOutLevelData& rField) { return rField.mnDim == nDimension; };
// look in column fields
- auto colit = std::find_if(pColFields.begin(), pColFields.end(), lFindDimension);
- if (colit != pColFields.end())
+ auto colit = std::find_if(mpColFields.begin(), mpColFields.end(), lFindDimension);
+ if (colit != mpColFields.end())
{
// collect the member names
insertNames(rNames, colit->maResult);
@@ -1184,8 +1308,8 @@ void ScDPOutput::GetMemberResultNames(ScDPUniqueStringSet& rNames, tools::Long n
}
// look in row fields
- auto rowit = std::find_if(pRowFields.begin(), pRowFields.end(), lFindDimension);
- if (rowit != pRowFields.end())
+ auto rowit = std::find_if(mpRowFields.begin(), mpRowFields.end(), lFindDimension);
+ if (rowit != mpRowFields.end())
{
// collect the member names
insertNames(rNames, rowit->maResult);
@@ -1195,7 +1319,7 @@ void ScDPOutput::GetMemberResultNames(ScDPUniqueStringSet& rNames, tools::Long n
void ScDPOutput::SetHeaderLayout(bool bUseGrid)
{
mbHeaderLayout = bUseGrid;
- bSizesValid = false;
+ mbSizesValid = false;
}
namespace {
@@ -1282,6 +1406,83 @@ void lcl_GetTableVars( sal_Int32& rGrandTotalCols, sal_Int32& rGrandTotalRows, s
}
+void ScDPOutput::GetRowFieldRange(SCCOL nCol, sal_Int32& nRowFieldStart, sal_Int32& nRowFieldEnd) const
+{
+ if (!mbHasCompactRowField)
+ {
+ nRowFieldStart = nCol;
+ nRowFieldEnd = nCol + 1;
+ return;
+ }
+
+ if (nCol >= static_cast<SCCOL>(maRowCompactFlags.size()))
+ {
+ nRowFieldStart = nRowFieldEnd = 0;
+ return;
+ }
+
+ nRowFieldStart = -1;
+ nRowFieldEnd = -1;
+ SCCOL nCurCol = 0;
+ sal_Int32 nField = 0;
+
+ for (const auto bCompact: maRowCompactFlags)
+ {
+ if (nCurCol == nCol && nRowFieldStart == -1)
+ nRowFieldStart = nField;
+
+ if (!bCompact)
+ ++nCurCol;
+
+ ++nField;
+
+ if (nCurCol == (nCol + 1) && nRowFieldStart != -1 && nRowFieldEnd == -1)
+ {
+ nRowFieldEnd = nField;
+ break;
+ }
+ }
+
+ if (nRowFieldStart != -1 && nRowFieldEnd == -1 && nCurCol == nCol)
+ nRowFieldEnd = static_cast<sal_Int32>(maRowCompactFlags.size());
+
+ if (nRowFieldStart == -1 || nRowFieldEnd == -1)
+ {
+ SAL_WARN("sc.core", "ScDPOutput::GetRowFieldRange : unable to find field range for nCol = " << nCol);
+ nRowFieldStart = nRowFieldEnd = 0;
+ }
+}
+
+sal_Int32 ScDPOutput::GetRowFieldCompact(SCCOL nColQuery, SCROW nRowQuery) const
+{
+ if (!mbHasCompactRowField)
+ return nColQuery - mnTabStartCol;
+
+ SCCOL nCol = nColQuery - mnTabStartCol;
+ sal_Int32 nStartField = 0;
+ sal_Int32 nEndField = 0;
+ GetRowFieldRange(nCol, nStartField, nEndField);
+
+ for (sal_Int32 nField = nEndField - 1; nField >= nStartField; --nField)
+ {
+ const uno::Sequence<sheet::MemberResult> rSequence = mpRowFields[nField].maResult;
+ const sheet::MemberResult* pArray = rSequence.getConstArray();
+ sal_Int32 nThisRowCount = rSequence.getLength();
+ SCROW nRow = nRowQuery - mnDataStartRow;
+ if (nRow >= 0 && nRow < nThisRowCount)
+ {
+ const sheet::MemberResult& rData = pArray[nRow];
+ if ((rData.Flags & sheet::MemberResultFlags::HASMEMBER)
+ && !(rData.Flags & sheet::MemberResultFlags::SUBTOTAL))
+ {
+ return nField;
+ }
+ }
+ }
+
+ return -1;
+}
+
void ScDPOutput::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData)
{
using namespace ::com::sun::star::sheet;
@@ -1289,8 +1490,8 @@ void ScDPOutput::GetPositionData(const ScAddress& rPos, DataPilotTablePositionDa
SCCOL nCol = rPos.Col();
SCROW nRow = rPos.Row();
SCTAB nTab = rPos.Tab();
- if ( nTab != aStartPos.Tab() )
- return; // wrong sheet
+ if (nTab != maStartPos.Tab())
+ return; // wrong sheet
// calculate output positions and sizes
@@ -1303,43 +1504,41 @@ void ScDPOutput::GetPositionData(const ScAddress& rPos, DataPilotTablePositionDa
{
vector<DataPilotFieldFilter> aFilters;
GetDataResultPositionData(aFilters, rPos);
- sal_Int32 nSize = aFilters.size();
DataPilotTableResultData aResData;
- aResData.FieldFilters.realloc(nSize);
- for (sal_Int32 i = 0; i < nSize; ++i)
- aResData.FieldFilters[i] = aFilters[i];
-
+ aResData.FieldFilters = comphelper::containerToSequence(aFilters);
aResData.DataFieldIndex = 0;
- Reference<beans::XPropertySet> xPropSet(xSource, UNO_QUERY);
+ Reference<beans::XPropertySet> xPropSet(mxSource, UNO_QUERY);
if (xPropSet.is())
{
sal_Int32 nDataFieldCount = ScUnoHelpFunctions::GetLongProperty( xPropSet,
SC_UNO_DP_DATAFIELDCOUNT );
if (nDataFieldCount > 0)
- aResData.DataFieldIndex = (nRow - nDataStartRow) % nDataFieldCount;
+ aResData.DataFieldIndex = (nRow - mnDataStartRow) % nDataFieldCount;
}
// Copy appropriate DataResult object from the cached sheet::DataResult table.
- if (aData.getLength() > nRow - nDataStartRow &&
- aData[nRow-nDataStartRow].getLength() > nCol-nDataStartCol)
- aResData.Result = aData[nRow-nDataStartRow][nCol-nDataStartCol];
+ if (maData.getLength() > nRow - mnDataStartRow &&
+ maData[nRow - mnDataStartRow].getLength() > nCol - mnDataStartCol)
+ aResData.Result = maData[nRow - mnDataStartRow][nCol - mnDataStartCol];
rPosData.PositionData <<= aResData;
return;
}
case DataPilotTablePositionType::COLUMN_HEADER:
{
- tools::Long nField = nRow - nTabStartRow - 1; // 1st line is used for the buttons
+ tools::Long nField = nRow - mnTabStartRow - 1; // 1st line is used for the buttons
if (nField < 0)
break;
- const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nField].maResult;
+ if (mpColFields.size() < o3tl::make_unsigned(nField) + 1 )
+ break;
+ const uno::Sequence<sheet::MemberResult> rSequence = mpColFields[nField].maResult;
if (!rSequence.hasElements())
break;
const sheet::MemberResult* pArray = rSequence.getConstArray();
- tools::Long nItem = nCol - nDataStartCol;
+ tools::Long nItem = nCol - mnDataStartCol;
// get origin of "continue" fields
while (nItem > 0 && ( pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
--nItem;
@@ -1350,25 +1549,27 @@ void ScDPOutput::GetPositionData(const ScAddress& rPos, DataPilotTablePositionDa
DataPilotTableHeaderData aHeaderData;
aHeaderData.MemberName = pArray[nItem].Name;
aHeaderData.Flags = pArray[nItem].Flags;
- aHeaderData.Dimension = static_cast<sal_Int32>(pColFields[nField].mnDim);
- aHeaderData.Hierarchy = static_cast<sal_Int32>(pColFields[nField].mnHier);
- aHeaderData.Level = static_cast<sal_Int32>(pColFields[nField].mnLevel);
+ aHeaderData.Dimension = static_cast<sal_Int32>(mpColFields[nField].mnDim);
+ aHeaderData.Hierarchy = static_cast<sal_Int32>(mpColFields[nField].mnHier);
+ aHeaderData.Level = static_cast<sal_Int32>(mpColFields[nField].mnLevel);
rPosData.PositionData <<= aHeaderData;
return;
}
case DataPilotTablePositionType::ROW_HEADER:
{
- tools::Long nField = nCol - nTabStartCol;
+ tools::Long nField = GetRowFieldCompact(nCol, nRow);
if (nField < 0)
break;
- const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nField].maResult;
+ if (mpRowFields.size() < o3tl::make_unsigned(nField) + 1 )
+ break;
+ const uno::Sequence<sheet::MemberResult> rSequence = mpRowFields[nField].maResult;
if (!rSequence.hasElements())
break;
const sheet::MemberResult* pArray = rSequence.getConstArray();
- tools::Long nItem = nRow - nDataStartRow;
+ tools::Long nItem = nRow - mnDataStartRow;
// get origin of "continue" fields
while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
--nItem;
@@ -1379,9 +1580,9 @@ void ScDPOutput::GetPositionData(const ScAddress& rPos, DataPilotTablePositionDa
DataPilotTableHeaderData aHeaderData;
aHeaderData.MemberName = pArray[nItem].Name;
aHeaderData.Flags = pArray[nItem].Flags;
- aHeaderData.Dimension = static_cast<sal_Int32>(pRowFields[nField].mnDim);
- aHeaderData.Hierarchy = static_cast<sal_Int32>(pRowFields[nField].mnHier);
- aHeaderData.Level = static_cast<sal_Int32>(pRowFields[nField].mnLevel);
+ aHeaderData.Dimension = static_cast<sal_Int32>(mpRowFields[nField].mnDim);
+ aHeaderData.Hierarchy = static_cast<sal_Int32>(mpRowFields[nField].mnHier);
+ aHeaderData.Level = static_cast<sal_Int32>(mpRowFields[nField].mnLevel);
rPosData.PositionData <<= aHeaderData;
return;
@@ -1392,7 +1593,7 @@ void ScDPOutput::GetPositionData(const ScAddress& rPos, DataPilotTablePositionDa
bool ScDPOutput::GetDataResultPositionData(vector<sheet::DataPilotFieldFilter>& rFilters, const ScAddress& rPos)
{
// Check to make sure there is at least one data field.
- Reference<beans::XPropertySet> xPropSet(xSource, UNO_QUERY);
+ Reference<beans::XPropertySet> xPropSet(mxSource, UNO_QUERY);
if (!xPropSet.is())
return false;
@@ -1409,42 +1610,42 @@ bool ScDPOutput::GetDataResultPositionData(vector<sheet::DataPilotFieldFilter>&
std::vector<OUString> aDataNames;
std::vector<OUString> aGivenNames;
sheet::DataPilotFieldOrientation eDataOrient;
- lcl_GetTableVars( nGrandTotalCols, nGrandTotalRows, nDataLayoutIndex, aDataNames, aGivenNames, eDataOrient, xSource );
+ lcl_GetTableVars( nGrandTotalCols, nGrandTotalRows, nDataLayoutIndex, aDataNames, aGivenNames, eDataOrient, mxSource);
SCCOL nCol = rPos.Col();
SCROW nRow = rPos.Row();
SCTAB nTab = rPos.Tab();
- if ( nTab != aStartPos.Tab() )
- return false; // wrong sheet
+ if (nTab != maStartPos.Tab())
+ return false; // wrong sheet
CalcSizes();
// test for data area.
- if (nCol < nDataStartCol || nCol > nTabEndCol || nRow < nDataStartRow || nRow > nTabEndRow)
+ if (nCol < mnDataStartCol || nCol > mnTabEndCol || nRow < mnDataStartRow || nRow > mnTabEndRow)
{
// Cell is outside the data field area.
return false;
}
- bool bFilterByCol = (nCol <= static_cast<SCCOL>(nTabEndCol - nGrandTotalCols));
- bool bFilterByRow = (nRow <= static_cast<SCROW>(nTabEndRow - nGrandTotalRows));
+ bool bFilterByCol = (nCol <= static_cast<SCCOL>(mnTabEndCol - nGrandTotalCols));
+ bool bFilterByRow = (nRow <= static_cast<SCROW>(mnTabEndRow - nGrandTotalRows));
// column fields
- for (size_t nColField = 0; nColField < pColFields.size() && bFilterByCol; ++nColField)
+ for (size_t nColField = 0; nColField < mpColFields.size() && bFilterByCol; ++nColField)
{
- if (pColFields[nColField].mnDim == nDataLayoutIndex)
+ if (mpColFields[nColField].mnDim == nDataLayoutIndex)
// There is no sense including the data layout field for filtering.
continue;
sheet::DataPilotFieldFilter filter;
- filter.FieldName = pColFields[nColField].maName;
+ filter.FieldName = mpColFields[nColField].maName;
- const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nColField].maResult;
+ const uno::Sequence<sheet::MemberResult> rSequence = mpColFields[nColField].maResult;
const sheet::MemberResult* pArray = rSequence.getConstArray();
- OSL_ENSURE(nDataStartCol + rSequence.getLength() - 1 == nTabEndCol, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
+ OSL_ENSURE(mnDataStartCol + rSequence.getLength() - 1 == mnTabEndCol, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
- tools::Long nItem = nCol - nDataStartCol;
+ tools::Long nItem = nCol - mnDataStartCol;
// get origin of "continue" fields
while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
--nItem;
@@ -1454,21 +1655,21 @@ bool ScDPOutput::GetDataResultPositionData(vector<sheet::DataPilotFieldFilter>&
}
// row fields
- for (size_t nRowField = 0; nRowField < pRowFields.size() && bFilterByRow; ++nRowField)
+ for (size_t nRowField = 0; nRowField < mpRowFields.size() && bFilterByRow; ++nRowField)
{
- if (pRowFields[nRowField].mnDim == nDataLayoutIndex)
+ if (mpRowFields[nRowField].mnDim == nDataLayoutIndex)
// There is no sense including the data layout field for filtering.
continue;
sheet::DataPilotFieldFilter filter;
- filter.FieldName = pRowFields[nRowField].maName;
+ filter.FieldName = mpRowFields[nRowField].maName;
- const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nRowField].maResult;
+ const uno::Sequence<sheet::MemberResult> rSequence = mpRowFields[nRowField].maResult;
const sheet::MemberResult* pArray = rSequence.getConstArray();
- OSL_ENSURE(nDataStartRow + rSequence.getLength() - 1 == nTabEndRow, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
+ OSL_ENSURE(mnDataStartRow + rSequence.getLength() - 1 == mnTabEndRow, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
- tools::Long nItem = nRow - nDataStartRow;
+ tools::Long nItem = nRow - mnDataStartRow;
// get origin of "continue" fields
while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
--nItem;
@@ -1484,7 +1685,7 @@ namespace {
OUString lcl_GetDataFieldName( std::u16string_view rSourceName, sal_Int16 eFunc )
{
- const char* pStrId = nullptr;
+ TranslateId pStrId;
switch ( eFunc )
{
case sheet::GeneralFunction2::SUM: pStrId = STR_FUN_TEXT_SUM; break;
@@ -1540,11 +1741,11 @@ bool ScDPOutput::IsFilterButton( const ScAddress& rPos )
SCCOL nCol = rPos.Col();
SCROW nRow = rPos.Row();
SCTAB nTab = rPos.Tab();
- if ( nTab != aStartPos.Tab() || !bDoFilter )
+ if (nTab != maStartPos.Tab() || !mbDoFilter)
return false; // wrong sheet or no button at all
// filter button is at top left
- return ( nCol == aStartPos.Col() && nRow == aStartPos.Row() );
+ return nCol == maStartPos.Col() && nRow == maStartPos.Row();
}
tools::Long ScDPOutput::GetHeaderDim( const ScAddress& rPos, sheet::DataPilotFieldOrientation& rOrient )
@@ -1552,7 +1753,7 @@ tools::Long ScDPOutput::GetHeaderDim( const ScAddress& rPos, sheet::DataPilotFie
SCCOL nCol = rPos.Col();
SCROW nRow = rPos.Row();
SCTAB nTab = rPos.Tab();
- if ( nTab != aStartPos.Tab() )
+ if (nTab != maStartPos.Tab())
return -1; // wrong sheet
// calculate output positions and sizes
@@ -1561,30 +1762,30 @@ tools::Long ScDPOutput::GetHeaderDim( const ScAddress& rPos, sheet::DataPilotFie
// test for column header
- if ( nRow == nTabStartRow && nCol >= nDataStartCol && o3tl::make_unsigned(nCol) < nDataStartCol + pColFields.size())
+ if ( nRow == mnTabStartRow && nCol >= mnDataStartCol && o3tl::make_unsigned(nCol) < mnDataStartCol + mpColFields.size())
{
rOrient = sheet::DataPilotFieldOrientation_COLUMN;
- tools::Long nField = nCol - nDataStartCol;
- return pColFields[nField].mnDim;
+ tools::Long nField = nCol - mnDataStartCol;
+ return mpColFields[nField].mnDim;
}
// test for row header
- if ( nRow+1 == nDataStartRow && nCol >= nTabStartCol && o3tl::make_unsigned(nCol) < nTabStartCol + pRowFields.size() )
+ if ( nRow+1 == mnDataStartRow && nCol >= mnTabStartCol && o3tl::make_unsigned(nCol) < mnTabStartCol + mpRowFields.size() )
{
rOrient = sheet::DataPilotFieldOrientation_ROW;
- tools::Long nField = nCol - nTabStartCol;
- return pRowFields[nField].mnDim;
+ tools::Long nField = nCol - mnTabStartCol;
+ return mpRowFields[nField].mnDim;
}
// test for page field
- SCROW nPageStartRow = aStartPos.Row() + ( bDoFilter ? 1 : 0 );
- if ( nCol == aStartPos.Col() && nRow >= nPageStartRow && o3tl::make_unsigned(nRow) < nPageStartRow + pPageFields.size() )
+ SCROW nPageStartRow = maStartPos.Row() + (mbDoFilter ? 1 : 0);
+ if ( nCol == maStartPos.Col() && nRow >= nPageStartRow && o3tl::make_unsigned(nRow) < nPageStartRow + mpPageFields.size() )
{
rOrient = sheet::DataPilotFieldOrientation_PAGE;
tools::Long nField = nRow - nPageStartRow;
- return pPageFields[nField].mnDim;
+ return mpPageFields[nField].mnDim;
}
//TODO: single data field (?)
@@ -1602,7 +1803,7 @@ bool ScDPOutput::GetHeaderDrag( const ScAddress& rPos, bool bMouseLeft, bool bMo
SCCOL nCol = rPos.Col();
SCROW nRow = rPos.Row();
SCTAB nTab = rPos.Tab();
- if ( nTab != aStartPos.Tab() )
+ if ( nTab != maStartPos.Tab() )
return false; // wrong sheet
// calculate output positions and sizes
@@ -1611,10 +1812,10 @@ bool ScDPOutput::GetHeaderDrag( const ScAddress& rPos, bool bMouseLeft, bool bMo
// test for column header
- if ( nCol >= nDataStartCol && nCol <= nTabEndCol &&
- nRow + 1 >= nMemberStartRow && o3tl::make_unsigned(nRow) < nMemberStartRow + pColFields.size())
+ if ( nCol >= mnDataStartCol && nCol <= mnTabEndCol &&
+ nRow + 1 >= mnMemberStartRow && o3tl::make_unsigned(nRow) < mnMemberStartRow + mpColFields.size())
{
- tools::Long nField = nRow - nMemberStartRow;
+ tools::Long nField = nRow - mnMemberStartRow;
if (nField < 0)
{
nField = 0;
@@ -1622,15 +1823,15 @@ bool ScDPOutput::GetHeaderDrag( const ScAddress& rPos, bool bMouseLeft, bool bMo
}
//TODO: find start of dimension
- rPosRect = tools::Rectangle( nDataStartCol, nMemberStartRow + nField,
- nTabEndCol, nMemberStartRow + nField -1 );
+ rPosRect = tools::Rectangle(mnDataStartCol, mnMemberStartRow + nField,
+ mnTabEndCol, mnMemberStartRow + nField - 1);
bool bFound = false; // is this within the same orientation?
bool bBeforeDrag = false;
bool bAfterDrag = false;
- for (tools::Long nPos=0; o3tl::make_unsigned(nPos)<pColFields.size() && !bFound; nPos++)
+ for (tools::Long nPos=0; o3tl::make_unsigned(nPos)<mpColFields.size() && !bFound; nPos++)
{
- if (pColFields[nPos].mnDim == nDragDim)
+ if (mpColFields[nPos].mnDim == nDragDim)
{
bFound = true;
if ( nField < nPos )
@@ -1667,24 +1868,24 @@ bool ScDPOutput::GetHeaderDrag( const ScAddress& rPos, bool bMouseLeft, bool bMo
// test for row header
// special case if no row fields
- bool bSpecial = ( nRow+1 >= nDataStartRow && nRow <= nTabEndRow &&
- pRowFields.empty() && nCol == nTabStartCol && bMouseLeft );
+ bool bSpecial = ( nRow+1 >= mnDataStartRow && nRow <= mnTabEndRow &&
+ mpRowFields.empty() && nCol == mnTabStartCol && bMouseLeft );
- if ( bSpecial || ( nRow+1 >= nDataStartRow && nRow <= nTabEndRow &&
- nCol + 1 >= nTabStartCol && o3tl::make_unsigned(nCol) < nTabStartCol + pRowFields.size() ) )
+ if ( bSpecial || ( nRow+1 >= mnDataStartRow && nRow <= mnTabEndRow &&
+ nCol + 1 >= mnTabStartCol && o3tl::make_unsigned(nCol) < mnTabStartCol + mpRowFields.size() ) )
{
- tools::Long nField = nCol - nTabStartCol;
+ tools::Long nField = nCol - mnTabStartCol;
//TODO: find start of dimension
- rPosRect = tools::Rectangle( nTabStartCol + nField, nDataStartRow - 1,
- nTabStartCol + nField - 1, nTabEndRow );
+ rPosRect = tools::Rectangle(mnTabStartCol + nField, mnDataStartRow - 1,
+ mnTabStartCol + nField - 1, mnTabEndRow);
bool bFound = false; // is this within the same orientation?
bool bBeforeDrag = false;
bool bAfterDrag = false;
- for (tools::Long nPos=0; o3tl::make_unsigned(nPos)<pRowFields.size() && !bFound; nPos++)
+ for (tools::Long nPos = 0; o3tl::make_unsigned(nPos) < mpRowFields.size() && !bFound; nPos++)
{
- if (pRowFields[nPos].mnDim == nDragDim)
+ if (mpRowFields[nPos].mnDim == nDragDim)
{
bFound = true;
if ( nField < nPos )
@@ -1720,9 +1921,9 @@ bool ScDPOutput::GetHeaderDrag( const ScAddress& rPos, bool bMouseLeft, bool bMo
// test for page fields
- SCROW nPageStartRow = aStartPos.Row() + ( bDoFilter ? 1 : 0 );
- if ( nCol >= aStartPos.Col() && nCol <= nTabEndCol &&
- nRow + 1 >= nPageStartRow && o3tl::make_unsigned(nRow) < nPageStartRow + pPageFields.size() )
+ SCROW nPageStartRow = maStartPos.Row() + (mbDoFilter ? 1 : 0);
+ if (nCol >= maStartPos.Col() && nCol <= mnTabEndCol &&
+ nRow + 1 >= nPageStartRow && o3tl::make_unsigned(nRow) < nPageStartRow + mpPageFields.size())
{
tools::Long nField = nRow - nPageStartRow;
if (nField < 0)
@@ -1732,15 +1933,15 @@ bool ScDPOutput::GetHeaderDrag( const ScAddress& rPos, bool bMouseLeft, bool bMo
}
//TODO: find start of dimension
- rPosRect = tools::Rectangle( aStartPos.Col(), nPageStartRow + nField,
- nTabEndCol, nPageStartRow + nField - 1 );
+ rPosRect = tools::Rectangle(maStartPos.Col(), nPageStartRow + nField,
+ mnTabEndCol, nPageStartRow + nField - 1);
bool bFound = false; // is this within the same orientation?
bool bBeforeDrag = false;
bool bAfterDrag = false;
- for (tools::Long nPos=0; o3tl::make_unsigned(nPos)<pPageFields.size() && !bFound; nPos++)
+ for (tools::Long nPos = 0; o3tl::make_unsigned(nPos) < mpPageFields.size() && !bFound; nPos++)
{
- if (pPageFields[nPos].mnDim == nDragDim)
+ if (mpPageFields[nPos].mnDim == nDragDim)
{
bFound = true;
if ( nField < nPos )
diff --git a/sc/source/core/data/dpoutputgeometry.cxx b/sc/source/core/data/dpoutputgeometry.cxx
index 427bcf2326f3..0c5307258c9b 100644
--- a/sc/source/core/data/dpoutputgeometry.cxx
+++ b/sc/source/core/data/dpoutputgeometry.cxx
@@ -37,10 +37,6 @@ ScDPOutputGeometry::ScDPOutputGeometry(const ScRange& rOutRange, bool bShowFilte
{
}
-ScDPOutputGeometry::~ScDPOutputGeometry()
-{
-}
-
void ScDPOutputGeometry::setRowFieldCount(sal_uInt32 nCount)
{
mnRowFields = nCount;
diff --git a/sc/source/core/data/dpresfilter.cxx b/sc/source/core/data/dpresfilter.cxx
index 346cbef8b4f1..50280805714a 100644
--- a/sc/source/core/data/dpresfilter.cxx
+++ b/sc/source/core/data/dpresfilter.cxx
@@ -11,18 +11,19 @@
#include <global.hxx>
#include <unotools/charclass.hxx>
-#include <rtl/math.hxx>
#include <sal/log.hxx>
#include <o3tl/hash_combine.hxx>
#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
#include <com/sun/star/uno/Sequence.hxx>
+#include <limits>
+#include <utility>
+
using namespace com::sun::star;
-using namespace std;
-ScDPResultFilter::ScDPResultFilter(const OUString& rDimName, bool bDataLayout) :
- maDimName(rDimName), mbHasValue(false), mbDataLayout(bDataLayout) {}
+ScDPResultFilter::ScDPResultFilter(OUString aDimName, bool bDataLayout) :
+ maDimName(std::move(aDimName)), mbHasValue(false), mbDataLayout(bDataLayout) {}
ScDPResultFilterContext::ScDPResultFilterContext() :
mnCol(0), mnRow(0) {}
@@ -35,12 +36,6 @@ size_t ScDPResultTree::NamePairHash::operator() (const NamePairType& rPair) cons
return seed;
}
-ScDPResultTree::DimensionNode::DimensionNode() {}
-
-ScDPResultTree::DimensionNode::~DimensionNode()
-{
-}
-
#if DEBUG_PIVOT_TABLE
void ScDPResultTree::DimensionNode::dump(int nLevel) const
{
@@ -104,12 +99,12 @@ void ScDPResultTree::add(
// See if this dimension exists.
auto& rDims = pMemNode->maChildDimensions;
- OUString aUpperName = ScGlobal::getCharClassPtr()->uppercase(filter.maDimName);
+ OUString aUpperName = ScGlobal::getCharClass().uppercase(filter.maDimName);
auto itDim = rDims.find(aUpperName);
if (itDim == rDims.end())
{
// New dimension. Insert it.
- auto r = rDims.emplace(aUpperName, std::make_unique<DimensionNode>());
+ auto r = rDims.emplace(aUpperName, DimensionNode());
assert(r.second);
itDim = r.first;
}
@@ -117,9 +112,9 @@ void ScDPResultTree::add(
pDimName = &itDim->first;
// Now, see if this dimension member exists.
- DimensionNode* pDim = itDim->second.get();
- MembersType& rMembersValueNames = pDim->maChildMembersValueNames;
- aUpperName = ScGlobal::getCharClassPtr()->uppercase(filter.maValueName);
+ DimensionNode& rDim = itDim->second;
+ MembersType& rMembersValueNames = rDim.maChildMembersValueNames;
+ aUpperName = ScGlobal::getCharClass().uppercase(filter.maValueName);
MembersType::iterator itMem = rMembersValueNames.find(aUpperName);
if (itMem == rMembersValueNames.end())
{
@@ -138,8 +133,8 @@ void ScDPResultTree::add(
// makes no sense to add it to the separate mapping.
if (!filter.maValue.isEmpty() && filter.maValue != filter.maValueName)
{
- MembersType& rMembersValues = pDim->maChildMembersValues;
- aUpperName = ScGlobal::getCharClassPtr()->uppercase(filter.maValue);
+ MembersType& rMembersValues = rDim.maChildMembersValues;
+ aUpperName = ScGlobal::getCharClass().uppercase(filter.maValue);
MembersType::iterator itMemVal = rMembersValues.find(aUpperName);
if (itMemVal == rMembersValues.end())
{
@@ -159,8 +154,8 @@ void ScDPResultTree::add(
if (pDimName && pMemName)
{
NamePairType aNames(
- ScGlobal::getCharClassPtr()->uppercase(*pDimName),
- ScGlobal::getCharClassPtr()->uppercase(*pMemName));
+ ScGlobal::getCharClass().uppercase(*pDimName),
+ ScGlobal::getCharClass().uppercase(*pMemName));
LeafValuesType::iterator it = maLeafValues.find(aNames);
if (it == maLeafValues.end())
@@ -171,7 +166,7 @@ void ScDPResultTree::add(
else
{
// This name pair already exists. Set the value to NaN.
- rtl::math::setNan(&it->second);
+ it->second = std::numeric_limits<double>::quiet_NaN();
}
}
@@ -192,7 +187,7 @@ bool ScDPResultTree::empty() const
void ScDPResultTree::clear()
{
- maPrimaryDimName = EMPTY_OUSTRING;
+ maPrimaryDimName.clear();
mpRoot.reset( new MemberNode );
}
@@ -203,22 +198,22 @@ const ScDPResultTree::ValuesType* ScDPResultTree::getResults(
for (const sheet::DataPilotFieldFilter& rFilter : rFilters)
{
auto itDim = pMember->maChildDimensions.find(
- ScGlobal::getCharClassPtr()->uppercase(rFilter.FieldName));
+ ScGlobal::getCharClass().uppercase(rFilter.FieldName));
if (itDim == pMember->maChildDimensions.end())
// Specified dimension not found.
return nullptr;
- const DimensionNode* pDim = itDim->second.get();
- MembersType::const_iterator itMem( pDim->maChildMembersValueNames.find(
- ScGlobal::getCharClassPtr()->uppercase( rFilter.MatchValueName)));
+ const DimensionNode& rDim = itDim->second;
+ MembersType::const_iterator itMem( rDim.maChildMembersValueNames.find(
+ ScGlobal::getCharClass().uppercase( rFilter.MatchValueName)));
- if (itMem == pDim->maChildMembersValueNames.end())
+ if (itMem == rDim.maChildMembersValueNames.end())
{
// Specified member name not found, try locale independent value.
- itMem = pDim->maChildMembersValues.find( ScGlobal::getCharClassPtr()->uppercase( rFilter.MatchValue));
+ itMem = rDim.maChildMembersValues.find( ScGlobal::getCharClass().uppercase( rFilter.MatchValue));
- if (itMem == pDim->maChildMembersValues.end())
+ if (itMem == rDim.maChildMembersValues.end())
// Specified member not found.
return nullptr;
}
@@ -235,10 +230,10 @@ const ScDPResultTree::ValuesType* ScDPResultTree::getResults(
while (pFieldMember->maChildDimensions.size() == 1)
{
auto itDim( pFieldMember->maChildDimensions.begin());
- const DimensionNode* pDim = itDim->second.get();
- if (pDim->maChildMembersValueNames.size() != 1)
+ const DimensionNode& rDim = itDim->second;
+ if (rDim.maChildMembersValueNames.size() != 1)
break; // while
- pFieldMember = pDim->maChildMembersValueNames.begin()->second.get();
+ pFieldMember = rDim.maChildMembersValueNames.begin()->second.get();
if (!pFieldMember->maValues.empty())
return &pFieldMember->maValues;
}
@@ -250,8 +245,8 @@ const ScDPResultTree::ValuesType* ScDPResultTree::getResults(
double ScDPResultTree::getLeafResult(const css::sheet::DataPilotFieldFilter& rFilter) const
{
NamePairType aPair(
- ScGlobal::getCharClassPtr()->uppercase(rFilter.FieldName),
- ScGlobal::getCharClassPtr()->uppercase(rFilter.MatchValueName));
+ ScGlobal::getCharClass().uppercase(rFilter.FieldName),
+ ScGlobal::getCharClass().uppercase(rFilter.MatchValueName));
LeafValuesType::const_iterator it = maLeafValues.find(aPair);
if (it != maLeafValues.end())
@@ -259,9 +254,7 @@ double ScDPResultTree::getLeafResult(const css::sheet::DataPilotFieldFilter& rFi
return it->second;
// Not found. Return an NaN.
- double fNan;
- rtl::math::setNan(&fNan);
- return fNan;
+ return std::numeric_limits<double>::quiet_NaN();
}
#if DEBUG_PIVOT_TABLE
diff --git a/sc/source/core/data/dpsave.cxx b/sc/source/core/data/dpsave.cxx
index cb8e56e6d6fa..6e1d5c56f085 100644
--- a/sc/source/core/data/dpsave.cxx
+++ b/sc/source/core/data/dpsave.cxx
@@ -25,11 +25,13 @@
#include <dputil.hxx>
#include <generalfunction.hxx>
#include <dptabdat.hxx>
+#include <pivot/PivotTableFormats.hxx>
#include <sal/types.h>
#include <sal/log.hxx>
#include <osl/diagnose.h>
#include <comphelper/stl_types.hxx>
+#include <unotools/charclass.hxx>
#include <com/sun/star/sheet/XDimensionsSupplier.hpp>
#include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp>
@@ -42,10 +44,11 @@
#include <com/sun/star/sheet/XMembersSupplier.hpp>
#include <com/sun/star/container/XNamed.hpp>
#include <com/sun/star/util/XCloneable.hpp>
-#include <tools/diagnose_ex.h>
+#include <comphelper/diagnose_ex.hxx>
#include <unordered_map>
#include <algorithm>
+#include <utility>
using namespace com::sun::star;
using namespace com::sun::star::sheet;
@@ -61,8 +64,8 @@ static void lcl_SetBoolProperty( const uno::Reference<beans::XPropertySet>& xPro
xProp->setPropertyValue( rName, uno::Any( bValue ) );
}
-ScDPSaveMember::ScDPSaveMember(const OUString& rName) :
- aName( rName ),
+ScDPSaveMember::ScDPSaveMember(OUString _aName) :
+ aName(std::move( _aName )),
nVisibleMode( SC_DPSAVEMODE_DONTKNOW ),
nShowDetailsMode( SC_DPSAVEMODE_DONTKNOW )
{
@@ -178,8 +181,8 @@ void ScDPSaveMember::Dump(int nIndent) const
#endif
-ScDPSaveDimension::ScDPSaveDimension(const OUString& rName, bool bDataLayout) :
- aName( rName ),
+ScDPSaveDimension::ScDPSaveDimension(OUString _aName, bool bDataLayout) :
+ aName(std::move( _aName )),
bIsDataLayout( bDataLayout ),
bDupFlag( false ),
nOrientation( sheet::DataPilotFieldOrientation_HIDDEN ),
@@ -300,7 +303,7 @@ void ScDPSaveDimension::AddMember(std::unique_ptr<ScDPSaveMember> pMember)
}
else
{
- maMemberList.erase(std::remove(maMemberList.begin(), maMemberList.end(), aExisting->second.get()), maMemberList.end());
+ std::erase(maMemberList, aExisting->second.get());
aExisting->second = std::move(pMember);
}
maMemberList.push_back( tmp );
@@ -319,9 +322,9 @@ void ScDPSaveDimension::SetOrientation(css::sheet::DataPilotFieldOrientation nNe
nOrientation = nNew;
}
-void ScDPSaveDimension::SetSubTotals(std::vector<ScGeneralFunction> const & rFuncs)
+void ScDPSaveDimension::SetSubTotals(std::vector<ScGeneralFunction> && rFuncs)
{
- maSubTotalFuncs = rFuncs;
+ maSubTotalFuncs = std::move(rFuncs);
bSubTotalDefault = false;
}
@@ -455,21 +458,21 @@ ScDPSaveMember* ScDPSaveDimension::GetExistingMemberByName(const OUString& rName
ScDPSaveMember* ScDPSaveDimension::GetMemberByName(const OUString& rName)
{
- auto res = maMemberHash.find (rName);
- if (res != maMemberHash.end())
- return res->second.get();
+ ScDPSaveMember* pResult = GetExistingMemberByName(rName);
+ if (pResult)
+ return pResult;
- ScDPSaveMember* pNew = new ScDPSaveMember( rName );
- maMemberHash[rName] = std::unique_ptr<ScDPSaveMember>(pNew);
- maMemberList.push_back( pNew );
- return pNew;
+ pResult = new ScDPSaveMember(rName);
+ maMemberHash[rName] = std::unique_ptr<ScDPSaveMember>(pResult);
+ maMemberList.push_back(pResult);
+ return pResult;
}
void ScDPSaveDimension::SetMemberPosition( const OUString& rName, sal_Int32 nNewPos )
{
ScDPSaveMember* pMember = GetMemberByName( rName ); // make sure it exists and is in the hash
- maMemberList.erase(std::remove( maMemberList.begin(), maMemberList.end(), pMember), maMemberList.end() );
+ std::erase(maMemberList, pMember);
maMemberList.insert( maMemberList.begin() + nNewPos, pMember );
}
@@ -518,8 +521,7 @@ void ScDPSaveDimension::WriteToSource( const uno::Reference<uno::XInterface>& xD
uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY );
if ( xHierSupp.is() )
{
- uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
- xHiers = new ScNameToIndexAccess( xHiersName );
+ xHiers = new ScNameToIndexAccess(xHierSupp->getHierarchies());
nHierCount = xHiers->getCount();
}
@@ -532,8 +534,7 @@ void ScDPSaveDimension::WriteToSource( const uno::Reference<uno::XInterface>& xD
uno::Reference<sheet::XLevelsSupplier> xLevSupp(xHiers->getByIndex(nHier), uno::UNO_QUERY);
if ( xLevSupp.is() )
{
- uno::Reference<container::XNameAccess> xLevelsName = xLevSupp->getLevels();
- xLevels = new ScNameToIndexAccess( xLevelsName );
+ xLevels = new ScNameToIndexAccess(xLevSupp->getLevels());
nLevCount = xLevels->getCount();
}
@@ -687,72 +688,76 @@ void ScDPSaveDimension::Dump(int nIndent) const
#endif
-ScDPSaveData::ScDPSaveData() :
- nColumnGrandMode( SC_DPSAVEMODE_DONTKNOW ),
- nRowGrandMode( SC_DPSAVEMODE_DONTKNOW ),
- nIgnoreEmptyMode( SC_DPSAVEMODE_DONTKNOW ),
- nRepeatEmptyMode( SC_DPSAVEMODE_DONTKNOW ),
- bFilterButton( true ),
- bDrillDown( true ),
- mbDimensionMembersBuilt(false)
-{
-}
-
-ScDPSaveData::ScDPSaveData(const ScDPSaveData& r) :
- nColumnGrandMode( r.nColumnGrandMode ),
- nRowGrandMode( r.nRowGrandMode ),
- nIgnoreEmptyMode( r.nIgnoreEmptyMode ),
- nRepeatEmptyMode( r.nRepeatEmptyMode ),
- bFilterButton( r.bFilterButton ),
- bDrillDown( r.bDrillDown ),
- mbDimensionMembersBuilt(r.mbDimensionMembersBuilt),
- mpGrandTotalName(r.mpGrandTotalName)
-{
- if ( r.pDimensionData )
- pDimensionData.reset( new ScDPDimensionSaveData( *r.pDimensionData ) );
-
- for (auto const& it : r.m_DimList)
+ScDPSaveData::ScDPSaveData()
+ : mnColumnGrandMode(SC_DPSAVEMODE_DONTKNOW)
+ , mnRowGrandMode(SC_DPSAVEMODE_DONTKNOW)
+ , mnIgnoreEmptyMode(SC_DPSAVEMODE_DONTKNOW)
+ , mnRepeatEmptyMode(SC_DPSAVEMODE_DONTKNOW)
+ , mbFilterButton(true)
+ , mbDrillDown(true)
+ , mbExpandCollapse(false)
+ , mbDimensionMembersBuilt(false)
+{
+}
+
+ScDPSaveData::ScDPSaveData(const ScDPSaveData& rOther)
+ : mnColumnGrandMode(rOther.mnColumnGrandMode)
+ , mnRowGrandMode(rOther.mnRowGrandMode)
+ , mnIgnoreEmptyMode(rOther.mnIgnoreEmptyMode)
+ , mnRepeatEmptyMode(rOther.mnRepeatEmptyMode)
+ , mbFilterButton(rOther.mbFilterButton)
+ , mbDrillDown(rOther.mbDrillDown)
+ , mbExpandCollapse(rOther.mbExpandCollapse)
+ , mbDimensionMembersBuilt(rOther.mbDimensionMembersBuilt)
+ , mpGrandTotalName(rOther.mpGrandTotalName)
+{
+ if (rOther.mpDimensionData)
+ mpDimensionData.reset(new ScDPDimensionSaveData(*rOther.mpDimensionData));
+ if (rOther.mpFormats)
+ mpFormats.reset(new sc::PivotTableFormats(*rOther.mpFormats));
+
+ for (auto const& rOtherSaveDimension : rOther.m_DimList)
{
- m_DimList.push_back(std::make_unique<ScDPSaveDimension>(*it));
+ m_DimList.push_back(std::make_unique<ScDPSaveDimension>(*rOtherSaveDimension));
}
}
-ScDPSaveData& ScDPSaveData::operator= ( const ScDPSaveData& r )
+ScDPSaveData& ScDPSaveData::operator=(const ScDPSaveData& rOther)
{
- if ( &r != this )
+ if (&rOther != this)
{
this->~ScDPSaveData();
- new( this ) ScDPSaveData ( r );
+ new(this)ScDPSaveData(rOther);
}
return *this;
}
-bool ScDPSaveData::operator== ( const ScDPSaveData& r ) const
+bool ScDPSaveData::operator== (const ScDPSaveData& rOther) const
{
- if ( nColumnGrandMode != r.nColumnGrandMode ||
- nRowGrandMode != r.nRowGrandMode ||
- nIgnoreEmptyMode != r.nIgnoreEmptyMode ||
- nRepeatEmptyMode != r.nRepeatEmptyMode ||
- bFilterButton != r.bFilterButton ||
- bDrillDown != r.bDrillDown ||
- mbDimensionMembersBuilt != r.mbDimensionMembersBuilt)
+ if (mnColumnGrandMode != rOther.mnColumnGrandMode ||
+ mnRowGrandMode != rOther.mnRowGrandMode ||
+ mnIgnoreEmptyMode != rOther.mnIgnoreEmptyMode ||
+ mnRepeatEmptyMode != rOther.mnRepeatEmptyMode ||
+ mbFilterButton != rOther.mbFilterButton ||
+ mbDrillDown != rOther.mbDrillDown ||
+ mbDimensionMembersBuilt != rOther.mbDimensionMembersBuilt)
return false;
- if ( pDimensionData || r.pDimensionData )
- if ( !pDimensionData || !r.pDimensionData || !( *pDimensionData == *r.pDimensionData ) )
+ if (mpDimensionData || rOther.mpDimensionData)
+ if (!mpDimensionData || !rOther.mpDimensionData || !(*mpDimensionData == *rOther.mpDimensionData))
return false;
- if (!(::comphelper::ContainerUniquePtrEquals(m_DimList, r.m_DimList)))
+ if (!(::comphelper::ContainerUniquePtrEquals(m_DimList, rOther.m_DimList)))
return false;
if (mpGrandTotalName)
{
- if (!r.mpGrandTotalName)
+ if (!rOther.mpGrandTotalName)
return false;
- if (*mpGrandTotalName != *r.mpGrandTotalName)
+ if (*mpGrandTotalName != *rOther.mpGrandTotalName)
return false;
}
- else if (r.mpGrandTotalName)
+ else if (rOther.mpGrandTotalName)
return false;
return true;
@@ -762,6 +767,21 @@ ScDPSaveData::~ScDPSaveData()
{
}
+void ScDPSaveData::setFormats(sc::PivotTableFormats const& rPivotTableFormats)
+{
+ mpFormats.reset(new sc::PivotTableFormats(rPivotTableFormats));
+}
+
+bool ScDPSaveData::hasFormats()
+{
+ return bool(mpFormats);
+}
+
+sc::PivotTableFormats const& ScDPSaveData::getFormats()
+{
+ return *mpFormats;
+}
+
void ScDPSaveData::SetGrandTotalName(const OUString& rName)
{
mpGrandTotalName = rName;
@@ -783,7 +803,7 @@ public:
void operator() (const ScDPSaveDimension* pDim)
{
size_t nRank = mrNames.size();
- mrNames.emplace(pDim->GetName(), nRank);
+ mrNames.emplace(ScGlobal::getCharClass().uppercase(pDim->GetName()), nRank);
}
};
@@ -962,9 +982,9 @@ void ScDPSaveData::SetPosition( ScDPSaveDimension* pDim, tools::Long nNew )
[&pDim](const std::unique_ptr<ScDPSaveDimension>& rxDim) { return pDim == rxDim.get(); });
if (it != m_DimList.end())
{
- // Tell vector<unique_ptr> to give up ownership of this element.
- // Don't delete this instance as it is re-inserted into the
- // container later.
+ // Tell vector<unique_ptr> to give up ownership of this element. Don't
+ // delete this instance as it is re-inserted into the container later.
+ // coverity[leaked_storage] - re-inserted into the container later
it->release();
m_DimList.erase(it);
}
@@ -982,32 +1002,37 @@ void ScDPSaveData::SetPosition( ScDPSaveDimension* pDim, tools::Long nNew )
void ScDPSaveData::SetColumnGrand(bool bSet)
{
- nColumnGrandMode = sal_uInt16(bSet);
+ mnColumnGrandMode = sal_uInt16(bSet);
}
void ScDPSaveData::SetRowGrand(bool bSet)
{
- nRowGrandMode = sal_uInt16(bSet);
+ mnRowGrandMode = sal_uInt16(bSet);
}
void ScDPSaveData::SetIgnoreEmptyRows(bool bSet)
{
- nIgnoreEmptyMode = sal_uInt16(bSet);
+ mnIgnoreEmptyMode = sal_uInt16(bSet);
}
void ScDPSaveData::SetRepeatIfEmpty(bool bSet)
{
- nRepeatEmptyMode = sal_uInt16(bSet);
+ mnRepeatEmptyMode = sal_uInt16(bSet);
}
void ScDPSaveData::SetFilterButton(bool bSet)
{
- bFilterButton = bSet;
+ mbFilterButton = bSet;
}
void ScDPSaveData::SetDrillDown(bool bSet)
{
- bDrillDown = bSet;
+ mbDrillDown = bSet;
+}
+
+void ScDPSaveData::SetExpandCollapse(bool bSet)
+{
+ mbExpandCollapse = bSet;
}
static void lcl_ResetOrient( const uno::Reference<sheet::XDimensionsSupplier>& xSource )
@@ -1041,12 +1066,10 @@ void ScDPSaveData::WriteToSource( const uno::Reference<sheet::XDimensionsSupplie
try
{
- if ( nIgnoreEmptyMode != SC_DPSAVEMODE_DONTKNOW )
- lcl_SetBoolProperty( xSourceProp,
- SC_UNO_DP_IGNOREEMPTY, static_cast<bool>(nIgnoreEmptyMode) );
- if ( nRepeatEmptyMode != SC_DPSAVEMODE_DONTKNOW )
- lcl_SetBoolProperty( xSourceProp,
- SC_UNO_DP_REPEATEMPTY, static_cast<bool>(nRepeatEmptyMode) );
+ if (mnIgnoreEmptyMode != SC_DPSAVEMODE_DONTKNOW)
+ lcl_SetBoolProperty(xSourceProp, SC_UNO_DP_IGNOREEMPTY, bool(mnIgnoreEmptyMode));
+ if (mnRepeatEmptyMode != SC_DPSAVEMODE_DONTKNOW)
+ lcl_SetBoolProperty(xSourceProp, SC_UNO_DP_REPEATEMPTY, bool(mnRepeatEmptyMode));
}
catch(uno::Exception&)
{
@@ -1131,12 +1154,10 @@ void ScDPSaveData::WriteToSource( const uno::Reference<sheet::XDimensionsSupplie
if ( xSourceProp.is() )
{
- if ( nColumnGrandMode != SC_DPSAVEMODE_DONTKNOW )
- lcl_SetBoolProperty( xSourceProp,
- SC_UNO_DP_COLGRAND, static_cast<bool>(nColumnGrandMode) );
- if ( nRowGrandMode != SC_DPSAVEMODE_DONTKNOW )
- lcl_SetBoolProperty( xSourceProp,
- SC_UNO_DP_ROWGRAND, static_cast<bool>(nRowGrandMode) );
+ if (mnColumnGrandMode != SC_DPSAVEMODE_DONTKNOW)
+ lcl_SetBoolProperty(xSourceProp, SC_UNO_DP_COLGRAND, bool(mnColumnGrandMode));
+ if (mnRowGrandMode != SC_DPSAVEMODE_DONTKNOW)
+ lcl_SetBoolProperty(xSourceProp, SC_UNO_DP_ROWGRAND, bool(mnRowGrandMode));
}
}
catch(uno::Exception const &)
@@ -1157,22 +1178,22 @@ bool ScDPSaveData::IsEmpty() const
void ScDPSaveData::RemoveAllGroupDimensions( const OUString& rSrcDimName, std::vector<OUString>* pDeletedNames )
{
- if (!pDimensionData)
+ if (!mpDimensionData)
// No group dimensions exist. Nothing to do.
return;
// Remove numeric group dimension (exists once at most). No need to delete
// anything in save data (grouping was done inplace in an existing base
// dimension).
- pDimensionData->RemoveNumGroupDimension(rSrcDimName);
+ mpDimensionData->RemoveNumGroupDimension(rSrcDimName);
// Remove named group dimension(s). Dimensions have to be removed from
// dimension save data and from save data too.
- const ScDPSaveGroupDimension* pExistingGroup = pDimensionData->GetGroupDimForBase(rSrcDimName);
+ const ScDPSaveGroupDimension* pExistingGroup = mpDimensionData->GetGroupDimForBase(rSrcDimName);
while ( pExistingGroup )
{
OUString aGroupDimName = pExistingGroup->GetGroupDimName();
- pDimensionData->RemoveGroupDimension(aGroupDimName); // pExistingGroup is deleted
+ mpDimensionData->RemoveGroupDimension(aGroupDimName); // pExistingGroup is deleted
// also remove SaveData settings for the dimension that no longer exists
RemoveDimensionByName(aGroupDimName);
@@ -1181,7 +1202,7 @@ void ScDPSaveData::RemoveAllGroupDimensions( const OUString& rSrcDimName, std::v
pDeletedNames->push_back(aGroupDimName);
// see if there are more group dimensions
- pExistingGroup = pDimensionData->GetGroupDimForBase(rSrcDimName);
+ pExistingGroup = mpDimensionData->GetGroupDimForBase(rSrcDimName);
if ( pExistingGroup && pExistingGroup->GetGroupDimName() == aGroupDimName )
{
@@ -1194,17 +1215,17 @@ void ScDPSaveData::RemoveAllGroupDimensions( const OUString& rSrcDimName, std::v
ScDPDimensionSaveData* ScDPSaveData::GetDimensionData()
{
- if (!pDimensionData)
- pDimensionData.reset( new ScDPDimensionSaveData );
- return pDimensionData.get();
+ if (!mpDimensionData)
+ mpDimensionData.reset(new ScDPDimensionSaveData);
+ return mpDimensionData.get();
}
-void ScDPSaveData::SetDimensionData( const ScDPDimensionSaveData* pNew )
+void ScDPSaveData::SetDimensionData(const ScDPDimensionSaveData* pNew)
{
- if ( pNew )
- pDimensionData.reset( new ScDPDimensionSaveData( *pNew ) );
+ if (pNew)
+ mpDimensionData.reset(new ScDPDimensionSaveData(*pNew));
else
- pDimensionData.reset();
+ mpDimensionData.reset();
}
void ScDPSaveData::BuildAllDimensionMembers(ScDPTableData* pData)
@@ -1284,8 +1305,20 @@ void ScDPSaveData::SyncAllDimensionMembers(ScDPTableData* pData)
for (size_t j = 0; j < nMemberCount; ++j)
{
const ScDPItemData* pMemberData = pData->GetMemberById(nDimIndex, rMembers[j]);
- OUString aMemName = pData->GetFormattedString(nDimIndex, *pMemberData, false);
- aMemNames.insert(aMemName);
+ // ScDPCache::GetItemDataById() (via
+ // ScDPTableData::GetMemberById(),
+ // ScDPGroupTableData::GetMemberById() through
+ // GetCacheTable().getCache()) may return nullptr.
+ if (pMemberData)
+ {
+ OUString aMemName = pData->GetFormattedString(nDimIndex, *pMemberData, false);
+ aMemNames.insert(aMemName);
+ }
+ else
+ {
+ SAL_WARN("sc.core", "No pMemberData for nDimIndex " << nDimIndex << ", rMembers[j] " << rMembers[j]
+ << ", j " << j);
+ }
}
it->RemoveObsoleteMembers(aMemNames);
diff --git a/sc/source/core/data/dpsdbtab.cxx b/sc/source/core/data/dpsdbtab.cxx
index 0eaa46dc6422..b56217c27f43 100644
--- a/sc/source/core/data/dpsdbtab.cxx
+++ b/sc/source/core/data/dpsdbtab.cxx
@@ -122,14 +122,14 @@ void ScDatabaseDPData::CreateCacheTable()
aCacheTable.fillTable();
}
-void ScDatabaseDPData::FilterCacheTable(const vector<ScDPFilteredCache::Criterion>& rCriteria, const std::unordered_set<sal_Int32>& rCatDims)
+void ScDatabaseDPData::FilterCacheTable(std::vector<ScDPFilteredCache::Criterion>&& rCriteria, std::unordered_set<sal_Int32>&& rCatDims)
{
CreateCacheTable();
aCacheTable.filterByPageDimension(
- rCriteria, (IsRepeatIfEmpty() ? rCatDims : std::unordered_set<sal_Int32>()));
+ rCriteria, (IsRepeatIfEmpty() ? std::move(rCatDims) : std::unordered_set<sal_Int32>()));
}
-void ScDatabaseDPData::GetDrillDownData(const vector<ScDPFilteredCache::Criterion>& rCriteria, const std::unordered_set<sal_Int32>& rCatDims, Sequence< Sequence<Any> >& rData)
+void ScDatabaseDPData::GetDrillDownData(std::vector<ScDPFilteredCache::Criterion>&& rCriteria, std::unordered_set<sal_Int32>&& rCatDims, Sequence< Sequence<Any> >& rData)
{
CreateCacheTable();
sal_Int32 nRowSize = aCacheTable.getRowSize();
@@ -137,7 +137,7 @@ void ScDatabaseDPData::GetDrillDownData(const vector<ScDPFilteredCache::Criterio
return;
aCacheTable.filterTable(
- rCriteria, rData, IsRepeatIfEmpty() ? rCatDims : std::unordered_set<sal_Int32>());
+ rCriteria, rData, IsRepeatIfEmpty() ? std::move(rCatDims) : std::unordered_set<sal_Int32>());
}
void ScDatabaseDPData::CalcResults(CalcInfo& rInfo, bool bAutoShow)
diff --git a/sc/source/core/data/dpshttab.cxx b/sc/source/core/data/dpshttab.cxx
index c15ba043fffe..ae9407a6a64c 100644
--- a/sc/source/core/data/dpshttab.cxx
+++ b/sc/source/core/data/dpshttab.cxx
@@ -17,6 +17,7 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
+#include <svl/numformat.hxx>
#include <svl/zforlist.hxx>
#include <unotools/charclass.hxx>
@@ -173,14 +174,14 @@ void ScSheetDPData::CreateCacheTable()
aCacheTable.fillTable(aQuery, bIgnoreEmptyRows, bRepeatIfEmpty);
}
-void ScSheetDPData::FilterCacheTable(const vector<ScDPFilteredCache::Criterion>& rCriteria, const std::unordered_set<sal_Int32>& rCatDims)
+void ScSheetDPData::FilterCacheTable(std::vector<ScDPFilteredCache::Criterion>&& rCriteria, std::unordered_set<sal_Int32>&& rCatDims)
{
CreateCacheTable();
aCacheTable.filterByPageDimension(
- rCriteria, (IsRepeatIfEmpty() ? rCatDims : std::unordered_set<sal_Int32>()));
+ rCriteria, (IsRepeatIfEmpty() ? std::move(rCatDims) : std::unordered_set<sal_Int32>()));
}
-void ScSheetDPData::GetDrillDownData(const vector<ScDPFilteredCache::Criterion>& rCriteria, const std::unordered_set<sal_Int32>& rCatDims, Sequence< Sequence<Any> >& rData)
+void ScSheetDPData::GetDrillDownData(std::vector<ScDPFilteredCache::Criterion>&& rCriteria, std::unordered_set<sal_Int32>&& rCatDims, Sequence< Sequence<Any> >& rData)
{
CreateCacheTable();
sal_Int32 nRowSize = aCacheTable.getRowSize();
@@ -188,7 +189,7 @@ void ScSheetDPData::GetDrillDownData(const vector<ScDPFilteredCache::Criterion>&
return;
aCacheTable.filterTable(
- rCriteria, rData, IsRepeatIfEmpty() ? rCatDims : std::unordered_set<sal_Int32>());
+ rCriteria, rData, IsRepeatIfEmpty() ? std::move(rCatDims) : std::unordered_set<sal_Int32>());
}
void ScSheetDPData::CalcResults(CalcInfo& rInfo, bool bAutoShow)
@@ -238,7 +239,7 @@ const ScRange& ScSheetSourceDesc::GetSourceRange() const
if (!pRangeName)
break;
- OUString aUpper = ScGlobal::getCharClassPtr()->uppercase(maRangeName);
+ OUString aUpper = ScGlobal::getCharClass().uppercase(maRangeName);
const ScRangeData* pData = pRangeName->findByUpperName(aUpper);
if (!pData)
break;
@@ -283,7 +284,7 @@ const ScDPCache* ScSheetSourceDesc::CreateCache(const ScDPDimensionSaveData* pDi
if (!mpDoc)
return nullptr;
- const char* pErrId = CheckSourceRange();
+ TranslateId pErrId = CheckSourceRange();
if (pErrId)
{
OSL_FAIL( "Error Create Cache" );
@@ -303,7 +304,7 @@ const ScDPCache* ScSheetSourceDesc::CreateCache(const ScDPDimensionSaveData* pDi
return rCaches.getCache(GetSourceRange(), pDimData);
}
-const char* ScSheetSourceDesc::CheckSourceRange() const
+TranslateId ScSheetSourceDesc::CheckSourceRange() const
{
if (!mpDoc)
return STR_ERR_DATAPILOTSOURCE;
@@ -316,7 +317,7 @@ const char* ScSheetSourceDesc::CheckSourceRange() const
if (rSrcRange.aStart.Col() > rSrcRange.aEnd.Col() || rSrcRange.aStart.Row() > rSrcRange.aEnd.Row())
return STR_ERR_DATAPILOTSOURCE;
- return nullptr;
+ return {};
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/dptabres.cxx b/sc/source/core/data/dptabres.cxx
index b3d1d894dd2a..1a4020e56e91 100644
--- a/sc/source/core/data/dptabres.cxx
+++ b/sc/source/core/data/dptabres.cxx
@@ -40,6 +40,7 @@
#include <math.h>
#include <float.h>
#include <algorithm>
+#include <limits>
#include <memory>
#include <unordered_map>
@@ -58,9 +59,9 @@ using ::com::sun::star::uno::Sequence;
namespace {
-const char* aFuncStrIds[] = // matching enum ScSubTotalFunc
+const TranslateId aFuncStrIds[] = // matching enum ScSubTotalFunc
{
- nullptr, // SUBTOTAL_FUNC_NONE
+ {}, // SUBTOTAL_FUNC_NONE
STR_FUN_TEXT_AVG, // SUBTOTAL_FUNC_AVE
STR_FUN_TEXT_COUNT, // SUBTOTAL_FUNC_CNT
STR_FUN_TEXT_COUNT, // SUBTOTAL_FUNC_CNT2
@@ -73,7 +74,7 @@ const char* aFuncStrIds[] = // matching enum ScSubTotalFunc
STR_FUN_TEXT_VAR, // SUBTOTAL_FUNC_VAR
STR_FUN_TEXT_VAR, // SUBTOTAL_FUNC_VARP
STR_FUN_TEXT_MEDIAN, // SUBTOTAL_FUNC_MED
- nullptr // SUBTOTAL_FUNC_SELECTION_COUNT - not used for pivot table
+ {} // SUBTOTAL_FUNC_SELECTION_COUNT - not used for pivot table
};
bool lcl_SearchMember( const std::vector<std::unique_ptr<ScDPResultMember>>& list, SCROW nOrder, SCROW& rIndex)
@@ -1296,10 +1297,10 @@ void ScDPResultMember::ProcessData( const vector< SCROW >& aChildMembers, const
* Parse subtotal string and replace all occurrences of '?' with the caption
* string. Do ensure that escaped characters are not translated.
*/
-static OUString lcl_parseSubtotalName(const OUString& rSubStr, std::u16string_view rCaption)
+static OUString lcl_parseSubtotalName(std::u16string_view rSubStr, std::u16string_view rCaption)
{
OUStringBuffer aNewStr;
- sal_Int32 n = rSubStr.getLength();
+ sal_Int32 n = rSubStr.size();
bool bEscaped = false;
for (sal_Int32 i = 0; i < n; ++i)
{
@@ -1335,8 +1336,7 @@ void ScDPResultMember::FillMemberResults(
OSL_ENSURE( rPos+nSize <= pSequences->getLength(), "bumm" );
bool bIsNumeric = false;
- double fValue;
- rtl::math::setNan(&fValue);
+ double fValue = std::numeric_limits<double>::quiet_NaN();
OUString aName;
if ( pMemberName ) // if pMemberName != NULL, use instead of real member name
{
@@ -1408,7 +1408,13 @@ void ScDPResultMember::FillMemberResults(
// set "continue" flag (removed for subtotals later)
for (tools::Long i=1; i<nSize; i++)
+ {
pArray[rPos+i].Flags |= sheet::MemberResultFlags::CONTINUE;
+ // tdf#113002 - add numeric flag to recurring data fields
+ if (bIsNumeric)
+ pArray[rPos + i].Flags |= sheet::MemberResultFlags::NUMERIC;
+ }
+
if ( pParentLevel && pParentLevel->getRepeatItemLabels() )
{
tools::Long nSizeNonEmpty = nSize;
@@ -1498,7 +1504,7 @@ void ScDPResultMember::FillMemberResults(
}
}
- rtl::math::setNan(&fValue); /* TODO: any numeric value to obtain? */
+ fValue = std::numeric_limits<double>::quiet_NaN(); /* TODO: any numeric value to obtain? */
pArray[rPos].Name = aName;
pArray[rPos].Caption = aSubStr;
pArray[rPos].Flags = ( pArray[rPos].Flags |
@@ -1850,7 +1856,7 @@ OUString ScDPDataMember::GetName() const
if (pResultMember)
return pResultMember->GetName();
else
- return EMPTY_OUSTRING;
+ return OUString();
}
bool ScDPDataMember::IsVisible() const
@@ -2767,7 +2773,10 @@ ScDPResultDimension::~ScDPResultDimension()
ScDPResultMember *ScDPResultDimension::FindMember( SCROW iData ) const
{
if( bIsDataLayout )
- return maMemberArray[0].get();
+ {
+ SAL_WARN_IF(maMemberArray.empty(), "sc.core", "MemberArray is empty");
+ return !maMemberArray.empty() ? maMemberArray[0].get() : nullptr;
+ }
MemberHash::const_iterator aRes = maMemberHash.find( iData );
if( aRes != maMemberHash.end()) {
@@ -2974,8 +2983,11 @@ void ScDPResultDimension::LateInitFrom(
tools::Long ScDPResultDimension::GetSize(tools::Long nMeasure) const
{
- tools::Long nTotal = 0;
tools::Long nMemberCount = maMemberArray.size();
+ if (!nMemberCount)
+ return 0;
+
+ tools::Long nTotal = 0;
if (bIsDataLayout)
{
OSL_ENSURE(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
@@ -3128,7 +3140,7 @@ void ScDPResultDimension::SortMembers( ScDPResultMember* pRefMember )
// handle children
// for data layout, call only once - sorting measure is always taken from settings
- tools::Long nLoopCount = bIsDataLayout ? 1 : nCount;
+ tools::Long nLoopCount = bIsDataLayout ? std::min<tools::Long>(1, nCount) : nCount;
for (tools::Long i=0; i<nLoopCount; i++)
{
ScDPResultMember* pMember = maMemberArray[i].get();
@@ -4064,10 +4076,6 @@ LateInitParams::LateInitParams(
{
}
-LateInitParams::~LateInitParams()
-{
-}
-
bool LateInitParams::IsEnd( size_t nPos ) const
{
return nPos >= mppDim.size();
diff --git a/sc/source/core/data/dptabsrc.cxx b/sc/source/core/data/dptabsrc.cxx
index 1950c8500d39..20ddc28a9f99 100644
--- a/sc/source/core/data/dptabsrc.cxx
+++ b/sc/source/core/data/dptabsrc.cxx
@@ -29,7 +29,6 @@
#include <rtl/math.hxx>
#include <sal/log.hxx>
#include <svl/itemprop.hxx>
-#include <vcl/svapp.hxx>
#include <dpcache.hxx>
#include <dptabres.hxx>
@@ -88,32 +87,25 @@ SC_SIMPLE_SERVICE_INFO( ScDPMember, "ScDPMember", "com.sun.star.sheet.
static bool lcl_GetBoolFromAny( const uno::Any& aAny )
{
auto b = o3tl::tryAccess<bool>(aAny);
- return b && *b;
+ return b.has_value() && *b;
}
-ScDPSource::ScDPSource( ScDPTableData* pD ) :
- pData( pD ),
- bColumnGrand( true ), // default is true
- bRowGrand( true ),
- bIgnoreEmptyRows( false ),
- bRepeatIfEmpty( false ),
- nDupCount( 0 ),
- bResultOverflow( false ),
- bPageFiltered( false )
+ScDPSource::ScDPSource(ScDPTableData* pData)
+ : mpData(pData)
{
- pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
+ mpData->SetEmptyFlags(mbIgnoreEmptyRows, mbRepeatIfEmpty);
}
ScDPSource::~ScDPSource()
{
// free lists
- pColResults.reset();
- pRowResults.reset();
+ mpColumnResults.reset();
+ mpRowResults.reset();
- pColResRoot.reset();
- pRowResRoot.reset();
- pResData.reset();
+ mpColumnResultRoot.reset();
+ mpRowResultRoot.reset();
+ mpResultData.reset();
}
const std::optional<OUString> & ScDPSource::GetGrandTotalName() const
@@ -276,26 +268,24 @@ void ScDPSource::SetOrientation(sal_Int32 nColumn, sheet::DataPilotFieldOrientat
bool ScDPSource::IsDataLayoutDimension(sal_Int32 nDim)
{
- return nDim == pData->GetColumnCount();
+ return nDim == mpData->GetColumnCount();
}
sheet::DataPilotFieldOrientation ScDPSource::GetDataLayoutOrientation()
{
- return GetOrientation(pData->GetColumnCount());
+ return GetOrientation(mpData->GetColumnCount());
}
bool ScDPSource::IsDateDimension(sal_Int32 nDim)
{
- return pData->IsDateDimension(nDim);
+ return mpData->IsDateDimension(nDim);
}
ScDPDimensions* ScDPSource::GetDimensionsObject()
{
- if (!pDimensions.is())
- {
- pDimensions = new ScDPDimensions(this);
- }
- return pDimensions.get();
+ if (!mpDimensions.is())
+ mpDimensions = new ScDPDimensions(this);
+ return mpDimensions.get();
}
uno::Reference<container::XNameAccess> SAL_CALL ScDPSource::getDimensions()
@@ -305,19 +295,19 @@ uno::Reference<container::XNameAccess> SAL_CALL ScDPSource::getDimensions()
void ScDPSource::SetDupCount( tools::Long nNew )
{
- nDupCount = nNew;
+ mnDupCount = nNew;
}
ScDPDimension* ScDPSource::AddDuplicated(std::u16string_view rNewName)
{
- OSL_ENSURE( pDimensions.is(), "AddDuplicated without dimensions?" );
+ OSL_ENSURE(mpDimensions.is(), "AddDuplicated without dimensions?");
// re-use
- tools::Long nOldDimCount = pDimensions->getCount();
+ tools::Long nOldDimCount = mpDimensions->getCount();
for (tools::Long i=0; i<nOldDimCount; i++)
{
- ScDPDimension* pDim = pDimensions->getByIndex(i);
+ ScDPDimension* pDim = mpDimensions->getByIndex(i);
if (pDim && pDim->getName() == rNewName)
{
//TODO: test if pDim is a duplicate of source
@@ -325,21 +315,21 @@ ScDPDimension* ScDPSource::AddDuplicated(std::u16string_view rNewName)
}
}
- SetDupCount( nDupCount + 1 );
- pDimensions->CountChanged(); // uses nDupCount
+ SetDupCount(mnDupCount + 1);
+ mpDimensions->CountChanged(); // uses mnDupCount
- return pDimensions->getByIndex( pDimensions->getCount() - 1 );
+ return mpDimensions->getByIndex(mpDimensions->getCount() - 1);
}
sal_Int32 ScDPSource::GetSourceDim(sal_Int32 nDim)
{
// original source dimension or data layout dimension?
- if ( nDim <= pData->GetColumnCount() )
+ if (nDim <= mpData->GetColumnCount())
return nDim;
- if ( nDim < pDimensions->getCount() )
+ if (nDim < mpDimensions->getCount())
{
- ScDPDimension* pDimObj = pDimensions->getByIndex( nDim );
+ ScDPDimension* pDimObj = mpDimensions->getByIndex( nDim );
if ( pDimObj )
{
tools::Long nSource = pDimObj->GetSourceDim();
@@ -354,16 +344,16 @@ sal_Int32 ScDPSource::GetSourceDim(sal_Int32 nDim)
uno::Sequence< uno::Sequence<sheet::DataResult> > SAL_CALL ScDPSource::getResults()
{
- CreateRes_Impl(); // create pColResRoot and pRowResRoot
+ CreateRes_Impl(); // create mpColumnResultRoot and mpRowResultRoot
- if ( bResultOverflow ) // set in CreateRes_Impl
+ if (mbResultOverflow) // set in CreateRes_Impl
{
// no results available
throw uno::RuntimeException();
}
- sal_Int32 nColCount = pColResRoot->GetSize(pResData->GetColStartMeasure());
- sal_Int32 nRowCount = pRowResRoot->GetSize(pResData->GetRowStartMeasure());
+ sal_Int32 nColCount = mpColumnResultRoot->GetSize(mpResultData->GetColStartMeasure());
+ sal_Int32 nRowCount = mpRowResultRoot->GetSize(mpResultData->GetRowStartMeasure());
// allocate full sequence
//TODO: leave out empty rows???
@@ -372,14 +362,13 @@ uno::Sequence< uno::Sequence<sheet::DataResult> > SAL_CALL ScDPSource::getResult
uno::Sequence<sheet::DataResult>* pRowAry = aSeq.getArray();
for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++)
{
- uno::Sequence<sheet::DataResult> aColSeq( nColCount );
// use default values of DataResult
- pRowAry[nRow] = aColSeq;
+ pRowAry[nRow] = uno::Sequence<sheet::DataResult>(nColCount);
}
ScDPResultFilterContext aFilterCxt;
- pRowResRoot->FillDataResults(
- pColResRoot.get(), aFilterCxt, aSeq, pResData->GetRowStartMeasure());
+ mpRowResultRoot->FillDataResults(
+ mpColumnResultRoot.get(), aFilterCxt, aSeq, mpResultData->GetRowStartMeasure());
maResFilterSet.swap(aFilterCxt.maFilterSet); // Keep this data for GETPIVOTDATA.
@@ -396,12 +385,7 @@ uno::Sequence<double> ScDPSource::getFilteredResults(
const ScDPResultTree::ValuesType* pVals = maResFilterSet.getResults(aFilters);
if (pVals && !pVals->empty())
{
- size_t n = pVals->size();
- uno::Sequence<double> aRet(n);
- for (size_t i = 0; i < n; ++i)
- aRet[i] = (*pVals)[i];
-
- return aRet;
+ return comphelper::containerToSequence(*pVals);
}
if (aFilters.getLength() == 1)
@@ -442,7 +426,7 @@ Sequence< Sequence<Any> > SAL_CALL ScDPSource::getDrillDownData(const Sequence<s
const OUString& aFieldName = rFilter.FieldName;
for (sal_Int32 nCol = 0; nCol < nColumnCount; ++nCol)
{
- if (aFieldName == pData->getDimensionName(nCol))
+ if (aFieldName == mpData->getDimensionName(nCol))
{
ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nCol );
ScDPMembers* pMembers = pDim->GetHierarchiesObject()->getByIndex(0)->
@@ -462,26 +446,26 @@ Sequence< Sequence<Any> > SAL_CALL ScDPSource::getDrillDownData(const Sequence<s
// Take into account the visibilities of field members.
ScDPResultVisibilityData aResVisData(this);
- pRowResRoot->FillVisibilityData(aResVisData);
- pColResRoot->FillVisibilityData(aResVisData);
+ mpRowResultRoot->FillVisibilityData(aResVisData);
+ mpColumnResultRoot->FillVisibilityData(aResVisData);
aResVisData.fillFieldFilters(aFilterCriteria);
Sequence< Sequence<Any> > aTabData;
std::unordered_set<sal_Int32> aCatDims;
GetCategoryDimensionIndices(aCatDims);
- pData->GetDrillDownData(aFilterCriteria, aCatDims, aTabData);
+ mpData->GetDrillDownData(std::move(aFilterCriteria), std::move(aCatDims), aTabData);
return aTabData;
}
OUString ScDPSource::getDataDescription()
{
- CreateRes_Impl(); // create pResData
+ CreateRes_Impl(); // create mpResultData
OUString aRet;
- if ( pResData->GetMeasureCount() == 1 )
+ if (mpResultData->GetMeasureCount() == 1)
{
bool bTotalResult = false;
- aRet = pResData->GetMeasureString(0, true, SUBTOTAL_FUNC_NONE, bTotalResult);
+ aRet = mpResultData->GetMeasureString(0, true, SUBTOTAL_FUNC_NONE, bTotalResult);
}
// empty for more than one measure
@@ -491,34 +475,34 @@ OUString ScDPSource::getDataDescription()
void ScDPSource::setIgnoreEmptyRows(bool bSet)
{
- bIgnoreEmptyRows = bSet;
- pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
+ mbIgnoreEmptyRows = bSet;
+ mpData->SetEmptyFlags(mbIgnoreEmptyRows, mbRepeatIfEmpty);
}
void ScDPSource::setRepeatIfEmpty(bool bSet)
{
- bRepeatIfEmpty = bSet;
- pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
+ mbRepeatIfEmpty = bSet;
+ mpData->SetEmptyFlags(mbIgnoreEmptyRows, mbRepeatIfEmpty);
}
void ScDPSource::disposeData()
{
maResFilterSet.clear();
- if ( pResData )
+ if (mpResultData)
{
// reset all data...
- pColResRoot.reset();
- pRowResRoot.reset();
- pResData.reset();
- pColResults.reset();
- pRowResults.reset();
- aColLevelList.clear();
- aRowLevelList.clear();
+ mpColumnResultRoot.reset();
+ mpRowResultRoot.reset();
+ mpResultData.reset();
+ mpColumnResults.reset();
+ mpRowResults.reset();
+ maColumnLevelList.clear();
+ maRowLevelList.clear();
}
- pDimensions.clear(); // settings have to be applied (from SaveData) again!
+ mpDimensions.clear(); // settings have to be applied (from SaveData) again!
SetDupCount( 0 );
maColDims.clear();
@@ -526,9 +510,9 @@ void ScDPSource::disposeData()
maDataDims.clear();
maPageDims.clear();
- pData->DisposeData(); // cached entries etc.
- bPageFiltered = false;
- bResultOverflow = false;
+ mpData->DisposeData(); // cached entries etc.
+ mbPageFiltered = false;
+ mbResultOverflow = false;
}
static tools::Long lcl_CountMinMembers(const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLevel, tools::Long nLevels )
@@ -678,13 +662,13 @@ void ScDPSource::FilterCacheByPageDimensions()
// be re-initialized. Currently, CreateRes_Impl always uses a fresh cache
// because ScDBDocFunc::DataPilotUpdate calls InvalidateData.
- if (bPageFiltered)
+ if (mbPageFiltered)
{
SAL_WARN( "sc.core","tried to apply page field filters several times");
- pData->DisposeData();
- pData->CreateCacheTable(); // re-initialize the cache table
- bPageFiltered = false;
+ mpData->DisposeData();
+ mpData->CreateCacheTable(); // re-initialize the cache table
+ mbPageFiltered = false;
}
// filter table by page dimensions.
@@ -729,14 +713,14 @@ void ScDPSource::FilterCacheByPageDimensions()
{
std::unordered_set<sal_Int32> aCatDims;
GetCategoryDimensionIndices(aCatDims);
- pData->FilterCacheTable(aCriteria, aCatDims);
- bPageFiltered = true;
+ mpData->FilterCacheTable(std::move(aCriteria), std::move(aCatDims));
+ mbPageFiltered = true;
}
}
void ScDPSource::CreateRes_Impl()
{
- if (pResData)
+ if (mpResultData)
return;
sheet::DataPilotFieldOrientation nDataOrient = GetDataLayoutOrientation();
@@ -744,7 +728,7 @@ void ScDPSource::CreateRes_Impl()
nDataOrient != sheet::DataPilotFieldOrientation_ROW ) )
{
// if more than one data dimension, data layout orientation must be set
- SetOrientation( pData->GetColumnCount(), sheet::DataPilotFieldOrientation_ROW );
+ SetOrientation(mpData->GetColumnCount(), sheet::DataPilotFieldOrientation_ROW);
nDataOrient = sheet::DataPilotFieldOrientation_ROW;
}
@@ -820,10 +804,10 @@ void ScDPSource::CreateRes_Impl()
aInfo.aDataSrcCols.push_back(nDimIndex);
}
- pResData.reset( new ScDPResultData(*this) );
- pResData->SetMeasureData(aDataFunctions, aDataRefValues, aDataRefOrient, aDataNames);
- pResData->SetDataLayoutOrientation(nDataOrient);
- pResData->SetLateInit( bLateInit );
+ mpResultData.reset( new ScDPResultData(*this) );
+ mpResultData->SetMeasureData(aDataFunctions, aDataRefValues, aDataRefOrient, aDataNames);
+ mpResultData->SetDataLayoutOrientation(nDataOrient);
+ mpResultData->SetLateInit( bLateInit );
bool bHasAutoShow = false;
@@ -845,16 +829,16 @@ void ScDPSource::CreateRes_Impl()
sheet::DataPilotFieldOrientation nDataLayoutOrient = GetDataLayoutOrientation();
tools::Long nColDimCount2 = maColDims.size() - (nDataLayoutOrient == sheet::DataPilotFieldOrientation_COLUMN ? 1 : 0);
tools::Long nRowDimCount2 = maRowDims.size() - (nDataLayoutOrient == sheet::DataPilotFieldOrientation_ROW ? 1 : 0);
- bool bShowColGrand = bColumnGrand && nColDimCount2 > 0;
- bool bShowRowGrand = bRowGrand && nRowDimCount2 > 0;
- pColResRoot.reset( new ScDPResultMember(pResData.get(), bShowColGrand) );
- pRowResRoot.reset( new ScDPResultMember(pResData.get(), bShowRowGrand) );
+ bool bShowColGrand = mbColumnGrand && nColDimCount2 > 0;
+ bool bShowRowGrand = mbRowGrand && nRowDimCount2 > 0;
+ mpColumnResultRoot.reset( new ScDPResultMember(mpResultData.get(), bShowColGrand) );
+ mpRowResultRoot.reset( new ScDPResultMember(mpResultData.get(), bShowRowGrand) );
FillCalcInfo(false, aInfo, bHasAutoShow);
tools::Long nColLevelCount = aInfo.aColLevels.size();
- pColResRoot->InitFrom( aInfo.aColDims, aInfo.aColLevels, 0, aInitState );
- pColResRoot->SetHasElements();
+ mpColumnResultRoot->InitFrom( aInfo.aColDims, aInfo.aColLevels, 0, aInitState );
+ mpColumnResultRoot->SetHasElements();
FillCalcInfo(true, aInfo, bHasAutoShow);
tools::Long nRowLevelCount = aInfo.aRowLevels.size();
@@ -865,8 +849,8 @@ void ScDPSource::CreateRes_Impl()
aInfo.aRowLevels[nRowLevelCount-1]->SetEnableLayout( false );
}
- pRowResRoot->InitFrom( aInfo.aRowDims, aInfo.aRowLevels, 0, aInitState );
- pRowResRoot->SetHasElements();
+ mpRowResultRoot->InitFrom( aInfo.aRowDims, aInfo.aRowLevels, 0, aInitState );
+ mpRowResultRoot->SetHasElements();
// initialize members object also for all page dimensions (needed for numeric groups)
for (const auto& rDimIndex : maPageDims)
@@ -893,7 +877,7 @@ void ScDPSource::CreateRes_Impl()
// resulting table is too big -> abort before calculating
// (this relies on late init, so no members are allocated in InitFrom above)
- bResultOverflow = true;
+ mbResultOverflow = true;
return;
}
@@ -901,37 +885,37 @@ void ScDPSource::CreateRes_Impl()
aInfo.aPageDims = maPageDims;
aInfo.pInitState = &aInitState;
- aInfo.pColRoot = pColResRoot.get();
- aInfo.pRowRoot = pRowResRoot.get();
- pData->CalcResults(aInfo, false);
+ aInfo.pColRoot = mpColumnResultRoot.get();
+ aInfo.pRowRoot = mpRowResultRoot.get();
+ mpData->CalcResults(aInfo, false);
- pColResRoot->CheckShowEmpty();
- pRowResRoot->CheckShowEmpty();
+ mpColumnResultRoot->CheckShowEmpty();
+ mpRowResultRoot->CheckShowEmpty();
// With all data processed, calculate the final results:
// UpdateDataResults calculates all original results from the collected values,
// and stores them as reference values if needed.
- pRowResRoot->UpdateDataResults( pColResRoot.get(), pResData->GetRowStartMeasure() );
+ mpRowResultRoot->UpdateDataResults(mpColumnResultRoot.get(), mpResultData->GetRowStartMeasure());
if ( bHasAutoShow ) // do the double calculation only if AutoShow is used
{
// Find the desired members and set bAutoHidden flag for the others
- pRowResRoot->DoAutoShow( pColResRoot.get() );
+ mpRowResultRoot->DoAutoShow(mpColumnResultRoot.get());
// Reset all results to empty, so they can be built again with data for the
// desired members only.
- pColResRoot->ResetResults();
- pRowResRoot->ResetResults();
- pData->CalcResults(aInfo, true);
+ mpColumnResultRoot->ResetResults();
+ mpRowResultRoot->ResetResults();
+ mpData->CalcResults(aInfo, true);
// Call UpdateDataResults again, with the new (limited) values.
- pRowResRoot->UpdateDataResults( pColResRoot.get(), pResData->GetRowStartMeasure() );
+ mpRowResultRoot->UpdateDataResults(mpColumnResultRoot.get(), mpResultData->GetRowStartMeasure());
}
// SortMembers does the sorting by a result dimension, using the original results,
// but not running totals etc.
- pRowResRoot->SortMembers( pColResRoot.get() );
+ mpRowResultRoot->SortMembers(mpColumnResultRoot.get());
// UpdateRunningTotals calculates running totals along column/row dimensions,
// differences from other members (named or relative), and column/row percentages
@@ -940,9 +924,9 @@ void ScDPSource::CreateRes_Impl()
// Column/row percentages and index values must be done after sorting, because the
// results may no longer be in the right order (row total for percentage of row is
// always 1).
- ScDPRunningTotalState aRunning( pColResRoot.get(), pRowResRoot.get() );
+ ScDPRunningTotalState aRunning(mpColumnResultRoot.get(), mpRowResultRoot.get());
ScDPRowTotals aTotals;
- pRowResRoot->UpdateRunningTotals( pColResRoot.get(), pResData->GetRowStartMeasure(), aRunning, aTotals );
+ mpRowResultRoot->UpdateRunningTotals(mpColumnResultRoot.get(), mpResultData->GetRowStartMeasure(), aRunning, aTotals);
#if DUMP_PIVOT_TABLE
DumpResults();
@@ -1001,44 +985,44 @@ void ScDPSource::FillLevelList( sheet::DataPilotFieldOrientation nOrientation, s
void ScDPSource::FillMemberResults()
{
- if ( pColResults || pRowResults )
+ if (mpColumnResults || mpRowResults)
return;
CreateRes_Impl();
- if ( bResultOverflow ) // set in CreateRes_Impl
+ if (mbResultOverflow) // set in CreateRes_Impl
{
// no results available -> abort (leave empty)
// exception is thrown in ScDPSource::getResults
return;
}
- FillLevelList( sheet::DataPilotFieldOrientation_COLUMN, aColLevelList );
- sal_Int32 nColLevelCount = aColLevelList.size();
+ FillLevelList(sheet::DataPilotFieldOrientation_COLUMN, maColumnLevelList);
+ sal_Int32 nColLevelCount = maColumnLevelList.size();
if (nColLevelCount)
{
- tools::Long nColDimSize = pColResRoot->GetSize(pResData->GetColStartMeasure());
- pColResults.reset(new uno::Sequence<sheet::MemberResult>[nColLevelCount]);
+ tools::Long nColDimSize = mpColumnResultRoot->GetSize(mpResultData->GetColStartMeasure());
+ mpColumnResults.reset(new uno::Sequence<sheet::MemberResult>[nColLevelCount]);
for (tools::Long i=0; i<nColLevelCount; i++)
- pColResults[i].realloc(nColDimSize);
+ mpColumnResults[i].realloc(nColDimSize);
tools::Long nPos = 0;
- pColResRoot->FillMemberResults( pColResults.get(), nPos, pResData->GetColStartMeasure(),
- true, nullptr, nullptr );
+ mpColumnResultRoot->FillMemberResults(mpColumnResults.get(), nPos, mpResultData->GetColStartMeasure(),
+ true, nullptr, nullptr);
}
- FillLevelList( sheet::DataPilotFieldOrientation_ROW, aRowLevelList );
- tools::Long nRowLevelCount = aRowLevelList.size();
+ FillLevelList(sheet::DataPilotFieldOrientation_ROW, maRowLevelList);
+ tools::Long nRowLevelCount = maRowLevelList.size();
if (nRowLevelCount)
{
- tools::Long nRowDimSize = pRowResRoot->GetSize(pResData->GetRowStartMeasure());
- pRowResults.reset( new uno::Sequence<sheet::MemberResult>[nRowLevelCount] );
+ tools::Long nRowDimSize = mpRowResultRoot->GetSize(mpResultData->GetRowStartMeasure());
+ mpRowResults.reset( new uno::Sequence<sheet::MemberResult>[nRowLevelCount] );
for (tools::Long i=0; i<nRowLevelCount; i++)
- pRowResults[i].realloc(nRowDimSize);
+ mpRowResults[i].realloc(nRowDimSize);
tools::Long nPos = 0;
- pRowResRoot->FillMemberResults( pRowResults.get(), nPos, pResData->GetRowStartMeasure(),
- true, nullptr, nullptr );
+ mpRowResultRoot->FillMemberResults(mpRowResults.get(), nPos, mpResultData->GetRowStartMeasure(),
+ true, nullptr, nullptr);
}
}
@@ -1047,19 +1031,19 @@ const uno::Sequence<sheet::MemberResult>* ScDPSource::GetMemberResults( const Sc
FillMemberResults();
sal_Int32 i = 0;
- sal_Int32 nColCount = aColLevelList.size();
+ sal_Int32 nColCount = maColumnLevelList.size();
for (i=0; i<nColCount; i++)
{
- ScDPLevel* pColLevel = aColLevelList[i];
+ ScDPLevel* pColLevel = maColumnLevelList[i];
if ( pColLevel == pLevel )
- return &pColResults[i];
+ return &mpColumnResults[i];
}
- sal_Int32 nRowCount = aRowLevelList.size();
+ sal_Int32 nRowCount = maRowLevelList.size();
for (i=0; i<nRowCount; i++)
{
- ScDPLevel* pRowLevel = aRowLevelList[i];
+ ScDPLevel* pRowLevel = maRowLevelList[i];
if ( pRowLevel == pLevel )
- return &pRowResults[i];
+ return &mpRowResults[i];
}
return nullptr;
}
@@ -1068,21 +1052,19 @@ const uno::Sequence<sheet::MemberResult>* ScDPSource::GetMemberResults( const Sc
uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPSource::getPropertySetInfo()
{
- SolarMutexGuard aGuard;
using beans::PropertyAttribute::READONLY;
static const SfxItemPropertyMapEntry aDPSourceMap_Impl[] =
{
- { u"" SC_UNO_DP_COLGRAND, 0, cppu::UnoType<bool>::get(), 0, 0 },
- { u"" SC_UNO_DP_DATADESC, 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0 },
- { u"" SC_UNO_DP_IGNOREEMPTY, 0, cppu::UnoType<bool>::get(), 0, 0 }, // for sheet data only
- { u"" SC_UNO_DP_REPEATEMPTY, 0, cppu::UnoType<bool>::get(), 0, 0 }, // for sheet data only
- { u"" SC_UNO_DP_ROWGRAND, 0, cppu::UnoType<bool>::get(), 0, 0 },
- { u"" SC_UNO_DP_ROWFIELDCOUNT, 0, cppu::UnoType<sal_Int32>::get(), READONLY, 0 },
- { u"" SC_UNO_DP_COLUMNFIELDCOUNT, 0, cppu::UnoType<sal_Int32>::get(), READONLY, 0 },
- { u"" SC_UNO_DP_DATAFIELDCOUNT, 0, cppu::UnoType<sal_Int32>::get(), READONLY, 0 },
- { u"" SC_UNO_DP_GRANDTOTAL_NAME, 0, cppu::UnoType<OUString>::get(), 0, 0 },
- { u"", 0, css::uno::Type(), 0, 0 }
+ { SC_UNO_DP_COLGRAND, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_DP_DATADESC, 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNO_DP_IGNOREEMPTY, 0, cppu::UnoType<bool>::get(), 0, 0 }, // for sheet data only
+ { SC_UNO_DP_REPEATEMPTY, 0, cppu::UnoType<bool>::get(), 0, 0 }, // for sheet data only
+ { SC_UNO_DP_ROWGRAND, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_DP_ROWFIELDCOUNT, 0, cppu::UnoType<sal_Int32>::get(), READONLY, 0 },
+ { SC_UNO_DP_COLUMNFIELDCOUNT, 0, cppu::UnoType<sal_Int32>::get(), READONLY, 0 },
+ { SC_UNO_DP_DATAFIELDCOUNT, 0, cppu::UnoType<sal_Int32>::get(), READONLY, 0 },
+ { SC_UNO_DP_GRANDTOTAL_NAME, 0, cppu::UnoType<OUString>::get(), 0, 0 },
};
static uno::Reference<beans::XPropertySetInfo> aRef =
new SfxItemPropertySetInfo( aDPSourceMap_Impl );
@@ -1092,9 +1074,9 @@ uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPSource::getPropertySetInfo(
void SAL_CALL ScDPSource::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
{
if (aPropertyName == SC_UNO_DP_COLGRAND)
- bColumnGrand = lcl_GetBoolFromAny(aValue);
+ mbColumnGrand = lcl_GetBoolFromAny(aValue);
else if (aPropertyName == SC_UNO_DP_ROWGRAND)
- bRowGrand = lcl_GetBoolFromAny(aValue);
+ mbRowGrand = lcl_GetBoolFromAny(aValue);
else if (aPropertyName == SC_UNO_DP_IGNOREEMPTY)
setIgnoreEmptyRows( lcl_GetBoolFromAny( aValue ) );
else if (aPropertyName == SC_UNO_DP_REPEATEMPTY)
@@ -1116,13 +1098,13 @@ uno::Any SAL_CALL ScDPSource::getPropertyValue( const OUString& aPropertyName )
{
uno::Any aRet;
if ( aPropertyName == SC_UNO_DP_COLGRAND )
- aRet <<= bColumnGrand;
+ aRet <<= mbColumnGrand;
else if ( aPropertyName == SC_UNO_DP_ROWGRAND )
- aRet <<= bRowGrand;
+ aRet <<= mbRowGrand;
else if ( aPropertyName == SC_UNO_DP_IGNOREEMPTY )
- aRet <<= bIgnoreEmptyRows;
+ aRet <<= mbIgnoreEmptyRows;
else if ( aPropertyName == SC_UNO_DP_REPEATEMPTY )
- aRet <<= bRepeatIfEmpty;
+ aRet <<= mbRepeatIfEmpty;
else if ( aPropertyName == SC_UNO_DP_DATADESC ) // read-only
aRet <<= getDataDescription();
else if ( aPropertyName == SC_UNO_DP_ROWFIELDCOUNT ) // read-only
@@ -1148,9 +1130,9 @@ uno::Any SAL_CALL ScDPSource::getPropertyValue( const OUString& aPropertyName )
void ScDPSource::DumpResults() const
{
std::cout << "+++++ column root" << std::endl;
- pColResRoot->Dump(1);
+ mpColumnResultRoot->Dump(1);
std::cout << "+++++ row root" << std::endl;
- pRowResRoot->Dump(1);
+ mpRowResultRoot->Dump(1);
}
#endif
@@ -1396,26 +1378,23 @@ const ScDPItemData& ScDPDimension::GetSelectedData()
uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPDimension::getPropertySetInfo()
{
- SolarMutexGuard aGuard;
-
static const SfxItemPropertyMapEntry aDPDimensionMap_Impl[] =
{
- { u"" SC_UNO_DP_FILTER, 0, cppu::UnoType<uno::Sequence<sheet::TableFilterField>>::get(), 0, 0 },
- { u"" SC_UNO_DP_FLAGS, 0, cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0 },
- { u"" SC_UNO_DP_FUNCTION, 0, cppu::UnoType<sheet::GeneralFunction>::get(), 0, 0 },
- { u"" SC_UNO_DP_FUNCTION2, 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
- { u"" SC_UNO_DP_ISDATALAYOUT, 0, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0 },
- { u"" SC_UNO_DP_NUMBERFO, 0, cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0 },
- { u"" SC_UNO_DP_ORIENTATION, 0, cppu::UnoType<sheet::DataPilotFieldOrientation>::get(), 0, 0 },
- { u"" SC_UNO_DP_ORIGINAL, 0, cppu::UnoType<container::XNamed>::get(), beans::PropertyAttribute::READONLY, 0 },
- { u"" SC_UNO_DP_ORIGINAL_POS, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
- { u"" SC_UNO_DP_POSITION, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
- { u"" SC_UNO_DP_REFVALUE, 0, cppu::UnoType<sheet::DataPilotFieldReference>::get(), 0, 0 },
- { u"" SC_UNO_DP_USEDHIERARCHY, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
- { u"" SC_UNO_DP_LAYOUTNAME, 0, cppu::UnoType<OUString>::get(), 0, 0 },
- { u"" SC_UNO_DP_FIELD_SUBTOTALNAME, 0, cppu::UnoType<OUString>::get(), 0, 0 },
- { u"" SC_UNO_DP_HAS_HIDDEN_MEMBER, 0, cppu::UnoType<bool>::get(), 0, 0 },
- { u"", 0, css::uno::Type(), 0, 0 }
+ { SC_UNO_DP_FILTER, 0, cppu::UnoType<uno::Sequence<sheet::TableFilterField>>::get(), 0, 0 },
+ { SC_UNO_DP_FLAGS, 0, cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNO_DP_FUNCTION, 0, cppu::UnoType<sheet::GeneralFunction>::get(), 0, 0 },
+ { SC_UNO_DP_FUNCTION2, 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { SC_UNO_DP_ISDATALAYOUT, 0, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNO_DP_NUMBERFO, 0, cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNO_DP_ORIENTATION, 0, cppu::UnoType<sheet::DataPilotFieldOrientation>::get(), 0, 0 },
+ { SC_UNO_DP_ORIGINAL, 0, cppu::UnoType<container::XNamed>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNO_DP_ORIGINAL_POS, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNO_DP_POSITION, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNO_DP_REFVALUE, 0, cppu::UnoType<sheet::DataPilotFieldReference>::get(), 0, 0 },
+ { SC_UNO_DP_USEDHIERARCHY, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNO_DP_LAYOUTNAME, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNO_DP_FIELD_SUBTOTALNAME, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNO_DP_HAS_HIDDEN_MEMBER, 0, cppu::UnoType<bool>::get(), 0, 0 },
};
static uno::Reference<beans::XPropertySetInfo> aRef =
new SfxItemPropertySetInfo( aDPDimensionMap_Impl );
@@ -1888,7 +1867,7 @@ ScDPLevel::ScDPLevel( ScDPSource* pSrc, sal_Int32 nD, sal_Int32 nH, sal_Int32 nL
nDim( nD ),
nHier( nH ),
nLev( nL ),
- aSortInfo( EMPTY_OUSTRING, true, sheet::DataPilotFieldSortMode::NAME ), // default: sort by name
+ aSortInfo( OUString(), true, sheet::DataPilotFieldSortMode::NAME ), // default: sort by name
nSortMeasure( 0 ),
nAutoMeasure( 0 ),
bShowEmpty( false ),
@@ -2066,19 +2045,16 @@ uno::Sequence<sal_Int16> ScDPLevel::getSubTotals() const
uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPLevel::getPropertySetInfo()
{
- SolarMutexGuard aGuard;
-
static const SfxItemPropertyMapEntry aDPLevelMap_Impl[] =
{
//TODO: change type of AutoShow/Layout/Sorting to API struct when available
- { u"" SC_UNO_DP_AUTOSHOW, 0, cppu::UnoType<sheet::DataPilotFieldAutoShowInfo>::get(), 0, 0 },
- { u"" SC_UNO_DP_LAYOUT, 0, cppu::UnoType<sheet::DataPilotFieldLayoutInfo>::get(), 0, 0 },
- { u"" SC_UNO_DP_SHOWEMPTY, 0, cppu::UnoType<bool>::get(), 0, 0 },
- { u"" SC_UNO_DP_REPEATITEMLABELS, 0, cppu::UnoType<bool>::get(), 0, 0 },
- { u"" SC_UNO_DP_SORTING, 0, cppu::UnoType<sheet::DataPilotFieldSortInfo>::get(), 0, 0 },
- { u"" SC_UNO_DP_SUBTOTAL, 0, cppu::UnoType<uno::Sequence<sheet::GeneralFunction>>::get(), 0, 0 },
- { u"" SC_UNO_DP_SUBTOTAL2, 0, cppu::UnoType<uno::Sequence<sal_Int16>>::get(), 0, 0 },
- { u"", 0, css::uno::Type(), 0, 0 }
+ { SC_UNO_DP_AUTOSHOW, 0, cppu::UnoType<sheet::DataPilotFieldAutoShowInfo>::get(), 0, 0 },
+ { SC_UNO_DP_LAYOUT, 0, cppu::UnoType<sheet::DataPilotFieldLayoutInfo>::get(), 0, 0 },
+ { SC_UNO_DP_SHOWEMPTY, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_DP_REPEATITEMLABELS, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_DP_SORTING, 0, cppu::UnoType<sheet::DataPilotFieldSortInfo>::get(), 0, 0 },
+ { SC_UNO_DP_SUBTOTAL, 0, cppu::UnoType<uno::Sequence<sheet::GeneralFunction>>::get(), 0, 0 },
+ { SC_UNO_DP_SUBTOTAL2, 0, cppu::UnoType<uno::Sequence<sal_Int16>>::get(), 0, 0 },
};
static uno::Reference<beans::XPropertySetInfo> aRef =
new SfxItemPropertySetInfo( aDPLevelMap_Impl );
@@ -2096,7 +2072,7 @@ void SAL_CALL ScDPLevel::setPropertyValue( const OUString& aPropertyName, const
uno::Sequence<sheet::GeneralFunction> aSeq;
aValue >>= aSeq;
aSubTotals.realloc(aSeq.getLength());
- std::transform(aSeq.begin(), aSeq.end(), aSubTotals.begin(),
+ std::transform(std::cbegin(aSeq), std::cend(aSeq), aSubTotals.getArray(),
[](const sheet::GeneralFunction& rFunc) -> sal_Int16 {
return static_cast<sal_Int16>(rFunc); });
}
@@ -2124,9 +2100,8 @@ uno::Any SAL_CALL ScDPLevel::getPropertyValue( const OUString& aPropertyName )
else if ( aPropertyName == SC_UNO_DP_SUBTOTAL )
{
const uno::Sequence<sal_Int16> aSeq = getSubTotals();
- uno::Sequence<sheet::GeneralFunction> aNewSeq;
- aNewSeq.realloc(aSeq.getLength());
- std::transform(aSeq.begin(), aSeq.end(), aNewSeq.begin(),
+ uno::Sequence<sheet::GeneralFunction> aNewSeq(aSeq.getLength());
+ std::transform(aSeq.begin(), aSeq.end(), aNewSeq.getArray(),
[](const sal_Int16 nFunc) -> sheet::GeneralFunction {
if (nFunc == sheet::GeneralFunction2::MEDIAN)
return sheet::GeneralFunction_NONE;
@@ -2388,14 +2363,14 @@ ScDPMember* ScDPMembers::getByIndex(sal_Int32 nIndex) const
else if ( nHier == SC_DAPI_HIERARCHY_WEEK && nLev == SC_DAPI_LEVEL_WEEKDAY )
{
nVal = nIndex; // DayOfWeek is 0-based
- aName = ScGlobal::GetCalendar()->getDisplayName(
+ aName = ScGlobal::GetCalendar().getDisplayName(
css::i18n::CalendarDisplayIndex::DAY,
sal::static_int_cast<sal_Int16>(nVal), 0 );
}
else if ( nHier == SC_DAPI_HIERARCHY_QUARTER && nLev == SC_DAPI_LEVEL_MONTH )
{
nVal = nIndex; // Month is 0-based
- aName = ScGlobal::GetCalendar()->getDisplayName(
+ aName = ScGlobal::GetCalendar().getDisplayName(
css::i18n::CalendarDisplayIndex::MONTH,
sal::static_int_cast<sal_Int16>(nVal), 0 );
}
@@ -2541,15 +2516,12 @@ void SAL_CALL ScDPMember::setName( const OUString& /* rNewName */ )
uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPMember::getPropertySetInfo()
{
- SolarMutexGuard aGuard;
-
static const SfxItemPropertyMapEntry aDPMemberMap_Impl[] =
{
- { u"" SC_UNO_DP_ISVISIBLE, 0, cppu::UnoType<bool>::get(), 0, 0 },
- { u"" SC_UNO_DP_POSITION, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
- { u"" SC_UNO_DP_SHOWDETAILS, 0, cppu::UnoType<bool>::get(), 0, 0 },
- { u"" SC_UNO_DP_LAYOUTNAME, 0, cppu::UnoType<OUString>::get(), 0, 0 },
- { u"", 0, css::uno::Type(), 0, 0 }
+ { SC_UNO_DP_ISVISIBLE, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_DP_POSITION, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNO_DP_SHOWDETAILS, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_DP_LAYOUTNAME, 0, cppu::UnoType<OUString>::get(), 0, 0 },
};
static uno::Reference<beans::XPropertySetInfo> aRef =
new SfxItemPropertySetInfo( aDPMemberMap_Impl );
@@ -2617,7 +2589,7 @@ const ScDPItemData* ScDPSource::GetItemDataById(sal_Int32 nDim, sal_Int32 nId)
const ScDPItemData* ScDPMembers::GetSrcItemDataByIndex(SCROW nIndex)
{
const std::vector< SCROW >& memberIds = pSource->GetData()->GetColumnEntries( nDim );
- if ( nIndex >= static_cast<tools::Long>(memberIds.size()) || nIndex < 0 )
+ if ( nIndex < 0 || o3tl::make_unsigned(nIndex) >= memberIds.size() )
return nullptr;
SCROW nId = memberIds[ nIndex ];
return pSource->GetItemDataById( nDim, nId );
diff --git a/sc/source/core/data/dputil.cxx b/sc/source/core/data/dputil.cxx
index 6fabf2e286dd..651d550935f9 100644
--- a/sc/source/core/data/dputil.cxx
+++ b/sc/source/core/data/dputil.cxx
@@ -17,8 +17,10 @@
#include <comphelper/string.hxx>
#include <unotools/localedatawrapper.hxx>
#include <unotools/calendarwrapper.hxx>
+#include <svl/numformat.hxx>
#include <svl/zforlist.hxx>
#include <rtl/math.hxx>
+#include <o3tl/string_view.hxx>
#include <osl/diagnose.h>
#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
@@ -56,14 +58,14 @@ OUString getSpecialDateName(double fValue, bool bFirst, SvNumberFormatter* pForm
}
-bool ScDPUtil::isDuplicateDimension(const OUString& rName)
+bool ScDPUtil::isDuplicateDimension(std::u16string_view rName)
{
- return rName.endsWith("*");
+ return o3tl::ends_with(rName, u"*");
}
OUString ScDPUtil::getSourceDimensionName(std::u16string_view rName)
{
- return comphelper::string::stripEnd(rName, '*');
+ return OUString(comphelper::string::stripEnd(rName, '*'));
}
sal_uInt8 ScDPUtil::getDuplicateIndex(const OUString& rName)
@@ -113,9 +115,9 @@ OUString ScDPUtil::getDateGroupName(
case sheet::DataPilotFieldGroupBy::YEARS:
return OUString::number(nValue);
case sheet::DataPilotFieldGroupBy::QUARTERS:
- return ScGlobal::getLocaleDataPtr()->getQuarterAbbreviation(sal_Int16(nValue-1)); // nValue is 1-based
+ return ScGlobal::getLocaleData().getQuarterAbbreviation(sal_Int16(nValue-1)); // nValue is 1-based
case css::sheet::DataPilotFieldGroupBy::MONTHS:
- return ScGlobal::GetCalendar()->getDisplayName(
+ return ScGlobal::GetCalendar().getDisplayName(
i18n::CalendarDisplayIndex::MONTH, sal_Int16(nValue-1), 0); // 0-based, get short name
case sheet::DataPilotFieldGroupBy::DAYS:
{
@@ -138,9 +140,7 @@ OUString ScDPUtil::getDateGroupName(
case sheet::DataPilotFieldGroupBy::MINUTES:
case sheet::DataPilotFieldGroupBy::SECONDS:
{
- OUStringBuffer aBuf(ScGlobal::getLocaleDataPtr()->getTimeSep());
- aBuf.append(getTwoDigitString(nValue));
- return aBuf.makeStringAndClear();
+ return ScGlobal::getLocaleData().getTimeSep() + getTwoDigitString(nValue);
}
break;
default:
@@ -153,16 +153,10 @@ OUString ScDPUtil::getDateGroupName(
double ScDPUtil::getNumGroupStartValue(double fValue, const ScDPNumGroupInfo& rInfo)
{
if (fValue < rInfo.mfStart && !rtl::math::approxEqual(fValue, rInfo.mfStart))
- {
- rtl::math::setInf(&fValue, true);
- return fValue;
- }
+ return -std::numeric_limits<double>::infinity();
if (fValue > rInfo.mfEnd && !rtl::math::approxEqual(fValue, rInfo.mfEnd))
- {
- rtl::math::setInf(&fValue, false);
- return fValue;
- }
+ return std::numeric_limits<double>::infinity();
double fDiff = fValue - rInfo.mfStart;
double fDiv = rtl::math::approxFloor( fDiff / rInfo.mfStep );
@@ -368,8 +362,8 @@ sal_Int32 ScDPUtil::getDatePartValue(
namespace {
-const char* aFuncStrIds[] = {
- nullptr, // SUBTOTAL_FUNC_NONE
+const TranslateId aFuncStrIds[] = {
+ {}, // SUBTOTAL_FUNC_NONE
STR_FUN_TEXT_AVG, // SUBTOTAL_FUNC_AVE
STR_FUN_TEXT_COUNT, // SUBTOTAL_FUNC_CNT
STR_FUN_TEXT_COUNT, // SUBTOTAL_FUNC_CNT2
@@ -382,7 +376,7 @@ const char* aFuncStrIds[] = {
STR_FUN_TEXT_VAR, // SUBTOTAL_FUNC_VAR
STR_FUN_TEXT_VAR, // SUBTOTAL_FUNC_VARP
STR_FUN_TEXT_MEDIAN, // SUBTOTAL_FUNC_MED
- nullptr // SUBTOTAL_FUNC_SELECTION_COUNT - not used for pivot table
+ {} // SUBTOTAL_FUNC_SELECTION_COUNT - not used for pivot table
};
}
@@ -390,7 +384,7 @@ const char* aFuncStrIds[] = {
OUString ScDPUtil::getDisplayedMeasureName(const OUString& rName, ScSubTotalFunc eFunc)
{
assert(unsigned(eFunc) < SAL_N_ELEMENTS(aFuncStrIds));
- const char* pId = aFuncStrIds[eFunc];
+ TranslateId pId = aFuncStrIds[eFunc];
if (!pId)
return rName;
return ScResId(pId) + // function name
diff --git a/sc/source/core/data/drawpage.cxx b/sc/source/core/data/drawpage.cxx
index 6b6f029fb205..9baa9be3ca6a 100644
--- a/sc/source/core/data/drawpage.cxx
+++ b/sc/source/core/data/drawpage.cxx
@@ -45,7 +45,7 @@ rtl::Reference<SdrPage> ScDrawPage::CloneSdrPage(SdrModel& rTargetModel) const
css::uno::Reference< css::uno::XInterface > ScDrawPage::createUnoPage()
{
- return static_cast<cppu::OWeakObject*>( new ScPageObj( this ) );
+ return cppu::getXWeak( new ScPageObj( this ) );
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/drwlayer.cxx b/sc/source/core/data/drwlayer.cxx
index 551b3c7db899..c34cad1f28d5 100644
--- a/sc/source/core/data/drwlayer.cxx
+++ b/sc/source/core/data/drwlayer.cxx
@@ -25,6 +25,7 @@
#include <scitems.hxx>
#include <editeng/eeitem.hxx>
+#include <editeng/fontitem.hxx>
#include <editeng/frmdiritem.hxx>
#include <sot/exchange.hxx>
#include <svx/objfac3d.hxx>
@@ -41,6 +42,16 @@
#include <svx/svdundo.hxx>
#include <svx/sdsxyitm.hxx>
#include <svx/svxids.hrc>
+#include <svx/sxcecitm.hxx>
+#include <svx/sdshitm.hxx>
+#include <svx/sdtditm.hxx>
+#include <svx/sdtagitm.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnstcit.hxx>
#include <i18nlangtag/mslangid.hxx>
#include <editeng/unolingu.hxx>
#include <svx/drawitem.hxx>
@@ -48,6 +59,7 @@
#include <editeng/scriptspaceitem.hxx>
#include <sfx2/objsh.hxx>
#include <svl/itempool.hxx>
+#include <utility>
#include <vcl/canvastools.hxx>
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
@@ -62,6 +74,7 @@
#include <drawpage.hxx>
#include <global.hxx>
#include <document.hxx>
+#include <docsh.hxx>
#include <userdat.hxx>
#include <markdata.hxx>
#include <globstr.hrc>
@@ -71,9 +84,12 @@
#include <attrib.hxx>
#include <charthelper.hxx>
#include <table.hxx>
+#include <stlpool.hxx>
+#include <detfunc.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <clipcontext.hxx>
+#include <clipparam.hxx>
-#include <vcl/fieldvalues.hxx>
#include <memory>
#include <algorithm>
#include <cstdlib>
@@ -107,7 +123,7 @@ ScUndoObjData::~ScUndoObjData()
void ScUndoObjData::Undo()
{
- ScDrawObjData* pData = ScDrawLayer::GetObjData( pObj );
+ ScDrawObjData* pData = ScDrawLayer::GetObjData( mxObj.get() );
OSL_ENSURE(pData,"ScUndoObjData: Data missing");
if (pData)
{
@@ -116,7 +132,7 @@ void ScUndoObjData::Undo()
}
// Undo also an untransformed anchor
- pData = ScDrawLayer::GetNonRotatedObjData( pObj );
+ pData = ScDrawLayer::GetNonRotatedObjData( mxObj.get() );
if (pData)
{
pData->maStart = aOldStt;
@@ -126,7 +142,7 @@ void ScUndoObjData::Undo()
void ScUndoObjData::Redo()
{
- ScDrawObjData* pData = ScDrawLayer::GetObjData( pObj );
+ ScDrawObjData* pData = ScDrawLayer::GetObjData( mxObj.get() );
OSL_ENSURE(pData,"ScUndoObjData: Data missing");
if (pData)
{
@@ -135,7 +151,7 @@ void ScUndoObjData::Redo()
}
// Redo also an untransformed anchor
- pData = ScDrawLayer::GetNonRotatedObjData( pObj );
+ pData = ScDrawLayer::GetNonRotatedObjData( mxObj.get() );
if (pData)
{
pData->maStart = aNewStt;
@@ -159,30 +175,30 @@ ScUndoAnchorData::~ScUndoAnchorData()
void ScUndoAnchorData::Undo()
{
// Trigger Object Change
- if (pObj->IsInserted() && pObj->getSdrPageFromSdrObject())
+ if (mxObj->IsInserted() && mxObj->getSdrPageFromSdrObject())
{
- SdrHint aHint(SdrHintKind::ObjectChange, *pObj);
- pObj->getSdrModelFromSdrObject().Broadcast(aHint);
+ SdrHint aHint(SdrHintKind::ObjectChange, *mxObj);
+ mxObj->getSdrModelFromSdrObject().Broadcast(aHint);
}
if (mbWasCellAnchored)
- ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *mpDoc, mnTab, mbWasResizeWithCell);
+ ScDrawLayer::SetCellAnchoredFromPosition(*mxObj, *mpDoc, mnTab, mbWasResizeWithCell);
else
- ScDrawLayer::SetPageAnchored( *pObj );
+ ScDrawLayer::SetPageAnchored( *mxObj );
}
void ScUndoAnchorData::Redo()
{
if (mbWasCellAnchored)
- ScDrawLayer::SetPageAnchored( *pObj );
+ ScDrawLayer::SetPageAnchored( *mxObj );
else
- ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *mpDoc, mnTab, mbWasResizeWithCell);
+ ScDrawLayer::SetCellAnchoredFromPosition(*mxObj, *mpDoc, mnTab, mbWasResizeWithCell);
// Trigger Object Change
- if (pObj->IsInserted() && pObj->getSdrPageFromSdrObject())
+ if (mxObj->IsInserted() && mxObj->getSdrPageFromSdrObject())
{
- SdrHint aHint(SdrHintKind::ObjectChange, *pObj);
- pObj->getSdrModelFromSdrObject().Broadcast(aHint);
+ SdrHint aHint(SdrHintKind::ObjectChange, *mxObj);
+ mxObj->getSdrModelFromSdrObject().Broadcast(aHint);
}
}
@@ -209,10 +225,7 @@ ScTabSizeChangedHint::~ScTabSizeChangedHint()
static void lcl_ReverseTwipsToMM( tools::Rectangle& rRect )
{
- rRect.SetLeft(convertMm100ToTwip(rRect.Left()));
- rRect.SetRight(convertMm100ToTwip(rRect.Right()));
- rRect.SetTop(convertMm100ToTwip(rRect.Top()));
- rRect.SetBottom(convertMm100ToTwip(rRect.Bottom()));
+ rRect = o3tl::convert(rRect, o3tl::Length::mm100, o3tl::Length::twip);
}
static ScRange lcl_getClipRangeFromClipDoc(ScDocument* pClipDoc, SCTAB nClipTab)
@@ -226,25 +239,28 @@ static ScRange lcl_getClipRangeFromClipDoc(ScDocument* pClipDoc, SCTAB nClipTab)
SCROW nClipEndY;
pClipDoc->GetClipStart(nClipStartX, nClipStartY);
pClipDoc->GetClipArea(nClipEndX, nClipEndY, true);
- nClipEndX = nClipEndX + nClipStartX;
+ nClipEndX += nClipStartX;
nClipEndY += nClipStartY; // GetClipArea returns the difference
return ScRange(nClipStartX, nClipStartY, nClipTab, nClipEndX, nClipEndY, nClipTab);
}
-ScDrawLayer::ScDrawLayer( ScDocument* pDocument, const OUString& rName ) :
+ScDrawLayer::ScDrawLayer( ScDocument* pDocument, OUString _aName ) :
FmFormModel(
nullptr,
pGlobalDrawPersist ? pGlobalDrawPersist : (pDocument ? pDocument->GetDocumentShell() : nullptr)),
- aName( rName ),
+ aName(std::move( _aName )),
pDoc( pDocument ),
bRecording( false ),
bAdjustEnabled( true ),
bHyphenatorSet( false )
{
+ SetVOCInvalidationIsReliable(true);
+ m_bThemedControls = false;
+
pGlobalDrawPersist = nullptr; // Only use once
- SfxObjectShell* pObjSh = pDocument ? pDocument->GetDocumentShell() : nullptr;
+ ScDocShell* pObjSh = pDocument ? pDocument->GetDocumentShell() : nullptr;
XColorListRef pXCol = XColorList::GetStdColorList();
if ( pObjSh )
{
@@ -263,53 +279,55 @@ ScDrawLayer::ScDrawLayer( ScDocument* pDocument, const OUString& rName ) :
SfxItemPool& rPool = GetItemPool();
rPool.SetDefaultMetric(MapUnit::Map100thMM);
SvxFrameDirectionItem aModeItem( SvxFrameDirection::Environment, EE_PARA_WRITINGDIR );
- rPool.SetPoolDefaultItem( aModeItem );
+ rPool.SetUserDefaultItem( aModeItem );
// #i33700#
// Set shadow distance defaults as PoolDefaultItems. Details see bug.
- rPool.SetPoolDefaultItem(makeSdrShadowXDistItem(300));
- rPool.SetPoolDefaultItem(makeSdrShadowYDistItem(300));
+ rPool.SetUserDefaultItem(makeSdrShadowXDistItem(300));
+ rPool.SetUserDefaultItem(makeSdrShadowYDistItem(300));
// default for script spacing depends on locale, see SdDrawDocument ctor in sd
LanguageType eOfficeLanguage = Application::GetSettings().GetLanguageTag().getLanguageType();
if (MsLangId::isKorean(eOfficeLanguage) || eOfficeLanguage == LANGUAGE_JAPANESE)
{
// secondary is edit engine pool
- rPool.GetSecondaryPool()->SetPoolDefaultItem( SvxScriptSpaceItem( false, EE_PARA_ASIANCJKSPACING ) );
+ rPool.GetSecondaryPool()->SetUserDefaultItem( SvxScriptSpaceItem( false, EE_PARA_ASIANCJKSPACING ) );
}
- rPool.FreezeIdRanges(); // the pool is also used directly
+ SetStyleSheetPool(pDocument ? pDocument->GetStyleSheetPool() : new ScStyleSheetPool(rPool, pDocument));
SdrLayerAdmin& rAdmin = GetLayerAdmin();
- rAdmin.NewLayer("vorne", sal_uInt8(SC_LAYER_FRONT));
- rAdmin.NewLayer("hinten", sal_uInt8(SC_LAYER_BACK));
- rAdmin.NewLayer("intern", sal_uInt8(SC_LAYER_INTERN));
+ rAdmin.NewLayer("vorne", SC_LAYER_FRONT.get());
+ rAdmin.NewLayer("hinten", SC_LAYER_BACK.get());
+ rAdmin.NewLayer("intern", SC_LAYER_INTERN.get());
// tdf#140252 use same name as in ctor of SdrLayerAdmin
- rAdmin.NewLayer(rAdmin.GetControlLayerName(), sal_uInt8(SC_LAYER_CONTROLS));
- rAdmin.NewLayer("hidden", sal_uInt8(SC_LAYER_HIDDEN));
+ rAdmin.NewLayer(rAdmin.GetControlLayerName(), SC_LAYER_CONTROLS.get());
+ rAdmin.NewLayer("hidden", SC_LAYER_HIDDEN.get());
// Set link for URL-Fields
ScModule* pScMod = SC_MOD();
Outliner& rOutliner = GetDrawOutliner();
rOutliner.SetCalcFieldValueHdl( LINK( pScMod, ScModule, CalcFieldValueHdl ) );
+ rOutliner.SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()));
Outliner& rHitOutliner = GetHitTestOutliner();
rHitOutliner.SetCalcFieldValueHdl( LINK( pScMod, ScModule, CalcFieldValueHdl ) );
+ rHitOutliner.SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()));
// set FontHeight pool defaults without changing static SdrEngineDefaults
SfxItemPool* pOutlinerPool = rOutliner.GetEditTextObjectPool();
if ( pOutlinerPool )
{
- m_pItemPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT )); // 12Pt
- m_pItemPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT_CJK )); // 12Pt
- m_pItemPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT_CTL )); // 12Pt
+ m_pItemPool->SetUserDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT )); // 12Pt
+ m_pItemPool->SetUserDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT_CJK )); // 12Pt
+ m_pItemPool->SetUserDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT_CTL )); // 12Pt
}
SfxItemPool* pHitOutlinerPool = rHitOutliner.GetEditTextObjectPool();
if ( pHitOutlinerPool )
{
- pHitOutlinerPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT )); // 12Pt
- pHitOutlinerPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT_CJK )); // 12Pt
- pHitOutlinerPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT_CTL )); // 12Pt
+ pHitOutlinerPool->SetUserDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT )); // 12Pt
+ pHitOutlinerPool->SetUserDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT_CJK )); // 12Pt
+ pHitOutlinerPool->SetUserDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT_CTL )); // 12Pt
}
// initial undo mode as in Calc document
@@ -338,6 +356,57 @@ ScDrawLayer::~ScDrawLayer()
}
}
+void ScDrawLayer::CreateDefaultStyles()
+{
+ // Default
+ auto pSheet = &GetStyleSheetPool()->Make(ScResId(STR_STYLENAME_STANDARD), SfxStyleFamily::Frame, SfxStyleSearchBits::ScStandard);
+ SetDefaultStyleSheet(static_cast<SfxStyleSheet*>(pSheet));
+
+ // Note
+ pSheet = &GetStyleSheetPool()->Make(ScResId(STR_STYLENAME_NOTE), SfxStyleFamily::Frame, SfxStyleSearchBits::ScStandard);
+
+ // caption tail arrow
+ ::basegfx::B2DPolygon aTriangle;
+ aTriangle.append(::basegfx::B2DPoint(10.0, 0.0));
+ aTriangle.append(::basegfx::B2DPoint(0.0, 30.0));
+ aTriangle.append(::basegfx::B2DPoint(20.0, 30.0));
+ aTriangle.setClosed(true);
+
+ auto pSet = &pSheet->GetItemSet();
+ pSet->Put(XLineStartItem(OUString(), ::basegfx::B2DPolyPolygon(aTriangle)).checkForUniqueItem(this));
+ pSet->Put(XLineStartWidthItem(200));
+ pSet->Put(XLineStartCenterItem(false));
+ pSet->Put(XLineStyleItem(drawing::LineStyle_SOLID));
+ pSet->Put(XFillStyleItem(drawing::FillStyle_SOLID));
+ pSet->Put(XFillColorItem(OUString(), ScDetectiveFunc::GetCommentColor()));
+ pSet->Put(SdrCaptionEscDirItem(SdrCaptionEscDir::BestFit));
+
+ // shadow
+ pSet->Put(makeSdrShadowItem(true));
+ pSet->Put(makeSdrShadowXDistItem(100));
+ pSet->Put(makeSdrShadowYDistItem(100));
+
+ // text attributes
+ pSet->Put(makeSdrTextLeftDistItem(100));
+ pSet->Put(makeSdrTextRightDistItem(100));
+ pSet->Put(makeSdrTextUpperDistItem(100));
+ pSet->Put(makeSdrTextLowerDistItem(100));
+ pSet->Put(makeSdrTextAutoGrowWidthItem(false));
+ pSet->Put(makeSdrTextAutoGrowHeightItem(true));
+
+ // text formatting
+ SfxItemSet aEditSet(GetItemPool());
+ ScPatternAttr::FillToEditItemSet(aEditSet, pDoc->getCellAttributeHelper().getDefaultCellAttribute().GetItemSet());
+
+ pSet->Put(aEditSet.Get(EE_CHAR_FONTINFO));
+ pSet->Put(aEditSet.Get(EE_CHAR_FONTINFO_CJK));
+ pSet->Put(aEditSet.Get(EE_CHAR_FONTINFO_CTL));
+
+ pSet->Put(aEditSet.Get(EE_CHAR_FONTHEIGHT));
+ pSet->Put(aEditSet.Get(EE_CHAR_FONTHEIGHT_CJK));
+ pSet->Put(aEditSet.Get(EE_CHAR_FONTHEIGHT_CTL));
+}
+
void ScDrawLayer::UseHyphenator()
{
if (!bHyphenatorSet)
@@ -373,8 +442,11 @@ SdrModel* ScDrawLayer::AllocModel() const
{
// Allocated model (for clipboard etc) must not have a pointer
// to the original model's document, pass NULL as document:
+ auto pNewModel = std::make_unique<ScDrawLayer>(nullptr, aName);
+ auto pNewPool = static_cast<ScStyleSheetPool*>(pNewModel->GetStyleSheetPool());
+ pNewPool->CopyUsedGraphicStylesFrom(GetStyleSheetPool());
- return new ScDrawLayer( nullptr, aName );
+ return pNewModel.release();
}
bool ScDrawLayer::ScAddPage( SCTAB nTab )
@@ -439,8 +511,7 @@ void ScDrawLayer::ScCopyPage( sal_uInt16 nOldPos, sal_uInt16 nNewPos )
SCTAB nNewTab = static_cast<SCTAB>(nNewPos);
SdrObjListIter aIter( pOldPage, SdrIterMode::Flat );
- SdrObject* pOldObject = aIter.Next();
- while (pOldObject)
+ while (SdrObject* pOldObject = aIter.Next())
{
ScDrawObjData* pOldData = GetObjData(pOldObject);
if (pOldData)
@@ -450,10 +521,10 @@ void ScDrawLayer::ScCopyPage( sal_uInt16 nOldPos, sal_uInt16 nNewPos )
}
// Clone to target SdrModel
- SdrObject* pNewObject(pOldObject->CloneSdrObject(*this));
+ rtl::Reference<SdrObject> pNewObject(pOldObject->CloneSdrObject(*this));
pNewObject->NbcMove(Size(0,0));
- pNewPage->InsertObject( pNewObject );
- ScDrawObjData* pNewData = GetObjData(pNewObject);
+ pNewPage->InsertObject( pNewObject.get() );
+ ScDrawObjData* pNewData = GetObjData(pNewObject.get());
if (pNewData)
{
pNewData->maStart.SetTab(nNewTab);
@@ -462,8 +533,6 @@ void ScDrawLayer::ScCopyPage( sal_uInt16 nOldPos, sal_uInt16 nNewPos )
if (bRecording)
AddCalcUndo( std::make_unique<SdrUndoInsertObj>( *pNewObject ) );
-
- pOldObject = aIter.Next();
}
}
@@ -488,7 +557,7 @@ void ScDrawLayer::ResetTab( SCTAB nStart, SCTAB nEnd )
continue;
SdrObjListIter aIter(pPage, SdrIterMode::Flat);
- for (SdrObject* pObj = aIter.Next(); pObj; pObj = aIter.Next())
+ while (SdrObject* pObj = aIter.Next())
{
ScDrawObjData* pData = GetObjData(pObj);
if (!pData)
@@ -516,11 +585,9 @@ void ScDrawLayer::MoveCells( SCTAB nTab, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SC
bool bNegativePage = pDoc && pDoc->IsNegativePage( nTab );
- const size_t nCount = pPage->GetObjCount();
- for ( size_t i = 0; i < nCount; ++i )
+ for (const rtl::Reference<SdrObject>& pObj : *pPage)
{
- SdrObject* pObj = pPage->GetObj( i );
- ScDrawObjData* pData = GetObjDataTab( pObj, nTab );
+ ScDrawObjData* pData = GetObjDataTab( pObj.get(), nTab );
if( pData )
{
const ScAddress aOldStt = pData->maStart;
@@ -540,21 +607,29 @@ void ScDrawLayer::MoveCells( SCTAB nTab, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SC
}
if (bChange)
{
- if ( dynamic_cast<const SdrRectObj*>( pObj) != nullptr && pData->maStart.IsValid() && pData->maEnd.IsValid() )
+ if ( dynamic_cast<const SdrRectObj*>( pObj.get()) != nullptr && pData->maStart.IsValid() && pData->maEnd.IsValid() )
pData->maStart.PutInOrder( pData->maEnd );
// Update also an untransformed anchor that's what we stored ( and still do ) to xml
- ScDrawObjData* pNoRotatedAnchor = GetNonRotatedObjData( pObj );
+ ScDrawObjData* pNoRotatedAnchor = GetNonRotatedObjData( pObj.get() );
if ( pNoRotatedAnchor )
{
- pNoRotatedAnchor->maStart.IncCol(nDx);
- pNoRotatedAnchor->maStart.IncRow(nDy);
- pNoRotatedAnchor->maEnd.IncCol(nDx);
- pNoRotatedAnchor->maEnd.IncRow(nDy);
+ const ScAddress aOldSttNoRotatedAnchor = pNoRotatedAnchor->maStart;
+ const ScAddress aOldEndNoRotatedAnchor = pNoRotatedAnchor->maEnd;
+ if ( aOldSttNoRotatedAnchor.IsValid() && IsInBlock( aOldSttNoRotatedAnchor, nCol1,nRow1, nCol2,nRow2 ) )
+ {
+ pNoRotatedAnchor->maStart.IncCol(nDx);
+ pNoRotatedAnchor->maStart.IncRow(nDy);
+ }
+ if ( aOldEndNoRotatedAnchor.IsValid() && IsInBlock( aOldEndNoRotatedAnchor, nCol1,nRow1, nCol2,nRow2 ) )
+ {
+ pNoRotatedAnchor->maEnd.IncCol(nDx);
+ pNoRotatedAnchor->maEnd.IncRow(nDy);
+ }
}
- AddCalcUndo( std::make_unique<ScUndoObjData>( pObj, aOldStt, aOldEnd, pData->maStart, pData->maEnd ) );
- RecalcPos( pObj, *pData, bNegativePage, bUpdateNoteCaptionPos );
+ AddCalcUndo( std::make_unique<ScUndoObjData>( pObj.get(), aOldStt, aOldEnd, pData->maStart, pData->maEnd ) );
+ RecalcPos( pObj.get(), *pData, bNegativePage, bUpdateNoteCaptionPos );
}
}
}
@@ -589,11 +664,9 @@ void ScDrawLayer::SetPageSize(sal_uInt16 nPageNo, const Size& rSize, bool bUpdat
bool bWasLocked = isLocked();
setLock(true);
- const size_t nCount = pPage->GetObjCount();
- for ( size_t i = 0; i < nCount; ++i )
+ for (const rtl::Reference<SdrObject>& pObj : *pPage)
{
- SdrObject* pObj = pPage->GetObj( i );
- ScDrawObjData* pData = GetObjDataTab( pObj, static_cast<SCTAB>(nPageNo) );
+ ScDrawObjData* pData = GetObjDataTab( pObj.get(), static_cast<SCTAB>(nPageNo) );
if( pData ) // cell anchored
{
if (pData->meType == ScDrawObjData::DrawingObject
@@ -602,28 +675,28 @@ void ScDrawLayer::SetPageSize(sal_uInt16 nPageNo, const Size& rSize, bool bUpdat
switch (eObjectHandling)
{
case ScObjectHandling::RecalcPosMode:
- RecalcPos(pObj, *pData, bNegativePage, bUpdateNoteCaptionPos);
+ RecalcPos(pObj.get(), *pData, bNegativePage, bUpdateNoteCaptionPos);
break;
case ScObjectHandling::MoveRTLMode:
- MoveRTL(pObj);
+ MoveRTL(pObj.get());
break;
case ScObjectHandling::MirrorRTLMode:
- MirrorRTL(pObj);
+ MirrorRTL(pObj.get());
break;
}
}
else // DetectiveArrow and CellNote
- RecalcPos(pObj, *pData, bNegativePage, bUpdateNoteCaptionPos);
+ RecalcPos(pObj.get(), *pData, bNegativePage, bUpdateNoteCaptionPos);
}
else // page anchored
{
switch (eObjectHandling)
{
case ScObjectHandling::MoveRTLMode:
- MoveRTL(pObj);
+ MoveRTL(pObj.get());
break;
case ScObjectHandling::MirrorRTLMode:
- MirrorRTL(pObj);
+ MirrorRTL(pObj.get());
break;
case ScObjectHandling::RecalcPosMode: // does not occur for page anchored shapes
break;
@@ -650,8 +723,8 @@ namespace
Point lcl_calcAvailableDiff(const ScDocument &rDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, const Point &aWantedDiff)
{
Point aAvailableDiff(aWantedDiff);
- tools::Long nHeight = static_cast<tools::Long>(rDoc.GetRowHeight( nRow, nTab ) * HMM_PER_TWIPS);
- tools::Long nWidth = static_cast<tools::Long>(rDoc.GetColWidth( nCol, nTab ) * HMM_PER_TWIPS);
+ tools::Long nHeight = o3tl::convert(rDoc.GetRowHeight( nRow, nTab ), o3tl::Length::twip, o3tl::Length::mm100);
+ tools::Long nWidth = o3tl::convert(rDoc.GetColWidth( nCol, nTab ), o3tl::Length::twip, o3tl::Length::mm100);
if (aAvailableDiff.Y() > nHeight)
aAvailableDiff.setY( nHeight );
if (aAvailableDiff.X() > nWidth)
@@ -682,13 +755,13 @@ bool lcl_AreRectanglesApproxEqual(const tools::Rectangle& rRectA, const tools::R
return true;
}
-bool lcl_NeedsMirrorYCorrection(SdrObject* pObj)
+bool lcl_NeedsMirrorYCorrection(const SdrObject* pObj)
{
- return pObj->GetObjIdentifier() == OBJ_CUSTOMSHAPE
- && static_cast<SdrObjCustomShape*>(pObj)->IsMirroredY();
+ return pObj->GetObjIdentifier() == SdrObjKind::CustomShape
+ && static_cast<const SdrObjCustomShape*>(pObj)->IsMirroredY();
}
-void lcl_SetLogicRectFromAnchor(SdrObject* pObj, ScDrawObjData& rAnchor, ScDocument* pDoc)
+void lcl_SetLogicRectFromAnchor(SdrObject* pObj, const ScDrawObjData& rAnchor, const ScDocument* pDoc)
{
// This is only used during initialization. At that time, shape handling is always LTR. No need
// to consider negative page.
@@ -720,13 +793,14 @@ void lcl_SetLogicRectFromAnchor(SdrObject* pObj, ScDrawObjData& rAnchor, ScDocum
const tools::Rectangle aEndCellRect(
pDoc->GetMMRect(rAnchor.maEnd.Col(), rAnchor.maEnd.Row(), rAnchor.maEnd.Col(),
rAnchor.maEnd.Row(), rAnchor.maEnd.Tab(), false /*bHiddenAsZero*/));
+
Point aEndPoint(aEndCellRect.Left(), aEndCellRect.Top());
aEndPoint.AdjustX(rAnchor.maEndOffset.getX());
aEndPoint.AdjustY(rAnchor.maEndOffset.getY());
// Set this as new, full sized logical rectangle
tools::Rectangle aNewRectangle(aStartPoint, aEndPoint);
- aNewRectangle.Justify();
+ aNewRectangle.Normalize();
if (!lcl_AreRectanglesApproxEqual(pObj->GetLogicRect(), aNewRectangle))
pObj->NbcSetLogicRect(lcl_makeSafeRectangle(aNewRectangle));
@@ -871,9 +945,9 @@ void ScDrawLayer::ResizeLastRectFromAnchor(const SdrObject* pObj, ScDrawObjData&
// Prepare scale relative to top-left of aCurrentCellRect
basegfx::B2DHomMatrix aChange;
- aChange.translate(-aCurrentCellRect.getX(), -aCurrentCellRect.getY());
+ aChange.translate(-aCurrentCellRect.Left(), -aCurrentCellRect.Top());
aChange.scale(fWidthFactor, fHeightFactor);
- aChange.translate(aCurrentCellRect.getX(), aCurrentCellRect.getY());
+ aChange.translate(aCurrentCellRect.Left(), aCurrentCellRect.Top());
// create B2DRange and transform by prepared scale
basegfx::B2DRange aNewRange = vcl::unotools::b2DRectangleFromRectangle(aRect);
@@ -882,8 +956,8 @@ void ScDrawLayer::ResizeLastRectFromAnchor(const SdrObject* pObj, ScDrawObjData&
// apply to aRect
aRect = tools::Rectangle(
- basegfx::fround(aNewRange.getMinX()), basegfx::fround(aNewRange.getMinY()),
- basegfx::fround(aNewRange.getMaxX()), basegfx::fround(aNewRange.getMaxY()));
+ basegfx::fround<tools::Long>(aNewRange.getMinX()), basegfx::fround<tools::Long>(aNewRange.getMinY()),
+ basegfx::fround<tools::Long>(aNewRange.getMaxX()), basegfx::fround<tools::Long>(aNewRange.getMaxY()));
}
}
}
@@ -937,7 +1011,7 @@ void ScDrawLayer::InitializeCellAnchoredObj(SdrObject* pObj, ScDrawObjData& rDat
const ScAnchorType aAnchorType = ScDrawLayer::GetAnchorType(*pObj);
if (aAnchorType == SCA_CELL_RESIZE)
{
- if (pObj->GetObjIdentifier() == OBJ_LINE)
+ if (pObj->GetObjIdentifier() == SdrObjKind::Line)
{
// Horizontal lines might have wrong start and end anchor because of erroneously applied
// 180deg rotation (tdf#137446). Other lines have wrong end anchor. Coordinates in
@@ -946,15 +1020,15 @@ void ScDrawLayer::InitializeCellAnchoredObj(SdrObject* pObj, ScDrawObjData& rDat
static_cast<SdrPathObj*>(pObj)->GetPathPoly().getB2DPolygon(0));
const basegfx::B2DPoint aB2DPoint0(aPoly.getB2DPoint(0));
const basegfx::B2DPoint aB2DPoint1(aPoly.getB2DPoint(1));
- const Point aPointLT(FRound(std::min(aB2DPoint0.getX(), aB2DPoint1.getX())),
- FRound(std::min(aB2DPoint0.getY(), aB2DPoint1.getY())));
- const Point aPointRB(FRound(std::max(aB2DPoint0.getX(), aB2DPoint1.getX())),
- FRound(std::max(aB2DPoint0.getY(), aB2DPoint1.getY())));
+ const Point aPointLT(basegfx::fround<tools::Long>(std::min(aB2DPoint0.getX(), aB2DPoint1.getX())),
+ basegfx::fround<tools::Long>(std::min(aB2DPoint0.getY(), aB2DPoint1.getY())));
+ const Point aPointRB(basegfx::fround<tools::Long>(std::max(aB2DPoint0.getX(), aB2DPoint1.getX())),
+ basegfx::fround<tools::Long>(std::max(aB2DPoint0.getY(), aB2DPoint1.getY())));
const tools::Rectangle aObjRect(aPointLT, aPointRB);
GetCellAnchorFromPosition(aObjRect, rNoRotatedAnchor, *pDoc, nTab1,
false /*bHiddenAsZero*/);
}
- else if (pObj->GetObjIdentifier() == OBJ_MEASURE)
+ else if (pObj->GetObjIdentifier() == SdrObjKind::Measure)
{
// Measure lines might have got wrong start and end anchor from XML import. Recreate
// anchor from start and end point.
@@ -967,6 +1041,18 @@ void ScDrawLayer::InitializeCellAnchoredObj(SdrObject* pObj, ScDrawObjData& rDat
GetCellAnchorFromPosition(aObjRect, rNoRotatedAnchor, *pDoc, rData.maStart.Tab(),
false /*bHiddenAsZero*/);
}
+ else if (pObj->IsResizeProtect())
+ {
+ // tdf#154005: This is a workaround for documents created with LO 6 and older.
+ rNoRotatedAnchor.mbResizeWithCell = false;
+ rData.mbResizeWithCell = false;
+ UpdateCellAnchorFromPositionEnd(*pObj, rNoRotatedAnchor, *pDoc, nTab1,
+ true /*bUseLogicRect*/);
+ }
+ else if (pObj->GetObjIdentifier() == SdrObjKind::Group)
+ {
+ // nothing to do.
+ }
else
{
// In case there are hidden rows or cols, versions 7.0 and earlier have written width and
@@ -977,7 +1063,7 @@ void ScDrawLayer::InitializeCellAnchoredObj(SdrObject* pObj, ScDrawObjData& rDat
lcl_SetLogicRectFromAnchor(pObj, rNoRotatedAnchor, pDoc);
}
}
- else // aAnchorType == SCA_CELL, other types will not occur here.
+ else // aAnchorType == SCA_CELL
{
// XML has no end cell address in this case. We generate it from position.
UpdateCellAnchorFromPositionEnd(*pObj, rNoRotatedAnchor, *pDoc, nTab1,
@@ -1025,13 +1111,17 @@ void ScDrawLayer::RecalcPos( SdrObject* pObj, ScDrawObjData& rData, bool bNegati
position must not be done, if the cell containing the note has not
been moved yet in the document. The calling code now passes an
additional boolean stating if the cells are already moved. */
- if( bUpdateNoteCaptionPos )
+ /* tdf #152081 Do not change hidden objects. That would produce zero height
+ or width and loss of caption.*/
+ if (bUpdateNoteCaptionPos && pObj->IsVisible())
+ {
/* When inside an undo action, there may be pending note captions
where cell note is already deleted (thus document cannot find
the note object anymore). The caption will be deleted later
with drawing undo. */
if( ScPostIt* pNote = pDoc->GetNote( rData.maStart ) )
pNote->UpdateCaptionPos( rData.maStart );
+ }
return;
}
@@ -1049,6 +1139,7 @@ void ScDrawLayer::RecalcPos( SdrObject* pObj, ScDrawObjData& rData, bool bNegati
// Validation circle for detective.
rData.setShapeRect(GetDocument(), pObj->GetLogicRect());
+ // rData.maStart should contain the address of the be validated cell.
tools::Rectangle aRect = GetCellRect(*GetDocument(), rData.maStart, true);
aRect.AdjustLeft( -250 );
aRect.AdjustRight(250 );
@@ -1062,7 +1153,13 @@ void ScDrawLayer::RecalcPos( SdrObject* pObj, ScDrawObjData& rData, bool bNegati
if (bRecording)
AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
rData.setShapeRect(GetDocument(), lcl_makeSafeRectangle(aRect));
+ // maStart has the meaning of "to be validated cell" in a validation circle. For usual
+ // drawing objects it has the meaning "left/top of logic/snap rect". Because the rectangle
+ // is expanded above, SetLogicRect() will set maStart to one cell left and one cell above
+ // of the to be validated cell. We need to backup the old value and restore it.
+ ScAddress aBackup(rData.maStart);
pObj->SetLogicRect(rData.getShapeRect());
+ rData.maStart = aBackup;
}
}
else if (rData.meType == ScDrawObjData::DetectiveArrow)
@@ -1197,7 +1294,7 @@ void ScDrawLayer::RecalcPos( SdrObject* pObj, ScDrawObjData& rData, bool bNegati
}
rData.setShapeRect(GetDocument(), lcl_makeSafeRectangle(rData.getShapeRect()), pObj->IsVisible());
- if (pObj->GetObjIdentifier() == OBJ_CUSTOMSHAPE)
+ if (pObj->GetObjIdentifier() == SdrObjKind::CustomShape)
pObj->AdjustToMaxRect(rData.getShapeRect());
else
pObj->SetSnapRect(rData.getShapeRect());
@@ -1209,7 +1306,7 @@ void ScDrawLayer::RecalcPos( SdrObject* pObj, ScDrawObjData& rData, bool bNegati
}
else
{
- Point aPos( rData.getShapeRect().getX(), rData.getShapeRect().getY() );
+ const Point aPos(rData.getShapeRect().TopLeft());
if ( pObj->GetRelativePos() != aPos )
{
if (bRecording)
@@ -1293,8 +1390,7 @@ bool ScDrawLayer::GetPrintArea( ScRange& rRange, bool bSetHor, bool bSetVer ) co
if (pPage)
{
SdrObjListIter aIter( pPage, SdrIterMode::Flat );
- SdrObject* pObject = aIter.Next();
- while (pObject)
+ while (SdrObject* pObject = aIter.Next())
{
//TODO: test Flags (hidden?)
@@ -1319,8 +1415,6 @@ bool ScDrawLayer::GetPrintArea( ScRange& rRange, bool bSetHor, bool bSetVer ) co
}
bAny = true;
}
-
- pObject = aIter.Next();
}
}
@@ -1337,15 +1431,15 @@ bool ScDrawLayer::GetPrintArea( ScRange& rRange, bool bSetHor, bool bSetVer ) co
if (bSetHor)
{
- nStartX = convertMm100ToTwip(nStartX);
- nEndX = convertMm100ToTwip(nEndX);
+ nStartX = o3tl::toTwips(nStartX, o3tl::Length::mm100);
+ nEndX = o3tl::toTwips(nEndX, o3tl::Length::mm100);
tools::Long nWidth;
nWidth = 0;
rRange.aStart.SetCol( 0 );
if (nWidth <= nStartX)
{
- for (SCCOL nCol : pDoc->GetColumnsRange(nTab, 0, MAXCOL))
+ for (SCCOL nCol : pDoc->GetColumnsRange(nTab, 0, pDoc->MaxCol()))
{
nWidth += pDoc->GetColWidth(nCol,nTab);
if (nWidth > nStartX)
@@ -1360,7 +1454,7 @@ bool ScDrawLayer::GetPrintArea( ScRange& rRange, bool bSetHor, bool bSetVer ) co
rRange.aEnd.SetCol( 0 );
if (nWidth <= nEndX)
{
- for (SCCOL nCol : pDoc->GetColumnsRange(nTab, 0, MAXCOL)) //TODO: start at Start
+ for (SCCOL nCol : pDoc->GetColumnsRange(nTab, 0, pDoc->MaxCol())) //TODO: start at Start
{
nWidth += pDoc->GetColWidth(nCol,nTab);
if (nWidth > nEndX)
@@ -1374,12 +1468,12 @@ bool ScDrawLayer::GetPrintArea( ScRange& rRange, bool bSetHor, bool bSetVer ) co
if (bSetVer)
{
- nStartY = convertMm100ToTwip(nStartY);
- nEndY = convertMm100ToTwip(nEndY);
+ nStartY = o3tl::toTwips(nStartY, o3tl::Length::mm100);
+ nEndY = o3tl::toTwips(nEndY, o3tl::Length::mm100);
SCROW nRow = pDoc->GetRowForHeight( nTab, nStartY);
rRange.aStart.SetRow( nRow>0 ? (nRow-1) : 0);
nRow = pDoc->GetRowForHeight( nTab, nEndY);
- rRange.aEnd.SetRow( nRow == MAXROW ? MAXROW :
+ rRange.aEnd.SetRow( nRow == pDoc->MaxRow() ? pDoc->MaxRow() :
(nRow>0 ? (nRow-1) : 0));
}
}
@@ -1490,7 +1584,7 @@ bool ScDrawLayer::HasObjectsInRows( SCTAB nTab, SCROW nStartRow, SCROW nEndRow )
aTestRect.AdjustTop(pDoc->GetRowHeight( 0, nStartRow-1, nTab) );
- if (nEndRow==MAXROW)
+ if (nEndRow==pDoc->MaxRow())
aTestRect.SetBottom( MAXMM );
else
{
@@ -1508,21 +1602,16 @@ bool ScDrawLayer::HasObjectsInRows( SCTAB nTab, SCROW nStartRow, SCROW nEndRow )
if ( bNegativePage )
MirrorRectRTL( aTestRect );
- bool bFound = false;
-
tools::Rectangle aObjRect;
SdrObjListIter aIter( pPage );
- SdrObject* pObject = aIter.Next();
- while ( pObject && !bFound )
+ while (SdrObject* pObject = aIter.Next())
{
aObjRect = pObject->GetSnapRect(); //TODO: GetLogicRect ?
- if (aTestRect.IsInside(aObjRect.TopLeft()) || aTestRect.IsInside(aObjRect.BottomLeft()))
- bFound = true;
-
- pObject = aIter.Next();
+ if (aTestRect.Contains(aObjRect.TopLeft()) || aTestRect.Contains(aObjRect.BottomLeft()))
+ return true;
}
- return bFound;
+ return false;
}
void ScDrawLayer::DeleteObjectsInArea( SCTAB nTab, SCCOL nCol1,SCROW nRow1,
@@ -1543,19 +1632,18 @@ void ScDrawLayer::DeleteObjectsInArea( SCTAB nTab, SCCOL nCol1,SCROW nRow1,
if (!nObjCount)
return;
- size_t nDelCount = 0;
tools::Rectangle aDelRect = pDoc->GetMMRect( nCol1, nRow1, nCol2, nRow2, nTab );
- tools::Rectangle aDelCircle = pDoc->GetMMRect( nCol1, nRow1, nCol2, nRow2, nTab );
+ tools::Rectangle aDelCircle = aDelRect;
aDelCircle.AdjustLeft(-250);
aDelCircle.AdjustRight(250);
aDelCircle.AdjustTop(-70);
aDelCircle.AdjustBottom(70);
- std::unique_ptr<SdrObject*[]> ppObj(new SdrObject*[nObjCount]);
+ std::vector<SdrObject*> ppObj;
+ ppObj.reserve(nObjCount);
SdrObjListIter aIter( pPage, SdrIterMode::Flat );
- SdrObject* pObject = aIter.Next();
- while (pObject)
+ while (SdrObject* pObject = aIter.Next())
{
// do not delete note caption, they are always handled by the cell note
// TODO: detective objects are still deleted, is this desired?
@@ -1566,35 +1654,33 @@ void ScDrawLayer::DeleteObjectsInArea( SCTAB nTab, SCCOL nCol1,SCROW nRow1,
if (pObjData && pObjData->meType == ScDrawObjData::ValidationCircle)
{
aObjRect = pObject->GetLogicRect();
- if(aDelCircle.IsInside(aObjRect))
- ppObj[nDelCount++] = pObject;
+ if(aDelCircle.Contains(aObjRect))
+ ppObj.push_back(pObject);
}
else
{
aObjRect = pObject->GetCurrentBoundRect();
- if (aDelRect.IsInside(aObjRect))
+ if (aDelRect.Contains(aObjRect))
{
if (bAnchored)
{
ScAnchorType aAnchorType = ScDrawLayer::GetAnchorType(*pObject);
if (aAnchorType == SCA_CELL || aAnchorType == SCA_CELL_RESIZE)
- ppObj[nDelCount++] = pObject;
+ ppObj.push_back(pObject);
}
else
- ppObj[nDelCount++] = pObject;
+ ppObj.push_back(pObject);
}
}
}
-
- pObject = aIter.Next();
}
if (bRecording)
- for (size_t i=1; i<=nDelCount; ++i)
- AddCalcUndo( std::make_unique<SdrUndoRemoveObj>( *ppObj[nDelCount-i] ) );
+ for (auto p : ppObj)
+ AddCalcUndo(std::make_unique<SdrUndoDelObj>(*p));
- for (size_t i=1; i<=nDelCount; ++i)
- pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
+ for (auto p : ppObj)
+ pPage->RemoveObject(p->GetOrdNum());
}
void ScDrawLayer::DeleteObjectsInSelection( const ScMarkData& rMark )
@@ -1606,8 +1692,7 @@ void ScDrawLayer::DeleteObjectsInSelection( const ScMarkData& rMark )
if ( !rMark.IsMultiMarked() )
return;
- ScRange aMarkRange;
- rMark.GetMultiMarkArea( aMarkRange );
+ const ScRange& aMarkRange = rMark.GetMultiMarkArea();
SCTAB nTabCount = pDoc->GetTableCount();
for (const SCTAB nTab : rMark)
@@ -1622,17 +1707,16 @@ void ScDrawLayer::DeleteObjectsInSelection( const ScMarkData& rMark )
const size_t nObjCount = pPage->GetObjCount();
if (nObjCount)
{
- size_t nDelCount = 0;
// Rectangle around the whole selection
tools::Rectangle aMarkBound = pDoc->GetMMRect(
aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), nTab );
- std::unique_ptr<SdrObject*[]> ppObj(new SdrObject*[nObjCount]);
+ std::vector<SdrObject*> ppObj;
+ ppObj.reserve(nObjCount);
SdrObjListIter aIter( pPage, SdrIterMode::Flat );
- SdrObject* pObject = aIter.Next();
- while (pObject)
+ while (SdrObject* pObject = aIter.Next())
{
// do not delete note caption, they are always handled by the cell note
// TODO: detective objects are still deleted, is this desired?
@@ -1641,30 +1725,29 @@ void ScDrawLayer::DeleteObjectsInSelection( const ScMarkData& rMark )
tools::Rectangle aObjRect = pObject->GetCurrentBoundRect();
ScRange aRange = pDoc->GetRange(nTab, aObjRect);
bool bObjectInMarkArea =
- aMarkBound.IsInside(aObjRect) && rMark.IsAllMarked(aRange);
+ aMarkBound.Contains(aObjRect) && rMark.IsAllMarked(aRange);
const ScDrawObjData* pObjData = ScDrawLayer::GetObjData(pObject);
ScAnchorType aAnchorType = ScDrawLayer::GetAnchorType(*pObject);
bool bObjectAnchoredToMarkedCell
= ((aAnchorType == SCA_CELL || aAnchorType == SCA_CELL_RESIZE)
- && pObjData && rMark.IsCellMarked(pObjData->maStart.Col(),
+ && pObjData && pObjData->maStart.IsValid()
+ && rMark.IsCellMarked(pObjData->maStart.Col(),
pObjData->maStart.Row()));
if (bObjectInMarkArea || bObjectAnchoredToMarkedCell)
{
- ppObj[nDelCount++] = pObject;
+ ppObj.push_back(pObject);
}
}
-
- pObject = aIter.Next();
}
// Delete objects (backwards)
if (bRecording)
- for (size_t i=1; i<=nDelCount; ++i)
- AddCalcUndo( std::make_unique<SdrUndoRemoveObj>( *ppObj[nDelCount-i] ) );
+ for (auto p : ppObj)
+ AddCalcUndo(std::make_unique<SdrUndoDelObj>(*p));
- for (size_t i=1; i<=nDelCount; ++i)
- pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
+ for (auto p : ppObj)
+ pPage->RemoveObject(p->GetOrdNum());
}
}
else
@@ -1685,55 +1768,107 @@ void ScDrawLayer::CopyToClip( ScDocument* pClipDoc, SCTAB nTab, const tools::Rec
ScDrawLayer* pDestModel = nullptr;
SdrPage* pDestPage = nullptr;
+ ScRange aClipRange = lcl_getClipRangeFromClipDoc(pClipDoc, nTab);
+
SdrObjListIter aIter( pSrcPage, SdrIterMode::Flat );
- SdrObject* pOldObject = aIter.Next();
- while (pOldObject)
+ while (SdrObject* pOldObject = aIter.Next())
{
- tools::Rectangle aObjRect = pOldObject->GetCurrentBoundRect();
+ // do not copy internal objects (detective) and note captions
+ if (pOldObject->GetLayer() == SC_LAYER_INTERN)
+ continue;
- bool bObjectInArea = rRange.IsInside(aObjRect);
const ScDrawObjData* pObjData = ScDrawLayer::GetObjData(pOldObject);
- if (pObjData)
+ if (IsNoteCaption(pObjData))
+ continue;
+
+ // Catch objects where the object itself is inside the rectangle to be copied.
+ bool bObjectInArea = rRange.Contains(pOldObject->GetCurrentBoundRect());
+ // Catch objects whose anchor is inside the rectangle to be copied.
+ if (!bObjectInArea && pObjData)
+ bObjectInArea = aClipRange.Contains(pObjData->maStart);
+ if (!bObjectInArea)
+ continue;
+
+ if (!pDestModel)
{
- ScRange aClipRange = lcl_getClipRangeFromClipDoc(pClipDoc, nTab);
- bObjectInArea = bObjectInArea || aClipRange.In(pObjData->maStart);
+ pDestModel = pClipDoc->GetDrawLayer(); // does the document already have a drawing layer?
+ if (!pDestModel)
+ {
+ // allocate drawing layer in clipboard document only if there are objects to copy
+
+ pClipDoc->InitDrawLayer(); //TODO: create contiguous pages
+ pDestModel = pClipDoc->GetDrawLayer();
+ }
+ if (pDestModel)
+ pDestPage = pDestModel->GetPage(static_cast<sal_uInt16>(nTab));
}
- // do not copy internal objects (detective) and note captions
- if (bObjectInArea && pOldObject->GetLayer() != SC_LAYER_INTERN
- && !IsNoteCaption(pOldObject))
+ OSL_ENSURE(pDestPage, "no page");
+ if (pDestPage)
{
- if ( !pDestModel )
+ // Clone to target SdrModel
+ rtl::Reference<SdrObject> pNewObject(pOldObject->CloneSdrObject(*pDestModel));
+ uno::Reference< chart2::XChartDocument > xOldChart( ScChartHelper::GetChartFromSdrObject( pOldObject ) );
+ if(!xOldChart.is())//#i110034# do not move charts as they lose all their data references otherwise
{
- pDestModel = pClipDoc->GetDrawLayer(); // does the document already have a drawing layer?
- if ( !pDestModel )
+ if (pObjData)
{
- // allocate drawing layer in clipboard document only if there are objects to copy
-
- pClipDoc->InitDrawLayer(); //TODO: create contiguous pages
- pDestModel = pClipDoc->GetDrawLayer();
+ // The object is anchored to cell. The position is determined by the start
+ // address. Copying into the clipboard does not change the anchor.
+ // ToDo: Adapt Offset relative to anchor cell size for cell anchored.
+ // ToDo: Adapt Offset and size for cell-anchored with resize objects.
+ // ToDo: Exclude object from resize if disallowed at object.
+ }
+ else
+ {
+ // The object is anchored to page. We make its position so, that the
+ // cell behind the object will have the same address in clipboard document as
+ // in source document. So we will be able to reconstruct the original cell
+ // address from position when pasting the object.
+ tools::Rectangle aObjRect = pOldObject->GetSnapRect();
+ ScRange aPseudoAnchor = pDoc->GetRange(nTab, aObjRect, true /*bHiddenAsZero*/);
+ tools::Rectangle aSourceCellRect
+ = GetCellRect(*pDoc, aPseudoAnchor.aStart, false /*bMergedCell*/);
+ tools::Rectangle aDestCellRect
+ = GetCellRect(*pClipDoc, aPseudoAnchor.aStart, false);
+ Point aMove = aDestCellRect.TopLeft() - aSourceCellRect.TopLeft();
+ pNewObject->NbcMove(Size(aMove.getX(), aMove.getY()));
}
- if (pDestModel)
- pDestPage = pDestModel->GetPage( static_cast<sal_uInt16>(nTab) );
}
- OSL_ENSURE( pDestPage, "no page" );
- if (pDestPage)
- {
- // Clone to target SdrModel
- SdrObject* pNewObject(pOldObject->CloneSdrObject(*pDestModel));
-
- uno::Reference< chart2::XChartDocument > xOldChart( ScChartHelper::GetChartFromSdrObject( pOldObject ) );
- if(!xOldChart.is())//#i110034# do not move charts as they lose all their data references otherwise
- pNewObject->NbcMove(Size(0,0));
- pDestPage->InsertObject( pNewObject );
+ pDestPage->InsertObject(pNewObject.get());
- // no undo needed in clipboard document
- // charts are not updated
+ // Store the chart's source data to the clipboard document, even when it's out of the
+ // copied range. It will be ignored when pasted to the same document; when pasted to
+ // another document, ScDocument::mpClipParam will provide the actually copied ranges,
+ // and the data copied here will be used to break connection and switch to own data
+ // in ScDrawLayer::CopyFromClip.
+ if (xOldChart && !xOldChart->hasInternalDataProvider())
+ {
+ sc::CopyToClipContext aCxt(*pClipDoc, false, true);
+ OUString aChartName = static_cast<SdrOle2Obj*>(pOldObject)->GetPersistName();
+ std::vector<ScRangeList> aRangesVector;
+ pDoc->GetChartRanges(aChartName, aRangesVector, *pDoc);
+ for (const ScRangeList& ranges : aRangesVector)
+ {
+ for (const ScRange& r : ranges)
+ {
+ for (SCTAB i = r.aStart.Tab(); i <= r.aEnd.Tab(); ++i)
+ {
+ ScTable* pTab = pDoc->FetchTable(i);
+ ScTable* pClipTab = pClipDoc->FetchTable(i);
+ if (!pTab || !pClipTab)
+ continue;
+ pTab->CopyToClip(aCxt, r.aStart.Col(), r.aStart.Row(), r.aEnd.Col(),
+ r.aEnd.Row(), pClipTab);
+ }
+ }
+ }
}
- }
- pOldObject = aIter.Next();
+ // no undo needed in clipboard document
+ // charts are not updated
+ }
}
}
@@ -1746,7 +1881,7 @@ static bool lcl_IsAllInRange( const ::std::vector< ScRangeList >& rRangesVector,
for ( size_t i = 0, nCount = rRanges.size(); i < nCount; i++ )
{
const ScRange & rRange = rRanges[ i ];
- if ( !rClipRange.In( rRange ) )
+ if ( !rClipRange.Contains( rRange ) )
{
return false; // at least one range is not valid
}
@@ -1756,7 +1891,8 @@ static bool lcl_IsAllInRange( const ::std::vector< ScRangeList >& rRangesVector,
return true; // everything is fine
}
-static bool lcl_MoveRanges( ::std::vector< ScRangeList >& rRangesVector, const ScRange& rSourceRange, const ScAddress& rDestPos )
+static bool lcl_MoveRanges( ::std::vector< ScRangeList >& rRangesVector, const ScRange& rSourceRange,
+ const ScAddress& rDestPos, const ScDocument& rDoc )
{
bool bChanged = false;
@@ -1766,12 +1902,12 @@ static bool lcl_MoveRanges( ::std::vector< ScRangeList >& rRangesVector, const S
for ( size_t i = 0, nCount = rRanges.size(); i < nCount; i++ )
{
ScRange & rRange = rRanges[ i ];
- if ( rSourceRange.In( rRange ) )
+ if ( rSourceRange.Contains( rRange ) )
{
SCCOL nDiffX = rDestPos.Col() - rSourceRange.aStart.Col();
SCROW nDiffY = rDestPos.Row() - rSourceRange.aStart.Row();
SCTAB nDiffZ = rDestPos.Tab() - rSourceRange.aStart.Tab();
- if (!rRange.Move( nDiffX, nDiffY, nDiffZ, aErrorRange))
+ if (!rRange.Move( nDiffX, nDiffY, nDiffZ, aErrorRange, rDoc ))
{
assert(!"can't move range");
}
@@ -1783,8 +1919,9 @@ static bool lcl_MoveRanges( ::std::vector< ScRangeList >& rRangesVector, const S
return bChanged;
}
-void ScDrawLayer::CopyFromClip( ScDrawLayer* pClipModel, SCTAB nSourceTab, const tools::Rectangle& rSourceRange,
- const ScAddress& rDestPos, const tools::Rectangle& rDestRange )
+void ScDrawLayer::CopyFromClip(ScDrawLayer* pClipModel, SCTAB nSourceTab,
+ const ScRange& rSourceRange, const ScAddress& rDestPos,
+ const ScRange& rDestRange, bool bTransposing)
{
OSL_ENSURE( pDoc, "ScDrawLayer::CopyFromClip without document" );
if ( !pDoc )
@@ -1799,14 +1936,6 @@ void ScDrawLayer::CopyFromClip( ScDrawLayer* pClipModel, SCTAB nSourceTab, const
return;
}
- bool bMirrorObj = ( rSourceRange.Left() < 0 && rSourceRange.Right() < 0 &&
- rDestRange.Left() > 0 && rDestRange.Right() > 0 ) ||
- ( rSourceRange.Left() > 0 && rSourceRange.Right() > 0 &&
- rDestRange.Left() < 0 && rDestRange.Right() < 0 );
- tools::Rectangle aMirroredSource = rSourceRange;
- if ( bMirrorObj )
- MirrorRectRTL( aMirroredSource );
-
SCTAB nDestTab = rDestPos.Tab();
SdrPage* pSrcPage = pClipModel->GetPage(static_cast<sal_uInt16>(nSourceTab));
@@ -1815,163 +1944,324 @@ void ScDrawLayer::CopyFromClip( ScDrawLayer* pClipModel, SCTAB nSourceTab, const
if ( !pSrcPage || !pDestPage )
return;
+ ScDocument* pClipDoc = pClipModel->GetDocument();
+ if (!pClipDoc)
+ return; // Can this happen? And if yes, what to do?
+
SdrObjListIter aIter( pSrcPage, SdrIterMode::Flat );
- SdrObject* pOldObject = aIter.Next();
+ if (!aIter.Count())
+ return; // no objects at all. Nothing to do.
- ScDocument* pClipDoc = pClipModel->GetDocument();
// a clipboard document and its source share the same document item pool,
// so the pointers can be compared to see if this is copy&paste within
// the same document
- bool bSameDoc = pDoc && pClipDoc && pDoc->GetPool() == pClipDoc->GetPool();
- bool bDestClip = pDoc && pDoc->IsClipboard();
+ bool bSameDoc = pDoc->GetPool() == pClipDoc->GetPool();
+ bool bDestClip = pDoc->IsClipboard(); // Happens while transposing. ToDo: Other cases?
//#i110034# charts need correct sheet names for xml range conversion during load
//so the target sheet name is temporarily renamed (if we have any SdrObjects)
OUString aDestTabName;
bool bRestoreDestTabName = false;
- if( pOldObject && !bSameDoc && !bDestClip )
+ if (!bSameDoc && !bDestClip)
{
- if( pDoc && pClipDoc )
+ OUString aSourceTabName;
+ if (pClipDoc->GetName(nSourceTab, aSourceTabName) && pDoc->GetName(nDestTab, aDestTabName)
+ && aSourceTabName != aDestTabName && pDoc->ValidNewTabName(aSourceTabName))
{
- OUString aSourceTabName;
- if( pClipDoc->GetName( nSourceTab, aSourceTabName )
- && pDoc->GetName( nDestTab, aDestTabName ) )
- {
- if( aSourceTabName != aDestTabName &&
- pDoc->ValidNewTabName(aSourceTabName) )
- {
- bRestoreDestTabName = pDoc->RenameTab( nDestTab, aSourceTabName );
- }
- }
+ bRestoreDestTabName = pDoc->RenameTab( nDestTab, aSourceTabName );
}
}
- // first mirror, then move
- Size aMove( rDestRange.Left() - aMirroredSource.Left(), rDestRange.Top() - aMirroredSource.Top() );
-
- tools::Long nDestWidth = rDestRange.GetWidth();
- tools::Long nDestHeight = rDestRange.GetHeight();
- tools::Long nSourceWidth = rSourceRange.GetWidth();
- tools::Long nSourceHeight = rSourceRange.GetHeight();
+ SCTAB nClipTab = bRestoreDestTabName ? nDestTab : nSourceTab;
+ ScRange aClipRange = lcl_getClipRangeFromClipDoc(pClipDoc, nClipTab);
- tools::Long nWidthDiff = nDestWidth - nSourceWidth;
- tools::Long nHeightDiff = nDestHeight - nSourceHeight;
+ // We are going to make all rectangle calculations on LTR, so determine whether doc is RTL.
+ bool bSourceRTL = pClipDoc->IsLayoutRTL(nSourceTab);
+ bool bDestRTL = pDoc->IsLayoutRTL(nDestTab);
- Fraction aHorFract(1,1);
- Fraction aVerFract(1,1);
- bool bResize = false;
- // sizes can differ by 1 from twips->1/100mm conversion for equal cell sizes,
- // don't resize to empty size when pasting into hidden columns or rows
- if ( std::abs(nWidthDiff) > 1 && nDestWidth > 1 && nSourceWidth > 1 )
+ while (SdrObject* pOldObject = aIter.Next())
{
- aHorFract = Fraction( nDestWidth, nSourceWidth );
- bResize = true;
- }
- if ( std::abs(nHeightDiff) > 1 && nDestHeight > 1 && nSourceHeight > 1 )
- {
- aVerFract = Fraction( nDestHeight, nSourceHeight );
- bResize = true;
- }
- Point aRefPos = rDestRange.TopLeft(); // for resizing (after moving)
-
- while (pOldObject)
- {
- tools::Rectangle aObjRect = pOldObject->GetCurrentBoundRect();
+ // ToDO: Can this happen? Such objects should not be in the clipboard document.
// do not copy internal objects (detective) and note captions
+ if ((pOldObject->GetLayer() == SC_LAYER_INTERN) || IsNoteCaption(pOldObject))
+ continue;
- SCTAB nClipTab = bRestoreDestTabName ? nDestTab : nSourceTab;
- ScRange aClipRange = lcl_getClipRangeFromClipDoc(pClipDoc, nClipTab);
-
- bool bObjectInArea = rSourceRange.IsInside(aObjRect);
+ // 'aIter' considers all objects on pSrcPage. But ScDocument::CopyBlockFromClip, which is used
+ // for filtered data, acts not on the total range but only on parts of it. So we need to look,
+ // whether an object is really contained in the current rSourceRange.
+ // For cell anchored objects we use the start address of the anchor, for page anchored objects
+ // we use the cell range behind the bounding box of the shape.
+ ScAddress aSrcObjStart;
const ScDrawObjData* pObjData = ScDrawLayer::GetObjData(pOldObject);
- if (pObjData) // Consider images anchored to the copied cell
- bObjectInArea = bObjectInArea || aClipRange.In(pObjData->maStart);
- if (bObjectInArea && (pOldObject->GetLayer() != SC_LAYER_INTERN)
- && !IsNoteCaption(pOldObject))
+ if (pObjData) // Object is anchored to cell.
{
- // Clone to target SdrModel
- SdrObject* pNewObject(pOldObject->CloneSdrObject(*this));
+ aSrcObjStart = (*pObjData).maStart;
+ }
+ else // Object is anchored to page.
+ {
+ aSrcObjStart = pClipDoc->GetRange(nSourceTab, pOldObject->GetCurrentBoundRect()).aStart;
+ }
+ if (!rSourceRange.Contains(aSrcObjStart))
+ continue;
+ // If object is anchored to a filtered cell, we will not copy it, because filtered rows are
+ // eliminated in paste. Copying would produce hidden objects which can only be accessed per
+ // macro.
+ if (pObjData && pClipDoc->RowFiltered((*pObjData).maStart.Row(), nSourceTab))
+ continue;
+
+ // Copy style sheet
+ auto pStyleSheet = pOldObject->GetStyleSheet();
+ if (pStyleSheet && !bSameDoc)
+ pDoc->GetStyleSheetPool()->CopyStyleFrom(pClipModel->GetStyleSheetPool(),
+ pStyleSheet->GetName(),
+ pStyleSheet->GetFamily(), true);
+
+ rtl::Reference<SdrObject> pNewObject(pOldObject->CloneSdrObject(*this));
+ tools::Rectangle aObjRect = pOldObject->GetSnapRect();
+ if (bSourceRTL)
+ {
+ MirrorRTL(pNewObject.get()); // We make the calculations in LTR.
+ MirrorRectRTL(aObjRect);
+ }
+
+ bool bCanResize = IsResizeWithCell(*pOldObject) && !pOldObject->IsResizeProtect();
+ // We do not resize charts or other OLE objects and do not resize when transposing.
+ bCanResize &= pOldObject->GetObjIdentifier() != SdrObjKind::OLE2;
+ bCanResize &= !bTransposing && !pClipDoc->GetClipParam().isTransposed();
+ if (bCanResize)
+ {
+ // Filtered rows are eliminated on paste. Filtered cols do not exist as of May 2023.
+ // Collapsed or hidden rows/cols are shown on paste.
+ // Idea: First calculate top left cell and bottom right cell of pasted object. Then
+ // calculate the object corners inside these cell and from that build new snap rectangle.
+ // We assume that pObjData is valid and pObjData and aObjRect correspond to each other
+ // in the source document.
+
+ // Start cell of object in source and destination. The case of a filtered start cell is
+ // already excluded above. aSrcObjStart = (*pObjData).maStart is already done above.
+ // If filtered rows exist in the total range, the range was divided into blocks which
+ // do not contain filtered rows. So the rows between start of aSourceRange and object
+ // start row do not contain filtered rows.
+ SCROW nStartRowDiff = aSrcObjStart.Row() - rSourceRange.aStart.Row();
+ SCCOL nStartColDiff = aSrcObjStart.Col() - rSourceRange.aStart.Col();
+ ScAddress aDestObjStart = rDestRange.aStart;
+ aDestObjStart.IncCol(nStartColDiff);
+ aDestObjStart.IncRow(nStartRowDiff);
+
+ // End cell of object in source and destination. We look at the amount of rows/cols to be
+ // added to get object end cell from object start cell.
+ ScAddress aSrcObjEnd = (*pObjData).maEnd;
+ SCCOL nColsToAdd = aSrcObjEnd.Col() - aSrcObjStart.Col();
+ SCROW nRowsToAdd
+ = pClipDoc->CountNonFilteredRows(aSrcObjStart.Row(), aSrcObjEnd.Row(), nSourceTab)
+ - 1;
+ ScAddress aDestObjEnd = aDestObjStart;
+ aDestObjEnd.IncCol(nColsToAdd);
+ aDestObjEnd.IncRow(nRowsToAdd);
+
+ // Position of object inside start and end cell in source. We describe the distance from
+ // cell corner to object corner as ratio of offset to cell width/height.
+ // We cannot use GetCellRect method, because that uses bHiddenAsZero=true.
+ Point aSrcObjTopLeftOffset = (*pObjData).maStartOffset;
+ tools::Rectangle aSrcStartRect
+ = pClipDoc->GetMMRect(aSrcObjStart.Col(), aSrcObjStart.Row(), aSrcObjStart.Col(),
+ aSrcObjStart.Row(), nSourceTab, false /*bHiddenAsZero*/);
+ if (bSourceRTL)
+ MirrorRectRTL(aSrcStartRect);
+ double fStartXRatio
+ = aSrcStartRect.getOpenWidth() == 0
+ ? 1.0
+ : double(aSrcObjTopLeftOffset.X()) / double(aSrcStartRect.getOpenWidth());
+ double fStartYRatio
+ = aSrcStartRect.getOpenHeight() == 0
+ ? 1.0
+ : double(aSrcObjTopLeftOffset.Y()) / double(aSrcStartRect.getOpenHeight());
+
+ Point aSrcObjBottomRightOffset = (*pObjData).maEndOffset;
+ tools::Rectangle aSrcEndRect
+ = pClipDoc->GetMMRect(aSrcObjEnd.Col(), aSrcObjEnd.Row(), aSrcObjEnd.Col(),
+ aSrcObjEnd.Row(), nSourceTab, false /*bHiddenAsZero*/);
+ if (bSourceRTL)
+ MirrorRectRTL(aSrcEndRect);
+ double fEndXRatio
+ = aSrcEndRect.getOpenWidth() == 0
+ ? 1.0
+ : double(aSrcObjBottomRightOffset.X()) / double(aSrcEndRect.getOpenWidth());
+ double fEndYRatio
+ = aSrcEndRect.getOpenHeight() == 0
+ ? 1.0
+ : double(aSrcObjBottomRightOffset.Y()) / double(aSrcEndRect.getOpenHeight());
+ // The end cell given in pObjData might be filtered. In that case the object is cut at
+ // the lower cell edge. The offset is as large as the cell.
+ if (pClipDoc->RowFiltered(aSrcObjEnd.Row(), nSourceTab))
+ fEndYRatio = 1.0;
+
+ // Position of object inside start and end cell in destination
+ tools::Rectangle aDestStartRect
+ = GetCellRect(*pDoc, aDestObjStart, false /*bMergedCell*/);
+ if (bDestRTL)
+ MirrorRectRTL(aDestStartRect);
+ Point aDestObjTopLeftOffset(fStartXRatio * aDestStartRect.getOpenWidth(),
+ fStartYRatio * aDestStartRect.getOpenHeight());
+ Point aDestObjTopLeft = aDestStartRect.TopLeft() + aDestObjTopLeftOffset;
+
+ tools::Rectangle aDestEndRect = GetCellRect(*pDoc, aDestObjEnd, false /*bMergedCell*/);
+ if (bDestRTL)
+ MirrorRectRTL(aDestEndRect);
+ Point aDestObjBottomRightOffset(fEndXRatio * aDestEndRect.getOpenWidth(),
+ fEndYRatio * aDestEndRect.getOpenHeight());
+ Point aDestObjBottomRight = aDestEndRect.TopLeft() + aDestObjBottomRightOffset;
+
+ // Fit new object into destination rectangle
+ tools::Rectangle aNewObjRect(aDestObjTopLeft, aDestObjBottomRight);
+ aNewObjRect = lcl_makeSafeRectangle(aNewObjRect);
+ if (pNewObject->GetObjIdentifier() == SdrObjKind::CustomShape)
+ pNewObject->AdjustToMaxRect(aNewObjRect);
+ else
+ pNewObject->SetSnapRect(aNewObjRect);
+ }
+ else
+ {
+ // We determine the MM-distance of the new object from its start cell in destination from
+ // the ratio of offset to cell width/height. Thus the object still starts in this cell
+ // even if the destination cell has different size. Otherwise we might lose objects when
+ // transposing.
+
+ // Start Cell address in source and destination
+ SCCOLROW nStartRowDiff = pClipDoc->CountNonFilteredRows(rSourceRange.aStart.Row(),
+ aSrcObjStart.Row(), nSourceTab)
+ - 1;
+ SCCOLROW nStartColDiff = aSrcObjStart.Col() - rSourceRange.aStart.Col();
+ if (bTransposing)
+ std::swap(nStartRowDiff, nStartColDiff);
+ ScAddress aDestObjStart = rDestRange.aStart;
+ aDestObjStart.IncCol(nStartColDiff);
+ aDestObjStart.IncRow(nStartRowDiff);
+
+ // Position of object inside start cell in source.
+ tools::Rectangle aSrcStartRect
+ = pClipDoc->GetMMRect(aSrcObjStart.Col(), aSrcObjStart.Row(), aSrcObjStart.Col(),
+ aSrcObjStart.Row(), nSourceTab, false /*bHiddenAsZero*/);
+ if (bSourceRTL)
+ MirrorRectRTL(aSrcStartRect);
+ Point aSrcObjTopLeftOffset = pObjData ? (*pObjData).maStartOffset
+ : aObjRect.TopLeft() - aSrcStartRect.TopLeft();
+
+ double fStartXRatio
+ = aSrcStartRect.getOpenWidth() == 0
+ ? 1.0
+ : double(aSrcObjTopLeftOffset.X()) / double(aSrcStartRect.getOpenWidth());
+ double fStartYRatio
+ = aSrcStartRect.getOpenHeight() == 0
+ ? 1.0
+ : double(aSrcObjTopLeftOffset.Y()) / double(aSrcStartRect.getOpenHeight());
+
+ // Position of object inside start cell in destination
+ tools::Rectangle aDestStartRect
+ = GetCellRect(*pDoc, aDestObjStart, false /*bMergedCell*/);
+ if (bDestRTL)
+ MirrorRectRTL(aDestStartRect);
+ Point aDestObjTopLeftOffset(fStartXRatio * aDestStartRect.getOpenWidth(),
+ fStartYRatio * aDestStartRect.getOpenHeight());
+ Point aDestObjTopLeft = aDestStartRect.TopLeft() + aDestObjTopLeftOffset;
+
+ // Move new object to new position
+ Point aMoveBy = aDestObjTopLeft - aObjRect.TopLeft();
+ pNewObject->NbcMove(Size(aMoveBy.getX(), aMoveBy.getY()));
+ }
- if ( bMirrorObj )
- MirrorRTL( pNewObject ); // first mirror, then move
+ if (bDestRTL)
+ MirrorRTL(pNewObject.get());
- pNewObject->NbcMove( aMove );
- if ( bResize )
- pNewObject->NbcResize( aRefPos, aHorFract, aVerFract );
+ // Changing object position or size does not automatically change its anchor.
+ if (IsCellAnchored(*pOldObject))
+ SetCellAnchoredFromPosition(*pNewObject, *pDoc, nDestTab,
+ IsResizeWithCell(*pOldObject));
- pDestPage->InsertObject( pNewObject );
+ // InsertObject includes broadcasts
+ // MakeNameUnique makes the pasted objects accessible via Navigator.
+ if (bDestClip)
+ pDestPage->InsertObject(pNewObject.get());
+ else
+ {
if (bRecording)
- AddCalcUndo( std::make_unique<SdrUndoInsertObj>( *pNewObject ) );
+ pDoc->EnableUndo(false);
+ pDestPage->InsertObjectThenMakeNameUnique(pNewObject.get());
+ if (bRecording)
+ pDoc->EnableUndo(true);
+ }
- //#i110034# handle chart data references (after InsertObject)
+ if (bRecording)
+ AddCalcUndo(std::make_unique<SdrUndoInsertObj>(*pNewObject));
- if ( pNewObject->GetObjIdentifier() == OBJ_OLE2 )
+ //#i110034# handle chart data references (after InsertObject)
+ if (pNewObject->GetObjIdentifier() == SdrObjKind::OLE2)
+ {
+ uno::Reference<embed::XEmbeddedObject> xIPObj
+ = static_cast<SdrOle2Obj*>(pNewObject.get())->GetObjRef();
+ uno::Reference<embed::XClassifiedObject> xClassified = xIPObj;
+ SvGlobalName aObjectClassName;
+ if (xClassified.is())
{
- uno::Reference< embed::XEmbeddedObject > xIPObj = static_cast<SdrOle2Obj*>(pNewObject)->GetObjRef();
- uno::Reference< embed::XClassifiedObject > xClassified = xIPObj;
- SvGlobalName aObjectClassName;
- if ( xClassified.is() )
+ try
{
- try {
- aObjectClassName = SvGlobalName( xClassified->getClassID() );
- } catch( uno::Exception& )
- {
- // TODO: handle error?
- }
+ aObjectClassName = SvGlobalName(xClassified->getClassID());
+ }
+ catch (uno::Exception&)
+ {
+ // TODO: handle error?
}
+ }
- if ( xIPObj.is() && SotExchange::IsChart( aObjectClassName ) )
+ if (xIPObj.is() && SotExchange::IsChart(aObjectClassName))
+ {
+ uno::Reference<chart2::XChartDocument> xNewChart(
+ ScChartHelper::GetChartFromSdrObject(pNewObject.get()));
+ if (xNewChart.is() && !xNewChart->hasInternalDataProvider())
{
- uno::Reference< chart2::XChartDocument > xNewChart( ScChartHelper::GetChartFromSdrObject( pNewObject ) );
- if( xNewChart.is() && !xNewChart->hasInternalDataProvider() )
+ OUString aChartName
+ = static_cast<SdrOle2Obj*>(pNewObject.get())->GetPersistName();
+ ::std::vector<ScRangeList> aRangesVector;
+ pDoc->GetChartRanges(aChartName, aRangesVector, *pDoc);
+ if (!aRangesVector.empty())
{
- OUString aChartName = static_cast<SdrOle2Obj*>(pNewObject)->GetPersistName();
- ::std::vector< ScRangeList > aRangesVector;
- pDoc->GetChartRanges( aChartName, aRangesVector, *pDoc );
- if( !aRangesVector.empty() )
- {
- bool bInSourceRange = false;
- if ( pClipDoc )
- {
- bInSourceRange = lcl_IsAllInRange( aRangesVector, aClipRange );
- }
+ bool bInSourceRange = false;
+ bInSourceRange = lcl_IsAllInRange(aRangesVector, aClipRange);
- // always lose references when pasting into a clipboard document (transpose)
- if ( ( bInSourceRange || bSameDoc ) && !bDestClip )
+ // always lose references when pasting into a clipboard document (transpose)
+ if ((bInSourceRange || bSameDoc) && !bDestClip)
+ {
+ if (bInSourceRange)
{
- if ( bInSourceRange )
- {
- if ( rDestPos != aClipRange.aStart )
- {
- // update the data ranges to the new (copied) position
- if ( lcl_MoveRanges( aRangesVector, aClipRange, rDestPos ) )
- pDoc->SetChartRanges( aChartName, aRangesVector );
- }
- }
- else
+ if (rDestPos != aClipRange.aStart)
{
- // leave the ranges unchanged
+ // update the data ranges to the new (copied) position
+ if (lcl_MoveRanges(aRangesVector, aClipRange, rDestPos, *pDoc))
+ pDoc->SetChartRanges(aChartName, aRangesVector);
}
}
else
{
- // pasting into a new document without the complete source data
- // -> break connection to source data and switch to own data
-
- uno::Reference< chart::XChartDocument > xOldChartDoc( ScChartHelper::GetChartFromSdrObject( pOldObject ), uno::UNO_QUERY );
- uno::Reference< chart::XChartDocument > xNewChartDoc( xNewChart, uno::UNO_QUERY );
- if( xOldChartDoc.is() && xNewChartDoc.is() )
- xNewChartDoc->attachData( xOldChartDoc->getData() );
-
- // (see ScDocument::UpdateChartListenerCollection, PastingDrawFromOtherDoc)
+ // leave the ranges unchanged
}
}
+ else
+ {
+ // pasting into a new document without the complete source data
+ // -> break connection to source data and switch to own data
+ uno::Reference<chart::XChartDocument> xOldChartDoc(
+ ScChartHelper::GetChartFromSdrObject(pOldObject), uno::UNO_QUERY);
+ uno::Reference<chart::XChartDocument> xNewChartDoc(xNewChart,
+ uno::UNO_QUERY);
+ if (xOldChartDoc.is() && xNewChartDoc.is())
+ xNewChartDoc->attachData(xOldChartDoc->getData());
+
+ // (see ScDocument::UpdateChartListenerCollection, PastingDrawFromOtherDoc)
+ }
}
}
}
}
-
- pOldObject = aIter.Next();
}
if( bRestoreDestTabName )
@@ -1984,11 +2274,11 @@ void ScDrawLayer::MirrorRTL( SdrObject* pObj )
if( !pDoc )
return;
- sal_uInt16 nIdent = pObj->GetObjIdentifier();
+ SdrObjKind nIdent = pObj->GetObjIdentifier();
// don't mirror OLE or graphics, otherwise ask the object
// if it can be mirrored
- bool bCanMirror = ( nIdent != OBJ_GRAF && nIdent != OBJ_OLE2 );
+ bool bCanMirror = ( nIdent != SdrObjKind::Graphic && nIdent != SdrObjKind::OLE2 );
if (bCanMirror)
{
SdrObjTransformInfoRec aInfo;
@@ -2120,10 +2410,8 @@ tools::Rectangle ScDrawLayer::GetCellRect( const ScDocument& rDoc, const ScAddre
aBotRight.AdjustY(rDoc.GetRowHeight( rPos.Row(), aEndPos.Row(), rPos.Tab() ) );
// twips -> 1/100 mm
- aTopLeft.setX( static_cast< tools::Long >( aTopLeft.X() * HMM_PER_TWIPS ) );
- aTopLeft.setY( static_cast< tools::Long >( aTopLeft.Y() * HMM_PER_TWIPS ) );
- aBotRight.setX( static_cast< tools::Long >( aBotRight.X() * HMM_PER_TWIPS ) );
- aBotRight.setY( static_cast< tools::Long >( aBotRight.Y() * HMM_PER_TWIPS ) );
+ aTopLeft = o3tl::convert(aTopLeft, o3tl::Length::twip, o3tl::Length::mm100);
+ aBotRight = o3tl::convert(aBotRight, o3tl::Length::twip, o3tl::Length::mm100);
aCellRect = tools::Rectangle( aTopLeft, aBotRight );
if( rDoc.IsNegativePage( rPos.Tab() ) )
@@ -2135,7 +2423,7 @@ tools::Rectangle ScDrawLayer::GetCellRect( const ScDocument& rDoc, const ScAddre
OUString ScDrawLayer::GetVisibleName( const SdrObject* pObj )
{
OUString aName = pObj->GetName();
- if ( pObj->GetObjIdentifier() == OBJ_OLE2 )
+ if ( pObj->GetObjIdentifier() == SdrObjKind::OLE2 )
{
// For OLE, the user defined name (GetName) is used
// if it's not empty (accepting possibly duplicate names),
@@ -2154,11 +2442,11 @@ static bool IsNamedObject( const SdrObject* pObj, std::u16string_view rName )
// (used to find a named object)
return ( pObj->GetName() == rName ||
- ( pObj->GetObjIdentifier() == OBJ_OLE2 &&
+ ( pObj->GetObjIdentifier() == SdrObjKind::OLE2 &&
static_cast<const SdrOle2Obj*>(pObj)->GetPersistName() == rName ) );
}
-SdrObject* ScDrawLayer::GetNamedObject( std::u16string_view rName, sal_uInt16 nId, SCTAB& rFoundTab ) const
+SdrObject* ScDrawLayer::GetNamedObject( std::u16string_view rName, SdrObjKind nId, SCTAB& rFoundTab ) const
{
sal_uInt16 nTabCount = GetPageCount();
for (sal_uInt16 nTab=0; nTab<nTabCount; nTab++)
@@ -2168,17 +2456,14 @@ SdrObject* ScDrawLayer::GetNamedObject( std::u16string_view rName, sal_uInt16 nI
if (pPage)
{
SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups );
- SdrObject* pObject = aIter.Next();
- while (pObject)
+ while (SdrObject* pObject = aIter.Next())
{
- if ( nId == 0 || pObject->GetObjIdentifier() == nId )
+ if ( nId == SdrObjKind::NONE || pObject->GetObjIdentifier() == nId )
if ( IsNamedObject( pObject, rName ) )
{
rFoundTab = static_cast<SCTAB>(nTab);
return pObject;
}
-
- pObject = aIter.Next();
}
}
}
@@ -2198,7 +2483,7 @@ OUString ScDrawLayer::GetNewGraphicName( tools::Long* pnCounter ) const
{
++nId;
aGraphicName = aBase + OUString::number( nId );
- bThere = ( GetNamedObject( aGraphicName, 0, nDummy ) != nullptr );
+ bThere = ( GetNamedObject( aGraphicName, SdrObjKind::NONE, nDummy ) != nullptr );
}
if ( pnCounter )
@@ -2219,20 +2504,15 @@ void ScDrawLayer::EnsureGraphicNames()
if (pPage)
{
SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups );
- SdrObject* pObject = aIter.Next();
/* The index passed to GetNewGraphicName() will be set to
the used index in each call. This prevents the repeated search
for all names from 1 to current index. */
tools::Long nCounter = 0;
- while (pObject)
- {
- if ( pObject->GetObjIdentifier() == OBJ_GRAF && pObject->GetName().isEmpty())
+ while (SdrObject* pObject = aIter.Next())
+ if ( pObject->GetObjIdentifier() == SdrObjKind::Graphic && pObject->GetName().isEmpty())
pObject->SetName( GetNewGraphicName( &nCounter ) );
-
- pObject = aIter.Next();
- }
}
}
}
@@ -2322,7 +2602,7 @@ void ScDrawLayer::SetCellAnchoredFromPosition( SdrObject &rObj, const ScDocument
aObjRect2 = rObj.GetLogicRect();
rObj.NbcMirror(aLeft, aRight);
}
- else if (rObj.GetObjIdentifier() == OBJ_MEASURE)
+ else if (rObj.GetObjIdentifier() == SdrObjKind::Measure)
{
// tdf#137576. A SdrMeasureObj might have a wrong logic rect here. TakeUnrotatedSnapRect
// calculates the current unrotated snap rectangle, sets logic rectangle and returns it.
@@ -2458,17 +2738,12 @@ ScDrawLayer::GetObjectsAnchoredToRows(SCTAB nTab, SCROW nStartRow, SCROW nEndRow
std::vector<SdrObject*> aObjects;
SdrObjListIter aIter( pPage, SdrIterMode::Flat );
- SdrObject* pObject = aIter.Next();
- ScRange aRange( 0, nStartRow, nTab, MAXCOL, nEndRow, nTab);
- while (pObject)
+ ScRange aRange( 0, nStartRow, nTab, pDoc->MaxCol(), nEndRow, nTab);
+ while (SdrObject* pObject = aIter.Next())
{
- if (!dynamic_cast<SdrCaptionObj*>(pObject)) // Caption objects are handled differently
- {
- ScDrawObjData* pObjData = GetObjData(pObject);
- if (pObjData && aRange.In(pObjData->maStart))
- aObjects.push_back(pObject);
- }
- pObject = aIter.Next();
+ ScDrawObjData* pObjData = GetObjData(pObject);
+ if (pObjData && aRange.Contains(pObjData->maStart))
+ aObjects.push_back(pObject);
}
return aObjects;
}
@@ -2482,17 +2757,15 @@ ScDrawLayer::GetObjectsAnchoredToRange(SCTAB nTab, SCCOL nCol, SCROW nStartRow,
std::map<SCROW, std::vector<SdrObject*>> aRowObjects;
SdrObjListIter aIter( pPage, SdrIterMode::Flat );
- SdrObject* pObject = aIter.Next();
ScRange aRange( nCol, nStartRow, nTab, nCol, nEndRow, nTab);
- while (pObject)
+ while (SdrObject* pObject = aIter.Next())
{
if (!dynamic_cast<SdrCaptionObj*>(pObject)) // Caption objects are handled differently
{
ScDrawObjData* pObjData = GetObjData(pObject);
- if (pObjData && aRange.In(pObjData->maStart))
+ if (pObjData && aRange.Contains(pObjData->maStart))
aRowObjects[pObjData->maStart.Row()].push_back(pObject);
}
- pObject = aIter.Next();
}
return aRowObjects;
}
@@ -2507,16 +2780,14 @@ bool ScDrawLayer::HasObjectsAnchoredInRange(const ScRange& rRange)
return false;
SdrObjListIter aIter( pPage, SdrIterMode::Flat );
- SdrObject* pObject = aIter.Next();
- while (pObject)
+ while (SdrObject* pObject = aIter.Next())
{
if (!dynamic_cast<SdrCaptionObj*>(pObject)) // Caption objects are handled differently
{
ScDrawObjData* pObjData = GetObjData(pObject);
- if (pObjData && rRange.In(pObjData->maStart)) // Object is in given range
+ if (pObjData && rRange.Contains(pObjData->maStart)) // Object is in given range
return true;
}
- pObject = aIter.Next();
}
return false;
}
@@ -2530,17 +2801,12 @@ std::vector<SdrObject*> ScDrawLayer::GetObjectsAnchoredToCols(SCTAB nTab, SCCOL
std::vector<SdrObject*> aObjects;
SdrObjListIter aIter(pPage, SdrIterMode::Flat);
- SdrObject* pObject = aIter.Next();
- ScRange aRange(nStartCol, 0, nTab, nEndCol, MAXROW, nTab);
- while (pObject)
+ ScRange aRange(nStartCol, 0, nTab, nEndCol, pDoc->MaxRow(), nTab);
+ while (SdrObject* pObject = aIter.Next())
{
- if (!dynamic_cast<SdrCaptionObj*>(pObject)) // Caption objects are handled differently
- {
- ScDrawObjData* pObjData = GetObjData(pObject);
- if (pObjData && aRange.In(pObjData->maStart))
- aObjects.push_back(pObject);
- }
- pObject = aIter.Next();
+ ScDrawObjData* pObjData = GetObjData(pObject);
+ if (pObjData && aRange.Contains(pObjData->maStart))
+ aObjects.push_back(pObject);
}
return aObjects;
}
@@ -2615,16 +2881,15 @@ ScDrawObjData* ScDrawLayer::GetObjDataTab( SdrObject* pObj, SCTAB nTab )
return pData;
}
-bool ScDrawLayer::IsNoteCaption( SdrObject* pObj )
+bool ScDrawLayer::IsNoteCaption(const ScDrawObjData* pData)
{
- ScDrawObjData* pData = pObj ? GetObjData( pObj ) : nullptr;
return pData && pData->meType == ScDrawObjData::CellNote;
}
ScDrawObjData* ScDrawLayer::GetNoteCaptionData( SdrObject* pObj, SCTAB nTab )
{
- ScDrawObjData* pData = pObj ? GetObjDataTab( pObj, nTab ) : nullptr;
- return (pData && pData->meType == ScDrawObjData::CellNote) ? pData : nullptr;
+ ScDrawObjData* pData = GetObjDataTab(pObj, nTab);
+ return IsNoteCaption(pData) ? pData : nullptr;
}
ScMacroInfo* ScDrawLayer::GetMacroInfo( SdrObject* pObj, bool bCreate )
@@ -2654,9 +2919,9 @@ void ScDrawLayer::SetChanged( bool bFlg /* = true */ )
FmFormModel::SetChanged( bFlg );
}
-css::uno::Reference< css::uno::XInterface > ScDrawLayer::createUnoModel()
+css::uno::Reference< css::frame::XModel > ScDrawLayer::createUnoModel()
{
- css::uno::Reference< css::uno::XInterface > xRet;
+ css::uno::Reference< css::frame::XModel > xRet;
if( pDoc && pDoc->GetDocumentShell() )
xRet = pDoc->GetDocumentShell()->GetModel();
diff --git a/sc/source/core/data/edittextiterator.cxx b/sc/source/core/data/edittextiterator.cxx
index ba913258729c..bdf7c9934161 100644
--- a/sc/source/core/data/edittextiterator.cxx
+++ b/sc/source/core/data/edittextiterator.cxx
@@ -18,7 +18,6 @@ EditTextIterator::EditTextIterator( const ScDocument& rDoc, SCTAB nTab ) :
mrTable(*rDoc.maTabs.at(nTab)),
mnCol(0),
mpCells(nullptr),
- maPos(sc::CellStoreType::const_position_type()),
miEnd(maPos.first)
{
init();
diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index 1c3fc8738746..7afa00b86543 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -53,7 +53,7 @@ static void lcl_GetMergeRange( SCCOL nX, SCROW nY, SCSIZE nArrY,
SCCOL nX1, SCROW nY1, SCTAB nTab,
SCCOL& rStartX, SCROW& rStartY, SCCOL& rEndX, SCROW& rEndY )
{
- CellInfo* pInfo = &pRowInfo[nArrY].pCellInfo[nX+1];
+ ScCellInfo* pInfo = &pRowInfo[nArrY].cellInfo(nX);
rStartX = nX;
rStartY = nY;
@@ -67,8 +67,8 @@ static void lcl_GetMergeRange( SCCOL nX, SCROW nY, SCSIZE nArrY,
--rStartX;
if (rStartX >= nX1 && !pDoc->ColHidden(rStartX, nTab, nullptr, &nLastCol))
{
- bHOver = pRowInfo[nArrY].pCellInfo[rStartX+1].bHOverlapped;
- bVOver = pRowInfo[nArrY].pCellInfo[rStartX+1].bVOverlapped;
+ bHOver = pRowInfo[nArrY].cellInfo(rStartX).bHOverlapped;
+ bVOver = pRowInfo[nArrY].cellInfo(rStartX).bVOverlapped;
}
else
{
@@ -90,7 +90,7 @@ static void lcl_GetMergeRange( SCCOL nX, SCROW nY, SCSIZE nArrY,
!pDoc->RowHidden(rStartY, nTab, nullptr, &nLastRow) &&
pRowInfo[nArrY].nRowNo == rStartY)
{
- bVOver = pRowInfo[nArrY].pCellInfo[rStartX+1].bVOverlapped;
+ bVOver = pRowInfo[nArrY].cellInfo(rStartX).bVOverlapped;
}
else
{
@@ -106,7 +106,7 @@ static void lcl_GetMergeRange( SCCOL nX, SCROW nY, SCSIZE nArrY,
!pDoc->RowHidden(rStartY, nTab, nullptr, &nLastRow) &&
pRowInfo[nArrY].nRowNo == rStartY)
{
- pMerge = &pRowInfo[nArrY].pCellInfo[rStartX+1].pPatternAttr->
+ pMerge = &pRowInfo[nArrY].cellInfo(rStartX).pPatternAttr->
GetItem(ATTR_MERGE);
}
else
@@ -123,8 +123,9 @@ class RowInfoFiller
ScDocument& mrDoc;
SCTAB mnTab;
RowInfo* mpRowInfo;
- SCCOL mnArrX;
+ SCCOL mnCol;
SCSIZE mnArrY;
+ SCCOL mnStartCol;
SCROW mnHiddenEndRow;
bool mbHiddenRow;
@@ -147,15 +148,15 @@ class RowInfoFiller
alignArray(nRow);
RowInfo& rThisRowInfo = mpRowInfo[mnArrY];
- CellInfo& rInfo = rThisRowInfo.pCellInfo[mnArrX];
- rInfo.maCell = rCell;
- rInfo.bEmptyCellText = false;
+ if(mnCol >= mnStartCol-1)
+ rThisRowInfo.cellInfo(mnCol).maCell = rCell;
+ rThisRowInfo.basicCellInfo(mnCol).bEmptyCellText = false;
++mnArrY;
}
public:
- RowInfoFiller(ScDocument& rDoc, SCTAB nTab, RowInfo* pRowInfo, SCCOL nArrX, SCSIZE nArrY) :
- mrDoc(rDoc), mnTab(nTab), mpRowInfo(pRowInfo), mnArrX(nArrX), mnArrY(nArrY),
+ RowInfoFiller(ScDocument& rDoc, SCTAB nTab, RowInfo* pRowInfo, SCCOL nCol, SCSIZE nArrY, SCCOL nStartCol) :
+ mrDoc(rDoc), mnTab(nTab), mpRowInfo(pRowInfo), mnCol(nCol), mnArrY(nArrY), mnStartCol(nStartCol),
mnHiddenEndRow(-1), mbHiddenRow(false) {}
void operator() (size_t nRow, double fVal)
@@ -185,13 +186,15 @@ public:
bool isRotateItemUsed(const ScDocumentPool *pPool)
{
- return pPool->GetItemCount2( ATTR_ROTATE_VALUE ) > 0;
+ ItemSurrogates aSurrogates;
+ pPool->GetItemSurrogates(aSurrogates, ATTR_ROTATE_VALUE);
+ return aSurrogates.size() > 0;
}
void initRowInfo(const ScDocument* pDoc, RowInfo* pRowInfo, const SCSIZE nMaxRow,
double fRowScale, SCROW nRow1, SCTAB nTab, SCROW& rYExtra, SCSIZE& rArrRow, SCROW& rRow2)
{
- sal_uInt16 nDocHeight = ScGlobal::nStdRowHeight;
+ sal_uInt16 nDocHeight = pDoc->GetSheetOptimalMinRowHeight(nTab);
SCROW nDocHeightEndRow = -1;
for (SCROW nSignedY=nRow1-1; nSignedY<=rYExtra; nSignedY++)
{
@@ -199,20 +202,20 @@ void initRowInfo(const ScDocument* pDoc, RowInfo* pRowInfo, const SCSIZE nMaxRow
if (nSignedY >= 0)
nY = nSignedY;
else
- nY = MAXROW+1; // invalid
+ nY = pDoc->MaxRow()+1; // invalid
if (nY > nDocHeightEndRow)
{
if (pDoc->ValidRow(nY))
nDocHeight = pDoc->GetRowHeight( nY, nTab, nullptr, &nDocHeightEndRow );
else
- nDocHeight = ScGlobal::nStdRowHeight;
+ nDocHeight = pDoc->GetSheetOptimalMinRowHeight(nTab);
}
- if ( rArrRow==0 || nDocHeight || nY > MAXROW )
+ if ( rArrRow==0 || nDocHeight || nY > pDoc->MaxRow() )
{
RowInfo* pThisRowInfo = &pRowInfo[rArrRow];
- pThisRowInfo->pCellInfo = nullptr; // is loaded below
+ // pThisRowInfo->pCellInfo is set below using allocCellInfo()
sal_uInt16 nHeight = static_cast<sal_uInt16>(
std::clamp(
@@ -224,6 +227,7 @@ void initRowInfo(const ScDocument* pDoc, RowInfo* pRowInfo, const SCSIZE nMaxRow
pThisRowInfo->bChanged = true;
pThisRowInfo->bAutoFilter = false;
pThisRowInfo->bPivotButton = false;
+ pThisRowInfo->bPivotToggle = false;
pThisRowInfo->nRotMaxCol = SC_ROTMAX_NONE;
++rArrRow;
@@ -240,18 +244,24 @@ void initRowInfo(const ScDocument* pDoc, RowInfo* pRowInfo, const SCSIZE nMaxRow
}
}
-void initCellInfo(RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nRotMax,
+void initCellInfo(RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nStartCol, SCCOL nRotMax,
const SvxShadowItem* pDefShadow)
{
for (SCSIZE nArrRow = 0; nArrRow < nArrCount; ++nArrRow)
{
RowInfo& rThisRowInfo = pRowInfo[nArrRow];
- rThisRowInfo.pCellInfo = new CellInfo[nRotMax + 1 + 2]; // to delete the caller!
-
- for (SCCOL nArrCol = 0; nArrCol <= nRotMax+2; ++nArrCol) // Preassign cell info
+ // A lot of memory (and performance allocating and initializing it) can
+ // be saved if we do not allocate CellInfo for columns before nStartCol.
+ // But code in ScOutputData::SetCellRotation(), ScOutputData::DrawRotatedFrame()
+ // and ScOutputData::SetCellRotations() accesses those. That depends on
+ // nRotMaxCol being set to something else than none, and the value is already
+ // initialized here. So allocate all those cells starting from column 0 only if needed.
+ SCCOL nMinCol = rThisRowInfo.nRotMaxCol != SC_ROTMAX_NONE ? 0 : nStartCol;
+ rThisRowInfo.allocCellInfo( nMinCol, nRotMax + 1 );
+
+ for (SCCOL nCol = nMinCol-1; nCol <= nRotMax+1; ++nCol) // Preassign cell info
{
- CellInfo& rInfo = rThisRowInfo.pCellInfo[nArrCol];
- rInfo.bEmptyCellText = true;
+ ScCellInfo& rInfo = rThisRowInfo.cellInfo(nCol);
rInfo.pShadowAttr = pDefShadow;
}
}
@@ -259,28 +269,26 @@ void initCellInfo(RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nRotMax,
void initColWidths(RowInfo* pRowInfo, const ScDocument* pDoc, double fColScale, SCTAB nTab, SCCOL nCol2, SCCOL nRotMax)
{
- for (SCCOL nArrCol=nCol2+3; nArrCol<=nRotMax+2; nArrCol++) // Add remaining widths
+ for (SCCOL nCol=nCol2+2; nCol<=nRotMax+1; nCol++) // Add remaining widths
{
- SCCOL nX = nArrCol-1;
- if ( pDoc->ValidCol(nX) )
+ if ( pDoc->ValidCol(nCol) )
{
- if (!pDoc->ColHidden(nX, nTab))
+ if (!pDoc->ColHidden(nCol, nTab))
{
- sal_uInt16 nThisWidth = static_cast<sal_uInt16>(pDoc->GetColWidth( nX, nTab ) * fColScale);
+ sal_uInt16 nThisWidth = static_cast<sal_uInt16>(pDoc->GetColWidth( nCol, nTab ) * fColScale);
if (!nThisWidth)
nThisWidth = 1;
- pRowInfo[0].pCellInfo[nArrCol].nWidth = nThisWidth;
+ pRowInfo[0].basicCellInfo(nCol).nWidth = nThisWidth;
}
}
}
}
bool handleConditionalFormat(ScConditionalFormatList& rCondFormList, const ScCondFormatIndexes& rCondFormats,
- CellInfo* pInfo, ScStyleSheetPool* pStlPool,
+ ScCellInfo* pInfo, ScTableInfo* pTableInfo, ScStyleSheetPool* pStlPool,
const ScAddress& rAddr, bool& bHidden, bool& bHideFormula, bool bTabProtect)
{
- bool bFound = false;
bool bAnyCondition = false;
for(const auto& rCondFormat : rCondFormats)
{
@@ -290,7 +298,7 @@ bool handleConditionalFormat(ScConditionalFormatList& rCondFormList, const ScCon
ScCondFormatData aData = pCondForm->GetData(
pInfo->maCell, rAddr);
- if (!aData.aStyleName.isEmpty())
+ if (!bAnyCondition && !aData.aStyleName.isEmpty())
{
SfxStyleSheetBase* pStyleSheet =
pStlPool->Find( aData.aStyleName, SfxStyleFamily::Para );
@@ -303,39 +311,35 @@ bool handleConditionalFormat(ScConditionalFormatList& rCondFormList, const ScCon
// TODO: moggi: looks like there is a bug around bHidden and bHideFormula
// They are normally for the whole pattern and not for a single cell
// we need to check already here for protected cells
- const SfxPoolItem* pItem;
- if ( bTabProtect && pInfo->pConditionSet->GetItemState( ATTR_PROTECTION, true, &pItem ) == SfxItemState::SET )
+ const ScProtectionAttr* pProtAttr;
+ if ( bTabProtect && (pProtAttr = pInfo->pConditionSet->GetItemIfSet( ATTR_PROTECTION )) )
{
- const ScProtectionAttr* pProtAttr = static_cast<const ScProtectionAttr*>(pItem);
bHidden = pProtAttr->GetHideCell();
bHideFormula = pProtAttr->GetHideFormula();
}
- bFound = true;
-
}
// if style is not there, treat like no condition
}
- if(aData.mxColorScale)
+ if(aData.mxColorScale && !pInfo->mxColorScale)
{
pInfo->mxColorScale = aData.mxColorScale;
- bFound = true;
}
- if(aData.pDataBar)
+ if(aData.pDataBar && !pInfo->pDataBar)
{
- pInfo->pDataBar = std::move(aData.pDataBar);
- bFound = true;
+ pInfo->pDataBar = aData.pDataBar.get();
+ pTableInfo->addDataBarInfo(std::move(aData.pDataBar));
}
- if(aData.pIconSet)
+ if(aData.pIconSet && !pInfo->pIconSet)
{
- pInfo->pIconSet = std::move(aData.pIconSet);
- bFound = true;
+ pInfo->pIconSet = aData.pIconSet.get();
+ pTableInfo->addIconSetInfo(std::move(aData.pIconSet));
}
- if (bFound)
+ if (bAnyCondition && pInfo->mxColorScale && pInfo->pIconSet && pInfo->pDataBar)
break;
}
@@ -359,11 +363,11 @@ void ScDocument::FillInfo(
RowInfo* pRowInfo = rTabInfo.mpRowInfo.get();
const SvxBrushItem* pDefBackground =
- &pPool->GetDefaultItem( ATTR_BACKGROUND );
+ &pPool->GetUserOrPoolDefaultItem( ATTR_BACKGROUND );
const ScMergeAttr* pDefMerge =
- &pPool->GetDefaultItem( ATTR_MERGE );
+ &pPool->GetUserOrPoolDefaultItem( ATTR_MERGE );
const SvxShadowItem* pDefShadow =
- &pPool->GetDefaultItem( ATTR_SHADOW );
+ &pPool->GetUserOrPoolDefaultItem( ATTR_SHADOW );
SCSIZE nArrRow;
SCSIZE nArrCount;
@@ -388,14 +392,14 @@ void ScDocument::FillInfo(
bool bAnyItem = isRotateItemUsed(pPool);
SCCOL nRotMax = nCol2;
- if ( bAnyItem && HasAttrib( 0, nRow1, nTab, MAXCOL, nRow2+1, nTab,
+ if ( bAnyItem && HasAttrib( 0, nRow1, nTab, MaxCol(), nRow2+1, nTab,
HasAttrFlags::Rotate | HasAttrFlags::Conditional ) )
{
//TODO: check Conditionals also for HasAttrFlags::Rotate ????
OSL_ENSURE( nArrCount>2, "nArrCount too small" );
FindMaxRotCol( nTab, &pRowInfo[1], nArrCount-1, nCol1, nCol2 );
- // FindMaxRotCol setzt nRotMaxCol
+ // FindMaxRotCol sets nRotMaxCol
for (nArrRow=0; nArrRow<nArrCount; nArrRow++)
if (pRowInfo[nArrRow].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nArrRow].nRotMaxCol > nRotMax)
@@ -404,7 +408,7 @@ void ScDocument::FillInfo(
// Allocate cell information only after the test rotation
// to nRotMax due to nRotateDir Flag
- initCellInfo(pRowInfo, nArrCount, nRotMax, pDefShadow);
+ initCellInfo(pRowInfo, nArrCount, nCol1, nRotMax, pDefShadow);
initColWidths(pRowInfo, this, fColScale, nTab, nCol2, nRotMax);
@@ -412,40 +416,43 @@ void ScDocument::FillInfo(
if (pCondFormList)
pCondFormList->startRendering();
- for (SCCOL nArrCol=0; nArrCol<=nCol2+2; nArrCol++) // left & right + 1
+ SCCOL nLastHiddenCheckedCol = -2;
+ bool bColHidden = false;
+ for (SCCOL nCol=-1; nCol<=nCol2+1; nCol++) // collect basic info also for all previous cols, and left & right + 1
{
- SCCOL nX = (nArrCol>0) ? nArrCol-1 : MAXCOL+1; // negative -> invalid
-
- if (ValidCol(nX))
+ if (ValidCol(nCol))
{
// #i58049#, #i57939# Hidden columns must be skipped here, or their attributes
// will disturb the output
+ if (nCol > nLastHiddenCheckedCol)
+ bColHidden = ColHidden(nCol, nTab, nullptr, &nLastHiddenCheckedCol);
// TODO: Optimize this loop.
- if (!ColHidden(nX, nTab))
+ if (!bColHidden)
{
- sal_uInt16 nThisWidth = static_cast<sal_uInt16>(std::clamp(GetColWidth( nX, nTab ) * fColScale, 1.0, double(std::numeric_limits<sal_uInt16>::max())));
+ sal_uInt16 nColWidth = GetColWidth( nCol, nTab, false ); // false=no need to check for hidden, checked above
+ sal_uInt16 nThisWidth = static_cast<sal_uInt16>(std::clamp(nColWidth * fColScale, 1.0, double(std::numeric_limits<sal_uInt16>::max())));
- pRowInfo[0].pCellInfo[nArrCol].nWidth = nThisWidth; //TODO: this should be enough
+ pRowInfo[0].basicCellInfo(nCol).nWidth = nThisWidth; //TODO: this should be enough
const ScAttrArray* pThisAttrArr; // Attribute
- if (nX < maTabs[nTab]->GetAllocatedColumnsCount())
+ if (nCol < maTabs[nTab]->GetAllocatedColumnsCount())
{
- ScColumn* pThisCol = &maTabs[nTab]->aCol[nX]; // Column data
+ ScColumn* pThisCol = &maTabs[nTab]->aCol[nCol]; // Column data
nArrRow = 1;
// Iterate between rows nY1 and nY2 and pick up non-empty
// cells that are not hidden.
- RowInfoFiller aFunc(*this, nTab, pRowInfo, nArrCol, nArrRow);
+ RowInfoFiller aFunc(*this, nTab, pRowInfo, nCol, nArrRow, nCol1);
sc::ParseAllNonEmpty(pThisCol->maCells.begin(), pThisCol->maCells, nRow1, nRow2,
aFunc);
pThisAttrArr = pThisCol->pAttrArray.get();
}
else
- pThisAttrArr = &maTabs[nTab]->aDefaultColAttrArray;
+ pThisAttrArr = &maTabs[nTab]->aDefaultColData.AttrArray();
- if (nX+1 >= nCol1) // Attribute/Blockmark from nX1-1
+ if (nCol+1 >= nCol1) // Attribute/Blockmark from nX1-1
{
nArrRow = 0;
@@ -468,12 +475,12 @@ void ScDocument::FillInfo(
if ( pThisAttrArr->Count() )
{
nThisRow = pThisAttrArr->mvData[nIndex].nEndRow; // End of range
- pPattern = pThisAttrArr->mvData[nIndex].pPattern;
+ pPattern = pThisAttrArr->mvData[nIndex].getScPatternAttr();
}
else
{
- nThisRow = MAXROW;
- pPattern = GetDefPattern();
+ nThisRow = MaxRow();
+ pPattern = &getCellAttributeHelper().getDefaultCellAttribute();
}
const SvxBrushItem* pBackground = &pPattern->GetItem(ATTR_BACKGROUND);
@@ -483,11 +490,11 @@ void ScDocument::FillInfo(
const SvxLineItem* pBLTRLine = &pPattern->GetItem( ATTR_BORDER_BLTR );
const SvxShadowItem* pShadowAttr = &pPattern->GetItem(ATTR_SHADOW);
- if (pShadowAttr != pDefShadow)
+ if (!SfxPoolItem::areSame(pShadowAttr, pDefShadow))
bAnyShadow = true;
const ScMergeAttr* pMergeAttr = &pPattern->GetItem(ATTR_MERGE);
- bool bMerged = ( pMergeAttr != pDefMerge && *pMergeAttr != *pDefMerge );
+ bool bMerged = !SfxPoolItem::areSame( pMergeAttr, pDefMerge );
ScMF nOverlap = pPattern->GetItemSet().
Get(ATTR_MERGE_FLAG).GetValue();
bool bHOverlapped(nOverlap & ScMF::Hor);
@@ -497,6 +504,9 @@ void ScDocument::FillInfo(
bool bScenario(nOverlap & ScMF::Scenario);
bool bPivotPopupButton(nOverlap & ScMF::ButtonPopup);
bool bFilterActive(nOverlap & ScMF::HiddenMember);
+ bool bPivotCollapseButton(nOverlap & ScMF::DpCollapse);
+ bool bPivotExpandButton(nOverlap & ScMF::DpExpand);
+ bool bPivotPopupButtonMulti(nOverlap & ScMF::ButtonPopup2);
if (bMerged||bHOverlapped||bVOverlapped)
bAnyMerged = true; // internal
@@ -519,20 +529,23 @@ void ScDocument::FillInfo(
bool bRowHidden = RowHidden(nCurRow, nTab, nullptr, &nLastHiddenRow);
if ( nArrRow==0 || !bRowHidden )
{
- if ( GetPreviewCellStyle( nX, nCurRow, nTab ) != nullptr )
+ if ( GetPreviewCellStyle( nCol, nCurRow, nTab ) != nullptr )
bAnyPreview = true;
RowInfo* pThisRowInfo = &pRowInfo[nArrRow];
- if (pBackground != pDefBackground) // Column background == Default ?
+ if (!SfxPoolItem::areSame(pBackground, pDefBackground)) // Column background == Default ?
pThisRowInfo->bEmptyBack = false;
if (bContainsCondFormat)
pThisRowInfo->bEmptyBack = false;
if (bAutoFilter)
pThisRowInfo->bAutoFilter = true;
- if (bPivotButton || bPivotPopupButton)
+ if (bPivotButton || bPivotPopupButton || bPivotPopupButtonMulti)
pThisRowInfo->bPivotButton = true;
+ if (bPivotCollapseButton || bPivotExpandButton)
+ pThisRowInfo->bPivotToggle = true;
- CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrCol];
- pInfo->pBackground = pBackground;
+ ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nCol);
+ ScBasicCellInfo* pBasicInfo = &pThisRowInfo->basicCellInfo(nCol);
+ pInfo->maBackground = SfxPoolItemHolder(*pPool, pBackground);
pInfo->pPatternAttr = pPattern;
pInfo->bMerged = bMerged;
pInfo->bHOverlapped = bHOverlapped;
@@ -540,6 +553,9 @@ void ScDocument::FillInfo(
pInfo->bAutoFilter = bAutoFilter;
pInfo->bPivotButton = bPivotButton;
pInfo->bPivotPopupButton = bPivotPopupButton;
+ pInfo->bPivotCollapseButton = bPivotCollapseButton;
+ pInfo->bPivotExpandButton = bPivotExpandButton;
+ pInfo->bPivotPopupButtonMulti = bPivotPopupButtonMulti;
pInfo->bFilterActive = bFilterActive;
pInfo->pLinesAttr = pLinesAttr;
pInfo->mpTLBRLine = pTLBRLine;
@@ -549,18 +565,19 @@ void ScDocument::FillInfo(
if (bScenario)
{
- pInfo->pBackground = ScGlobal::GetButtonBrushItem();
+ pInfo->maBackground = SfxPoolItemHolder(*pPool, ScGlobal::GetButtonBrushItem());
pThisRowInfo->bEmptyBack = false;
}
if (bContainsCondFormat && pCondFormList)
{
- bAnyCondition |= handleConditionalFormat(*pCondFormList, rCondFormats, pInfo, pStlPool, ScAddress(nX, nCurRow, nTab),
+ bAnyCondition |= handleConditionalFormat(*pCondFormList, rCondFormats,
+ pInfo, &rTabInfo, pStlPool, ScAddress(nCol, nCurRow, nTab),
bHidden, bHideFormula, bTabProtect);
}
- if (bHidden || (bFormulaMode && bHideFormula && pInfo->maCell.meType == CELLTYPE_FORMULA))
- pInfo->bEmptyCellText = true;
+ if (bHidden || (bFormulaMode && bHideFormula && pInfo->maCell.getType() == CELLTYPE_FORMULA))
+ pBasicInfo->bEmptyCellText = true;
++nArrRow;
}
@@ -580,7 +597,7 @@ void ScDocument::FillInfo(
if (pMarkData && pMarkData->IsMultiMarked())
{
// Block marks
- ScMarkArray aThisMarkArr(pMarkData->GetMarkArray( nX ));
+ ScMarkArray aThisMarkArr(pMarkData->GetMarkArray( nCol ));
nArrRow = 1;
nCurRow = nRow1; // single rows
@@ -608,17 +625,12 @@ void ScDocument::FillInfo(
else // columns in front
{
for (nArrRow=1; nArrRow+1<nArrCount; nArrRow++)
- {
- RowInfo* pThisRowInfo = &pRowInfo[nArrRow];
- CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrCol];
-
- pInfo->nWidth = nThisWidth; //TODO: or check only 0 ??
- }
+ pRowInfo[nArrRow].basicCellInfo(nCol).nWidth = nThisWidth; //TODO: or check only 0 ??
}
}
}
else
- pRowInfo[0].pCellInfo[nArrCol].nWidth = STD_COL_WIDTH;
+ pRowInfo[0].basicCellInfo(nCol).nWidth = STD_COL_WIDTH;
// STD_COL_WIDTH farthest to the left and right is needed for DrawExtraShadow
}
@@ -632,13 +644,12 @@ void ScDocument::FillInfo(
{
for (nArrRow=0; nArrRow<nArrCount; nArrRow++)
{
- for (SCCOL nArrCol=nCol1; nArrCol<=nCol2+2; nArrCol++) // 1 more left and right
+ for (SCCOL nCol=nCol1-1; nCol<=nCol2+1; nCol++) // 1 more left and right
{
- CellInfo* pInfo = &pRowInfo[nArrRow].pCellInfo[nArrCol];
- SCCOL nCol = (nArrCol>0) ? nArrCol-1 : MAXCOL+1;
+ ScCellInfo* pInfo = &pRowInfo[nArrRow].cellInfo(nCol);
ScPatternAttr* pModifiedPatt = nullptr;
- if ( ValidCol(nCol) && pRowInfo[nArrRow].nRowNo <= MAXROW )
+ if ( ValidCol(nCol) && pRowInfo[nArrRow].nRowNo <= MaxRow() )
{
if ( ScStyleSheet* pPreviewStyle = GetPreviewCellStyle( nCol, pRowInfo[nArrRow].nRowNo, nTab ) )
{
@@ -652,35 +663,34 @@ void ScDocument::FillInfo(
if (pCondSet)
{
- const SfxPoolItem* pItem;
-
// Background
- if ( pCondSet->GetItemState( ATTR_BACKGROUND, true, &pItem ) == SfxItemState::SET )
+ if ( const SvxBrushItem* pItem = pCondSet->GetItemIfSet( ATTR_BACKGROUND ) )
{
- pInfo->pBackground = static_cast<const SvxBrushItem*>(pItem);
+ pInfo->maBackground = SfxPoolItemHolder(*pPool, pItem);
pRowInfo[nArrRow].bEmptyBack = false;
}
// Border
- if ( pCondSet->GetItemState( ATTR_BORDER, true, &pItem ) == SfxItemState::SET )
- pInfo->pLinesAttr = static_cast<const SvxBoxItem*>(pItem);
+ if ( const SvxBoxItem* pItem = pCondSet->GetItemIfSet( ATTR_BORDER ) )
+ pInfo->pLinesAttr = pItem;
- if ( pCondSet->GetItemState( ATTR_BORDER_TLBR, true, &pItem ) == SfxItemState::SET )
- pInfo->mpTLBRLine = static_cast< const SvxLineItem* >( pItem );
- if ( pCondSet->GetItemState( ATTR_BORDER_BLTR, true, &pItem ) == SfxItemState::SET )
- pInfo->mpBLTRLine = static_cast< const SvxLineItem* >( pItem );
+ if ( const SvxLineItem* pItem = pCondSet->GetItemIfSet( ATTR_BORDER_TLBR ) )
+ pInfo->mpTLBRLine = pItem;
+ if ( const SvxLineItem* pItem = pCondSet->GetItemIfSet( ATTR_BORDER_BLTR ) )
+ pInfo->mpBLTRLine = pItem;
// Shadow
- if ( pCondSet->GetItemState( ATTR_SHADOW, true, &pItem ) == SfxItemState::SET )
+ if ( const SvxShadowItem* pItem = pCondSet->GetItemIfSet( ATTR_SHADOW ) )
{
- pInfo->pShadowAttr = static_cast<const SvxShadowItem*>(pItem);
+ pInfo->pShadowAttr = pItem;
bAnyShadow = true;
}
}
if( bAnyCondition && pInfo->mxColorScale)
{
pRowInfo[nArrRow].bEmptyBack = false;
- pInfo->pBackground = &pPool->Put(SvxBrushItem(*pInfo->mxColorScale, ATTR_BACKGROUND));
+ const SvxBrushItem aBrushItem(*pInfo->mxColorScale, ATTR_BACKGROUND);
+ pInfo->maBackground = SfxPoolItemHolder(*pPool, &aBrushItem);
}
}
}
@@ -697,10 +707,9 @@ void ScDocument::FillInfo(
RowInfo* pThisRowInfo = &pRowInfo[nArrRow];
SCROW nSignedY = nArrRow ? pThisRowInfo->nRowNo : nRow1-1;
- for (SCCOL nArrCol=nCol1; nArrCol<=nCol2+2; nArrCol++) // 1 more left and right
+ for (SCCOL nCol=nCol1-1; nCol<=nCol2+1; nCol++) // 1 more left and right
{
- SCCOL nSignedX = nArrCol - 1;
- CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrCol];
+ ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nCol);
if (pInfo->bMerged || pInfo->bHOverlapped || pInfo->bVOverlapped)
{
@@ -708,28 +717,49 @@ void ScDocument::FillInfo(
SCROW nStartY;
SCCOL nEndX;
SCROW nEndY;
- lcl_GetMergeRange( nSignedX,nSignedY, nArrRow, this,pRowInfo, nCol1,nRow1,nTab,
+ lcl_GetMergeRange( nCol,nSignedY, nArrRow, this,pRowInfo, nCol1,nRow1,nTab,
nStartX,nStartY, nEndX,nEndY );
const ScPatternAttr* pStartPattern = GetPattern( nStartX,nStartY,nTab );
const SfxItemSet* pStartCond = GetCondResult( nStartX,nStartY,nTab );
- const SfxPoolItem* pItem;
// Copy Background (or in output.cxx)
- if ( !pStartCond || pStartCond->
- GetItemState(ATTR_BACKGROUND,true,&pItem) != SfxItemState::SET )
- pItem = &pStartPattern->GetItem(ATTR_BACKGROUND);
- pInfo->pBackground = static_cast<const SvxBrushItem*>(pItem);
+ const SvxBrushItem* pBrushItem = nullptr;
+ if ( !pStartCond ||
+ !(pBrushItem = pStartCond->GetItemIfSet(ATTR_BACKGROUND)) )
+ pBrushItem = &pStartPattern->GetItem(ATTR_BACKGROUND);
+ pInfo->maBackground = SfxPoolItemHolder(*pPool, pBrushItem);
pRowInfo[nArrRow].bEmptyBack = false;
// Shadow
- if ( !pStartCond || pStartCond->
- GetItemState(ATTR_SHADOW,true,&pItem) != SfxItemState::SET )
- pItem = &pStartPattern->GetItem(ATTR_SHADOW);
- pInfo->pShadowAttr = static_cast<const SvxShadowItem*>(pItem);
- if (pInfo->pShadowAttr != pDefShadow)
+ const SvxShadowItem* pShadowItem = nullptr;
+ if ( !pStartCond ||
+ !(pShadowItem = pStartCond->GetItemIfSet(ATTR_SHADOW)) )
+ pShadowItem = &pStartPattern->GetItem(ATTR_SHADOW);
+ pInfo->pShadowAttr = pShadowItem;
+ if (!SfxPoolItem::areSame(pInfo->pShadowAttr, pDefShadow))
bAnyShadow = true;
+
+ const ScCondFormatIndexes& rCondFormatIndex
+ = pStartPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData();
+
+ if (pCondFormList && !pStartCond && !rCondFormatIndex.empty())
+ {
+ for (const auto& rItem : rCondFormatIndex)
+ {
+ const ScConditionalFormat* pCondForm = pCondFormList->GetFormat(rItem);
+ if (pCondForm)
+ {
+ ScCondFormatData aData = pCondForm->GetData(
+ pInfo->maCell, ScAddress(nStartX, nStartY, nTab));
+
+ // Color scale
+ if (aData.mxColorScale && !pInfo->mxColorScale)
+ pInfo->mxColorScale = aData.mxColorScale;
+ }
+ }
+ }
}
}
}
@@ -742,12 +772,12 @@ void ScDocument::FillInfo(
bool bTop = ( nArrRow == 0 );
bool bBottom = ( nArrRow+1 == nArrCount );
- for (SCCOL nArrCol=nCol1; nArrCol<=nCol2+2; nArrCol++) // 1 more left and right
+ for (SCCOL nCol=nCol1-1; nCol<=nCol2+1; nCol++) // 1 more left and right
{
- bool bLeft = ( nArrCol == nCol1 );
- bool bRight = ( nArrCol == nCol2+2 );
+ bool bLeft = ( nCol == nCol1-1 );
+ bool bRight = ( nCol == nCol2+1 );
- CellInfo* pInfo = &pRowInfo[nArrRow].pCellInfo[nArrCol];
+ ScCellInfo* pInfo = &pRowInfo[nArrRow].cellInfo(nCol);
const SvxShadowItem* pThisAttr = pInfo->pShadowAttr;
SvxShadowLocation eLoc = pThisAttr ? pThisAttr->GetLocation() : SvxShadowLocation::NONE;
if (eLoc != SvxShadowLocation::NONE)
@@ -757,19 +787,19 @@ void ScDocument::FillInfo(
SCCOL nDxPos = 1;
SCCOL nDxNeg = -1;
- while ( nArrCol+nDxPos < nCol2+2 && pRowInfo[0].pCellInfo[nArrCol+nDxPos].nWidth == 0 )
+ while ( nCol+nDxPos < nCol2+1 && pRowInfo[0].basicCellInfo(nCol+nDxPos).nWidth == 0 )
++nDxPos;
- while ( nArrCol+nDxNeg > nCol1 && pRowInfo[0].pCellInfo[nArrCol+nDxNeg].nWidth == 0 )
+ while ( nCol+nDxNeg > nCol1-1 && pRowInfo[0].basicCellInfo(nCol+nDxNeg).nWidth == 0 )
--nDxNeg;
bool bLeftDiff = !bLeft &&
- pRowInfo[nArrRow].pCellInfo[nArrCol+nDxNeg].pShadowAttr->GetLocation() == SvxShadowLocation::NONE;
+ pRowInfo[nArrRow].cellInfo(nCol+nDxNeg).pShadowAttr->GetLocation() == SvxShadowLocation::NONE;
bool bRightDiff = !bRight &&
- pRowInfo[nArrRow].pCellInfo[nArrCol+nDxPos].pShadowAttr->GetLocation() == SvxShadowLocation::NONE;
+ pRowInfo[nArrRow].cellInfo(nCol+nDxPos).pShadowAttr->GetLocation() == SvxShadowLocation::NONE;
bool bTopDiff = !bTop &&
- pRowInfo[nArrRow-1].pCellInfo[nArrCol].pShadowAttr->GetLocation() == SvxShadowLocation::NONE;
+ pRowInfo[nArrRow-1].cellInfo(nCol).pShadowAttr->GetLocation() == SvxShadowLocation::NONE;
bool bBottomDiff = !bBottom &&
- pRowInfo[nArrRow+1].pCellInfo[nArrCol].pShadowAttr->GetLocation() == SvxShadowLocation::NONE;
+ pRowInfo[nArrRow+1].cellInfo(nCol).pShadowAttr->GetLocation() == SvxShadowLocation::NONE;
if ( bLayoutRTL )
{
@@ -791,80 +821,80 @@ void ScDocument::FillInfo(
case SvxShadowLocation::BottomRight:
if (bBottomDiff)
{
- pRowInfo[nArrRow+1].pCellInfo[nArrCol].pHShadowOrigin = pThisAttr;
- pRowInfo[nArrRow+1].pCellInfo[nArrCol].eHShadowPart =
+ pRowInfo[nArrRow+1].cellInfo(nCol).pHShadowOrigin = pThisAttr;
+ pRowInfo[nArrRow+1].cellInfo(nCol).eHShadowPart =
bLeftDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ;
}
if (bRightDiff)
{
- pRowInfo[nArrRow].pCellInfo[nArrCol+1].pVShadowOrigin = pThisAttr;
- pRowInfo[nArrRow].pCellInfo[nArrCol+1].eVShadowPart =
+ pRowInfo[nArrRow].cellInfo(nCol+1).pVShadowOrigin = pThisAttr;
+ pRowInfo[nArrRow].cellInfo(nCol+1).eVShadowPart =
bTopDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT;
}
if (bBottomDiff && bRightDiff)
{
- pRowInfo[nArrRow+1].pCellInfo[nArrCol+1].pHShadowOrigin = pThisAttr;
- pRowInfo[nArrRow+1].pCellInfo[nArrCol+1].eHShadowPart = SC_SHADOW_CORNER;
+ pRowInfo[nArrRow+1].cellInfo(nCol+1).pHShadowOrigin = pThisAttr;
+ pRowInfo[nArrRow+1].cellInfo(nCol+1).eHShadowPart = SC_SHADOW_CORNER;
}
break;
case SvxShadowLocation::BottomLeft:
if (bBottomDiff)
{
- pRowInfo[nArrRow+1].pCellInfo[nArrCol].pHShadowOrigin = pThisAttr;
- pRowInfo[nArrRow+1].pCellInfo[nArrCol].eHShadowPart =
+ pRowInfo[nArrRow+1].cellInfo(nCol).pHShadowOrigin = pThisAttr;
+ pRowInfo[nArrRow+1].cellInfo(nCol).eHShadowPart =
bRightDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ;
}
if (bLeftDiff)
{
- pRowInfo[nArrRow].pCellInfo[nArrCol-1].pVShadowOrigin = pThisAttr;
- pRowInfo[nArrRow].pCellInfo[nArrCol-1].eVShadowPart =
+ pRowInfo[nArrRow].cellInfo(nCol-1).pVShadowOrigin = pThisAttr;
+ pRowInfo[nArrRow].cellInfo(nCol-1).eVShadowPart =
bTopDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT;
}
if (bBottomDiff && bLeftDiff)
{
- pRowInfo[nArrRow+1].pCellInfo[nArrCol-1].pHShadowOrigin = pThisAttr;
- pRowInfo[nArrRow+1].pCellInfo[nArrCol-1].eHShadowPart = SC_SHADOW_CORNER;
+ pRowInfo[nArrRow+1].cellInfo(nCol-1).pHShadowOrigin = pThisAttr;
+ pRowInfo[nArrRow+1].cellInfo(nCol-1).eHShadowPart = SC_SHADOW_CORNER;
}
break;
case SvxShadowLocation::TopRight:
if (bTopDiff)
{
- pRowInfo[nArrRow-1].pCellInfo[nArrCol].pHShadowOrigin = pThisAttr;
- pRowInfo[nArrRow-1].pCellInfo[nArrCol].eHShadowPart =
+ pRowInfo[nArrRow-1].cellInfo(nCol).pHShadowOrigin = pThisAttr;
+ pRowInfo[nArrRow-1].cellInfo(nCol).eHShadowPart =
bLeftDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ;
}
if (bRightDiff)
{
- pRowInfo[nArrRow].pCellInfo[nArrCol+1].pVShadowOrigin = pThisAttr;
- pRowInfo[nArrRow].pCellInfo[nArrCol+1].eVShadowPart =
+ pRowInfo[nArrRow].cellInfo(nCol+1).pVShadowOrigin = pThisAttr;
+ pRowInfo[nArrRow].cellInfo(nCol+1).eVShadowPart =
bBottomDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT;
}
if (bTopDiff && bRightDiff)
{
- pRowInfo[nArrRow-1].pCellInfo[nArrCol+1].pHShadowOrigin = pThisAttr;
- pRowInfo[nArrRow-1].pCellInfo[nArrCol+1].eHShadowPart = SC_SHADOW_CORNER;
+ pRowInfo[nArrRow-1].cellInfo(nCol+1).pHShadowOrigin = pThisAttr;
+ pRowInfo[nArrRow-1].cellInfo(nCol+1).eHShadowPart = SC_SHADOW_CORNER;
}
break;
case SvxShadowLocation::TopLeft:
if (bTopDiff)
{
- pRowInfo[nArrRow-1].pCellInfo[nArrCol].pHShadowOrigin = pThisAttr;
- pRowInfo[nArrRow-1].pCellInfo[nArrCol].eHShadowPart =
+ pRowInfo[nArrRow-1].cellInfo(nCol).pHShadowOrigin = pThisAttr;
+ pRowInfo[nArrRow-1].cellInfo(nCol).eHShadowPart =
bRightDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ;
}
if (bLeftDiff)
{
- pRowInfo[nArrRow].pCellInfo[nArrCol-1].pVShadowOrigin = pThisAttr;
- pRowInfo[nArrRow].pCellInfo[nArrCol-1].eVShadowPart =
+ pRowInfo[nArrRow].cellInfo(nCol-1).pVShadowOrigin = pThisAttr;
+ pRowInfo[nArrRow].cellInfo(nCol-1).eVShadowPart =
bBottomDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT;
}
if (bTopDiff && bLeftDiff)
{
- pRowInfo[nArrRow-1].pCellInfo[nArrCol-1].pHShadowOrigin = pThisAttr;
- pRowInfo[nArrRow-1].pCellInfo[nArrCol-1].eHShadowPart = SC_SHADOW_CORNER;
+ pRowInfo[nArrRow-1].cellInfo(nCol-1).pHShadowOrigin = pThisAttr;
+ pRowInfo[nArrRow-1].cellInfo(nCol-1).eHShadowPart = SC_SHADOW_CORNER;
}
break;
@@ -881,10 +911,11 @@ void ScDocument::FillInfo(
// *** create the frame border array ***
- // RowInfo structs are filled in the range [ 0 , nArrCount-1 ]
- // each RowInfo contains CellInfo structs in the range [ nX1-1 , nX2+1 ]
+ // RowInfo structs are filled in the range [ 0 , nArrCount-1 ],
+ // each RowInfo contains ScCellInfo structs in the range [ nCol1-1 , nCol2+1 ]
+ // and ScBasicCellInfo structs in the range [ -1, nCol2+1 ]
- size_t nColCount = nCol2 - nCol1 + 3;
+ size_t nColCount = nCol2 - nCol1 + 1 + 2;
size_t nRowCount = nArrCount;
svx::frame::Array& rArray = rTabInfo.maArray;
@@ -895,21 +926,22 @@ void ScDocument::FillInfo(
sal_uInt16 nCellInfoY = static_cast< sal_uInt16 >( nRow );
RowInfo& rThisRowInfo = pRowInfo[ nCellInfoY ];
- for( size_t nCol = 0; nCol < nColCount; ++nCol )
+ for( SCCOL nCol = nCol1 - 1; nCol <= nCol2 + 1; ++nCol ) // 1 more left and right
{
- sal_uInt16 nCellInfoX = static_cast< sal_uInt16 >( nCol + nCol1 );
- const CellInfo& rInfo = rThisRowInfo.pCellInfo[ nCellInfoX ];
-
+ const ScCellInfo& rInfo = rThisRowInfo.cellInfo( nCol );
const SvxBoxItem* pBox = rInfo.pLinesAttr;
const SvxLineItem* pTLBR = rInfo.mpTLBRLine;
const SvxLineItem* pBLTR = rInfo.mpBLTRLine;
- size_t nFirstCol = nCol;
+ size_t colToIndex = -(nCol1 - 1);
+ // These are rArray indexes (0-based), not really rows/columns.
+ size_t nX = nCol + colToIndex;
+ size_t nFirstCol = nX;
size_t nFirstRow = nRow;
// *** merged cells *** -------------------------------------------
- if( !rArray.IsMerged( nCol, nRow ) && (rInfo.bMerged || rInfo.bHOverlapped || rInfo.bVOverlapped) )
+ if( !rArray.IsMerged( nX, nRow ) && (rInfo.bMerged || rInfo.bHOverlapped || rInfo.bVOverlapped) )
{
// *** insert merged range in svx::frame::Array ***
@@ -918,11 +950,10 @@ void ScDocument::FillInfo(
complete merged range, then calculate dimensions and
document position of the visible range. */
- // note: document columns are always one less than CellInfoX coords
// note: document rows must be looked up in RowInfo structs
// current column and row in document coordinates
- SCCOL nCurrDocCol = static_cast< SCCOL >( nCellInfoX - 1 );
+ SCCOL nCurrDocCol = nCol;
SCROW nCurrDocRow = static_cast< SCROW >( (nCellInfoY > 0) ? rThisRowInfo.nRowNo : (nRow1 - 1) );
// find entire merged range in document, returns signed document coordinates
@@ -938,15 +969,13 @@ void ScDocument::FillInfo(
SCCOL nLastRealDocCol = nLastRealDocColS;
SCROW nLastRealDocRow = nLastRealDocRowS;
- // first visible column (nX1-1 is first processed document column)
+ // first visible column (nCol1-1 is first processed document column)
SCCOL nFirstDocCol = (nCol1 > 0) ? ::std::max< SCCOL >( nFirstRealDocCol, nCol1 - 1 ) : nFirstRealDocCol;
- sal_uInt16 nFirstCellInfoX = static_cast< sal_uInt16 >( nFirstDocCol + 1 );
- nFirstCol = static_cast< size_t >( nFirstCellInfoX - nCol1 );
+ nFirstCol = nFirstDocCol + colToIndex;
- // last visible column (nX2+1 is last processed document column)
- SCCOL nLastDocCol = (nCol2 < MAXCOL) ? ::std::min< SCCOL >( nLastRealDocCol, nCol2 + 1 ) : nLastRealDocCol;
- sal_uInt16 nLastCellInfoX = static_cast< sal_uInt16 >( nLastDocCol + 1 );
- size_t nLastCol = static_cast< size_t >( nLastCellInfoX - nCol1 );
+ // last visible column (nCol2+1 is last processed document column)
+ SCCOL nLastDocCol = (nCol2 < MaxCol()) ? ::std::min< SCCOL >( nLastRealDocCol, nCol2 + 1 ) : nLastRealDocCol;
+ size_t nLastCol = nLastDocCol + colToIndex;
// first visible row
sal_uInt16 nFirstCellInfoY = nCellInfoY;
@@ -975,7 +1004,7 @@ void ScDocument::FillInfo(
tools::Long nSize = 0;
for( SCCOL nDocCol = nFirstRealDocCol; nDocCol < nFirstDocCol; ++nDocCol )
nSize += std::max( tools::Long(GetColWidth( nDocCol, nTab ) * fColScale), tools::Long(1) );
- rArray.SetAddMergedLeftSize( nCol, nRow, nSize );
+ rArray.SetAddMergedLeftSize( nX, nRow, nSize );
}
// additional space after last column
if( nLastCol + 1 == nColCount )
@@ -983,7 +1012,7 @@ void ScDocument::FillInfo(
tools::Long nSize = 0;
for( SCCOL nDocCol = nLastDocCol + 1; nDocCol <= nLastRealDocCol; ++nDocCol )
nSize += std::max( tools::Long(GetColWidth( nDocCol, nTab ) * fColScale), tools::Long(1) );
- rArray.SetAddMergedRightSize( nCol, nRow, nSize );
+ rArray.SetAddMergedRightSize( nX, nRow, nSize );
}
// additional space above first row
if( nFirstRow == 0 )
@@ -991,7 +1020,7 @@ void ScDocument::FillInfo(
tools::Long nSize = 0;
for( SCROW nDocRow = nFirstRealDocRow; nDocRow < nFirstDocRow; ++nDocRow )
nSize += std::max( tools::Long(GetRowHeight( nDocRow, nTab ) * fRowScale), tools::Long(1) );
- rArray.SetAddMergedTopSize( nCol, nRow, nSize );
+ rArray.SetAddMergedTopSize( nX, nRow, nSize );
}
// additional space beyond last row
if( nLastRow + 1 == nRowCount )
@@ -999,7 +1028,7 @@ void ScDocument::FillInfo(
tools::Long nSize = 0;
for( SCROW nDocRow = nLastDocRow + 1; nDocRow <= nLastRealDocRow; ++nDocRow )
nSize += std::max( tools::Long(GetRowHeight( nDocRow, nTab ) * fRowScale), tools::Long(1) );
- rArray.SetAddMergedBottomSize( nCol, nRow, nSize );
+ rArray.SetAddMergedBottomSize( nX, nRow, nSize );
}
// *** use line attributes from real origin cell ***
@@ -1043,19 +1072,27 @@ void ScDocument::FillInfo(
rArray.MirrorSelfX();
}
-ScTableInfo::ScTableInfo(const SCSIZE capacity)
- : mpRowInfo(new RowInfo[capacity])
- , mnArrCount(0)
- , mnArrCapacity(capacity)
+/// We seem to need to allocate three extra rows here, not sure why
+///
+ScTableInfo::ScTableInfo(SCROW nStartRow, SCROW nEndRow, bool bHintOnly)
+ : mnArrCount(0)
+ , mnArrCapacity(nEndRow - nStartRow + 4)
, mbPageMode(false)
{
- memset(static_cast<void*>(mpRowInfo.get()), 0, mnArrCapacity * sizeof(RowInfo));
+ assert(nStartRow >= 0);
+ assert(nEndRow >= nStartRow);
+ if (bHintOnly && mnArrCapacity > 1024)
+ {
+ SAL_INFO("sc.core", "ScTableInfo excessive capacity: " << mnArrCapacity << " start: " << nStartRow << " end: " << nEndRow);
+ mnArrCapacity = 1024;
+ }
+ mpRowInfo.reset(new RowInfo[mnArrCapacity] {});
}
ScTableInfo::~ScTableInfo()
{
for( SCSIZE nIdx = 0; nIdx < mnArrCapacity; ++nIdx )
- delete [] mpRowInfo[ nIdx ].pCellInfo;
+ mpRowInfo[ nIdx ].freeCellInfo();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 3eef76bf3550..529ea73a7e6e 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -51,9 +51,9 @@
#include <comphelper/threadpool.hxx>
#include <editeng/editobj.hxx>
-#include <tools/cpuid.hxx>
#include <formula/errorcodes.hxx>
#include <svl/intitem.hxx>
+#include <svl/numformat.hxx>
#include <formulagroup.hxx>
#include <listenercontext.hxx>
#include <types.hxx>
@@ -440,7 +440,7 @@ void adjustRangeName(formula::FormulaToken* pToken, ScDocument& rNewDoc, const S
{
// If this happened we have a real problem.
pToken->SetIndex(0);
- OSL_FAIL("inserting the range name should not fail");
+ assert(!"inserting the range name should not fail");
return;
}
@@ -477,49 +477,31 @@ void adjustDBRange(formula::FormulaToken* pToken, ScDocument& rNewDoc, const ScD
pToken->SetIndex(pNewDBData->GetIndex());
}
-struct AreaListenerKey
-{
- ScRange maRange;
- bool mbStartFixed;
- bool mbEndFixed;
-
- AreaListenerKey( const ScRange& rRange, bool bStartFixed, bool bEndFixed ) :
- maRange(rRange), mbStartFixed(bStartFixed), mbEndFixed(bEndFixed) {}
-
- bool operator < ( const AreaListenerKey& r ) const
- {
- if (maRange.aStart.Tab() != r.maRange.aStart.Tab())
- return maRange.aStart.Tab() < r.maRange.aStart.Tab();
- if (maRange.aStart.Col() != r.maRange.aStart.Col())
- return maRange.aStart.Col() < r.maRange.aStart.Col();
- if (maRange.aStart.Row() != r.maRange.aStart.Row())
- return maRange.aStart.Row() < r.maRange.aStart.Row();
- if (maRange.aEnd.Tab() != r.maRange.aEnd.Tab())
- return maRange.aEnd.Tab() < r.maRange.aEnd.Tab();
- if (maRange.aEnd.Col() != r.maRange.aEnd.Col())
- return maRange.aEnd.Col() < r.maRange.aEnd.Col();
- if (maRange.aEnd.Row() != r.maRange.aEnd.Row())
- return maRange.aEnd.Row() < r.maRange.aEnd.Row();
- if (mbStartFixed != r.mbStartFixed)
- return r.mbStartFixed;
- if (mbEndFixed != r.mbEndFixed)
- return r.mbEndFixed;
-
- return false;
- }
-};
-
-typedef std::map<AreaListenerKey, std::unique_ptr<sc::FormulaGroupAreaListener>> AreaListenersType;
-
}
-struct ScFormulaCellGroup::Impl
+bool AreaListenerKey::operator < ( const AreaListenerKey& r ) const
{
- AreaListenersType m_AreaListeners;
-};
+ if (maRange.aStart.Tab() != r.maRange.aStart.Tab())
+ return maRange.aStart.Tab() < r.maRange.aStart.Tab();
+ if (maRange.aStart.Col() != r.maRange.aStart.Col())
+ return maRange.aStart.Col() < r.maRange.aStart.Col();
+ if (maRange.aStart.Row() != r.maRange.aStart.Row())
+ return maRange.aStart.Row() < r.maRange.aStart.Row();
+ if (maRange.aEnd.Tab() != r.maRange.aEnd.Tab())
+ return maRange.aEnd.Tab() < r.maRange.aEnd.Tab();
+ if (maRange.aEnd.Col() != r.maRange.aEnd.Col())
+ return maRange.aEnd.Col() < r.maRange.aEnd.Col();
+ if (maRange.aEnd.Row() != r.maRange.aEnd.Row())
+ return maRange.aEnd.Row() < r.maRange.aEnd.Row();
+ if (mbStartFixed != r.mbStartFixed)
+ return r.mbStartFixed;
+ if (mbEndFixed != r.mbEndFixed)
+ return r.mbEndFixed;
+
+ return false;
+}
ScFormulaCellGroup::ScFormulaCellGroup() :
- mpImpl(new Impl),
mnRefCount(0),
mpTopCell(nullptr),
mnLength(0),
@@ -538,15 +520,7 @@ ScFormulaCellGroup::~ScFormulaCellGroup()
void ScFormulaCellGroup::setCode( const ScTokenArray& rCode )
{
- mpCode = rCode.Clone();
- mbInvariant = mpCode->IsInvariant();
- mpCode->GenHash();
-}
-
-void ScFormulaCellGroup::setCode( std::unique_ptr<ScTokenArray> pCode )
-{
- mpCode = std::move(pCode); // takes ownership of the token array.
- mpCode->Finalize(); // Reduce memory usage if needed.
+ mpCode = rCode.CloneValue();
mbInvariant = mpCode->IsInvariant();
mpCode->GenHash();
}
@@ -575,30 +549,32 @@ sc::FormulaGroupAreaListener* ScFormulaCellGroup::getAreaListener(
{
AreaListenerKey aKey(rRange, bStartFixed, bEndFixed);
- AreaListenersType::iterator it = mpImpl->m_AreaListeners.lower_bound(aKey);
- if (it == mpImpl->m_AreaListeners.end() || mpImpl->m_AreaListeners.key_comp()(aKey, it->first))
+ AreaListenersType::iterator it = m_AreaListeners.lower_bound(aKey);
+ if (it == m_AreaListeners.end() || m_AreaListeners.key_comp()(aKey, it->first))
{
// Insert a new one.
- it = mpImpl->m_AreaListeners.insert(
- it, std::make_pair(aKey, std::make_unique<sc::FormulaGroupAreaListener>(
- rRange, (*ppTopCell)->GetDocument(), (*ppTopCell)->aPos, mnLength, bStartFixed, bEndFixed)));
+ it = m_AreaListeners.emplace_hint(
+ it, std::piecewise_construct,
+ std::forward_as_tuple(aKey),
+ std::forward_as_tuple(
+ rRange, (*ppTopCell)->GetDocument(), (*ppTopCell)->aPos, mnLength, bStartFixed, bEndFixed));
}
- return it->second.get();
+ return &it->second;
}
void ScFormulaCellGroup::endAllGroupListening( ScDocument& rDoc )
{
- for (const auto& rEntry : mpImpl->m_AreaListeners)
+ for (auto& rEntry : m_AreaListeners)
{
- sc::FormulaGroupAreaListener *const pListener = rEntry.second.get();
- ScRange aListenRange = pListener->getListeningRange();
+ sc::FormulaGroupAreaListener& rListener = rEntry.second;
+ ScRange aListenRange = rListener.getListeningRange();
// This "always listen" special range is never grouped.
bool bGroupListening = (aListenRange != BCA_LISTEN_ALWAYS);
- rDoc.EndListeningArea(aListenRange, bGroupListening, pListener);
+ rDoc.EndListeningArea(aListenRange, bGroupListening, &rListener);
}
- mpImpl->m_AreaListeners.clear();
+ m_AreaListeners.clear();
}
ScFormulaCell::ScFormulaCell( ScDocument& rDoc, const ScAddress& rPos ) :
@@ -616,6 +592,7 @@ ScFormulaCell::ScFormulaCell( ScDocument& rDoc, const ScAddress& rPos ) :
mbPostponedDirty(false),
mbIsExtRef(false),
mbSeenInPath(false),
+ mbFreeFlying(false),
cMatrixFlag(ScMatrixMode::NONE),
nSeenInIteration(0),
nFormatType(SvNumFormatType::NUMBER),
@@ -648,6 +625,7 @@ ScFormulaCell::ScFormulaCell( ScDocument& rDoc, const ScAddress& rPos,
mbPostponedDirty(false),
mbIsExtRef(false),
mbSeenInPath(false),
+ mbFreeFlying(false),
cMatrixFlag ( cMatInd ),
nSeenInIteration(0),
nFormatType ( SvNumFormatType::NUMBER ),
@@ -683,6 +661,7 @@ ScFormulaCell::ScFormulaCell(
mbPostponedDirty(false),
mbIsExtRef(false),
mbSeenInPath(false),
+ mbFreeFlying(false),
cMatrixFlag ( cMatInd ),
nSeenInIteration(0),
nFormatType ( SvNumFormatType::NUMBER ),
@@ -735,6 +714,7 @@ ScFormulaCell::ScFormulaCell(
mbPostponedDirty(false),
mbIsExtRef(false),
mbSeenInPath(false),
+ mbFreeFlying(false),
cMatrixFlag ( cMatInd ),
nSeenInIteration(0),
nFormatType ( SvNumFormatType::NUMBER ),
@@ -784,11 +764,12 @@ ScFormulaCell::ScFormulaCell(
mbPostponedDirty(false),
mbIsExtRef(false),
mbSeenInPath(false),
+ mbFreeFlying(false),
cMatrixFlag ( cInd ),
nSeenInIteration(0),
nFormatType(xGroup->mnFormatType),
eTempGrammar( eGrammar),
- pCode(xGroup->mpCode ? xGroup->mpCode.get() : new ScTokenArray(rDoc)),
+ pCode(xGroup->mpCode ? &*xGroup->mpCode : new ScTokenArray(rDoc)),
rDocument( rDoc ),
pPrevious(nullptr),
pNext(nullptr),
@@ -801,7 +782,6 @@ ScFormulaCell::ScFormulaCell(
}
ScFormulaCell::ScFormulaCell(const ScFormulaCell& rCell, ScDocument& rDoc, const ScAddress& rPos, ScCloneFlags nCloneFlags) :
- SvtListener(),
bDirty( rCell.bDirty ),
bTableOpDirty( false ),
bChanged( rCell.bChanged ),
@@ -816,6 +796,7 @@ ScFormulaCell::ScFormulaCell(const ScFormulaCell& rCell, ScDocument& rDoc, const
mbPostponedDirty(false),
mbIsExtRef(false),
mbSeenInPath(false),
+ mbFreeFlying(false),
cMatrixFlag ( rCell.cMatrixFlag ),
nSeenInIteration(0),
nFormatType( rCell.nFormatType ),
@@ -946,6 +927,9 @@ ScFormulaCell::~ScFormulaCell()
if (!mxGroup || !mxGroup->mpCode)
// Formula token is not shared.
delete pCode;
+
+ if (mxGroup && mxGroup->mpTopCell == this)
+ mxGroup->mpTopCell = nullptr;
}
ScFormulaCell* ScFormulaCell::Clone() const
@@ -963,15 +947,14 @@ size_t ScFormulaCell::GetHash() const
return pCode->GetHash();
}
-void ScFormulaCell::GetFormula( OUStringBuffer& rBuffer,
- const FormulaGrammar::Grammar eGrammar, const ScInterpreterContext* pContext ) const
+OUString ScFormulaCell::GetFormula( const FormulaGrammar::Grammar eGrammar, ScInterpreterContext* pContext ) const
{
if( pCode->GetCodeError() != FormulaError::NONE && !pCode->GetLen() )
{
- rBuffer = ScGlobal::GetErrorString(pCode->GetCodeError());
- return;
+ return ScGlobal::GetErrorString(pCode->GetCodeError());
}
- else if( cMatrixFlag == ScMatrixMode::Reference )
+ OUStringBuffer buffer;
+ if( cMatrixFlag == ScMatrixMode::Reference )
{
// Reference to another cell that contains a matrix formula.
formula::FormulaTokenArrayPlainIterator aIter(*pCode);
@@ -990,13 +973,12 @@ void ScFormulaCell::GetFormula( OUStringBuffer& rBuffer,
if (pCell)
{
- pCell->GetFormula( rBuffer, eGrammar, pContext );
- return;
+ return pCell->GetFormula( eGrammar, pContext );
}
else
{
ScCompiler aComp( rDocument, aPos, *pCode, eGrammar, false, false, pContext );
- aComp.CreateStringFromTokenArray( rBuffer );
+ aComp.CreateStringFromTokenArray( buffer );
}
}
else
@@ -1007,26 +989,19 @@ void ScFormulaCell::GetFormula( OUStringBuffer& rBuffer,
else
{
ScCompiler aComp( rDocument, aPos, *pCode, eGrammar, false, false, pContext );
- aComp.CreateStringFromTokenArray( rBuffer );
+ aComp.CreateStringFromTokenArray( buffer );
}
- rBuffer.insert( 0, '=');
+ buffer.insert( 0, '=');
if( cMatrixFlag != ScMatrixMode::NONE )
{
- rBuffer.insert( 0, '{');
- rBuffer.append( '}');
+ buffer.insert( 0, '{');
+ buffer.append( '}');
}
+ return buffer.makeStringAndClear();
}
-void ScFormulaCell::GetFormula( OUString& rFormula, const FormulaGrammar::Grammar eGrammar,
- const ScInterpreterContext* pContext ) const
-{
- OUStringBuffer rBuffer( rFormula );
- GetFormula( rBuffer, eGrammar, pContext );
- rFormula = rBuffer.makeStringAndClear();
-}
-
-OUString ScFormulaCell::GetFormula( sc::CompileFormulaContext& rCxt, const ScInterpreterContext* pContext ) const
+OUString ScFormulaCell::GetFormula( sc::CompileFormulaContext& rCxt, ScInterpreterContext* pContext ) const
{
OUStringBuffer aBuf;
if (pCode->GetCodeError() != FormulaError::NONE && !pCode->GetLen())
@@ -1095,6 +1070,13 @@ void ScFormulaCell::GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows )
if (pMat)
{
pMat->GetDimensions( rCols, rRows );
+ if (pCode->IsHyperLink())
+ {
+ // Row 2 element is the URL that is not to be displayed and the
+ // result dimension not to be extended.
+ assert(rRows == 2);
+ rRows = 1;
+ }
return;
}
}
@@ -1308,9 +1290,8 @@ void ScFormulaCell::CompileXML( sc::CompileFormulaContext& rCxt, ScProgress& rPr
// The initial '=' is optional in ODFF.
const sal_Int32 nLeadingEqual = (aFormula.getLength() > 0 && aFormula[0] == '=') ? 1 : 0;
- OUString aShouldBe = aShouldBeBuf.makeStringAndClear();
- if (aFormula.getLength() == aShouldBe.getLength() + nLeadingEqual &&
- aFormula.match( aShouldBe, nLeadingEqual))
+ if (aFormula.getLength() == aShouldBeBuf.getLength() + nLeadingEqual &&
+ aFormula.match( aShouldBeBuf, nLeadingEqual))
{
// Put them in the same formula group.
ScFormulaCellGroupRef xGroup = pPreviousCell->GetCellGroup();
@@ -1645,9 +1626,12 @@ bool ScFormulaCell::Interpret(SCROW nStartOffset, SCROW nEndOffset)
// recursion list in reverse order.
if (rRecursionHelper.IsInReturn())
{
- if (rRecursionHelper.GetRecursionCount() > 0 ||
- !rRecursionHelper.IsDoingRecursion())
+ bool bFreeFlyingInserted = false;
+ if (rRecursionHelper.GetRecursionCount() > 0 || !rRecursionHelper.IsDoingRecursion())
+ {
rRecursionHelper.Insert( this, bOldRunning, aResult);
+ bFreeFlyingInserted = mbFreeFlying;
+ }
bool bIterationFromRecursion = false;
bool bResumeIteration = false;
do
@@ -1867,6 +1851,22 @@ bool ScFormulaCell::Interpret(SCROW nStartOffset, SCROW nEndOffset)
rRecursionHelper.Clear();
}
} while (bIterationFromRecursion || bResumeIteration);
+
+ if (bFreeFlyingInserted)
+ {
+ // Remove this from recursion list, it may get deleted.
+ // It additionally also should mean that the recursion/iteration
+ // ends here as it must had been triggered by this free-flying
+ // out-of-sheets cell
+ const bool bOnlyThis = (rRecursionHelper.GetList().size() == 1);
+ rRecursionHelper.GetList().remove_if([this](const ScFormulaRecursionEntry& r){return r.pCell == this;});
+ if (bOnlyThis)
+ {
+ assert(rRecursionHelper.GetList().empty());
+ if (rRecursionHelper.GetList().empty())
+ rRecursionHelper.EndIteration();
+ }
+ }
}
#if DEBUG_CALCULATION
@@ -2088,7 +2088,7 @@ void ScFormulaCell::InterpretTail( ScInterpreterContext& rContext, ScInterpretTa
nFormatType = rContext.GetFormatTable()->GetType( nOldFormatIndex);
}
if (nOldFormatIndex !=
- ScGlobal::GetStandardFormat( *rContext.GetFormatTable(), nOldFormatIndex, nFormatType))
+ ScGlobal::GetStandardFormat(rContext, nOldFormatIndex, nFormatType))
bForceNumberFormat = false;
}
}
@@ -2138,8 +2138,7 @@ void ScFormulaCell::InterpretTail( ScInterpreterContext& rContext, ScInterpretTa
}
if (bSetFormat && (bForceNumberFormat || ((nFormatIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0)))
- nFormatIndex = ScGlobal::GetStandardFormat(*rContext.GetFormatTable(),
- nFormatIndex, nFormatType);
+ nFormatIndex = ScGlobal::GetStandardFormat(rContext, nFormatIndex, nFormatType);
// Do not replace a General format (which was the reason why
// mbNeedsNumberFormat was set) with a General format.
@@ -2149,7 +2148,8 @@ void ScFormulaCell::InterpretTail( ScInterpreterContext& rContext, ScInterpretTa
// XXX if mbNeedsNumberFormat was set even if the current format
// was not General then we'd have to obtain the current format here
// and check at least the types.
- if (bSetFormat && (bForceNumberFormat || ((nFormatIndex % SV_COUNTRY_LANGUAGE_OFFSET) != 0)))
+ const bool bSetNumberFormat = bSetFormat && (bForceNumberFormat || ((nFormatIndex % SV_COUNTRY_LANGUAGE_OFFSET) != 0));
+ if (bSetNumberFormat && !rDocument.IsInLayoutStrings())
{
// set number format explicitly
if (!rDocument.IsThreadedGroupCalcInProgress())
@@ -2272,7 +2272,7 @@ void ScFormulaCell::InterpretTail( ScInterpreterContext& rContext, ScInterpretTa
if ( pCode->IsRecalcModeForced() )
{
- sal_uLong nValidation = rDocument.GetAttr(
+ sal_uInt32 nValidation = rDocument.GetAttr(
aPos.Col(), aPos.Row(), aPos.Tab(), ATTR_VALIDDATA )->GetValue();
if ( nValidation )
{
@@ -2330,10 +2330,14 @@ void ScFormulaCell::InterpretTail( ScInterpreterContext& rContext, ScInterpretTa
OSL_ENSURE( pCode->GetCodeError() != FormulaError::NONE, "no RPN code and no errors ?!?!" );
ResetDirty();
}
+
+ pCode->ClearRecalcModeMustAfterImport();
}
void ScFormulaCell::HandleStuffAfterParallelCalculation(ScInterpreter* pInterpreter)
{
+ aResult.HandleStuffAfterParallelCalculation();
+
if( !pCode->GetCodeLen() )
return;
@@ -2545,7 +2549,7 @@ void ScFormulaCell::SetDirty( bool bDirtyFlag )
// the FormulaTree, once in there it would be assumed that its
// dependents already had been tracked and it would be skipped on a
// subsequent notify. Postpone tracking until all listeners are set.
- if (!rDocument.IsImportingXML())
+ if (!rDocument.IsImportingXML() && !rDocument.IsInsertingFromOtherDoc())
rDocument.TrackFormulas();
}
@@ -2646,10 +2650,6 @@ void ScFormulaCell::AddRecalcMode( ScRecalcMode nBits )
{
if ( (nBits & ScRecalcMode::EMask) != ScRecalcMode::NORMAL )
SetDirtyVar();
- if ( nBits & ScRecalcMode::ONLOAD_ONCE )
- { // OnLoadOnce is used only to set Dirty after filter import.
- nBits = (nBits & ~ScRecalcMode::EMask) | ScRecalcMode::NORMAL;
- }
pCode->AddRecalcMode( nBits );
}
@@ -2674,7 +2674,7 @@ void ScFormulaCell::SetHybridFormula( const OUString& r,
aResult.SetHybridFormula( r); eTempGrammar = eGrammar;
}
-const OUString& ScFormulaCell::GetHybridFormula() const
+OUString ScFormulaCell::GetHybridFormula() const
{
return aResult.GetHybridFormula();
}
@@ -2689,19 +2689,19 @@ void ScFormulaCell::GetURLResult( OUString& rURL, OUString& rCellText )
// Cell Text uses the Cell format while the URL uses
// the default format for the type.
const sal_uInt32 nCellFormat = rDocument.GetNumberFormat( aPos );
- SvNumberFormatter* pFormatter = rDocument.GetFormatTable();
+ ScInterpreterContext& rContext = rDocument.GetNonThreadedContext();
- const sal_uInt32 nURLFormat = ScGlobal::GetStandardFormat( *pFormatter, nCellFormat, SvNumFormatType::NUMBER);
+ const sal_uInt32 nURLFormat = ScGlobal::GetStandardFormat(rContext, nCellFormat, SvNumFormatType::NUMBER);
if ( IsValue() )
{
double fValue = GetValue();
- pFormatter->GetOutputString( fValue, nCellFormat, rCellText, &pColor );
+ rContext.NFGetOutputString( fValue, nCellFormat, rCellText, &pColor );
}
else
{
aCellString = GetString().getString();
- pFormatter->GetOutputString( aCellString, nCellFormat, rCellText, &pColor );
+ rContext.NFGetOutputString( aCellString, nCellFormat, rCellText, &pColor );
}
ScConstMatrixRef xMat( aResult.GetMatrix());
if (xMat)
@@ -2710,16 +2710,16 @@ void ScFormulaCell::GetURLResult( OUString& rURL, OUString& rCellText )
if (!xMat->IsValue(0, 1))
rURL = xMat->GetString(0, 1).getString();
else
- pFormatter->GetOutputString(
+ rContext.NFGetOutputString(
xMat->GetDouble(0, 1), nURLFormat, rURL, &pColor);
}
if(rURL.isEmpty())
{
if(IsValue())
- pFormatter->GetOutputString( GetValue(), nURLFormat, rURL, &pColor );
+ rContext.NFGetOutputString( GetValue(), nURLFormat, rURL, &pColor );
else
- pFormatter->GetOutputString( aCellString, nURLFormat, rURL, &pColor );
+ rContext.NFGetOutputString( aCellString, nURLFormat, rURL, &pColor );
}
}
@@ -3054,8 +3054,7 @@ ScFormulaCell::HasRefListExpressibleAsOneReference(ScRange& rRange) const
{
// Collect all consecutive references, starting by the one
// already found
- std::vector<formula::FormulaToken*> aReferences;
- aReferences.push_back(pFirstReference);
+ std::vector<formula::FormulaToken*> aReferences { pFirstReference };
FormulaToken* pToken(aIter.NextRPN());
FormulaToken* pFunction(nullptr);
while (pToken)
@@ -3123,13 +3122,13 @@ bool ScFormulaCell::UpdatePosOnShift( const sc::RefUpdateContext& rCxt )
// No movement.
return false;
- if (!rCxt.maRange.In(aPos))
+ if (!rCxt.maRange.Contains(aPos))
return false;
// This formula cell itself is being shifted during cell range
// insertion or deletion. Update its position.
ScAddress aErrorPos( ScAddress::UNINITIALIZED );
- if (!aPos.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorPos))
+ if (!aPos.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorPos, rCxt.mrDoc))
{
assert(!"can't move ScFormulaCell");
}
@@ -3208,7 +3207,7 @@ bool checkCompileColRowName(
ScAddress aAbs = rRef.toAbs(rDoc, aPos);
if (rDoc.ValidAddress(aAbs))
{
- if (rCxt.maRange.In(aAbs))
+ if (rCxt.maRange.Contains(aAbs))
return true;
}
}
@@ -3377,7 +3376,7 @@ bool ScFormulaCell::UpdateReferenceOnMove(
aUndoPos = *pUndoCellPos;
ScAddress aOldPos( aPos );
- bool bCellInMoveTarget = rCxt.maRange.In(aPos);
+ bool bCellInMoveTarget = rCxt.maRange.Contains(aPos);
if ( bCellInMoveTarget )
{
@@ -3455,7 +3454,7 @@ bool ScFormulaCell::UpdateReferenceOnMove(
// #i36299# Don't duplicate action during cut&paste / drag&drop
// on a cell in the range moved, start/end listeners is done
// via ScDocument::DeleteArea() and ScDocument::CopyFromClip().
- && !(rDocument.IsInsertingFromOtherDoc() && rCxt.maRange.In(aPos));
+ && !(rDocument.IsInsertingFromOtherDoc() && rCxt.maRange.Contains(aPos));
if ( bNewListening )
EndListeningTo(rDocument, pOldCode.get(), aOldPos);
@@ -3508,7 +3507,7 @@ bool ScFormulaCell::UpdateReferenceOnCopy(
aUndoPos = *pUndoCellPos;
ScAddress aOldPos( aPos );
- if (rCxt.maRange.In(aPos))
+ if (rCxt.maRange.Contains(aPos))
{
// The cell is being moved or copied to a new position. I guess the
// position has been updated prior to this call? Determine
@@ -3801,7 +3800,7 @@ void ScFormulaCell::UpdateTranspose( const ScRange& rSource, const ScAddress& rD
rDest.Tab() + rSource.aEnd.Tab() - rSource.aStart.Tab() ) );
// cell within range
- if ( aDestRange.In( aOldPos ) )
+ if ( aDestRange.Contains( aOldPos ) )
{
// References of these cells were not changed by ScTokenArray::AdjustReferenceOnMove()
// Count back Positions
@@ -4008,7 +4007,9 @@ ScFormulaCellGroupRef ScFormulaCell::CreateCellGroup( SCROW nLen, bool bInvarian
mxGroup->mpTopCell = this;
mxGroup->mbInvariant = bInvariant;
mxGroup->mnLength = nLen;
- mxGroup->mpCode.reset(pCode); // Move this to the shared location.
+ mxGroup->mpCode = std::move(*pCode); // Move this to the shared location.
+ delete pCode;
+ pCode = &*mxGroup->mpCode;
return mxGroup;
}
@@ -4030,7 +4031,7 @@ void ScFormulaCell::SetCellGroup( const ScFormulaCellGroupRef &xRef )
delete pCode;
mxGroup = xRef;
- pCode = mxGroup->mpCode.get();
+ pCode = &*mxGroup->mpCode;
mxGroup->mnWeight = 0; // invalidate
}
@@ -4432,7 +4433,53 @@ struct ScDependantsCalculator
return nRowLen;
}
- bool DoIt()
+ // Because Lookup will extend the Result Vector under certain circumstances listed at:
+ // https://wiki.documentfoundation.org/Documentation/Calc_Functions/LOOKUP
+ // then if the Lookup has a Result Vector only accept the Lookup for parallelization
+ // of the Result Vector has the same dimensions as the Search Vector.
+ bool LookupResultVectorMismatch(sal_Int32 nTokenIdx)
+ {
+ if (nTokenIdx >= 3)
+ {
+ FormulaToken** pRPNArray = mrCode.GetCode();
+ if (pRPNArray[nTokenIdx - 1]->GetOpCode() == ocPush && // <- result vector
+ pRPNArray[nTokenIdx - 2]->GetOpCode() == ocPush && // <- search vector
+ pRPNArray[nTokenIdx - 2]->GetType() == svDoubleRef &&
+ pRPNArray[nTokenIdx - 3]->GetOpCode() == ocPush) // <- search criterion
+ {
+ auto res = pRPNArray[nTokenIdx - 1];
+ // If Result vector is just a single cell reference
+ // LOOKUP extends it as a column vector.
+ if (res->GetType() == svSingleRef)
+ return true;
+
+ // If Result vector is a cell range and the match position
+ // falls outside its length, it gets automatically extended
+ // to the length of Search vector, but in the direction of
+ // Result vector.
+ if (res->GetType() == svDoubleRef)
+ {
+ ScComplexRefData aRef1 = *res->GetDoubleRef();
+ ScComplexRefData aRef2 = *pRPNArray[nTokenIdx - 2]->GetDoubleRef();
+ ScRange resultRange = aRef1.toAbs(mrDoc, mrPos);
+ ScRange sourceRange = aRef2.toAbs(mrDoc, mrPos);
+
+ SCROW nResultRows = resultRange.aEnd.Row() - resultRange.aStart.Row();
+ SCROW nSourceRows = sourceRange.aEnd.Row() - sourceRange.aStart.Row();
+ if (nResultRows != nSourceRows)
+ return true;
+
+ SCCOL nResultCols = resultRange.aEnd.Col() - resultRange.aStart.Col();
+ SCCOL nSourceCols = sourceRange.aEnd.Col() - sourceRange.aStart.Col();
+ if (nResultCols != nSourceCols)
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ bool DoIt(ScRangeList* pSuccessfulDependencies, ScAddress* pDirtiedAddress)
{
// Partially from ScGroupTokenConverter::convert in sc/source/core/data/grouptokenconverter.cxx
@@ -4460,6 +4507,21 @@ struct ScDependantsCalculator
return false;
}
+ if (p->GetOpCode() == ocLookup && LookupResultVectorMismatch(nTokenIdx))
+ {
+ SAL_INFO("sc.core.formulacell", "Lookup Result Vector size doesn't match Search Vector");
+ return false;
+ }
+
+ if (p->GetOpCode() == ocRange)
+ {
+ // We are just looking at svSingleRef/svDoubleRef, so we will miss that ocRange constructs
+ // a range from its arguments, and only examining the individual args doesn't capture the
+ // true range of dependencies
+ SAL_WARN("sc.core.formulacell", "dynamic range, dropping as candidate for parallelizing");
+ return false;
+ }
+
switch (p->GetType())
{
case svSingleRef:
@@ -4469,7 +4531,7 @@ struct ScDependantsCalculator
return false;
ScAddress aRefPos = aRef.toAbs(mrDoc, mrPos);
- if (!mrDoc.TableExists(aRefPos.Tab()))
+ if (!mrDoc.HasTable(aRefPos.Tab()))
return false; // or true?
if (aRef.IsRowRel())
@@ -4506,7 +4568,7 @@ struct ScDependantsCalculator
ScRange aAbs = aRef.toAbs(mrDoc, mrPos);
// Multiple sheet
- if (aRef.Ref1.Tab() != aRef.Ref2.Tab())
+ if (aAbs.aStart.Tab() != aAbs.aEnd.Tab())
return false;
bool bIsRef1RowRel = aRef.Ref1.IsRowRel();
@@ -4546,10 +4608,17 @@ struct ScDependantsCalculator
continue;
}
+ SCROW nFirstRefStartRow = bIsRef1RowRel ? aAbs.aStart.Row() + mnStartOffset : aAbs.aStart.Row();
+ SCROW nLastRefEndRow = bIsRef2RowRel ? aAbs.aEnd.Row() + mnEndOffset : aAbs.aEnd.Row();
+
+ SCROW nFirstRefEndRow = bIsRef1RowRel ? aAbs.aStart.Row() + mnEndOffset : aAbs.aStart.Row();
+ SCROW nLastRefStartRow = bIsRef2RowRel ? aAbs.aEnd.Row() + mnStartOffset : aAbs.aEnd.Row();
+
// The first row that will be referenced through the doubleref.
- SCROW nFirstRefRow = bIsRef1RowRel ? aAbs.aStart.Row() + mnStartOffset : aAbs.aStart.Row();
+ SCROW nFirstRefRow = std::min(nFirstRefStartRow, nLastRefStartRow);
// The last row that will be referenced through the doubleref.
- SCROW nLastRefRow = bIsRef2RowRel ? aAbs.aEnd.Row() + mnEndOffset : aAbs.aEnd.Row();
+ SCROW nLastRefRow = std::max(nLastRefEndRow, nFirstRefEndRow);
+
// Number of rows to be evaluated from nFirstRefRow.
SCROW nArrayLength = nLastRefRow - nFirstRefRow + 1;
assert(nArrayLength > 0);
@@ -4583,7 +4652,7 @@ struct ScDependantsCalculator
nStartRow = 0;
}
if (!mrDoc.HandleRefArrayForParallelism(ScAddress(nCol, nStartRow, rRange.aStart.Tab()),
- nLength, mxGroup))
+ nLength, mxGroup, pDirtiedAddress))
return false;
}
}
@@ -4591,6 +4660,9 @@ struct ScDependantsCalculator
if (bHasSelfReferences)
mxGroup->mbPartOfCycle = true;
+ if (pSuccessfulDependencies && !bHasSelfReferences)
+ *pSuccessfulDependencies = aRangeList;
+
return !bHasSelfReferences;
}
};
@@ -4613,7 +4685,8 @@ bool ScFormulaCell::InterpretFormulaGroup(SCROW nStartOffset, SCROW nEndOffset)
if (mxGroup->meCalcState == sc::GroupCalcDisabled)
{
- aScope.addMessage("group calc disabled");
+ static constexpr OUStringLiteral MESSAGE = u"group calc disabled";
+ aScope.addMessage(MESSAGE);
return false;
}
@@ -4651,15 +4724,6 @@ bool ScFormulaCell::InterpretFormulaGroup(SCROW nStartOffset, SCROW nEndOffset)
}
}
- // Guard against endless recursion of Interpret() calls, for this to work
- // ScFormulaCell::InterpretFormulaGroup() must never be called through
- // anything else than ScFormulaCell::Interpret(), same as
- // ScFormulaCell::InterpretTail()
- RecursionCounter aRecursionCounter( rRecursionHelper, this);
-
- bool bDependencyComputed = false;
- bool bDependencyCheckFailed = false;
-
// Get rid of -1's in offsets (defaults) or any invalid offsets.
SCROW nMaxOffset = mxGroup->mnLength - 1;
nStartOffset = nStartOffset < 0 ? 0 : std::min(nStartOffset, nMaxOffset);
@@ -4671,6 +4735,18 @@ bool ScFormulaCell::InterpretFormulaGroup(SCROW nStartOffset, SCROW nEndOffset)
nEndOffset = nMaxOffset;
}
+ if (nEndOffset == nStartOffset && forceType == ForceCalculationNone)
+ return false; // Do not use threads for a single row.
+
+ // Guard against endless recursion of Interpret() calls, for this to work
+ // ScFormulaCell::InterpretFormulaGroup() must never be called through
+ // anything else than ScFormulaCell::Interpret(), same as
+ // ScFormulaCell::InterpretTail()
+ RecursionCounter aRecursionCounter( rRecursionHelper, this);
+
+ bool bDependencyComputed = false;
+ bool bDependencyCheckFailed = false;
+
// Preference order: First try OpenCL, then threading.
// TODO: Do formula-group span computation for OCL too if nStartOffset/nEndOffset are non default.
if( InterpretFormulaGroupOpenCL(aScope, bDependencyComputed, bDependencyCheckFailed))
@@ -4684,7 +4760,9 @@ bool ScFormulaCell::InterpretFormulaGroup(SCROW nStartOffset, SCROW nEndOffset)
bool ScFormulaCell::CheckComputeDependencies(sc::FormulaLogger::GroupScope& rScope, bool fromFirstRow,
SCROW nStartOffset, SCROW nEndOffset,
- bool bCalcDependencyOnly)
+ bool bCalcDependencyOnly,
+ ScRangeList* pSuccessfulDependencies,
+ ScAddress* pDirtiedAddress)
{
ScRecursionHelper& rRecursionHelper = rDocument.GetRecursionHelper();
// iterate over code in the formula ...
@@ -4697,7 +4775,7 @@ bool ScFormulaCell::CheckComputeDependencies(sc::FormulaLogger::GroupScope& rSco
// (We can only reach here from a multi-group dependency evaluation attempt).
// (These two have to be in pairs always for any given formula-group)
ScDependantsCalculator aCalculator(rDocument, *pCode, *this, mxGroup->mpTopCell->aPos, fromFirstRow, nStartOffset, nEndOffset);
- return aCalculator.DoIt();
+ return aCalculator.DoIt(pSuccessfulDependencies, pDirtiedAddress);
}
bool bOKToParallelize = false;
@@ -4712,7 +4790,7 @@ bool ScFormulaCell::CheckComputeDependencies(sc::FormulaLogger::GroupScope& rSco
ScFormulaGroupDependencyComputeGuard aDepComputeGuard(rRecursionHelper);
ScDependantsCalculator aCalculator(rDocument, *pCode, *this, mxGroup->mpTopCell->aPos, fromFirstRow, nStartOffset, nEndOffset);
- bOKToParallelize = aCalculator.DoIt();
+ bOKToParallelize = aCalculator.DoIt(pSuccessfulDependencies, pDirtiedAddress);
}
@@ -4818,7 +4896,8 @@ bool ScFormulaCell::InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope
pCode->IsEnabledForThreading() &&
ScCalcConfig::isThreadingEnabled())
{
- if(!bDependencyComputed && !CheckComputeDependencies(aScope, false, nStartOffset, nEndOffset))
+ ScRangeList aOrigDependencies;
+ if(!bDependencyComputed && !CheckComputeDependencies(aScope, false, nStartOffset, nEndOffset, false, &aOrigDependencies))
{
bDependencyComputed = true;
bDependencyCheckFailed = true;
@@ -4827,8 +4906,6 @@ bool ScFormulaCell::InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope
bDependencyComputed = true;
- const static bool bHyperThreadingActive = cpuid::hasHyperThreading();
-
// Then do the threaded calculation
class Executor : public comphelper::ThreadTask
@@ -4882,9 +4959,6 @@ bool ScFormulaCell::InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope
comphelper::ThreadPool& rThreadPool(comphelper::ThreadPool::getSharedOptimalPool());
sal_Int32 nThreadCount = rThreadPool.getWorkerCount();
- if ( bHyperThreadingActive && nThreadCount >= 2 )
- nThreadCount /= 2;
-
SAL_INFO("sc.threaded", "Running " << nThreadCount << " threads");
o3tl::sorted_vector<ScFormulaCellGroup*> aFGSet;
@@ -4900,6 +4974,8 @@ bool ScFormulaCell::InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope
nColEnd = lcl_probeLeftOrRightFGs(mxGroup, rDocument, aFGSet, aFGMap, false);
}
+ bool bFGOK = true;
+ ScAddress aDirtiedAddress(ScAddress::INITIALIZE_INVALID);
if (nColStart != nColEnd)
{
ScCheckIndependentFGGuard aGuard(rRecursionHelper, &aFGSet);
@@ -4908,7 +4984,8 @@ bool ScFormulaCell::InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope
if (nCurrCol == aPos.Col())
continue;
- bool bFGOK = aFGMap[nCurrCol]->CheckComputeDependencies(aScope, false, nStartOffset, nEndOffset, true);
+ bFGOK = aFGMap[nCurrCol]->CheckComputeDependencies(aScope, false, nStartOffset, nEndOffset,
+ true, nullptr, &aDirtiedAddress);
if (!bFGOK || !aGuard.AreGroupsIndependent())
{
nColEnd = nColStart = aPos.Col();
@@ -4917,6 +4994,17 @@ bool ScFormulaCell::InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope
}
}
+ // tdf#156677 it is possible that if a check of a column in the new range fails that the check has
+ // now left a cell that the original range depended on in a Dirty state. So if the dirtied cell
+ // was part of the original dependencies re-run the initial CheckComputeDependencies to fix it.
+ if (!bFGOK && aDirtiedAddress.IsValid() && aOrigDependencies.Find(aDirtiedAddress))
+ {
+ SAL_WARN("sc.core.formulacell", "rechecking dependencies due to a dirtied cell during speculative probe");
+ const bool bRedoEntryCheckSucceeded = CheckComputeDependencies(aScope, false, nStartOffset, nEndOffset);
+ assert(bRedoEntryCheckSucceeded && "if it worked on the original range it should work again on that range");
+ (void)bRedoEntryCheckSucceeded;
+ }
+
std::vector<std::unique_ptr<ScInterpreter>> aInterpreters(nThreadCount);
{
assert(!rDocument.IsThreadedGroupCalcInProgress());
@@ -4924,6 +5012,13 @@ bool ScFormulaCell::InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope
ScMutationDisable aGuard(rDocument, ScMutationGuardFlags::CORE);
+ // Here we turn off ref-counting for the contents of pCode on the basis
+ // that pCode is not modified by interpreting and when interpreting is
+ // complete all token refcounts will be back to their initial ref count
+ FormulaToken** pArray = pCode->GetArray();
+ for (sal_uInt16 i = 0, n = pCode->GetLen(); i < n; ++i)
+ pArray[i]->SetRefCntPolicy(RefCntPolicy::None);
+
// Start nThreadCount new threads
std::shared_ptr<comphelper::ThreadTaskTag> aTag = comphelper::ThreadPool::createThreadTaskTag();
ScThreadedInterpreterContextGetterGuard aContextGetterGuard(nThreadCount, rDocument, pNonThreadedFormatter);
@@ -4945,6 +5040,13 @@ bool ScFormulaCell::InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope
// if they don't get joined from elsewhere before (via ThreadPool::waitUntilDone).
rThreadPool.waitUntilDone(aTag, false);
+ // Drop any caches that reference Tokens before restoring ref counting policy
+ for (int i = 0; i < nThreadCount; ++i)
+ aInterpreters[i]->DropTokenCaches();
+
+ for (sal_uInt16 i = 0, n = pCode->GetLen(); i < n; ++i)
+ pArray[i]->SetRefCntPolicy(RefCntPolicy::ThreadSafe);
+
rDocument.SetThreadedGroupCalcInProgress(false);
for (int i = 0; i < nThreadCount; ++i)
@@ -5236,11 +5338,11 @@ void startListeningArea(
{ // automagically
if ( rRef1.IsColRel() )
{ // ColName
- aCell2.SetRow(MAXROW);
+ aCell2.SetRow(rDoc.MaxRow());
}
else
{ // RowName
- aCell2.SetCol(MAXCOL);
+ aCell2.SetCol(rDoc.MaxCol());
}
}
rDoc.StartListeningArea(ScRange(aCell1, aCell2), false, pCell);
@@ -5348,11 +5450,11 @@ void endListeningArea(
{ // automagically
if ( rRef1.IsColRel() )
{ // ColName
- aCell2.SetRow(MAXROW);
+ aCell2.SetRow(rDoc.MaxRow());
}
else
{ // RowName
- aCell2.SetCol(MAXCOL);
+ aCell2.SetCol(rDoc.MaxCol());
}
}
@@ -5498,12 +5600,12 @@ sal_Int32 ScFormulaCell::GetWeight() const
ScTokenArray* ScFormulaCell::GetSharedCode()
{
- return mxGroup ? mxGroup->mpCode.get() : nullptr;
+ return mxGroup ? &*mxGroup->mpCode : nullptr;
}
const ScTokenArray* ScFormulaCell::GetSharedCode() const
{
- return mxGroup ? mxGroup->mpCode.get() : nullptr;
+ return mxGroup ? &*mxGroup->mpCode : nullptr;
}
void ScFormulaCell::SyncSharedCode()
@@ -5512,7 +5614,7 @@ void ScFormulaCell::SyncSharedCode()
// Not a shared formula cell.
return;
- pCode = mxGroup->mpCode.get();
+ pCode = &*mxGroup->mpCode;
}
#if DUMP_COLUMN_STORAGE
diff --git a/sc/source/core/data/funcdesc.cxx b/sc/source/core/data/funcdesc.cxx
index c7ea3cc5f927..b9cfb51ae9c1 100644
--- a/sc/source/core/data/funcdesc.cxx
+++ b/sc/source/core/data/funcdesc.cxx
@@ -49,7 +49,7 @@ struct ScFuncDescCore
/*
* Pointer to list of strings
*/
- const char** pResource;
+ const TranslateId* pResource;
/*
* Count of list of strings
*/
@@ -74,7 +74,7 @@ struct ScFuncDescCore
/*
* Help ID, HID_FUNC_...
*/
- const char* pHelpId;
+ OUString pHelpId;
/*
* Number of parameters. VAR_ARGS if variable number, or
* VAR_ARGS+number if number of fixed parameters and variable
@@ -161,8 +161,7 @@ OUString ScFuncDesc::GetParamList() const
aSig.append(maDefArgNames[i]);
if ( i != nArgCount-1 )
{
- aSig.append(sep);
- aSig.append( " " );
+ aSig.append(sep + " " );
}
}
// If only suppressed parameters follow the last added parameter,
@@ -175,46 +174,35 @@ OUString ScFuncDesc::GetParamList() const
{
for ( sal_uInt16 nArg = 0; nArg < nVarArgsStart; nArg++ )
{
- aSig.append(maDefArgNames[nArg]);
- aSig.append(sep);
- aSig.append( " " );
+ aSig.append(maDefArgNames[nArg] + sep + " ");
}
/* NOTE: Currently there are no suppressed var args parameters. If
* there were, we'd have to cope with it here and above for the fix
* parameters. For now parameters are always added, so no special
* treatment of a trailing "; " necessary. */
- aSig.append(maDefArgNames[nVarArgsStart]);
- aSig.append('1');
- aSig.append(sep);
- aSig.append(' ');
- aSig.append(maDefArgNames[nVarArgsStart]);
- aSig.append('2');
- aSig.append(sep);
- aSig.append(" ... ");
+ aSig.append(maDefArgNames[nVarArgsStart]
+ + "1"
+ + sep + " "
+ + maDefArgNames[nVarArgsStart]
+ + "2"
+ + sep + " ... ");
}
else
{
for ( sal_uInt16 nArg = 0; nArg < nVarArgsStart; nArg++ )
{
- aSig.append(maDefArgNames[nArg]);
- aSig.append(sep);
- aSig.append( " " );
+ aSig.append(maDefArgNames[nArg] + sep + " ");
}
- aSig.append(maDefArgNames[nVarArgsStart]);
- aSig.append('1');
- aSig.append(sep);
- aSig.append(maDefArgNames[nVarArgsStart+1]);
- aSig.append('1');
- aSig.append(sep);
- aSig.append( " " );
- aSig.append(maDefArgNames[nVarArgsStart]);
- aSig.append('2');
- aSig.append(sep);
- aSig.append(maDefArgNames[nVarArgsStart+1]);
- aSig.append('2');
- aSig.append(sep);
- aSig.append( " ... " );
+ aSig.append(maDefArgNames[nVarArgsStart]
+ + "1" + sep
+ + maDefArgNames[nVarArgsStart+1]
+ + "1" + sep
+ + " "
+ + maDefArgNames[nVarArgsStart]
+ + "2" + sep
+ + maDefArgNames[nVarArgsStart+1]
+ + "2" + sep + " ... " );
}
}
@@ -232,11 +220,9 @@ OUString ScFuncDesc::getSignature() const
OUString aParamList = GetParamList();
if( !aParamList.isEmpty() )
{
- aSig.append( "( " );
- aSig.append(aParamList);
+ aSig.append( "( " + aParamList
// U+00A0 (NBSP) prevents automatic line break
- aSig.append( u'\x00A0' );
- aSig.append( ")" );
+ + u"\x00A0" ")" );
}
else
aSig.append( "()" );
@@ -252,9 +238,7 @@ OUString ScFuncDesc::getFormula( const ::std::vector< OUString >& _aArguments )
if(mxFuncName)
{
- aFormula.append( *mxFuncName );
-
- aFormula.append( "(" );
+ aFormula.append( *mxFuncName + "(" );
if ( nArgCount > 0 && !_aArguments.empty() && !_aArguments[0].isEmpty())
{
::std::vector< OUString >::const_iterator aIter = _aArguments.begin();
@@ -264,8 +248,7 @@ OUString ScFuncDesc::getFormula( const ::std::vector< OUString >& _aArguments )
++aIter;
while( aIter != aEnd && !aIter->isEmpty() )
{
- aFormula.append( sep );
- aFormula.append( *aIter );
+ aFormula.append( sep + *aIter );
++aIter;
}
}
@@ -350,7 +333,7 @@ void ScFuncDesc::initArgumentInfo() const
}
}
-OString ScFuncDesc::getHelpId() const
+OUString ScFuncDesc::getHelpId() const
{
return sHelpId;
}
@@ -392,12 +375,13 @@ bool ScFuncDesc::isParameterOptional(sal_uInt32 _nPos) const
bool ScFuncDesc::compareByName(const ScFuncDesc* a, const ScFuncDesc* b)
{
- return (ScGlobal::GetCaseCollator()->compareString(*a->mxFuncName, *b->mxFuncName ) < 0);
+ return (ScGlobal::GetCaseCollator().compareString(*a->mxFuncName, *b->mxFuncName ) < 0);
}
#define ENTRY(CODE) CODE, SAL_N_ELEMENTS(CODE)
-ScFunctionList::ScFunctionList()
+ScFunctionList::ScFunctionList( bool bEnglishFunctionNames )
+ : mbEnglishFunctionNames( bEnglishFunctionNames )
{
sal_Int32 nMaxFuncNameLen = 0; // Length of longest function name
@@ -576,8 +560,8 @@ ScFunctionList::ScFunctionList()
{ SC_OPCODE_NOMINAL, ENTRY(SC_OPCODE_NOMINAL_ARY), 0, ID_FUNCTION_GRP_FINANCIAL, HID_FUNC_NOMINAL, 2, { 0, 0 }, 0 },
{ SC_OPCODE_SUB_TOTAL, ENTRY(SC_OPCODE_SUB_TOTAL_ARY), 0, ID_FUNCTION_GRP_MATH, HID_FUNC_TEILERGEBNIS, 2, { 0, 0 }, 0 },
{ SC_OPCODE_DB_SUM, ENTRY(SC_OPCODE_DB_SUM_ARY), 0, ID_FUNCTION_GRP_DATABASE, HID_FUNC_DBSUMME, 3, { 0, 0, 0 }, 0 },
- { SC_OPCODE_DB_COUNT, ENTRY(SC_OPCODE_DB_COUNT_ARY), 0, ID_FUNCTION_GRP_DATABASE, HID_FUNC_DBANZAHL, 3, { 0, 0, 0 }, 0 },
- { SC_OPCODE_DB_COUNT_2, ENTRY(SC_OPCODE_DB_COUNT_2_ARY), 0, ID_FUNCTION_GRP_DATABASE, HID_FUNC_DBANZAHL2, 3, { 0, 0, 0 }, 0 },
+ { SC_OPCODE_DB_COUNT, ENTRY(SC_OPCODE_DB_COUNT_ARY), 0, ID_FUNCTION_GRP_DATABASE, HID_FUNC_DBANZAHL, 3, { 0, 1, 0 }, 0 },
+ { SC_OPCODE_DB_COUNT_2, ENTRY(SC_OPCODE_DB_COUNT_2_ARY), 0, ID_FUNCTION_GRP_DATABASE, HID_FUNC_DBANZAHL2, 3, { 0, 1, 0 }, 0 },
{ SC_OPCODE_DB_AVERAGE, ENTRY(SC_OPCODE_DB_AVERAGE_ARY), 0, ID_FUNCTION_GRP_DATABASE, HID_FUNC_DBMITTELWERT, 3, { 0, 0, 0 }, 0 },
{ SC_OPCODE_DB_GET, ENTRY(SC_OPCODE_DB_GET_ARY), 0, ID_FUNCTION_GRP_DATABASE, HID_FUNC_DBAUSZUG, 3, { 0, 0, 0 }, 0 },
{ SC_OPCODE_DB_MAX, ENTRY(SC_OPCODE_DB_MAX_ARY), 0, ID_FUNCTION_GRP_DATABASE, HID_FUNC_DBMAX, 3, { 0, 0, 0 }, 0 },
@@ -601,7 +585,7 @@ ScFunctionList::ScFunctionList()
{ SC_OPCODE_AREAS, ENTRY(SC_OPCODE_AREAS_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_BEREICHE, 1, { 0 }, 0 },
{ SC_OPCODE_CURRENCY, ENTRY(SC_OPCODE_CURRENCY_ARY), 0, ID_FUNCTION_GRP_TEXT, HID_FUNC_DM, 2, { 0, 1 }, 0 },
{ SC_OPCODE_REPLACE, ENTRY(SC_OPCODE_REPLACE_ARY), 0, ID_FUNCTION_GRP_TEXT, HID_FUNC_ERSETZEN, 4, { 0, 0, 0, 0 }, 0 },
- { SC_OPCODE_FIXED, ENTRY(SC_OPCODE_FIXED_ARY), 0, ID_FUNCTION_GRP_TEXT, HID_FUNC_FEST, 3, { 0, 0, 1 }, 0 },
+ { SC_OPCODE_FIXED, ENTRY(SC_OPCODE_FIXED_ARY), 0, ID_FUNCTION_GRP_TEXT, HID_FUNC_FEST, 3, { 0, 1, 1 }, 0 },
{ SC_OPCODE_FIND, ENTRY(SC_OPCODE_FIND_ARY), 0, ID_FUNCTION_GRP_TEXT, HID_FUNC_FINDEN, 3, { 0, 0, 1 }, 0 },
{ SC_OPCODE_EXACT, ENTRY(SC_OPCODE_EXACT_ARY), 0, ID_FUNCTION_GRP_TEXT, HID_FUNC_IDENTISCH, 2, { 0, 0 }, 0 },
{ SC_OPCODE_LEFT, ENTRY(SC_OPCODE_LEFT_ARY), 0, ID_FUNCTION_GRP_TEXT, HID_FUNC_LINKS, 2, { 0, 1 }, 0 },
@@ -691,6 +675,8 @@ ScFunctionList::ScFunctionList()
{ SC_OPCODE_CELL, ENTRY(SC_OPCODE_CELL_ARY), 0, ID_FUNCTION_GRP_INFO, HID_FUNC_ZELLE, 2, { 0, 1 }, 0 },
{ SC_OPCODE_ISPMT, ENTRY(SC_OPCODE_ISPMT_ARY), 0, ID_FUNCTION_GRP_FINANCIAL, HID_FUNC_ISPMT, 4, { 0, 0, 0, 0 }, 0 },
{ SC_OPCODE_HYPERLINK, ENTRY(SC_OPCODE_HYPERLINK_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_HYPERLINK, 2, { 0, 1 }, 0 },
+ { SC_OPCODE_X_LOOKUP, ENTRY(SC_OPCODE_X_LOOKUP_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_XLOOKUP_MS, 6, { 0, 0, 0, 1, 1, 1 }, 0 },
+ { SC_OPCODE_X_MATCH, ENTRY(SC_OPCODE_X_MATCH_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_XMATCH_MS, 4, { 0, 0, 1, 1 }, 0 },
{ SC_OPCODE_GET_PIVOT_DATA, ENTRY(SC_OPCODE_GET_PIVOT_DATA_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_GETPIVOTDATA, VAR_ARGS+2, { 0, 0, 1 }, 0 },
{ SC_OPCODE_EUROCONVERT, ENTRY(SC_OPCODE_EUROCONVERT_ARY), 0, ID_FUNCTION_GRP_MATH, HID_FUNC_EUROCONVERT, 5, { 0, 0, 0, 1, 1 }, 0 },
{ SC_OPCODE_NUMBERVALUE, ENTRY(SC_OPCODE_NUMBERVALUE_ARY), 0, ID_FUNCTION_GRP_TEXT, HID_FUNC_NUMBERVALUE, 3, { 0, 1, 1 }, 0 },
@@ -738,7 +724,7 @@ ScFunctionList::ScFunctionList()
{ SC_OPCODE_F_TEST_MS, ENTRY(SC_OPCODE_F_TEST_MS_ARY), 0, ID_FUNCTION_GRP_STATISTIC, HID_FUNC_F_TEST_MS, 2, { 0, 0 }, 0 },
{ SC_OPCODE_EXP_DIST_MS, ENTRY(SC_OPCODE_EXP_DIST_MS_ARY), 0, ID_FUNCTION_GRP_STATISTIC, HID_FUNC_EXP_DIST_MS, 3, { 0, 0, 0 }, 0 },
{ SC_OPCODE_HYP_GEOM_DIST_MS, ENTRY(SC_OPCODE_HYP_GEOM_DIST_MS_ARY), 0, ID_FUNCTION_GRP_STATISTIC, HID_FUNC_HYP_GEOM_DIST_MS, 5, { 0, 0, 0, 0, 0 }, 0 },
- { SC_OPCODE_POISSON_DIST_MS, ENTRY(SC_OPCODE_POISSON_DIST_MS_ARY), 0, ID_FUNCTION_GRP_STATISTIC, HID_FUNC_POISSON_DIST_MS, 3, { 0, 0, 1 }, 0 },
+ { SC_OPCODE_POISSON_DIST_MS, ENTRY(SC_OPCODE_POISSON_DIST_MS_ARY), 0, ID_FUNCTION_GRP_STATISTIC, HID_FUNC_POISSON_DIST_MS, 3, { 0, 0, 0 }, 0 },
{ SC_OPCODE_WEIBULL_MS, ENTRY(SC_OPCODE_WEIBULL_MS_ARY), 0, ID_FUNCTION_GRP_STATISTIC, HID_FUNC_WEIBULL_DIST_MS, 4, { 0, 0, 0, 0 }, 0 },
{ SC_OPCODE_GAMMA_DIST_MS, ENTRY(SC_OPCODE_GAMMA_DIST_MS_ARY), 0, ID_FUNCTION_GRP_STATISTIC, HID_FUNC_GAMMADIST_MS, 4, { 0, 0, 0, 0 }, 0 },
{ SC_OPCODE_GAMMA_INV_MS, ENTRY(SC_OPCODE_GAMMA_INV_MS_ARY), 0, ID_FUNCTION_GRP_STATISTIC, HID_FUNC_GAMMAINV_MS, 3, { 0, 0, 0 }, 0 },
@@ -800,7 +786,11 @@ ScFunctionList::ScFunctionList()
{ SC_OPCODE_SEARCHB, ENTRY(SC_OPCODE_SEARCHB_ARY), 0, ID_FUNCTION_GRP_TEXT, HID_FUNC_SEARCHB, 3, { 0, 0, 1 }, 0 },
{ SC_OPCODE_REGEX, ENTRY(SC_OPCODE_REGEX_ARY), 0, ID_FUNCTION_GRP_TEXT, HID_FUNC_REGEX, 4, { 0, 0, 1, 1 }, 0 },
{ SC_OPCODE_FOURIER, ENTRY(SC_OPCODE_FOURIER_ARY), 0, ID_FUNCTION_GRP_MATRIX, HID_FUNC_FOURIER, 5, { 0, 0, 1, 1, 1 }, 0 },
- { SC_OPCODE_RANDBETWEEN_NV, ENTRY(SC_OPCODE_RANDBETWEEN_NV_ARY), 0, ID_FUNCTION_GRP_MATH, HID_FUNC_RANDBETWEEN_NV, 2, { 0, 0 }, 0 }
+ { SC_OPCODE_RANDBETWEEN_NV, ENTRY(SC_OPCODE_RANDBETWEEN_NV_ARY), 0, ID_FUNCTION_GRP_MATH, HID_FUNC_RANDBETWEEN_NV, 2, { 0, 0 }, 0 },
+ { SC_OPCODE_FILTER, ENTRY(SC_OPCODE_FILTER_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_FILTER_MS, 3, { 0, 0, 1 }, 0 },
+ { SC_OPCODE_SORT, ENTRY(SC_OPCODE_SORT_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_SORT_MS, 4, { 0, 1, 1, 1 }, 0 },
+ { SC_OPCODE_SORTBY, ENTRY(SC_OPCODE_SORTBY_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_SORTBY_MS, PAIRED_VAR_ARGS + 1, { 0, 0, 1 }, 0 },
+ { SC_OPCODE_MAT_SEQUENCE, ENTRY(SC_OPCODE_MAT_SEQUENCE_ARY), 0, ID_FUNCTION_GRP_MATRIX, HID_FUNC_MSEQUENCE_MS, 4, { 0, 1, 1, 1 }, 0 },
};
ScFuncDesc* pDesc = nullptr;
@@ -958,7 +948,7 @@ ScFunctionList::ScFunctionList()
pDesc = new ScFuncDesc;
pDesc->nFIndex = nNextId++;
- if ( pUnoAddIns->FillFunctionDesc( nFunc, *pDesc ) )
+ if ( pUnoAddIns->FillFunctionDesc( nFunc, *pDesc, mbEnglishFunctionNames ) )
{
tmpFuncVector.push_back(pDesc);
nStrLen = pDesc->mxFuncName->getLength();
@@ -1018,7 +1008,7 @@ const ScFuncDesc* ScFunctionList::GetFunction( sal_uInt32 nIndex ) const
sal_uInt32 ScFunctionCategory::getCount() const
{
- return m_pCategory->size();
+ return m_rCategory.size();
}
OUString ScFunctionCategory::getName() const
@@ -1031,8 +1021,8 @@ OUString ScFunctionCategory::getName() const
const formula::IFunctionDescription* ScFunctionCategory::getFunction(sal_uInt32 _nPos) const
{
const ScFuncDesc* pDesc = nullptr;
- if(_nPos < m_pCategory->size())
- pDesc = m_pCategory->at(_nPos);
+ if(_nPos < m_rCategory.size())
+ pDesc = m_rCategory.at(_nPos);
return pDesc;
}
@@ -1050,8 +1040,7 @@ ScFunctionMgr::ScFunctionMgr()
OSL_ENSURE( pFuncList, "Functionlist not found." );
sal_uInt32 catCount[MAX_FUNCCAT] = {0};
- aCatLists[0].reset( new ::std::vector<const ScFuncDesc*> );
- aCatLists[0]->reserve(pFuncList->GetCount());
+ aCatLists[0].reserve(pFuncList->GetCount());
// Retrieve all functions, store in cumulative ("All") category, and count
// number of functions in each category
@@ -1060,29 +1049,28 @@ ScFunctionMgr::ScFunctionMgr()
OSL_ENSURE((pDesc->nCategory) < MAX_FUNCCAT, "Unknown category");
if ((pDesc->nCategory) < MAX_FUNCCAT)
++catCount[pDesc->nCategory];
- aCatLists[0]->push_back(pDesc);
+ aCatLists[0].push_back(pDesc);
}
// Sort functions in cumulative category by name
- ::std::sort(aCatLists[0]->begin(), aCatLists[0]->end(), ScFuncDesc::compareByName);
+ ::std::sort(aCatLists[0].begin(), aCatLists[0].end(), ScFuncDesc::compareByName);
// Allocate correct amount of space for categories
for (sal_uInt16 i = 1; i < MAX_FUNCCAT; ++i)
{
- aCatLists[i].reset( new ::std::vector<const ScFuncDesc*> );
- aCatLists[i]->reserve(catCount[i]);
+ aCatLists[i].reserve(catCount[i]);
}
// Fill categories with the corresponding functions (still sorted by name)
- for (auto const& elemList : *aCatLists[0])
+ for (auto const& elemList : aCatLists[0])
{
if ((elemList->nCategory) < MAX_FUNCCAT)
- aCatLists[elemList->nCategory]->push_back(elemList);
+ aCatLists[elemList->nCategory].push_back(elemList);
}
// Initialize iterators
- pCurCatListIter = aCatLists[0]->end();
- pCurCatListEnd = aCatLists[0]->end();
+ pCurCatListIter = aCatLists[0].end();
+ pCurCatListEnd = aCatLists[0].end();
}
ScFunctionMgr::~ScFunctionMgr()
@@ -1105,14 +1093,14 @@ const ScFuncDesc* ScFunctionMgr::First( sal_uInt16 nCategory ) const
const ScFuncDesc* pDesc = nullptr;
if ( nCategory < MAX_FUNCCAT )
{
- pCurCatListIter = aCatLists[nCategory]->begin();
- pCurCatListEnd = aCatLists[nCategory]->end();
+ pCurCatListIter = aCatLists[nCategory].begin();
+ pCurCatListEnd = aCatLists[nCategory].end();
pDesc = *pCurCatListIter;
}
else
{
- pCurCatListIter = aCatLists[0]->end();
- pCurCatListEnd = aCatLists[0]->end();
+ pCurCatListIter = aCatLists[0].end();
+ pCurCatListEnd = aCatLists[0].end();
}
return pDesc;
}
@@ -1140,7 +1128,7 @@ const formula::IFunctionCategory* ScFunctionMgr::getCategory(sal_uInt32 nCategor
if ( nCategory < (MAX_FUNCCAT-1) )
{
if (m_aCategories.find(nCategory) == m_aCategories.end())
- m_aCategories[nCategory] = std::make_shared<ScFunctionCategory>(aCatLists[nCategory+1].get(),nCategory); // aCatLists[0] is "all"
+ m_aCategories[nCategory] = std::make_shared<ScFunctionCategory>(aCatLists[nCategory+1],nCategory); // aCatLists[0] is "all"
return m_aCategories[nCategory].get();
}
return nullptr;
diff --git a/sc/source/core/data/global.cxx b/sc/source/core/data/global.cxx
index 55415f1fdbd7..a46f46b3cffb 100644
--- a/sc/source/core/data/global.cxx
+++ b/sc/source/core/data/global.cxx
@@ -21,8 +21,10 @@
#include <svx/algitem.hxx>
#include <editeng/brushitem.hxx>
#include <editeng/editobj.hxx>
+#include <svl/itempool.hxx>
#include <svl/srchitem.hxx>
#include <editeng/langitem.hxx>
+#include <o3tl/string_view.hxx>
#include <o3tl/unit_conversion.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/dispatch.hxx>
@@ -31,6 +33,7 @@
#include <sfx2/viewfrm.hxx>
#include <sfx2/viewsh.hxx>
#include <svl/intitem.hxx>
+#include <svl/numformat.hxx>
#include <svl/stritem.hxx>
#include <svl/zforlist.hxx>
#include <svl/zformat.hxx>
@@ -70,8 +73,10 @@
#include <scmod.hxx>
#include <editutil.hxx>
#include <docsh.hxx>
+#include <sharedstringpoolpurge.hxx>
+#include <formulaopt.hxx>
-tools::SvRef<ScDocShell> ScGlobal::xDrawClipDocShellRef;
+rtl::Reference<ScDocShell> ScGlobal::xDrawClipDocShellRef;
std::unique_ptr<SvxSearchItem> ScGlobal::xSearchItem;
std::unique_ptr<ScAutoFormat> ScGlobal::xAutoFormat;
std::atomic<LegacyFuncCollection*> ScGlobal::pLegacyFuncCollection(nullptr);
@@ -79,14 +84,13 @@ std::atomic<ScUnoAddInCollection*> ScGlobal::pAddInCollection(nullptr);
std::unique_ptr<ScUserList> ScGlobal::xUserList;
LanguageType ScGlobal::eLnge = LANGUAGE_SYSTEM;
std::atomic<css::lang::Locale*> ScGlobal::pLocale(nullptr);
-std::unique_ptr<SvtSysLocale> ScGlobal::xSysLocale;
-std::unique_ptr<CalendarWrapper> ScGlobal::xCalendar;
+std::optional<SvtSysLocale> ScGlobal::oSysLocale;
+std::optional<CalendarWrapper> ScGlobal::oCalendar;
std::atomic<CollatorWrapper*> ScGlobal::pCollator(nullptr);
std::atomic<CollatorWrapper*> ScGlobal::pCaseCollator(nullptr);
std::atomic<::utl::TransliterationWrapper*> ScGlobal::pTransliteration(nullptr);
std::atomic<::utl::TransliterationWrapper*> ScGlobal::pCaseTransliteration(nullptr);
css::uno::Reference< css::i18n::XOrdinalSuffix> ScGlobal::xOrdinalSuffix;
-const OUString ScGlobal::aEmptyOUString;
OUString ScGlobal::aStrClipDocName;
std::unique_ptr<SvxBrushItem> ScGlobal::xEmptyBrushItem;
@@ -98,6 +102,7 @@ std::unique_ptr<ScFunctionMgr> ScGlobal::xStarCalcFunctionMgr;
std::atomic<ScUnitConverter*> ScGlobal::pUnitConverter(nullptr);
std::unique_ptr<SvNumberFormatter> ScGlobal::xEnglishFormatter;
std::unique_ptr<ScFieldEditEngine> ScGlobal::xFieldEditEngine;
+std::atomic<sc::SharedStringPoolPurge*> ScGlobal::pSharedStringPoolPurge;
double ScGlobal::nScreenPPTX = 96.0;
double ScGlobal::nScreenPPTY = 96.0;
@@ -114,6 +119,9 @@ sal_uInt16 nScFillModeMouseModifier = 0; //FIXME: And this
bool ScGlobal::bThreadedGroupCalcInProgress = false;
+InputHandlerFunctionNames ScGlobal::maInputHandlerFunctionNames;
+
+
// Static functions
bool ScGlobal::HasAttrChanged( const SfxItemSet& rNewAttrs,
@@ -131,17 +139,17 @@ bool ScGlobal::HasAttrChanged( const SfxItemSet& rNewAttrs,
// Both Items set
// PoolItems, meaning comparing pointers is valid
if ( SfxItemState::SET == eOldState )
- bInvalidate = (pNewItem != pOldItem);
+ bInvalidate = !SfxPoolItem::areSame(pNewItem, pOldItem);
}
else
{
// Contains a Default Item
// PoolItems, meaning Item comparison necessary
if (!pOldItem)
- pOldItem = &rOldAttrs.GetPool()->GetDefaultItem( nWhich );
+ pOldItem = &rOldAttrs.GetPool()->GetUserOrPoolDefaultItem( nWhich );
if (!pNewItem)
- pNewItem = &rNewAttrs.GetPool()->GetDefaultItem( nWhich );
+ pNewItem = &rNewAttrs.GetPool()->GetUserOrPoolDefaultItem( nWhich );
bInvalidate = (*pNewItem != *pOldItem);
}
@@ -149,13 +157,12 @@ bool ScGlobal::HasAttrChanged( const SfxItemSet& rNewAttrs,
return bInvalidate;
}
-sal_uInt32 ScGlobal::GetStandardFormat( SvNumberFormatter& rFormatter,
+sal_uInt32 ScGlobal::GetStandardFormat( ScInterpreterContext& rContext,
sal_uInt32 nFormat, SvNumFormatType nType )
{
- const SvNumberformat* pFormat = rFormatter.GetEntry( nFormat );
- if ( pFormat )
- return rFormatter.GetStandardFormat( nFormat, nType, pFormat->GetLanguage() );
- return rFormatter.GetStandardFormat( nType, eLnge );
+ if (const SvNumberformat* pFormat = rContext.NFGetFormatEntry(nFormat))
+ return rContext.NFGetStandardFormat( nFormat, nType, pFormat->GetLanguage() );
+ return rContext.NFGetStandardFormat( nType, eLnge );
}
sal_uInt16 ScGlobal::GetStandardRowHeight()
@@ -179,6 +186,20 @@ bool ScGlobal::CheckWidthInvalidate( bool& bNumFormatChanged,
const SfxItemSet& rNewAttrs,
const SfxItemSet& rOldAttrs )
{
+ // Here ScPatternAttr::FastEqualPatternSets was used before. This implies that
+ // the two given SfxItemSet are internal ones from ScPatternAttr, but there is
+ // no guarantee here for that. Also that former method contained the comment
+ // "Actually test_tdf133629 from UITest_calc_tests9 somehow manages to have
+ // a different range (and I don't understand enough why), so better be safe and compare fully."
+ // which may be based on this usage. I check for that already in
+ // ScPatternAttr::operator==, seems not to be triggered there.
+ // All in all: Better use SfxItemSet::operator== here, and not one specialized
+ // on the SfxItemSets of ScPatternAttr
+ if (rNewAttrs == rOldAttrs)
+ {
+ bNumFormatChanged = false;
+ return false;
+ }
// Check whether attribute changes in rNewAttrs compared to rOldAttrs render
// the text width at a cell invalid
bNumFormatChanged =
@@ -300,7 +321,7 @@ void ScGlobal::SetUserList( const ScUserList* pNewList )
OUString ScGlobal::GetErrorString(FormulaError nErr)
{
- const char* pErrNumber;
+ TranslateId pErrNumber;
switch (nErr)
{
case FormulaError::NoRef:
@@ -332,7 +353,7 @@ OUString ScGlobal::GetErrorString(FormulaError nErr)
OUString ScGlobal::GetLongErrorString(FormulaError nErr)
{
- const char* pErrNumber;
+ TranslateId pErrNumber;
switch (nErr)
{
case FormulaError::NONE:
@@ -377,9 +398,11 @@ OUString ScGlobal::GetLongErrorString(FormulaError nErr)
case FormulaError::UnknownOpCode:
case FormulaError::UnknownStackVariable:
case FormulaError::UnknownToken:
- case FormulaError::NoCode:
pErrNumber = STR_LONG_ERR_SYNTAX;
break;
+ case FormulaError::NoCode:
+ pErrNumber = STR_LONG_ERR_NO_CODE;
+ break;
case FormulaError::CircularReference:
pErrNumber = STR_LONG_ERR_CIRC_REF;
break;
@@ -436,7 +459,7 @@ void ScGlobal::Init()
// FIXME: So remove this variable?
eLnge = LANGUAGE_SYSTEM;
- xSysLocale = std::make_unique<SvtSysLocale>();
+ oSysLocale.emplace();
xEmptyBrushItem = std::make_unique<SvxBrushItem>( COL_TRANSPARENT, ATTR_BACKGROUND );
xButtonBrushItem = std::make_unique<SvxBrushItem>( Color(), ATTR_BACKGROUND );
@@ -486,21 +509,19 @@ void ScGlobal::SetClipDocName( const OUString& rNew )
aStrClipDocName = rNew;
}
-void ScGlobal::InitTextHeight(const SfxItemPool* pPool)
+void ScGlobal::InitTextHeight(SfxItemPool& rPool)
{
- if (!pPool)
- {
- OSL_FAIL("ScGlobal::InitTextHeight: No Pool");
- return;
- }
-
- const ScPatternAttr& rPattern = pPool->GetDefaultItem(ATTR_PATTERN);
+ // this gets handed over the m_pMessagePool in ScModule::ScModule, so
+ // the previously used item ScPatternAttr is unchanged. This allows to
+ // just use an temporary incarnation of a CellAttributeHelper here
+ const CellAttributeHelper aTempHelper(rPool);
+ const ScPatternAttr& rDefaultCellAttribute(aTempHelper.getDefaultCellAttribute());
OutputDevice* pDefaultDev = Application::GetDefaultDevice();
ScopedVclPtrInstance< VirtualDevice > pVirtWindow( *pDefaultDev );
pVirtWindow->SetMapMode(MapMode(MapUnit::MapPixel));
vcl::Font aDefFont;
- rPattern.GetFont(aDefFont, SC_AUTOCOL_BLACK, pVirtWindow); // Font color doesn't matter here
+ rDefaultCellAttribute.fillFontOnly(aDefFont, pVirtWindow); // Font color doesn't matter here
pVirtWindow->SetFont(aDefFont);
sal_uInt16 nTest = static_cast<sal_uInt16>(
pVirtWindow->PixelToLogic(Size(0, pVirtWindow->GetTextHeight()), MapMode(MapUnit::MapTwip)).Height());
@@ -508,7 +529,7 @@ void ScGlobal::InitTextHeight(const SfxItemPool* pPool)
if (nTest > nDefFontHeight)
nDefFontHeight = nTest;
- const SvxMarginItem& rMargin = rPattern.GetItem(ATTR_MARGIN);
+ const SvxMarginItem& rMargin(rDefaultCellAttribute.GetItem(ATTR_MARGIN));
nTest = static_cast<sal_uInt16>(nDefFontHeight + rMargin.GetTopMargin()
+ rMargin.GetBottomMargin() - STD_ROWHEIGHT_DIFF);
@@ -524,8 +545,8 @@ void ScGlobal::Clear()
ExitExternalFunc();
ClearAutoFormat();
xSearchItem.reset();
- delete pLegacyFuncCollection.load(); pLegacyFuncCollection = nullptr;
- delete pAddInCollection.load(); pAddInCollection = nullptr;
+ delete pLegacyFuncCollection.exchange(nullptr);
+ delete pAddInCollection.exchange(nullptr);
xUserList.reset();
xStarCalcFunctionList.reset(); // Destroy before ResMgr!
xStarCalcFunctionMgr.reset();
@@ -536,45 +557,46 @@ void ScGlobal::Clear()
xEmptyBrushItem.reset();
xButtonBrushItem.reset();
xEnglishFormatter.reset();
- delete pCaseTransliteration.load(); pCaseTransliteration = nullptr;
- delete pTransliteration.load(); pTransliteration = nullptr;
- delete pCaseCollator.load(); pCaseCollator = nullptr;
- delete pCollator.load(); pCollator = nullptr;
- xCalendar.reset();
- xSysLocale.reset();
- delete pLocale.load(); pLocale = nullptr;
-
- delete pUnitConverter.load(); pUnitConverter = nullptr;
+ delete pCaseTransliteration.exchange(nullptr);
+ delete pTransliteration.exchange(nullptr);
+ delete pCaseCollator.exchange(nullptr);
+ delete pCollator.exchange(nullptr);
+ oCalendar.reset();
+ oSysLocale.reset();
+ delete pLocale.exchange(nullptr);
+
+ delete pUnitConverter.exchange(nullptr);
xFieldEditEngine.reset();
+ delete pSharedStringPoolPurge.exchange(nullptr);
xDrawClipDocShellRef.clear();
}
-rtl_TextEncoding ScGlobal::GetCharsetValue( const OUString& rCharSet )
+rtl_TextEncoding ScGlobal::GetCharsetValue( std::u16string_view rCharSet )
{
// new TextEncoding values
if ( CharClass::isAsciiNumeric( rCharSet ) )
{
- sal_Int32 nVal = rCharSet.toInt32();
+ sal_Int32 nVal = o3tl::toInt32(rCharSet);
if ( nVal == RTL_TEXTENCODING_DONTKNOW )
return osl_getThreadTextEncoding();
return static_cast<rtl_TextEncoding>(nVal);
}
// old CharSet values for compatibility
- else if (rCharSet.equalsIgnoreAsciiCase("ANSI") ) return RTL_TEXTENCODING_MS_1252;
- else if (rCharSet.equalsIgnoreAsciiCase("MAC") ) return RTL_TEXTENCODING_APPLE_ROMAN;
- else if (rCharSet.equalsIgnoreAsciiCase("IBMPC") ) return RTL_TEXTENCODING_IBM_850;
- else if (rCharSet.equalsIgnoreAsciiCase("IBMPC_437")) return RTL_TEXTENCODING_IBM_437;
- else if (rCharSet.equalsIgnoreAsciiCase("IBMPC_850")) return RTL_TEXTENCODING_IBM_850;
- else if (rCharSet.equalsIgnoreAsciiCase("IBMPC_860")) return RTL_TEXTENCODING_IBM_860;
- else if (rCharSet.equalsIgnoreAsciiCase("IBMPC_861")) return RTL_TEXTENCODING_IBM_861;
- else if (rCharSet.equalsIgnoreAsciiCase("IBMPC_863")) return RTL_TEXTENCODING_IBM_863;
- else if (rCharSet.equalsIgnoreAsciiCase("IBMPC_865")) return RTL_TEXTENCODING_IBM_865;
+ else if (o3tl::equalsIgnoreAsciiCase(rCharSet, u"ANSI") ) return RTL_TEXTENCODING_MS_1252;
+ else if (o3tl::equalsIgnoreAsciiCase(rCharSet, u"MAC") ) return RTL_TEXTENCODING_APPLE_ROMAN;
+ else if (o3tl::equalsIgnoreAsciiCase(rCharSet, u"IBMPC") ) return RTL_TEXTENCODING_IBM_850;
+ else if (o3tl::equalsIgnoreAsciiCase(rCharSet, u"IBMPC_437")) return RTL_TEXTENCODING_IBM_437;
+ else if (o3tl::equalsIgnoreAsciiCase(rCharSet, u"IBMPC_850")) return RTL_TEXTENCODING_IBM_850;
+ else if (o3tl::equalsIgnoreAsciiCase(rCharSet, u"IBMPC_860")) return RTL_TEXTENCODING_IBM_860;
+ else if (o3tl::equalsIgnoreAsciiCase(rCharSet, u"IBMPC_861")) return RTL_TEXTENCODING_IBM_861;
+ else if (o3tl::equalsIgnoreAsciiCase(rCharSet, u"IBMPC_863")) return RTL_TEXTENCODING_IBM_863;
+ else if (o3tl::equalsIgnoreAsciiCase(rCharSet, u"IBMPC_865")) return RTL_TEXTENCODING_IBM_865;
// Some wrong "help" on the net mentions UTF8 and even unoconv uses it,
// which worked accidentally if the system encoding is UTF-8 anyway, so
// support it ;) but only when reading.
- else if (rCharSet.equalsIgnoreAsciiCase("UTF8")) return RTL_TEXTENCODING_UTF8;
- else if (rCharSet.equalsIgnoreAsciiCase("UTF-8")) return RTL_TEXTENCODING_UTF8;
+ else if (o3tl::equalsIgnoreAsciiCase(rCharSet, u"UTF8")) return RTL_TEXTENCODING_UTF8;
+ else if (o3tl::equalsIgnoreAsciiCase(rCharSet, u"UTF-8")) return RTL_TEXTENCODING_UTF8;
else return osl_getThreadTextEncoding();
}
@@ -610,7 +632,7 @@ ScFunctionList* ScGlobal::GetStarCalcFunctionList()
{
assert(!bThreadedGroupCalcInProgress);
if ( !xStarCalcFunctionList )
- xStarCalcFunctionList.reset(new ScFunctionList);
+ xStarCalcFunctionList.reset( new ScFunctionList( SC_MOD()->GetFormulaOptions().GetUseEnglishFuncName()));
return xStarCalcFunctionList.get();
}
@@ -629,6 +651,40 @@ void ScGlobal::ResetFunctionList()
// FunctionMgr has pointers into FunctionList, must also be updated
xStarCalcFunctionMgr.reset();
xStarCalcFunctionList.reset();
+ // Building new names also needs InputHandler data to be refreshed.
+ maInputHandlerFunctionNames = InputHandlerFunctionNames();
+}
+
+const InputHandlerFunctionNames& ScGlobal::GetInputHandlerFunctionNames()
+{
+ if (maInputHandlerFunctionNames.maFunctionData.empty())
+ {
+ const OUString aParenthesesReplacement( cParenthesesReplacement);
+ const ScFunctionList* pFuncList = GetStarCalcFunctionList();
+ const sal_uInt32 nListCount = pFuncList->GetCount();
+ const CharClass* pCharClass = (pFuncList->IsEnglishFunctionNames()
+ ? ScCompiler::GetCharClassEnglish()
+ : ScCompiler::GetCharClassLocalized());
+ for (sal_uInt32 i=0; i < nListCount; ++i)
+ {
+ const ScFuncDesc* pDesc = pFuncList->GetFunction( i );
+ if ( pDesc->mxFuncName )
+ {
+ OUString aFuncName(pCharClass->uppercase(*(pDesc->mxFuncName)));
+ // fdo#75264 fill maFormulaChar with all characters used in formula names
+ for (sal_Int32 j = 0; j < aFuncName.getLength(); j++)
+ maInputHandlerFunctionNames.maFunctionChar.insert(aFuncName[j]);
+ maInputHandlerFunctionNames.maFunctionData.insert(
+ ScTypedStrData(*(pDesc->mxFuncName) + aParenthesesReplacement, 0.0, 0.0,
+ ScTypedStrData::Standard));
+ pDesc->initArgumentInfo();
+ OUString aEntry = pDesc->getSignature();
+ maInputHandlerFunctionNames.maFunctionDataPara.insert(
+ ScTypedStrData(aEntry, 0.0, 0.0, ScTypedStrData::Standard));
+ }
+ }
+ }
+ return maInputHandlerFunctionNames;
}
ScUnitConverter* ScGlobal::GetUnitConverter()
@@ -651,19 +707,19 @@ const sal_Unicode* ScGlobal::UnicodeStrChr( const sal_Unicode* pStr,
return nullptr;
}
-OUString ScGlobal::addToken(const OUString& rTokenList, std::u16string_view rToken,
+OUString ScGlobal::addToken(std::u16string_view rTokenList, std::u16string_view rToken,
sal_Unicode cSep, sal_Int32 nSepCount, bool bForceSep)
{
OUStringBuffer aBuf(rTokenList);
- if( bForceSep || (!rToken.empty() && !rTokenList.isEmpty()) )
+ if( bForceSep || (!rToken.empty() && !rTokenList.empty()) )
comphelper::string::padToLength(aBuf, aBuf.getLength() + nSepCount, cSep);
aBuf.append(rToken);
return aBuf.makeStringAndClear();
}
-bool ScGlobal::IsQuoted( const OUString& rString, sal_Unicode cQuote )
+bool ScGlobal::IsQuoted( std::u16string_view rString, sal_Unicode cQuote )
{
- return (rString.getLength() >= 2) && (rString[0] == cQuote) && (rString[ rString.getLength() - 1 ] == cQuote);
+ return (rString.size() >= 2) && (rString[0] == cQuote) && (rString[ rString.size() - 1 ] == cQuote);
}
void ScGlobal::AddQuotes( OUString& rString, sal_Unicode cQuote, bool bEscapeEmbedded )
@@ -761,7 +817,8 @@ void ScGlobal::OpenURL(const OUString& rURL, const OUString& rTarget, bool bIgno
// OpenURL is always called in the GridWindow by mouse clicks in some way or another.
// That's why pScActiveViewShell and nScClickMouseModifier are correct.
- if (!bIgnoreSettings && !ShouldOpenURL())
+ // Fragments pointing into the current document should be always opened.
+ if (!bIgnoreSettings && !(ShouldOpenURL() || rURL.startsWith("#")))
return;
SfxViewFrame* pViewFrm = SfxViewFrame::Current();
@@ -770,11 +827,11 @@ void ScGlobal::OpenURL(const OUString& rURL, const OUString& rTarget, bool bIgno
OUString aUrlName( rURL );
SfxViewFrame* pFrame = nullptr;
- const SfxObjectShell* pObjShell = nullptr;
+ SfxObjectShell* pObjShell = nullptr;
OUString aReferName;
if ( pScActiveViewShell )
{
- pFrame = pScActiveViewShell->GetViewFrame();
+ pFrame = &pScActiveViewShell->GetViewFrame();
pObjShell = pFrame->GetObjectShell();
const SfxMedium* pMed = pObjShell->GetMedium();
if (pMed)
@@ -804,6 +861,9 @@ void ScGlobal::OpenURL(const OUString& rURL, const OUString& rTarget, bool bIgno
aUrlName = aNewUrlName;
}
+ if (!SfxObjectShell::AllowedLinkProtocolFromDocument(aUrlName, pObjShell, pFrame ? pFrame->GetFrameWeld() : nullptr))
+ return;
+
SfxStringItem aUrl( SID_FILE_NAME, aUrlName );
SfxStringItem aTarget( SID_TARGETNAME, rTarget );
if ( nScClickMouseModifier & KEY_SHIFT ) // control-click -> into new window
@@ -823,9 +883,8 @@ void ScGlobal::OpenURL(const OUString& rURL, const OUString& rTarget, bool bIgno
bool ScGlobal::ShouldOpenURL()
{
- SvtSecurityOptions aSecOpt;
bool bCtrlClickHappened = (nScClickMouseModifier & KEY_MOD1);
- bool bCtrlClickSecOption = aSecOpt.IsOptionSet( SvtSecurityOptions::EOption::CtrlClickHyperlink );
+ bool bCtrlClickSecOption = SvtSecurityOptions::IsOptionSet( SvtSecurityOptions::EOption::CtrlClickHyperlink );
if( bCtrlClickHappened && ! bCtrlClickSecOption )
{
// return since ctrl+click happened when the
@@ -954,12 +1013,12 @@ void ScGlobal::AddLanguage( SfxItemSet& rSet, const SvNumberFormatter& rFormatte
OSL_ENSURE( rSet.GetItemState( ATTR_LANGUAGE_FORMAT, false ) == SfxItemState::DEFAULT,
"ScGlobal::AddLanguage - language already added");
- const SfxPoolItem* pHardItem;
- if ( rSet.GetItemState( ATTR_VALUE_FORMAT, false, &pHardItem ) != SfxItemState::SET )
+ const SfxUInt32Item* pHardItem = rSet.GetItemIfSet( ATTR_VALUE_FORMAT, false );
+ if ( !pHardItem )
return;
const SvNumberformat* pHardFormat = rFormatter.GetEntry(
- static_cast<const SfxUInt32Item*>(pHardItem)->GetValue() );
+ pHardItem->GetValue() );
sal_uInt32 nParentFmt = 0; // Pool default
const SfxItemSet* pParent = rSet.GetParent();
@@ -972,9 +1031,9 @@ void ScGlobal::AddLanguage( SfxItemSet& rSet, const SvNumberFormatter& rFormatte
rSet.Put( SvxLanguageItem( pHardFormat->GetLanguage(), ATTR_LANGUAGE_FORMAT ) );
}
-utl::TransliterationWrapper* ScGlobal::GetpTransliteration()
+utl::TransliterationWrapper& ScGlobal::GetTransliteration()
{
- return comphelper::doubleCheckedInit( pTransliteration,
+ return *comphelper::doubleCheckedInit( pTransliteration,
[]()
{
const LanguageType eOfficeLanguage = Application::GetSettings().GetLanguageTag().getLanguageType();
@@ -984,9 +1043,9 @@ utl::TransliterationWrapper* ScGlobal::GetpTransliteration()
return p;
});
}
-::utl::TransliterationWrapper* ScGlobal::GetCaseTransliteration()
+::utl::TransliterationWrapper& ScGlobal::GetCaseTransliteration()
{
- return comphelper::doubleCheckedInit( pCaseTransliteration,
+ return *comphelper::doubleCheckedInit( pCaseTransliteration,
[]()
{
const LanguageType eOfficeLanguage = Application::GetSettings().GetLanguageTag().getLanguageType();
@@ -996,58 +1055,80 @@ utl::TransliterationWrapper* ScGlobal::GetpTransliteration()
return p;
});
}
+utl::TransliterationWrapper& ScGlobal::GetTransliteration(bool bCaseSensitive)
+{
+ return bCaseSensitive ? GetCaseTransliteration() : GetTransliteration();
+}
-const LocaleDataWrapper* ScGlobal::getLocaleDataPtr()
+const LocaleDataWrapper& ScGlobal::getLocaleData()
{
OSL_ENSURE(
- xSysLocale,
+ oSysLocale,
"ScGlobal::getLocaleDataPtr() called before ScGlobal::Init()");
- return &xSysLocale->GetLocaleData();
+ return oSysLocale->GetLocaleData();
}
-const CharClass* ScGlobal::getCharClassPtr()
+const CharClass& ScGlobal::getCharClass()
{
OSL_ENSURE(
- xSysLocale,
+ oSysLocale,
"ScGlobal::getCharClassPtr() called before ScGlobal::Init()");
- return xSysLocale->GetCharClassPtr();
+ return oSysLocale->GetCharClass();
}
-CalendarWrapper* ScGlobal::GetCalendar()
+CalendarWrapper& ScGlobal::GetCalendar()
{
assert(!bThreadedGroupCalcInProgress);
- if ( !xCalendar )
+ if ( !oCalendar )
{
- xCalendar.reset( new CalendarWrapper( ::comphelper::getProcessComponentContext() ) );
- xCalendar->loadDefaultCalendar( *GetLocale() );
+ oCalendar.emplace( ::comphelper::getProcessComponentContext() );
+ oCalendar->loadDefaultCalendar( GetLocale() );
}
- return xCalendar.get();
+ return *oCalendar;
}
-CollatorWrapper* ScGlobal::GetCollator()
+
+namespace {
+
+struct GetMutex {
+ osl::Mutex * operator ()() {
+ static osl::Mutex m;
+ return &m;
+ }
+};
+
+}
+
+CollatorWrapper& ScGlobal::GetCollator()
{
- return comphelper::doubleCheckedInit( pCollator,
+ return *comphelper::doubleCheckedInit( pCollator,
[]()
{
CollatorWrapper* p = new CollatorWrapper( ::comphelper::getProcessComponentContext() );
- p->loadDefaultCollator( *GetLocale(), SC_COLLATOR_IGNORES );
+ p->loadDefaultCollator( GetLocale(), SC_COLLATOR_IGNORES );
return p;
- });
+ },
+ GetMutex());
}
-CollatorWrapper* ScGlobal::GetCaseCollator()
+CollatorWrapper& ScGlobal::GetCaseCollator()
{
- return comphelper::doubleCheckedInit( pCaseCollator,
+ return *comphelper::doubleCheckedInit( pCaseCollator,
[]()
{
CollatorWrapper* p = new CollatorWrapper( ::comphelper::getProcessComponentContext() );
- p->loadDefaultCollator( *GetLocale(), 0 );
+ p->loadDefaultCollator( GetLocale(), 0 );
return p;
- });
+ },
+ GetMutex());
}
-css::lang::Locale* ScGlobal::GetLocale()
+CollatorWrapper& ScGlobal::GetCollator(bool bCaseSensitive)
{
- return comphelper::doubleCheckedInit( pLocale,
+ return bCaseSensitive ? GetCaseCollator() : GetCollator();
+}
+css::lang::Locale& ScGlobal::GetLocale()
+{
+ return *comphelper::doubleCheckedInit( pLocale,
[]() { return new css::lang::Locale( Application::GetSettings().GetLanguageTag().getLocale()); });
}
@@ -1065,6 +1146,12 @@ ScFieldEditEngine& ScGlobal::GetStaticFieldEditEngine()
return *xFieldEditEngine;
}
+sc::SharedStringPoolPurge& ScGlobal::GetSharedStringPoolPurge()
+{
+ return *comphelper::doubleCheckedInit( pSharedStringPoolPurge,
+ []() { return new sc::SharedStringPoolPurge; });
+}
+
OUString ScGlobal::ReplaceOrAppend( const OUString& rString,
std::u16string_view rPlaceholder, const OUString& rReplacement )
{
diff --git a/sc/source/core/data/global2.cxx b/sc/source/core/data/global2.cxx
index 87c13da7a616..4a9237a38f9f 100644
--- a/sc/source/core/data/global2.cxx
+++ b/sc/source/core/data/global2.cxx
@@ -19,19 +19,23 @@
#include <sfx2/docfile.hxx>
#include <sfx2/objsh.hxx>
-#include <unotools/configmgr.hxx>
+#include <comphelper/configuration.hxx>
#include <unotools/pathoptions.hxx>
#include <tools/urlobj.hxx>
+#include <svl/numformat.hxx>
#include <svl/zforlist.hxx>
#include <formula/errorcodes.hxx>
#include <sal/log.hxx>
#include <rtl/character.hxx>
+#include <rtl/math.hxx>
+#include <o3tl/string_view.hxx>
#include <global.hxx>
#include <rangeutl.hxx>
#include <compiler.hxx>
#include <paramisc.hxx>
#include <calcconfig.hxx>
+#include <interpretercontext.hxx>
// struct ScImportParam:
@@ -288,13 +292,13 @@ OUString ScGlobal::GetAbsDocName( const OUString& rFileName,
if (!pShell || !pShell->HasName())
{ // maybe relative to document path working directory
INetURLObject aObj;
- if (!utl::ConfigManager::IsFuzzing())
+ if (!comphelper::IsFuzzing())
{
aObj.SetSmartURL(SvtPathOptions().GetWorkPath());
aObj.setFinalSlash(); // it IS a path
}
else
- aObj.SetSmartURL("file:///tmp/document");
+ aObj.SetSmartURL(u"file:///tmp/document");
bool bWasAbs = true;
aAbsName = aObj.smartRel2Abs( rFileName, bWasAbs ).GetMainURL(INetURLObject::DecodeMechanism::NONE);
// returned string must be encoded because it's used directly to create SfxMedium
@@ -321,15 +325,9 @@ OUString ScGlobal::GetAbsDocName( const OUString& rFileName,
OUString ScGlobal::GetDocTabName( std::u16string_view rFileName,
std::u16string_view rTabName )
{
- OUString aDocTab = OUString::Concat("'") + rFileName;
- sal_Int32 nPos = 1;
- while( (nPos = aDocTab.indexOf( '\'', nPos )) != -1 )
- { // escape Quotes
- aDocTab = aDocTab.replaceAt( nPos, 0, "\\" );
- nPos += 2;
- }
- aDocTab += "'" + OUStringChar(SC_COMPILER_FILE_TAB_SEP) + rTabName;
- // "'Doc'#Tab"
+ OUString aDocTab(rFileName);
+ // "'Doc'#Tab"
+ aDocTab = "'" + aDocTab.replaceAll(u"'", u"\\'") + "'" + OUStringChar(SC_COMPILER_FILE_TAB_SEP) + rTabName;
return aDocTab;
}
@@ -354,7 +352,7 @@ bool isEmptyString( const OUString& rStr )
double ScGlobal::ConvertStringToValue( const OUString& rStr, const ScCalcConfig& rConfig,
FormulaError & rError, FormulaError nStringNoValueError,
- SvNumberFormatter* pFormatter, SvNumFormatType & rCurFmtType )
+ ScInterpreterContext& rContext, SvNumFormatType & rCurFmtType )
{
// We keep ScCalcConfig::StringConversion::LOCALE default until
// we provide a friendly way to convert string numbers into numbers in the UI.
@@ -388,11 +386,8 @@ double ScGlobal::ConvertStringToValue( const OUString& rStr, const ScCalcConfig&
return fValue;
}
- if (!pFormatter)
- goto Label_fallback_to_unambiguous;
-
sal_uInt32 nFIndex = 0;
- if (!pFormatter->IsNumberFormat(rStr, nFIndex, fValue))
+ if (!rContext.NFIsNumberFormat(rStr, nFIndex, fValue))
{
rError = nStringNoValueError;
fValue = 0.0;
@@ -401,7 +396,6 @@ double ScGlobal::ConvertStringToValue( const OUString& rStr, const ScCalcConfig&
}
break;
case ScCalcConfig::StringConversion::UNAMBIGUOUS:
-Label_fallback_to_unambiguous:
{
if (!rConfig.mbEmptyStringAsZero)
{
@@ -446,7 +440,7 @@ Label_fallback_to_unambiguous:
const sal_Int32 nLimit[done] = {0,12,31,0,59,59,0};
State eState = (bDate ? month : minute);
rCurFmtType = (bDate ? SvNumFormatType::DATE : SvNumFormatType::TIME);
- nUnit[eState-1] = rStr.copy( 0, nParseEnd).toInt32();
+ nUnit[eState-1] = o3tl::toInt32(rStr.subView( 0, nParseEnd));
const sal_Unicode* pLastStart = p;
// Ensure there's no preceding sign. Negative dates
// currently aren't handled correctly. Also discard
@@ -472,7 +466,7 @@ Label_fallback_to_unambiguous:
// We had at least one digit.
if (eState < done)
{
- nUnit[eState] = rStr.copy( pLastStart - pStart, p - pLastStart).toInt32();
+ nUnit[eState] = o3tl::toInt32(rStr.subView( pLastStart - pStart, p - pLastStart));
if (nLimit[eState] && nLimit[eState] < nUnit[eState])
rError = nStringNoValueError;
}
@@ -543,7 +537,7 @@ Label_fallback_to_unambiguous:
// Catch the very last unit at end of string.
if (p > pLastStart && eState < done)
{
- nUnit[eState] = rStr.copy( pLastStart - pStart, p - pLastStart).toInt32();
+ nUnit[eState] = o3tl::toInt32(rStr.subView( pLastStart - pStart, p - pLastStart));
if (nLimit[eState] && nLimit[eState] < nUnit[eState])
rError = nStringNoValueError;
}
@@ -568,14 +562,7 @@ Label_fallback_to_unambiguous:
rError = nStringNoValueError;
else
{
- if (pFormatter)
- fValue = aDate - pFormatter->GetNullDate();
- else
- {
- SAL_WARN("sc.core","ScGlobal::ConvertStringToValue - fixed null date");
- static Date aDefaultNullDate( 30, 12, 1899);
- fValue = aDate - aDefaultNullDate;
- }
+ fValue = aDate - rContext.NFGetNullDate();
}
}
fValue += ((nUnit[hour] * 3600) + (nUnit[minute] * 60) + nUnit[second] + fFraction) / 86400.0;
diff --git a/sc/source/core/data/globalx.cxx b/sc/source/core/data/globalx.cxx
index 554d59d7adab..1fac6e9c11b4 100644
--- a/sc/source/core/data/globalx.cxx
+++ b/sc/source/core/data/globalx.cxx
@@ -22,7 +22,7 @@
#include <osl/diagnose.h>
#include <osl/file.hxx>
#include <tools/urlobj.hxx>
-#include <tools/diagnose_ex.h>
+#include <comphelper/diagnose_ex.hxx>
#include <ucbhelper/content.hxx>
#include <unotools/pathoptions.hxx>
@@ -32,7 +32,7 @@
#include <com/sun/star/i18n/OrdinalSuffix.hpp>
#include <comphelper/processfactory.hxx>
-#include <unotools/configmgr.hxx>
+#include <comphelper/configuration.hxx>
#include <unotools/localedatawrapper.hxx>
namespace com::sun::star::ucb { class XCommandEnvironment; }
@@ -43,7 +43,7 @@ using namespace ::com::sun::star::ucb;
void ScGlobal::InitAddIns()
{
- if (utl::ConfigManager::IsFuzzing())
+ if (comphelper::IsFuzzing())
return;
// multi paths separated by semicolons
@@ -126,7 +126,7 @@ OUString ScGlobal::GetOrdinalSuffix( sal_Int32 nNumber)
xOrdinalSuffix = i18n::OrdinalSuffix::create( ::comphelper::getProcessComponentContext() );
}
uno::Sequence< OUString > aSuffixes = xOrdinalSuffix->getOrdinalSuffix( nNumber,
- ScGlobal::getLocaleDataPtr()->getLanguageTag().getLocale());
+ ScGlobal::getLocaleData().getLanguageTag().getLocale());
if ( aSuffixes.hasElements() )
return aSuffixes[0];
else
diff --git a/sc/source/core/data/grouptokenconverter.cxx b/sc/source/core/data/grouptokenconverter.cxx
index 6b71284a9325..4d427fc32bab 100644
--- a/sc/source/core/data/grouptokenconverter.cxx
+++ b/sc/source/core/data/grouptokenconverter.cxx
@@ -195,7 +195,7 @@ bool ScGroupTokenConverter::convert( const ScTokenArray& rCode, sc::FormulaLogge
ScRange aAbs = aRef.toAbs(mrDoc, mrPos);
// Multiple sheets not handled by vector/matrix.
- if (aRef.Ref1.Tab() != aRef.Ref2.Tab())
+ if (aAbs.aStart.Tab() != aAbs.aEnd.Tab())
return false;
// Check for self reference.
@@ -257,7 +257,8 @@ bool ScGroupTokenConverter::convert( const ScTokenArray& rCode, sc::FormulaLogge
aArrays.push_back(aArray);
}
- formula::DoubleVectorRefToken aTok(aArrays, nArrayLength, nRefRowSize, bAbsFirst, bAbsLast);
+ std::vector<formula::VectorRefArray> aArraysTmp = aArrays;
+ formula::DoubleVectorRefToken aTok( std::move(aArraysTmp), nArrayLength, nRefRowSize, bAbsFirst, bAbsLast );
mrGroupTokens.AddToken(aTok);
rScope.addRefMessage(mrPos, aAbs.aStart, nRequestedLength, aArrays);
diff --git a/sc/source/core/data/listenercontext.cxx b/sc/source/core/data/listenercontext.cxx
index e247026a5f7e..e8bfd49ae7e5 100644
--- a/sc/source/core/data/listenercontext.cxx
+++ b/sc/source/core/data/listenercontext.cxx
@@ -10,6 +10,7 @@
#include <listenercontext.hxx>
#include <document.hxx>
#include <mtvelements.hxx>
+#include <utility>
namespace sc {
@@ -17,8 +18,8 @@ StartListeningContext::StartListeningContext(ScDocument& rDoc) :
mrDoc(rDoc), mpSet(std::make_shared<ColumnBlockPositionSet>(rDoc)) {}
StartListeningContext::StartListeningContext(
- ScDocument& rDoc, const std::shared_ptr<ColumnBlockPositionSet>& pSet) :
- mrDoc(rDoc), mpSet(pSet) {}
+ ScDocument& rDoc, std::shared_ptr<ColumnBlockPositionSet> pSet) :
+ mrDoc(rDoc), mpSet(std::move(pSet)) {}
void StartListeningContext::setColumnSet( const std::shared_ptr<const ColumnSet>& rpColSet )
{
@@ -36,12 +37,12 @@ ColumnBlockPosition* StartListeningContext::getBlockPosition(SCTAB nTab, SCCOL n
}
EndListeningContext::EndListeningContext(ScDocument& rDoc, ScTokenArray* pOldCode) :
- mrDoc(rDoc), maSet(), mpPosSet(std::make_shared<ColumnBlockPositionSet>(rDoc)),
+ mrDoc(rDoc), mpPosSet(std::make_shared<ColumnBlockPositionSet>(rDoc)),
mpOldCode(pOldCode), maPosDelta(0,0,0) {}
EndListeningContext::EndListeningContext(
- ScDocument& rDoc, const std::shared_ptr<ColumnBlockPositionSet>& pSet, ScTokenArray* pOldCode) :
- mrDoc(rDoc), maSet(), mpPosSet(pSet),
+ ScDocument& rDoc, std::shared_ptr<ColumnBlockPositionSet> pSet, ScTokenArray* pOldCode) :
+ mrDoc(rDoc), mpPosSet(std::move(pSet)),
mpOldCode(pOldCode), maPosDelta(0,0,0) {}
void EndListeningContext::setPositionDelta( const ScAddress& rDelta )
@@ -71,7 +72,7 @@ void EndListeningContext::addEmptyBroadcasterPosition(SCTAB nTab, SCCOL nCol, SC
void EndListeningContext::purgeEmptyBroadcasters()
{
PurgeListenerAction aAction(mrDoc);
- maSet.executeAction(aAction);
+ maSet.executeAction(mrDoc, aAction);
}
PurgeListenerAction::PurgeListenerAction(ScDocument& rDoc) :
diff --git a/sc/source/core/data/markarr.cxx b/sc/source/core/data/markarr.cxx
index 9b1d3d834659..9b93c32f2d42 100644
--- a/sc/source/core/data/markarr.cxx
+++ b/sc/source/core/data/markarr.cxx
@@ -42,10 +42,6 @@ ScMarkArray::ScMarkArray( const ScMarkArray & rOther )
operator=(rOther);
}
-ScMarkArray::~ScMarkArray()
-{
-}
-
void ScMarkArray::Reset( bool bMarked, SCSIZE nNeeded )
{
// always create pData here
@@ -213,9 +209,9 @@ void ScMarkArray::SetMarkArea( SCROW nStartRow, SCROW nEndRow, bool bMarked )
optimised init-from-range-list. Specifically this is optimised for cases
where we have very large data columns with lots and lots of ranges.
*/
-void ScMarkArray::Set( const std::vector<ScMarkEntry> & rMarkEntries )
+void ScMarkArray::Set( std::vector<ScMarkEntry> && rMarkEntries )
{
- mvData = rMarkEntries;
+ mvData = std::move(rMarkEntries);
}
bool ScMarkArray::IsAllMarked( SCROW nStartRow, SCROW nEndRow ) const
@@ -436,10 +432,6 @@ ScMarkArrayIter::ScMarkArrayIter( const ScMarkArray* pNewArray ) :
{
}
-ScMarkArrayIter::~ScMarkArrayIter()
-{
-}
-
void ScMarkArrayIter::reset( const ScMarkArray* pNewArray )
{
pArray = pNewArray;
diff --git a/sc/source/core/data/markdata.cxx b/sc/source/core/data/markdata.cxx
index 7b45c51ecbea..54379a554705 100644
--- a/sc/source/core/data/markdata.cxx
+++ b/sc/source/core/data/markdata.cxx
@@ -36,17 +36,12 @@
ScMarkData::ScMarkData(const ScSheetLimits& rSheetLimits) :
- maTabMarked(),
aMultiSel(rSheetLimits),
mrSheetLimits(rSheetLimits)
{
ResetMark();
}
-ScMarkData::~ScMarkData()
-{
-}
-
ScMarkData& ScMarkData::operator=(const ScMarkData& rOther)
{
maTabMarked = rOther.maTabMarked;
@@ -109,16 +104,6 @@ void ScMarkData::SetMarkArea( const ScRange& rRange )
}
}
-void ScMarkData::GetMarkArea( ScRange& rRange ) const
-{
- rRange = aMarkRange; //TODO: inline ?
-}
-
-void ScMarkData::GetMultiMarkArea( ScRange& rRange ) const
-{
- rRange = aMultiRange;
-}
-
void ScMarkData::SetMultiMarkArea( const ScRange& rRange, bool bMark, bool bSetupMulti )
{
if ( aMultiSel.IsEmpty() )
@@ -579,13 +564,20 @@ std::vector<sc::ColRowSpan> ScMarkData::GetMarkedColSpans() const
bool ScMarkData::IsAllMarked( const ScRange& rRange ) const
{
- if ( !bMultiMarked )
- return false;
-
SCCOL nStartCol = rRange.aStart.Col();
SCROW nStartRow = rRange.aStart.Row();
SCCOL nEndCol = rRange.aEnd.Col();
SCROW nEndRow = rRange.aEnd.Row();
+
+ if ( !bMultiMarked )
+ {
+ if ( bMarked && !bMarkIsNeg &&
+ aMarkRange.aStart.Col() <= nStartCol && aMarkRange.aEnd.Col() >= nEndCol &&
+ aMarkRange.aStart.Row() <= nStartRow && aMarkRange.aEnd.Row() >= nEndRow )
+ return true;
+ return false;
+ }
+
bool bOk = true;
if ( nStartCol == 0 && nEndCol == mrSheetLimits.mnMaxCol )
@@ -598,6 +590,22 @@ bool ScMarkData::IsAllMarked( const ScRange& rRange ) const
return bOk;
}
+SCCOL ScMarkData::GetStartOfEqualColumns( SCCOL nLastCol, SCCOL nMinCol ) const
+{
+ if( !bMultiMarked )
+ {
+ if ( bMarked && !bMarkIsNeg )
+ {
+ if( aMarkRange.aEnd.Col() >= nMinCol && aMarkRange.aStart.Col() < nLastCol )
+ return aMarkRange.aEnd.Col() + 1;
+ if( aMarkRange.aEnd.Col() >= nLastCol && aMarkRange.aStart.Col() <= nMinCol )
+ return aMarkRange.aStart.Col();
+ }
+ return nMinCol;
+ }
+ return aMultiSel.GetStartOfEqualColumns( nLastCol, nMinCol );
+}
+
SCROW ScMarkData::GetNextMarked( SCCOL nCol, SCROW nRow, bool bUp ) const
{
if ( !bMultiMarked )
@@ -939,35 +947,4 @@ void ScMarkData::GetSelectionCover( ScRange& rRange )
}
}
-ScMarkArray ScMarkData::GetMarkArray( SCCOL nCol ) const
-{
- return aMultiSel.GetMarkArray( nCol );
-}
-
-//iterators
-ScMarkData::iterator ScMarkData::begin()
-{
- return maTabMarked.begin();
-}
-
-ScMarkData::iterator ScMarkData::end()
-{
- return maTabMarked.end();
-}
-
-ScMarkData::const_iterator ScMarkData::begin() const
-{
- return maTabMarked.begin();
-}
-
-ScMarkData::const_iterator ScMarkData::end() const
-{
- return maTabMarked.end();
-}
-
-ScMarkData::const_reverse_iterator ScMarkData::rbegin() const
-{
- return maTabMarked.rbegin();
-}
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/markmulti.cxx b/sc/source/core/data/markmulti.cxx
index 3a41f8c51b17..9cfcd19f8819 100644
--- a/sc/source/core/data/markmulti.cxx
+++ b/sc/source/core/data/markmulti.cxx
@@ -23,6 +23,8 @@
#include <segmenttree.hxx>
#include <sheetlimits.hxx>
+#include <o3tl/safeint.hxx>
+
#include <algorithm>
ScMultiSel::ScMultiSel(const ScSheetLimits& rSheetLimits)
@@ -30,10 +32,6 @@ ScMultiSel::ScMultiSel(const ScSheetLimits& rSheetLimits)
{
}
-ScMultiSel::~ScMultiSel()
-{
-}
-
ScMultiSel& ScMultiSel::operator=(const ScMultiSel& rOther)
{
aMultiSelContainer = rOther.aMultiSelContainer;
@@ -156,6 +154,25 @@ bool ScMultiSel::HasEqualRowsMarked( SCCOL nCol1, SCCOL nCol2 ) const
return true;
}
+SCCOL ScMultiSel::GetStartOfEqualColumns( SCCOL nLastCol, SCCOL nMinCol ) const
+{
+ if( nMinCol > nLastCol )
+ return nMinCol;
+ if( nLastCol >= static_cast<SCCOL>(aMultiSelContainer.size()))
+ {
+ if( nMinCol >= static_cast<SCCOL>(aMultiSelContainer.size()))
+ return nMinCol;
+ SCCOL nCol = static_cast<SCCOL>(aMultiSelContainer.size()) - 1;
+ while( nCol >= nMinCol && aMultiSelContainer[nCol] == aRowSel )
+ --nCol;
+ return nCol + 1;
+ }
+ SCCOL nCol = nLastCol - 1;
+ while( nCol >= nMinCol && aMultiSelContainer[nCol] == aMultiSelContainer[nLastCol] )
+ --nCol;
+ return nCol + 1;
+}
+
SCROW ScMultiSel::GetNextMarked( SCCOL nCol, SCROW nRow, bool bUp ) const
{
if ( nCol >= static_cast<SCCOL>(aMultiSelContainer.size()) || !aMultiSelContainer[nCol].HasMarks() )
@@ -216,7 +233,7 @@ void ScMultiSel::SetMarkArea( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, S
nLast = aRowSel.GetMarkEnd( nBeg, false );
}
- if ( nBeg != mrSheetLimits.GetMaxRowCount() && nLast >= nEndRow )
+ if ( nBeg != mrSheetLimits.GetMaxRowCount() && nLast >= nEndRow && nBeg <= nEndRow )
MarkAllCols( nBeg, nEndRow );
else
{
@@ -227,7 +244,7 @@ void ScMultiSel::SetMarkArea( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, S
if ( nBeg != mrSheetLimits.GetMaxRowCount() )
nLast = aRowSel.GetMarkEnd( nBeg, false );
}
- if ( nBeg != mrSheetLimits.GetMaxRowCount() && nLast >= nEndRow )
+ if ( nBeg != mrSheetLimits.GetMaxRowCount() && nLast >= nEndRow && nBeg <= nEndRow )
MarkAllCols( nBeg, nEndRow );
}
@@ -247,7 +264,7 @@ void ScMultiSel::SetMarkArea( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, S
void ScMultiSel::Set( ScRangeList const & rList )
{
Clear();
- if (rList.size() == 0)
+ if (rList.empty())
return;
// sort by row to make the combining/merging faster
@@ -261,7 +278,6 @@ void ScMultiSel::Set( ScRangeList const & rList )
std::vector<std::vector<ScMarkEntry>> aMarkEntriesPerCol(mrSheetLimits.mnMaxCol+1);
SCCOL nMaxCol = -1;
- int i = 0;
for (const ScRange& rRange : aNewList)
{
SCCOL nStartCol = rRange.aStart.Col();
@@ -294,16 +310,12 @@ void ScMultiSel::Set( ScRangeList const & rList )
}
nMaxCol = std::max(nMaxCol, nEndCol);
}
- ++i;
}
aMultiSelContainer.resize(nMaxCol+1, ScMarkArray(mrSheetLimits));
for (SCCOL nCol = 0; nCol<=nMaxCol; ++nCol)
if (!aMarkEntriesPerCol[nCol].empty())
- {
- aMultiSelContainer[nCol].Set( aMarkEntriesPerCol[nCol] );
- aMarkEntriesPerCol[nCol].clear(); // reduce peak memory usage
- }
+ aMultiSelContainer[nCol].Set( std::move(aMarkEntriesPerCol[nCol]) );
}
bool ScMultiSel::IsRowMarked( SCROW nRow ) const
@@ -374,7 +386,7 @@ void ScMultiSel::ShiftCols(SCCOL nStartCol, sal_Int32 nColOffset)
}
aRowSel = aNewMultiSel.aRowSel;
- if (!(nColOffset > 0 && nStartCol > 0 && nStartCol < static_cast<SCCOL>(aNewMultiSel.aMultiSelContainer.size())))
+ if (!(nColOffset > 0 && nStartCol > 0 && o3tl::make_unsigned(nStartCol) < aNewMultiSel.aMultiSelContainer.size()))
return;
// insert nColOffset new columns, and select their cells if they are selected
@@ -397,11 +409,6 @@ void ScMultiSel::ShiftRows(SCROW nStartRow, sal_Int32 nRowOffset)
aRowSel.Shift(nStartRow, nRowOffset);
}
-const ScMarkArray& ScMultiSel::GetRowSelArray() const
-{
- return aRowSel;
-}
-
const ScMarkArray* ScMultiSel::GetMultiSelArray( SCCOL nCol ) const
{
if (nCol >= static_cast<SCCOL>(aMultiSelContainer.size()))
@@ -445,10 +452,6 @@ ScMultiSelIter::ScMultiSelIter( const ScMultiSel& rMultiSel, SCCOL nCol ) :
}
}
-ScMultiSelIter::~ScMultiSelIter()
-{
-}
-
bool ScMultiSelIter::Next( SCROW& rTop, SCROW& rBottom )
{
if (pRowSegs)
diff --git a/sc/source/core/data/mtvelements.cxx b/sc/source/core/data/mtvelements.cxx
index 792b4e9d60e6..9f5399701d31 100644
--- a/sc/source/core/data/mtvelements.cxx
+++ b/sc/source/core/data/mtvelements.cxx
@@ -31,6 +31,9 @@ void CellStoreEvent::element_block_acquired(const mdds::mtv::base_element_block*
case sc::element_type_formula:
++mpCol->mnBlkCountFormula;
break;
+ case sc::element_type_cellnote:
+ ++mpCol->mnBlkCountCellNotes;
+ break;
default:
;
}
@@ -46,16 +49,34 @@ void CellStoreEvent::element_block_released(const mdds::mtv::base_element_block*
case sc::element_type_formula:
--mpCol->mnBlkCountFormula;
break;
+ case sc::element_type_cellnote:
+ --mpCol->mnBlkCountCellNotes;
+ break;
default:
;
}
}
+void CellStoreEvent::stop()
+{
+ mpCol = nullptr;
+}
+
+void CellStoreEvent::swap(CellStoreEvent& other)
+{
+ std::swap(mpCol, other.mpCol);
+}
+
+const ScColumn* CellStoreEvent::getColumn() const
+{
+ return mpCol;
+}
+
ColumnBlockPositionSet::ColumnBlockPositionSet(ScDocument& rDoc) : mrDoc(rDoc) {}
ColumnBlockPosition* ColumnBlockPositionSet::getBlockPosition(SCTAB nTab, SCCOL nCol)
{
- osl::MutexGuard aGuard(&maMtxTables);
+ std::scoped_lock aGuard(maMtxTables);
TablesType::iterator itTab = maTables.find(nTab);
if (itTab == maTables.end())
@@ -93,7 +114,7 @@ ColumnBlockPosition* ColumnBlockPositionSet::getBlockPosition(SCTAB nTab, SCCOL
void ColumnBlockPositionSet::clear()
{
- osl::MutexGuard aGuard(&maMtxTables);
+ std::scoped_lock aGuard(maMtxTables);
maTables.clear();
}
@@ -161,16 +182,16 @@ ScRefCellValue toRefCell( const sc::CellStoreType::const_iterator& itPos, size_t
{
case sc::element_type_numeric:
// Numeric cell
- return ScRefCellValue(sc::numeric_block::at(*itPos->data, nOffset));
+ return ScRefCellValue(sc::numeric_block::get_value(*itPos->data, nOffset));
case sc::element_type_string:
// String cell
return ScRefCellValue(&sc::string_block::at(*itPos->data, nOffset));
case sc::element_type_edittext:
// Edit cell
- return ScRefCellValue(sc::edittext_block::at(*itPos->data, nOffset));
+ return ScRefCellValue(sc::edittext_block::get_value(*itPos->data, nOffset));
case sc::element_type_formula:
// Formula cell
- return ScRefCellValue(sc::formula_block::at(*itPos->data, nOffset));
+ return ScRefCellValue(sc::formula_block::get_value(*itPos->data, nOffset));
default:
;
}
diff --git a/sc/source/core/data/pagepar.cxx b/sc/source/core/data/pagepar.cxx
index 35a270e39391..7e996fc64b9c 100644
--- a/sc/source/core/data/pagepar.cxx
+++ b/sc/source/core/data/pagepar.cxx
@@ -26,10 +26,6 @@ ScPageTableParam::ScPageTableParam()
Reset();
}
-ScPageTableParam::~ScPageTableParam()
-{
-}
-
void ScPageTableParam::Reset()
{
bCellContent = true;
@@ -49,10 +45,6 @@ ScPageAreaParam::ScPageAreaParam()
Reset();
}
-ScPageAreaParam::~ScPageAreaParam()
-{
-}
-
void ScPageAreaParam::Reset()
{
bPrintArea = bRepeatRow = bRepeatCol = false;
diff --git a/sc/source/core/data/patattr.cxx b/sc/source/core/data/patattr.cxx
index d5f137f09117..42bb54937a45 100644
--- a/sc/source/core/data/patattr.cxx
+++ b/sc/source/core/data/patattr.cxx
@@ -46,6 +46,8 @@
#include <editeng/wrlmitem.hxx>
#include <editeng/justifyitem.hxx>
#include <svl/intitem.hxx>
+#include <svl/numformat.hxx>
+#include <svl/whiter.hxx>
#include <svl/zforlist.hxx>
#include <vcl/outdev.hxx>
#include <tools/fract.hxx>
@@ -54,60 +56,380 @@
#include <attrib.hxx>
#include <patattr.hxx>
-#include <docpool.hxx>
#include <stlsheet.hxx>
#include <stlpool.hxx>
#include <document.hxx>
-#include <global.hxx>
#include <globstr.hrc>
#include <scresid.hxx>
#include <validat.hxx>
#include <scmod.hxx>
#include <fillinfo.hxx>
-#include <boost/functional/hash.hpp>
+#include <comphelper/lok.hxx>
+#include <tabvwsh.hxx>
+
+CellAttributeHelper::CellAttributeHelper(SfxItemPool& rSfxItemPool)
+: mrSfxItemPool(rSfxItemPool)
+, mpDefaultCellAttribute(nullptr)
+, maRegisteredCellAttributes()
+, mpLastHit(nullptr)
+, mnCurrentMaxKey(0)
+{
+}
-ScPatternAttr::ScPatternAttr( std::unique_ptr<SfxItemSet>&& pItemSet, const OUString& rStyleName )
- : SfxSetItem ( ATTR_PATTERN, std::move(pItemSet) ),
- pName ( rStyleName ),
- pStyle ( nullptr ),
- mnKey(0)
+CellAttributeHelper::~CellAttributeHelper()
{
+ delete mpDefaultCellAttribute;
}
-ScPatternAttr::ScPatternAttr( std::unique_ptr<SfxItemSet>&& pItemSet )
- : SfxSetItem ( ATTR_PATTERN, std::move(pItemSet) ),
- pStyle ( nullptr ),
- mnKey(0)
+static int CompareStringPtr(const OUString* lhs, const OUString* rhs)
{
+ if (lhs == rhs)
+ return 0;
+ if (lhs && rhs)
+ return (*lhs).compareTo(*rhs);
+ if (!lhs && rhs)
+ return -1;
+ return 1;
}
-ScPatternAttr::ScPatternAttr( SfxItemPool* pItemPool )
- : SfxSetItem ( ATTR_PATTERN, std::make_unique<SfxItemSet>( *pItemPool, svl::Items<ATTR_PATTERN_START, ATTR_PATTERN_END>{} ) ),
- pStyle ( nullptr ),
- mnKey(0)
+const ScPatternAttr* CellAttributeHelper::registerAndCheck(const ScPatternAttr& rCandidate, bool bPassingOwnership) const
{
+ if (&rCandidate == &getDefaultCellAttribute())
+ return &rCandidate;
+
+ assert(rCandidate.pCellAttributeHelper == this && "WRONG CellAttributeHelper in ScPatternAttr (!)");
+
+ if (rCandidate.isRegistered())
+ {
+ assert(!bPassingOwnership && "Trying to register an already registered CellAttribute with ownership change (!)");
+ rCandidate.mnRefCount++;
+ return &rCandidate;
+ }
+
+ if (ScPatternAttr::areSame(mpLastHit, &rCandidate))
+ {
+ // hit for single-entry cache, make use of it
+ mpLastHit->mnRefCount++;
+ if (bPassingOwnership)
+ delete &rCandidate;
+ return mpLastHit;
+ }
+ const OUString* pCandidateStyleName = rCandidate.GetStyleName();
+ auto it = maRegisteredCellAttributes.lower_bound(pCandidateStyleName);
+ for (; it != maRegisteredCellAttributes.end(); ++it)
+ {
+ const ScPatternAttr* pCheck = *it;
+ if (CompareStringPtr(pCheck->GetStyleName(), pCandidateStyleName) != 0)
+ break;
+ if (ScPatternAttr::areSame(pCheck, &rCandidate))
+ {
+ pCheck->mnRefCount++;
+ if (bPassingOwnership)
+ delete &rCandidate;
+ mpLastHit = pCheck;
+ return pCheck;
+ }
+ }
+
+ const ScPatternAttr* pCandidate(bPassingOwnership ? &rCandidate : new ScPatternAttr(rCandidate));
+ pCandidate->mnRefCount++;
+ const_cast<ScPatternAttr*>(pCandidate)->SetPAKey(mnCurrentMaxKey++);
+ maRegisteredCellAttributes.insert(pCandidate);
+ mpLastHit = pCandidate;
+ return pCandidate;
}
-ScPatternAttr::ScPatternAttr( const ScPatternAttr& rPatternAttr )
- : SfxSetItem ( rPatternAttr ),
- pName ( rPatternAttr.pName ),
- pStyle ( rPatternAttr.pStyle ),
- mnKey(rPatternAttr.mnKey)
+void CellAttributeHelper::doUnregister(const ScPatternAttr& rCandidate)
{
+ if (&rCandidate == &getDefaultCellAttribute())
+ return;
+
+ assert(rCandidate.isRegistered());
+ rCandidate.mnRefCount--;
+
+ if (0 != rCandidate.mnRefCount)
+ return;
+
+ if (mpLastHit == &rCandidate)
+ mpLastHit = nullptr;
+
+ maRegisteredCellAttributes.erase(&rCandidate);
+ delete &rCandidate;
}
-ScPatternAttr::~ScPatternAttr()
+const ScPatternAttr& CellAttributeHelper::getDefaultCellAttribute() const
+{
+ // *have* to create on-demand due to mrScDocument.GetPool() *can* be nullptr
+ // since mxPoolHelper is *only* created for SCDOCMODE_DOCUMENT and
+ // SCDOCMODE_FUNCTIONACCESS (!)
+ if (!mpDefaultCellAttribute)
+ {
+ // GetRscString only works after ScGlobal::Init (indicated by the EmptyBrushItem)
+ // TODO: Write additional method ScGlobal::IsInit() or somesuch
+ // or detect whether this is the Secondary Pool for a MessagePool
+ if (ScGlobal::GetEmptyBrushItem())
+ {
+ const OUString aInitialStyle(ScResId(STR_STYLENAME_STANDARD));
+ mpDefaultCellAttribute = new ScPatternAttr(
+ *const_cast<CellAttributeHelper*>(this),
+ nullptr, // no SfxItemSet
+ &aInitialStyle);
+ }
+ else
+ {
+ mpDefaultCellAttribute = new ScPatternAttr(*const_cast<CellAttributeHelper*>(this));
+ }
+ }
+ return *mpDefaultCellAttribute;
+}
+
+void CellAttributeHelper::CellStyleDeleted(const ScStyleSheet& rStyle)
+{
+ const OUString& rCandidateStyleName = rStyle.GetName();
+ auto it = maRegisteredCellAttributes.lower_bound(&rCandidateStyleName);
+ for (; it != maRegisteredCellAttributes.end(); ++it)
+ {
+ const ScPatternAttr* pCheck = *it;
+ if (CompareStringPtr(pCheck->GetStyleName(), &rCandidateStyleName) != 0)
+ break;
+ if (&rStyle == pCheck->GetStyleSheet())
+ const_cast<ScPatternAttr*>(pCheck)->StyleToName();
+ }
+}
+
+void CellAttributeHelper::CellStyleCreated(ScDocument& rDoc, const OUString& rName)
+{
+ // If a style was created, don't keep any pattern with its name string in the pool,
+ // because it would compare equal to a pattern with a pointer to the new style.
+ // Calling StyleSheetChanged isn't enough because the pool may still contain items
+ // for undo or clipboard content.
+ std::vector<const ScPatternAttr*> aChanged;
+ auto it = maRegisteredCellAttributes.lower_bound(&rName);
+ while(it != maRegisteredCellAttributes.end())
+ {
+ const ScPatternAttr* pCheck = *it;
+ if (CompareStringPtr(pCheck->GetStyleName(), &rName) != 0)
+ break;
+ if (nullptr == pCheck->GetStyleSheet())
+ if (const_cast<ScPatternAttr*>(pCheck)->UpdateStyleSheet(rDoc)) // find and store style pointer
+ {
+ aChanged.push_back(pCheck);
+ // if the name changed, we have to re-insert it
+ it = maRegisteredCellAttributes.erase(it);
+ }
+ else
+ ++it;
+ else
+ ++it;
+ }
+ for (const ScPatternAttr* p : aChanged)
+ maRegisteredCellAttributes.insert(p);
+}
+
+void CellAttributeHelper::UpdateAllStyleSheets(ScDocument& rDoc)
+{
+ bool bNameChanged = false;
+ for (const ScPatternAttr* pCheck : maRegisteredCellAttributes)
+ bNameChanged |= const_cast<ScPatternAttr*>(pCheck)->UpdateStyleSheet(rDoc);
+ if (bNameChanged)
+ ReIndexRegistered();
+
+ // force existence, then access
+ getDefaultCellAttribute();
+ mpDefaultCellAttribute->UpdateStyleSheet(rDoc);
+}
+
+void CellAttributeHelper::AllStylesToNames()
+{
+ for (const ScPatternAttr* pCheck : maRegisteredCellAttributes)
+ const_cast<ScPatternAttr*>(pCheck)->StyleToName();
+
+ // force existence, then access
+ getDefaultCellAttribute();
+ mpDefaultCellAttribute->StyleToName();
+}
+
+/// If the style name changed, we need to reindex.
+void CellAttributeHelper::ReIndexRegistered()
+{
+ RegisteredAttrSet aNewSet;
+ for (auto const & p : maRegisteredCellAttributes)
+ aNewSet.insert(p);
+ maRegisteredCellAttributes = std::move(aNewSet);
+}
+
+bool CellAttributeHelper::RegisteredAttrSetLess::operator()(const ScPatternAttr* lhs, const ScPatternAttr* rhs) const
+{
+ int cmp = CompareStringPtr(lhs->GetStyleName(), rhs->GetStyleName());
+ if (cmp < 0)
+ return true;
+ if (cmp > 0)
+ return false;
+ return lhs < rhs;
+}
+bool CellAttributeHelper::RegisteredAttrSetLess::operator()(const ScPatternAttr* lhs, const OUString* rhs) const
+{
+ int cmp = CompareStringPtr(lhs->GetStyleName(), rhs);
+ if (cmp < 0)
+ return true;
+ if (cmp > 0)
+ return false;
+ return lhs < static_cast<const ScPatternAttr*>(nullptr);
+}
+bool CellAttributeHelper::RegisteredAttrSetLess::operator()(const OUString* lhs, const ScPatternAttr* rhs) const
+{
+ int cmp = CompareStringPtr(lhs, rhs->GetStyleName());
+ if (cmp < 0)
+ return true;
+ if (cmp > 0)
+ return false;
+ return static_cast<const ScPatternAttr*>(nullptr) < rhs;
+}
+
+
+CellAttributeHolder::CellAttributeHolder(const ScPatternAttr* pNew, bool bPassingOwnership)
+: mpScPatternAttr(nullptr)
+{
+ if (nullptr != pNew)
+ suppress_fun_call_w_exception(mpScPatternAttr = pNew->getCellAttributeHelper().registerAndCheck(*pNew, bPassingOwnership));
+}
+
+CellAttributeHolder::CellAttributeHolder(const CellAttributeHolder& rHolder)
+: mpScPatternAttr(nullptr)
+{
+ if (rHolder.getScPatternAttr())
+ suppress_fun_call_w_exception(mpScPatternAttr = rHolder.getScPatternAttr()->getCellAttributeHelper().registerAndCheck(*rHolder.getScPatternAttr(), false));
+}
+
+CellAttributeHolder::CellAttributeHolder(CellAttributeHolder&& rHolder) noexcept
+: mpScPatternAttr(rHolder.mpScPatternAttr)
+{
+ rHolder.mpScPatternAttr = nullptr;
+}
+
+CellAttributeHolder::~CellAttributeHolder()
+{
+ if (nullptr != mpScPatternAttr)
+ suppress_fun_call_w_exception(mpScPatternAttr->getCellAttributeHelper().doUnregister(*mpScPatternAttr));
+}
+
+CellAttributeHolder& CellAttributeHolder::operator=(const CellAttributeHolder& rHolder)
{
+ if (nullptr != mpScPatternAttr)
+ {
+ mpScPatternAttr->getCellAttributeHelper().doUnregister(*mpScPatternAttr);
+ mpScPatternAttr = nullptr;
+ }
+
+ if (rHolder.getScPatternAttr())
+ mpScPatternAttr = rHolder.getScPatternAttr()->getCellAttributeHelper().registerAndCheck(*rHolder.getScPatternAttr(), false);
+
+ return *this;
}
-ScPatternAttr* ScPatternAttr::Clone( SfxItemPool *pPool ) const
+CellAttributeHolder& CellAttributeHolder::operator=(CellAttributeHolder&& rHolder)
{
- ScPatternAttr* pPattern = new ScPatternAttr( GetItemSet().Clone(true, pPool) );
+ if (nullptr != mpScPatternAttr)
+ {
+ mpScPatternAttr->getCellAttributeHelper().doUnregister(*mpScPatternAttr);
+ mpScPatternAttr = nullptr;
+ }
- pPattern->pStyle = pStyle;
- pPattern->pName = pName;
+ std::swap(mpScPatternAttr, rHolder.mpScPatternAttr);
+ assert(!rHolder.mpScPatternAttr);
+
+ return *this;
+}
- return pPattern;
+bool CellAttributeHolder::operator==(const CellAttributeHolder& rHolder) const
+{
+ // here we have registered entries, so no need to test for equality
+ return mpScPatternAttr == rHolder.mpScPatternAttr;
+}
+
+void CellAttributeHolder::setScPatternAttr(const ScPatternAttr* pNew, bool bPassingOwnership)
+{
+ if (nullptr != mpScPatternAttr)
+ mpScPatternAttr->getCellAttributeHelper().doUnregister(*mpScPatternAttr);
+
+ mpScPatternAttr = nullptr;
+
+ if (nullptr != pNew)
+ mpScPatternAttr = pNew->getCellAttributeHelper().registerAndCheck(*pNew, bPassingOwnership);
+}
+
+bool CellAttributeHolder::areSame(const CellAttributeHolder* p1, const CellAttributeHolder* p2)
+{
+ if (p1 == p2)
+ // pointer compare, this handles already
+ // nullptr and if indeed handed over twice
+ return true;
+
+ if (nullptr == p1 || nullptr == p2)
+ // one ptr is nullptr, not both, that would
+ // have triggered above
+ return false;
+
+ // return content compare using operator== at last
+ return *p1 == *p2;
+}
+
+#ifdef DBG_UTIL
+static size_t nUsedScPatternAttr(0);
+#endif
+
+const WhichRangesContainer aScPatternAttrSchema(svl::Items<ATTR_PATTERN_START, ATTR_PATTERN_END>);
+
+ScPatternAttr::ScPatternAttr(CellAttributeHelper& rHelper, const SfxItemSet* pItemSet, const OUString* pStyleName)
+: maLocalSfxItemSet(rHelper.GetPool(), aScPatternAttrSchema)
+, mxVisible()
+, pStyle(nullptr)
+, pCellAttributeHelper(&rHelper)
+, mnPAKey(0)
+, mnRefCount(0)
+#ifdef DBG_UTIL
+, m_nSerialNumber(nUsedScPatternAttr++)
+, m_bDeleted(false)
+#endif
+{
+ if (nullptr != pStyleName)
+ moName = *pStyleName;
+
+ // We need to ensure that ScPatternAttr is using the correct WhichRange,
+ // see comments in commit message. This does transfers the items with
+ // minimized overhead, too
+ if (nullptr != pItemSet)
+ {
+ // CAUTION: Use bInvalidAsDefault == false for the ::Put,
+ // we *need* to take over also Items/Slots in state
+ // SfxItemState::INVALID aka IsInvalidItem, this is a precious
+ // value/information e.g. in ScDocument::CreateSelectionPattern
+ maLocalSfxItemSet.Put(*pItemSet, false);
+ }
+}
+
+ScPatternAttr::ScPatternAttr(const ScPatternAttr& rPatternAttr)
+: maLocalSfxItemSet(rPatternAttr.maLocalSfxItemSet)
+, moName(rPatternAttr.moName)
+, mxVisible()
+, pStyle(rPatternAttr.pStyle)
+, pCellAttributeHelper(rPatternAttr.pCellAttributeHelper)
+, mnPAKey(rPatternAttr.mnPAKey)
+, mnRefCount(0)
+#ifdef DBG_UTIL
+, m_nSerialNumber(nUsedScPatternAttr++)
+, m_bDeleted(false)
+#endif
+{
+}
+
+ScPatternAttr::~ScPatternAttr()
+{
+#ifdef DBG_UTIL
+ m_bDeleted = true;
+#endif
+ // should no longer be referenced, complain if not so
+ assert(!isRegistered());
}
static bool StrCmp( const OUString* pStr1, const OUString* pStr2 )
@@ -121,36 +443,74 @@ static bool StrCmp( const OUString* pStr1, const OUString* pStr2 )
return *pStr1 == *pStr2;
}
-static bool EqualPatternSets( const SfxItemSet& rSet1, const SfxItemSet& rSet2 )
+constexpr size_t compareSize = ATTR_PATTERN_END - ATTR_PATTERN_START + 1;
+
+bool ScPatternAttr::operator==(const ScPatternAttr& rCmp) const
{
- // #i62090# The SfxItemSet in the SfxSetItem base class always has the same ranges
- // (single range from ATTR_PATTERN_START to ATTR_PATTERN_END), and the items are pooled,
- // so it's enough to compare just the pointers (Count just because it's even faster).
+ // check if same incarnation
+ if (this == &rCmp)
+ return true;
+
+ // check everything except the SfxItemSet from base class SfxSetItem
+ if (!StrCmp(GetStyleName(), rCmp.GetStyleName()))
+ return false;
+
+ // here we need to compare the SfxItemSet. We *know* that these are
+ // all simple (one range, same range)
+ const SfxItemSet& rSet1(maLocalSfxItemSet);
+ const SfxItemSet& rSet2(rCmp.maLocalSfxItemSet);
+
+ // the former method 'FastEqualPatternSets' mentioned:
+ // "Actually test_tdf133629 from UITest_calc_tests9 somehow manages to have
+ // a different range (and I don't understand enough why), so better be safe and compare fully."
+ // in that case the hash code above would already fail, too
+ assert(rSet1.TotalCount() == compareSize && rSet2.TotalCount() == compareSize);
- if ( rSet1.Count() != rSet2.Count() )
+ // check pools, do not accept different pools
+ if (rSet1.GetPool() != rSet2.GetPool())
return false;
- SfxPoolItem const ** pItems1 = rSet1.GetItems_Impl(); // inline method of SfxItemSet
- SfxPoolItem const ** pItems2 = rSet2.GetItems_Impl();
+ // check count of set items, has to be equal
+ if (rSet1.Count() != rSet2.Count())
+ return false;
- return ( 0 == memcmp( pItems1, pItems2, (ATTR_PATTERN_END - ATTR_PATTERN_START + 1) * sizeof(pItems1[0]) ) );
+ // both have no items, done
+ if (0 == rSet1.Count())
+ return true;
+
+ // compare each item separately
+ const SfxPoolItem **ppItem1(rSet1.GetItems_Impl());
+ const SfxPoolItem **ppItem2(rSet2.GetItems_Impl());
+
+ // are all pointers the same?
+ if (0 == memcmp(ppItem1, ppItem2, compareSize * sizeof(ppItem1[0])))
+ return true;
+
+ for (sal_uInt16 nPos(0); nPos < compareSize; nPos++)
+ {
+ if (!SfxPoolItem::areSame(*ppItem1, *ppItem2))
+ return false;
+ ++ppItem1;
+ ++ppItem2;
+ }
+
+ return true;
}
-bool ScPatternAttr::operator==( const SfxPoolItem& rCmp ) const
+bool ScPatternAttr::areSame(const ScPatternAttr* pItem1, const ScPatternAttr* pItem2)
{
- // #i62090# Use quick comparison between ScPatternAttr's ItemSets
+ if (pItem1 == pItem2)
+ // pointer compare, this handles already
+ // nullptr and if indeed handed over twice
+ return true;
- if (!SfxPoolItem::operator==(rCmp) )
- return false;
- if (!mxHashCode)
- CalcHashCode();
- auto const & rOther = static_cast<const ScPatternAttr&>(rCmp);
- if (!rOther.mxHashCode)
- rOther.CalcHashCode();
- if (*mxHashCode != *rOther.mxHashCode)
+ if (nullptr == pItem1 || nullptr == pItem2)
+ // one ptr is nullptr, not both, that would
+ // have triggered above
return false;
- return EqualPatternSets( GetItemSet(), rOther.GetItemSet() ) &&
- StrCmp( GetStyleName(), rOther.GetStyleName() );
+
+ // return content compare using operator== at last
+ return *pItem1 == *pItem2;
}
SvxCellOrientation ScPatternAttr::GetCellOrientation( const SfxItemSet& rItemSet, const SfxItemSet* pCondSet )
@@ -181,7 +541,11 @@ SvxCellOrientation ScPatternAttr::GetCellOrientation( const SfxItemSet* pCondSet
namespace {
void getFontIDsByScriptType(SvtScriptType nScript,
-sal_uInt16& nFontId, sal_uInt16& nHeightId, sal_uInt16& nWeightId, sal_uInt16& nPostureId, sal_uInt16& nLangId)
+ TypedWhichId<SvxFontItem>& nFontId,
+ TypedWhichId<SvxFontHeightItem>& nHeightId,
+ TypedWhichId<SvxWeightItem>& nWeightId,
+ TypedWhichId<SvxPostureItem>& nPostureId,
+ TypedWhichId<SvxLanguageItem>& nLangId)
{
if ( nScript == SvtScriptType::ASIAN )
{
@@ -211,11 +575,26 @@ sal_uInt16& nFontId, sal_uInt16& nHeightId, sal_uInt16& nWeightId, sal_uInt16& n
}
-void ScPatternAttr::GetFont(
+void ScPatternAttr::fillFont(
vcl::Font& rFont, const SfxItemSet& rItemSet, ScAutoFontColorMode eAutoMode,
const OutputDevice* pOutDev, const Fraction* pScale,
const SfxItemSet* pCondSet, SvtScriptType nScript,
- const Color* pBackConfigColor, const Color* pTextConfigColor )
+ const Color* pBackConfigColor, const Color* pTextConfigColor)
+{
+ model::ComplexColor aComplexColor;
+
+ // determine effective font color
+ ScPatternAttr::fillFontOnly(rFont, rItemSet, pOutDev, pScale, pCondSet, nScript);
+ ScPatternAttr::fillColor(aComplexColor, rItemSet, eAutoMode, pCondSet, pBackConfigColor, pTextConfigColor);
+
+ // set font effects
+ rFont.SetColor(aComplexColor.getFinalColor());
+}
+
+void ScPatternAttr::fillFontOnly(
+ vcl::Font& rFont, const SfxItemSet& rItemSet,
+ const OutputDevice* pOutDev, const Fraction* pScale,
+ const SfxItemSet* pCondSet, SvtScriptType nScript)
{
// Read items
@@ -231,81 +610,87 @@ void ScPatternAttr::GetFont(
bool bShadow;
FontEmphasisMark eEmphasis;
FontRelief eRelief;
- Color aColor;
LanguageType eLang;
- sal_uInt16 nFontId, nHeightId, nWeightId, nPostureId, nLangId;
+ TypedWhichId<SvxFontItem> nFontId(0);
+ TypedWhichId<SvxFontHeightItem> nHeightId(0);
+ TypedWhichId<SvxWeightItem> nWeightId(0);
+ TypedWhichId<SvxPostureItem> nPostureId(0);
+ TypedWhichId<SvxLanguageItem> nLangId(0);
getFontIDsByScriptType(nScript, nFontId, nHeightId, nWeightId, nPostureId, nLangId);
- if ( pCondSet )
+ if (pCondSet)
{
- const SfxPoolItem* pItem;
-
- if ( pCondSet->GetItemState( nFontId, true, &pItem ) != SfxItemState::SET )
- pItem = &rItemSet.Get( nFontId );
- pFontAttr = static_cast<const SvxFontItem*>(pItem);
-
- if ( pCondSet->GetItemState( nHeightId, true, &pItem ) != SfxItemState::SET )
- pItem = &rItemSet.Get( nHeightId );
- nFontHeight = static_cast<const SvxFontHeightItem*>(pItem)->GetHeight();
-
- if ( pCondSet->GetItemState( nWeightId, true, &pItem ) != SfxItemState::SET )
- pItem = &rItemSet.Get( nWeightId );
- eWeight = static_cast<const SvxWeightItem*>(pItem)->GetValue();
-
- if ( pCondSet->GetItemState( nPostureId, true, &pItem ) != SfxItemState::SET )
- pItem = &rItemSet.Get( nPostureId );
- eItalic = static_cast<const SvxPostureItem*>(pItem)->GetValue();
-
- if ( pCondSet->GetItemState( ATTR_FONT_UNDERLINE, true, &pItem ) != SfxItemState::SET )
- pItem = &rItemSet.Get( ATTR_FONT_UNDERLINE );
- eUnder = static_cast<const SvxUnderlineItem*>(pItem)->GetValue();
-
- if ( pCondSet->GetItemState( ATTR_FONT_OVERLINE, true, &pItem ) != SfxItemState::SET )
- pItem = &rItemSet.Get( ATTR_FONT_OVERLINE );
- eOver = static_cast<const SvxOverlineItem*>(pItem)->GetValue();
-
- if ( pCondSet->GetItemState( ATTR_FONT_WORDLINE, true, &pItem ) != SfxItemState::SET )
- pItem = &rItemSet.Get( ATTR_FONT_WORDLINE );
- bWordLine = static_cast<const SvxWordLineModeItem*>(pItem)->GetValue();
-
- if ( pCondSet->GetItemState( ATTR_FONT_CROSSEDOUT, true, &pItem ) != SfxItemState::SET )
- pItem = &rItemSet.Get( ATTR_FONT_CROSSEDOUT );
- eStrike = static_cast<const SvxCrossedOutItem*>(pItem)->GetValue();
-
- if ( pCondSet->GetItemState( ATTR_FONT_CONTOUR, true, &pItem ) != SfxItemState::SET )
- pItem = &rItemSet.Get( ATTR_FONT_CONTOUR );
- bOutline = static_cast<const SvxContourItem*>(pItem)->GetValue();
-
- if ( pCondSet->GetItemState( ATTR_FONT_SHADOWED, true, &pItem ) != SfxItemState::SET )
- pItem = &rItemSet.Get( ATTR_FONT_SHADOWED );
- bShadow = static_cast<const SvxShadowedItem*>(pItem)->GetValue();
-
- if ( pCondSet->GetItemState( ATTR_FONT_EMPHASISMARK, true, &pItem ) != SfxItemState::SET )
- pItem = &rItemSet.Get( ATTR_FONT_EMPHASISMARK );
- eEmphasis = static_cast<const SvxEmphasisMarkItem*>(pItem)->GetEmphasisMark();
-
- if ( pCondSet->GetItemState( ATTR_FONT_RELIEF, true, &pItem ) != SfxItemState::SET )
- pItem = &rItemSet.Get( ATTR_FONT_RELIEF );
- eRelief = static_cast<const SvxCharReliefItem*>(pItem)->GetValue();
-
- if ( pCondSet->GetItemState( ATTR_FONT_COLOR, true, &pItem ) != SfxItemState::SET )
- pItem = &rItemSet.Get( ATTR_FONT_COLOR );
- aColor = static_cast<const SvxColorItem*>(pItem)->GetValue();
-
- if ( pCondSet->GetItemState( nLangId, true, &pItem ) != SfxItemState::SET )
- pItem = &rItemSet.Get( nLangId );
- eLang = static_cast<const SvxLanguageItem*>(pItem)->GetLanguage();
+ pFontAttr = pCondSet->GetItemIfSet( nFontId );
+ if ( !pFontAttr )
+ pFontAttr = &rItemSet.Get( nFontId );
+
+ const SvxFontHeightItem* pFontHeightItem = pCondSet->GetItemIfSet( nHeightId );
+ if ( !pFontHeightItem )
+ pFontHeightItem = &rItemSet.Get( nHeightId );
+ nFontHeight = pFontHeightItem->GetHeight();
+
+ const SvxWeightItem* pFontHWeightItem = pCondSet->GetItemIfSet( nWeightId );
+ if ( !pFontHWeightItem )
+ pFontHWeightItem = &rItemSet.Get( nWeightId );
+ eWeight = pFontHWeightItem->GetValue();
+
+ const SvxPostureItem* pPostureItem = pCondSet->GetItemIfSet( nPostureId );
+ if ( !pPostureItem )
+ pPostureItem = &rItemSet.Get( nPostureId );
+ eItalic = pPostureItem->GetValue();
+
+ const SvxUnderlineItem* pUnderlineItem = pCondSet->GetItemIfSet( ATTR_FONT_UNDERLINE );
+ if ( !pUnderlineItem )
+ pUnderlineItem = &rItemSet.Get( ATTR_FONT_UNDERLINE );
+ eUnder = pUnderlineItem->GetValue();
+
+ const SvxOverlineItem* pOverlineItem = pCondSet->GetItemIfSet( ATTR_FONT_OVERLINE );
+ if ( !pOverlineItem )
+ pOverlineItem = &rItemSet.Get( ATTR_FONT_OVERLINE );
+ eOver = pOverlineItem->GetValue();
+
+ const SvxWordLineModeItem* pWordlineItem = pCondSet->GetItemIfSet( ATTR_FONT_WORDLINE );
+ if ( !pWordlineItem )
+ pWordlineItem = &rItemSet.Get( ATTR_FONT_WORDLINE );
+ bWordLine = pWordlineItem->GetValue();
+
+ const SvxCrossedOutItem* pCrossedOutItem = pCondSet->GetItemIfSet( ATTR_FONT_CROSSEDOUT );
+ if ( !pCrossedOutItem )
+ pCrossedOutItem = &rItemSet.Get( ATTR_FONT_CROSSEDOUT );
+ eStrike = pCrossedOutItem->GetValue();
+
+ const SvxContourItem* pContourItem = pCondSet->GetItemIfSet( ATTR_FONT_CONTOUR );
+ if ( !pContourItem )
+ pContourItem = &rItemSet.Get( ATTR_FONT_CONTOUR );
+ bOutline = pContourItem->GetValue();
+
+ const SvxShadowedItem* pShadowedItem = pCondSet->GetItemIfSet( ATTR_FONT_SHADOWED );
+ if ( !pShadowedItem )
+ pShadowedItem = &rItemSet.Get( ATTR_FONT_SHADOWED );
+ bShadow = pShadowedItem->GetValue();
+
+ const SvxEmphasisMarkItem* pEmphasisMarkItem = pCondSet->GetItemIfSet( ATTR_FONT_EMPHASISMARK );
+ if ( !pEmphasisMarkItem )
+ pEmphasisMarkItem = &rItemSet.Get( ATTR_FONT_EMPHASISMARK );
+ eEmphasis = pEmphasisMarkItem->GetEmphasisMark();
+
+ const SvxCharReliefItem* pCharReliefItem = pCondSet->GetItemIfSet( ATTR_FONT_RELIEF );
+ if ( !pCharReliefItem )
+ pCharReliefItem = &rItemSet.Get( ATTR_FONT_RELIEF );
+ eRelief = pCharReliefItem->GetValue();
+
+ const SvxLanguageItem* pLanguageItem = pCondSet->GetItemIfSet( nLangId );
+ if ( !pLanguageItem )
+ pLanguageItem = &rItemSet.Get( nLangId );
+ eLang = pLanguageItem->GetLanguage();
}
else // Everything from rItemSet
{
- pFontAttr = &static_cast<const SvxFontItem&>(rItemSet.Get( nFontId ));
- nFontHeight = static_cast<const SvxFontHeightItem&>(
- rItemSet.Get( nHeightId )).GetHeight();
- eWeight = static_cast<const SvxWeightItem&>(
- rItemSet.Get( nWeightId )).GetValue();
- eItalic = static_cast<const SvxPostureItem&>(
- rItemSet.Get( nPostureId )).GetValue();
+ pFontAttr = &rItemSet.Get( nFontId );
+ nFontHeight = rItemSet.Get( nHeightId ).GetHeight();
+ eWeight = rItemSet.Get( nWeightId ).GetValue();
+ eItalic = rItemSet.Get( nPostureId ).GetValue();
eUnder = rItemSet.Get( ATTR_FONT_UNDERLINE ).GetValue();
eOver = rItemSet.Get( ATTR_FONT_OVERLINE ).GetValue();
bWordLine = rItemSet.Get( ATTR_FONT_WORDLINE ).GetValue();
@@ -314,9 +699,8 @@ void ScPatternAttr::GetFont(
bShadow = rItemSet.Get( ATTR_FONT_SHADOWED ).GetValue();
eEmphasis = rItemSet.Get( ATTR_FONT_EMPHASISMARK ).GetEmphasisMark();
eRelief = rItemSet.Get( ATTR_FONT_RELIEF ).GetValue();
- aColor = rItemSet.Get( ATTR_FONT_COLOR ).GetValue();
// for graphite language features
- eLang = static_cast<const SvxLanguageItem&>(rItemSet.Get( nLangId )).GetLanguage();
+ eLang = rItemSet.Get( nLangId ).GetLanguage();
}
OSL_ENSURE(pFontAttr,"Oops?");
@@ -362,32 +746,71 @@ void ScPatternAttr::GetFont(
rFont.SetFontSize( Size( 0, static_cast<tools::Long>(nFontHeight) ) );
}
- // determine effective font color
+ // set font effects
+ rFont.SetWeight( eWeight );
+ rFont.SetItalic( eItalic );
+ rFont.SetUnderline( eUnder );
+ rFont.SetOverline( eOver );
+ rFont.SetWordLineMode( bWordLine );
+ rFont.SetStrikeout( eStrike );
+ rFont.SetOutline( bOutline );
+ rFont.SetShadow( bShadow );
+ rFont.SetEmphasisMark( eEmphasis );
+ rFont.SetRelief( eRelief );
+ rFont.SetTransparent( true );
+}
- if ( ( aColor == COL_AUTO && eAutoMode != SC_AUTOCOL_RAW ) ||
- eAutoMode == SC_AUTOCOL_IGNOREFONT || eAutoMode == SC_AUTOCOL_IGNOREALL )
+void ScPatternAttr::fillColor(model::ComplexColor& rComplexColor, const SfxItemSet& rItemSet, ScAutoFontColorMode eAutoMode, const SfxItemSet* pCondSet, const Color* pBackConfigColor, const Color* pTextConfigColor)
+{
+ model::ComplexColor aComplexColor;
+
+ Color aColor;
+
+ SvxColorItem const* pColorItem = nullptr;
+
+ if (pCondSet)
+ pColorItem = pCondSet->GetItemIfSet(ATTR_FONT_COLOR);
+
+ if (!pColorItem)
+ pColorItem = &rItemSet.Get(ATTR_FONT_COLOR);
+
+ if (pColorItem)
{
- if ( eAutoMode == SC_AUTOCOL_BLACK )
- aColor = COL_BLACK;
+ aComplexColor = pColorItem->getComplexColor();
+ aColor = pColorItem->GetValue();
+ }
+
+ if (aComplexColor.getType() == model::ColorType::Unused)
+ {
+ aComplexColor.setColor(aColor);
+ }
+
+ if ((aColor == COL_AUTO && eAutoMode != ScAutoFontColorMode::Raw)
+ || eAutoMode == ScAutoFontColorMode::IgnoreFont
+ || eAutoMode == ScAutoFontColorMode::IgnoreAll)
+ {
+ // get background color from conditional or own set
+ Color aBackColor;
+ if ( pCondSet )
+ {
+ const SvxBrushItem* pItem = pCondSet->GetItemIfSet(ATTR_BACKGROUND);
+ if (!pItem)
+ pItem = &rItemSet.Get(ATTR_BACKGROUND);
+ aBackColor = pItem->GetColor();
+ }
else
{
- // get background color from conditional or own set
- Color aBackColor;
- if ( pCondSet )
- {
- const SfxPoolItem* pItem;
- if ( pCondSet->GetItemState( ATTR_BACKGROUND, true, &pItem ) != SfxItemState::SET )
- pItem = &rItemSet.Get( ATTR_BACKGROUND );
- aBackColor = static_cast<const SvxBrushItem*>(pItem)->GetColor();
- }
- else
- aBackColor = rItemSet.Get( ATTR_BACKGROUND ).GetColor();
+ aBackColor = rItemSet.Get(ATTR_BACKGROUND).GetColor();
+ }
- // if background color attribute is transparent, use window color for brightness comparisons
- if ( aBackColor == COL_TRANSPARENT ||
- eAutoMode == SC_AUTOCOL_IGNOREBACK || eAutoMode == SC_AUTOCOL_IGNOREALL )
+ // if background color attribute is transparent, use window color for brightness comparisons
+ if (aBackColor == COL_TRANSPARENT
+ || eAutoMode == ScAutoFontColorMode::IgnoreBack
+ || eAutoMode == ScAutoFontColorMode::IgnoreAll)
+ {
+ if (!comphelper::LibreOfficeKit::isActive())
{
- if ( eAutoMode == SC_AUTOCOL_PRINT )
+ if ( eAutoMode == ScAutoFontColorMode::Print )
aBackColor = COL_WHITE;
else if ( pBackConfigColor )
{
@@ -397,157 +820,152 @@ void ScPatternAttr::GetFont(
else
aBackColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
}
-
- // get system text color for comparison
- Color aSysTextColor;
- if ( eAutoMode == SC_AUTOCOL_PRINT )
- aSysTextColor = COL_BLACK;
- else if ( pTextConfigColor )
- {
- // pTextConfigColor can be used to avoid repeated lookup of the configured color
- aSysTextColor = *pTextConfigColor;
- }
else
- aSysTextColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
-
- // select the resulting color
- if ( aBackColor.IsDark() && aSysTextColor.IsDark() )
- {
- // use white instead of dark on dark
- aColor = COL_WHITE;
- }
- else if ( aBackColor.IsBright() && aSysTextColor.IsBright() )
{
- // use black instead of bright on bright
- aColor = COL_BLACK;
- }
- else
- {
- // use aSysTextColor (black for SC_AUTOCOL_PRINT, from style settings otherwise)
- aColor = aSysTextColor;
+ // Get document color from current view instead
+ SfxViewShell* pSfxViewShell = SfxViewShell::Current();
+ ScTabViewShell* pViewShell = dynamic_cast<ScTabViewShell*>(pSfxViewShell);
+ if (pViewShell)
+ {
+ const ScViewRenderingOptions& rViewRenderingOptions = pViewShell->GetViewRenderingData();
+ aBackColor = rViewRenderingOptions.GetDocColor();
+ }
}
}
- }
- // set font effects
- rFont.SetWeight( eWeight );
- rFont.SetItalic( eItalic );
- rFont.SetUnderline( eUnder );
- rFont.SetOverline( eOver );
- rFont.SetWordLineMode( bWordLine );
- rFont.SetStrikeout( eStrike );
- rFont.SetOutline( bOutline );
- rFont.SetShadow( bShadow );
- rFont.SetEmphasisMark( eEmphasis );
- rFont.SetRelief( eRelief );
- rFont.SetColor( aColor );
- rFont.SetTransparent( true );
-}
+ // get system text color for comparison
+ Color aSysTextColor;
+ if (eAutoMode == ScAutoFontColorMode::Print)
+ {
+ aSysTextColor = COL_BLACK;
+ }
+ else if (pTextConfigColor)
+ {
+ // pTextConfigColor can be used to avoid repeated lookup of the configured color
+ aSysTextColor = *pTextConfigColor;
+ }
+ else
+ {
+ aSysTextColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
+ }
-void ScPatternAttr::GetFont(
- vcl::Font& rFont, ScAutoFontColorMode eAutoMode,
- const OutputDevice* pOutDev, const Fraction* pScale,
- const SfxItemSet* pCondSet, SvtScriptType nScript,
- const Color* pBackConfigColor, const Color* pTextConfigColor ) const
-{
- GetFont( rFont, GetItemSet(), eAutoMode, pOutDev, pScale, pCondSet, nScript, pBackConfigColor, pTextConfigColor );
+ // select the resulting color
+ if ( aBackColor.IsDark() && aSysTextColor.IsDark() )
+ {
+ // use white instead of dark on dark
+ aColor = COL_WHITE;
+ }
+ else if ( aBackColor.IsBright() && aSysTextColor.IsBright() )
+ {
+ // use black instead of bright on bright
+ aColor = COL_BLACK;
+ }
+ else
+ {
+ // use aSysTextColor (black for ScAutoFontColorMode::Print, from style settings otherwise)
+ aColor = aSysTextColor;
+ }
+ }
+ aComplexColor.setFinalColor(aColor);
+ rComplexColor = aComplexColor;
}
ScDxfFont ScPatternAttr::GetDxfFont(const SfxItemSet& rItemSet, SvtScriptType nScript)
{
- sal_uInt16 nFontId, nHeightId, nWeightId, nPostureId, nLangId;
+ TypedWhichId<SvxFontItem> nFontId(0);
+ TypedWhichId<SvxFontHeightItem> nHeightId(0);
+ TypedWhichId<SvxWeightItem> nWeightId(0);
+ TypedWhichId<SvxPostureItem> nPostureId(0);
+ TypedWhichId<SvxLanguageItem> nLangId(0);
getFontIDsByScriptType(nScript, nFontId, nHeightId, nWeightId, nPostureId, nLangId);
- const SfxPoolItem* pItem;
ScDxfFont aReturn;
- if ( rItemSet.GetItemState( nFontId, true, &pItem ) == SfxItemState::SET )
+ if ( const SvxFontItem* pItem = rItemSet.GetItemIfSet( nFontId ) )
{
- pItem = &rItemSet.Get( nFontId );
- aReturn.pFontAttr = static_cast<const SvxFontItem*>(pItem);
+ aReturn.pFontAttr = pItem;
}
- if ( rItemSet.GetItemState( nHeightId, true, &pItem ) == SfxItemState::SET )
+ if ( const SvxFontHeightItem* pItem = rItemSet.GetItemIfSet( nHeightId ) )
{
- pItem = &rItemSet.Get( nHeightId );
- aReturn.nFontHeight = static_cast<const SvxFontHeightItem*>(pItem)->GetHeight();
+ aReturn.nFontHeight = pItem->GetHeight();
}
- if ( rItemSet.GetItemState( nWeightId, true, &pItem ) == SfxItemState::SET )
+ if ( const SvxWeightItem* pItem = rItemSet.GetItemIfSet( nWeightId ) )
{
- pItem = &rItemSet.Get( nWeightId );
- aReturn.eWeight = static_cast<const SvxWeightItem*>(pItem)->GetValue();
+ aReturn.eWeight = pItem->GetValue();
}
- if ( rItemSet.GetItemState( nPostureId, true, &pItem ) == SfxItemState::SET )
+ if ( const SvxPostureItem* pItem = rItemSet.GetItemIfSet( nPostureId ) )
{
- pItem = &rItemSet.Get( nPostureId );
- aReturn.eItalic = static_cast<const SvxPostureItem*>(pItem)->GetValue();
+ aReturn.eItalic = pItem->GetValue();
}
- if ( rItemSet.GetItemState( ATTR_FONT_UNDERLINE, true, &pItem ) == SfxItemState::SET )
+ if ( const SvxUnderlineItem* pItem = rItemSet.GetItemIfSet( ATTR_FONT_UNDERLINE ) )
{
pItem = &rItemSet.Get( ATTR_FONT_UNDERLINE );
- aReturn.eUnder = static_cast<const SvxUnderlineItem*>(pItem)->GetValue();
+ aReturn.eUnder = pItem->GetValue();
}
- if ( rItemSet.GetItemState( ATTR_FONT_OVERLINE, true, &pItem ) == SfxItemState::SET )
+ if ( const SvxOverlineItem* pItem = rItemSet.GetItemIfSet( ATTR_FONT_OVERLINE ) )
{
- pItem = &rItemSet.Get( ATTR_FONT_OVERLINE );
- aReturn.eOver = static_cast<const SvxOverlineItem*>(pItem)->GetValue();
+ aReturn.eOver = pItem->GetValue();
}
- if ( rItemSet.GetItemState( ATTR_FONT_WORDLINE, true, &pItem ) == SfxItemState::SET )
+ if ( const SvxWordLineModeItem* pItem = rItemSet.GetItemIfSet( ATTR_FONT_WORDLINE ) )
{
- pItem = &rItemSet.Get( ATTR_FONT_WORDLINE );
- aReturn.bWordLine = static_cast<const SvxWordLineModeItem*>(pItem)->GetValue();
+ aReturn.bWordLine = pItem->GetValue();
}
- if ( rItemSet.GetItemState( ATTR_FONT_CROSSEDOUT, true, &pItem ) == SfxItemState::SET )
+ if ( const SvxCrossedOutItem* pItem = rItemSet.GetItemIfSet( ATTR_FONT_CROSSEDOUT ) )
{
pItem = &rItemSet.Get( ATTR_FONT_CROSSEDOUT );
- aReturn.eStrike = static_cast<const SvxCrossedOutItem*>(pItem)->GetValue();
+ aReturn.eStrike = pItem->GetValue();
}
- if ( rItemSet.GetItemState( ATTR_FONT_CONTOUR, true, &pItem ) == SfxItemState::SET )
+ if ( const SvxContourItem* pItem = rItemSet.GetItemIfSet( ATTR_FONT_CONTOUR ) )
{
- pItem = &rItemSet.Get( ATTR_FONT_CONTOUR );
- aReturn.bOutline = static_cast<const SvxContourItem*>(pItem)->GetValue();
+ aReturn.bOutline = pItem->GetValue();
}
- if ( rItemSet.GetItemState( ATTR_FONT_SHADOWED, true, &pItem ) == SfxItemState::SET )
+ if ( const SvxShadowedItem* pItem = rItemSet.GetItemIfSet( ATTR_FONT_SHADOWED ) )
{
pItem = &rItemSet.Get( ATTR_FONT_SHADOWED );
- aReturn.bShadow = static_cast<const SvxShadowedItem*>(pItem)->GetValue();
+ aReturn.bShadow = pItem->GetValue();
}
- if ( rItemSet.GetItemState( ATTR_FONT_EMPHASISMARK, true, &pItem ) == SfxItemState::SET )
+ if ( const SvxEmphasisMarkItem* pItem = rItemSet.GetItemIfSet( ATTR_FONT_EMPHASISMARK ) )
{
- pItem = &rItemSet.Get( ATTR_FONT_EMPHASISMARK );
- aReturn.eEmphasis = static_cast<const SvxEmphasisMarkItem*>(pItem)->GetEmphasisMark();
+ aReturn.eEmphasis = pItem->GetEmphasisMark();
}
- if ( rItemSet.GetItemState( ATTR_FONT_RELIEF, true, &pItem ) == SfxItemState::SET )
+ if ( const SvxCharReliefItem* pItem = rItemSet.GetItemIfSet( ATTR_FONT_RELIEF ) )
{
- pItem = &rItemSet.Get( ATTR_FONT_RELIEF );
- aReturn.eRelief = static_cast<const SvxCharReliefItem*>(pItem)->GetValue();
+ aReturn.eRelief = pItem->GetValue();
}
- if ( rItemSet.GetItemState( ATTR_FONT_COLOR, true, &pItem ) == SfxItemState::SET )
+ if ( const SvxColorItem* pItem = rItemSet.GetItemIfSet( ATTR_FONT_COLOR ) )
{
- pItem = &rItemSet.Get( ATTR_FONT_COLOR );
- aReturn.aColor = static_cast<const SvxColorItem*>(pItem)->GetValue();
+ aReturn.aColor = pItem->GetValue();
}
- if ( rItemSet.GetItemState( nLangId, true, &pItem ) == SfxItemState::SET )
+ if ( const SvxLanguageItem* pItem = rItemSet.GetItemIfSet( nLangId ) )
{
- pItem = &rItemSet.Get( nLangId );
- aReturn.eLang = static_cast<const SvxLanguageItem*>(pItem)->GetLanguage();
+ aReturn.eLang = pItem->GetLanguage();
}
return aReturn;
}
+template <class T>
+static void lcl_populate( std::unique_ptr<T>& rxItem, TypedWhichId<T> nWhich, const SfxItemSet& rSrcSet, const SfxItemSet* pCondSet )
+{
+ const T* pItem = pCondSet->GetItemIfSet( nWhich );
+ if ( !pItem )
+ pItem = &rSrcSet.Get( nWhich );
+ rxItem.reset(pItem->Clone());
+}
+
void ScPatternAttr::FillToEditItemSet( SfxItemSet& rEditSet, const SfxItemSet& rSrcSet, const SfxItemSet* pCondSet )
{
// Read Items
@@ -576,106 +994,109 @@ void ScPatternAttr::FillToEditItemSet( SfxItemSet& rEditSet, const SfxItemSet& r
if ( pCondSet )
{
- const SfxPoolItem* pItem;
-
- if ( pCondSet->GetItemState( ATTR_FONT_COLOR, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_FONT_COLOR );
- aColorItem.reset(static_cast<SvxColorItem*>(pItem->Clone()));
-
- if ( pCondSet->GetItemState( ATTR_FONT, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_FONT );
- aFontItem.reset(static_cast<SvxFontItem*>(pItem->Clone()));
-
- if ( pCondSet->GetItemState( ATTR_CJK_FONT, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_CJK_FONT );
- aCjkFontItem.reset(static_cast<SvxFontItem*>(pItem->Clone()));
-
- if ( pCondSet->GetItemState( ATTR_CTL_FONT, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_CTL_FONT );
- aCtlFontItem.reset(static_cast<SvxFontItem*>(pItem->Clone()));
-
- if ( pCondSet->GetItemState( ATTR_FONT_HEIGHT, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_FONT_HEIGHT );
- nTHeight = static_cast<const SvxFontHeightItem*>(pItem)->GetHeight();
- if ( pCondSet->GetItemState( ATTR_CJK_FONT_HEIGHT, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_CJK_FONT_HEIGHT );
- nCjkTHeight = static_cast<const SvxFontHeightItem*>(pItem)->GetHeight();
- if ( pCondSet->GetItemState( ATTR_CTL_FONT_HEIGHT, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_CTL_FONT_HEIGHT );
- nCtlTHeight = static_cast<const SvxFontHeightItem*>(pItem)->GetHeight();
-
- if ( pCondSet->GetItemState( ATTR_FONT_WEIGHT, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_FONT_WEIGHT );
- eWeight = static_cast<const SvxWeightItem*>(pItem)->GetValue();
- if ( pCondSet->GetItemState( ATTR_CJK_FONT_WEIGHT, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_CJK_FONT_WEIGHT );
- eCjkWeight = static_cast<const SvxWeightItem*>(pItem)->GetValue();
- if ( pCondSet->GetItemState( ATTR_CTL_FONT_WEIGHT, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_CTL_FONT_WEIGHT );
- eCtlWeight = static_cast<const SvxWeightItem*>(pItem)->GetValue();
-
- if ( pCondSet->GetItemState( ATTR_FONT_POSTURE, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_FONT_POSTURE );
- eItalic = static_cast<const SvxPostureItem*>(pItem)->GetValue();
- if ( pCondSet->GetItemState( ATTR_CJK_FONT_POSTURE, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_CJK_FONT_POSTURE );
- eCjkItalic = static_cast<const SvxPostureItem*>(pItem)->GetValue();
- if ( pCondSet->GetItemState( ATTR_CTL_FONT_POSTURE, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_CTL_FONT_POSTURE );
- eCtlItalic = static_cast<const SvxPostureItem*>(pItem)->GetValue();
-
- if ( pCondSet->GetItemState( ATTR_FONT_UNDERLINE, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_FONT_UNDERLINE );
- aUnderlineItem.reset(static_cast<SvxUnderlineItem*>(pItem->Clone()));
-
- if ( pCondSet->GetItemState( ATTR_FONT_OVERLINE, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_FONT_OVERLINE );
- aOverlineItem.reset(static_cast<SvxOverlineItem*>(pItem->Clone()));
-
- if ( pCondSet->GetItemState( ATTR_FONT_WORDLINE, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_FONT_WORDLINE );
- bWordLine = static_cast<const SvxWordLineModeItem*>(pItem)->GetValue();
-
- if ( pCondSet->GetItemState( ATTR_FONT_CROSSEDOUT, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_FONT_CROSSEDOUT );
- eStrike = static_cast<const SvxCrossedOutItem*>(pItem)->GetValue();
-
- if ( pCondSet->GetItemState( ATTR_FONT_CONTOUR, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_FONT_CONTOUR );
- bOutline = static_cast<const SvxContourItem*>(pItem)->GetValue();
-
- if ( pCondSet->GetItemState( ATTR_FONT_SHADOWED, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_FONT_SHADOWED );
- bShadow = static_cast<const SvxShadowedItem*>(pItem)->GetValue();
-
- if ( pCondSet->GetItemState( ATTR_FORBIDDEN_RULES, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_FORBIDDEN_RULES );
- bForbidden = static_cast<const SvxForbiddenRuleItem*>(pItem)->GetValue();
-
- if ( pCondSet->GetItemState( ATTR_FONT_EMPHASISMARK, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_FONT_EMPHASISMARK );
- eEmphasis = static_cast<const SvxEmphasisMarkItem*>(pItem)->GetEmphasisMark();
- if ( pCondSet->GetItemState( ATTR_FONT_RELIEF, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_FONT_RELIEF );
- eRelief = static_cast<const SvxCharReliefItem*>(pItem)->GetValue();
-
- if ( pCondSet->GetItemState( ATTR_FONT_LANGUAGE, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_FONT_LANGUAGE );
- eLang = static_cast<const SvxLanguageItem*>(pItem)->GetLanguage();
- if ( pCondSet->GetItemState( ATTR_CJK_FONT_LANGUAGE, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_CJK_FONT_LANGUAGE );
- eCjkLang = static_cast<const SvxLanguageItem*>(pItem)->GetLanguage();
- if ( pCondSet->GetItemState( ATTR_CTL_FONT_LANGUAGE, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_CTL_FONT_LANGUAGE );
- eCtlLang = static_cast<const SvxLanguageItem*>(pItem)->GetLanguage();
-
- if ( pCondSet->GetItemState( ATTR_HYPHENATE, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_HYPHENATE );
- bHyphenate = static_cast<const ScHyphenateCell*>(pItem)->GetValue();
-
- if ( pCondSet->GetItemState( ATTR_WRITINGDIR, true, &pItem ) != SfxItemState::SET )
- pItem = &rSrcSet.Get( ATTR_WRITINGDIR );
- eDirection = static_cast<const SvxFrameDirectionItem*>(pItem)->GetValue();
+ lcl_populate(aColorItem, ATTR_FONT_COLOR, rSrcSet, pCondSet);
+ lcl_populate(aFontItem, ATTR_FONT, rSrcSet, pCondSet);
+ lcl_populate(aCjkFontItem, ATTR_CJK_FONT, rSrcSet, pCondSet);
+ lcl_populate(aCtlFontItem, ATTR_CTL_FONT, rSrcSet, pCondSet);
+
+ const SvxFontHeightItem* pFontHeightItem = pCondSet->GetItemIfSet( ATTR_FONT_HEIGHT );
+ if (!pFontHeightItem)
+ pFontHeightItem = &rSrcSet.Get( ATTR_FONT_HEIGHT );
+ nTHeight = pFontHeightItem->GetHeight();
+ pFontHeightItem = pCondSet->GetItemIfSet( ATTR_CJK_FONT_HEIGHT );
+ if ( !pFontHeightItem )
+ pFontHeightItem = &rSrcSet.Get( ATTR_CJK_FONT_HEIGHT );
+ nCjkTHeight = pFontHeightItem->GetHeight();
+ pFontHeightItem = pCondSet->GetItemIfSet( ATTR_CTL_FONT_HEIGHT );
+ if ( !pFontHeightItem )
+ pFontHeightItem = &rSrcSet.Get( ATTR_CTL_FONT_HEIGHT );
+ nCtlTHeight = pFontHeightItem->GetHeight();
+
+ const SvxWeightItem* pWeightItem = pCondSet->GetItemIfSet( ATTR_FONT_WEIGHT );
+ if ( !pWeightItem )
+ pWeightItem = &rSrcSet.Get( ATTR_FONT_WEIGHT );
+ eWeight = pWeightItem->GetValue();
+ pWeightItem = pCondSet->GetItemIfSet( ATTR_CJK_FONT_WEIGHT );
+ if ( !pWeightItem )
+ pWeightItem = &rSrcSet.Get( ATTR_CJK_FONT_WEIGHT );
+ eCjkWeight = pWeightItem->GetValue();
+ pWeightItem = pCondSet->GetItemIfSet( ATTR_CTL_FONT_WEIGHT );
+ if ( !pWeightItem )
+ pWeightItem = &rSrcSet.Get( ATTR_CTL_FONT_WEIGHT );
+ eCtlWeight = pWeightItem->GetValue();
+
+ const SvxPostureItem* pPostureItem = pCondSet->GetItemIfSet( ATTR_FONT_POSTURE );
+ if ( !pPostureItem )
+ pPostureItem = &rSrcSet.Get( ATTR_FONT_POSTURE );
+ eItalic = pPostureItem->GetValue();
+ pPostureItem = pCondSet->GetItemIfSet( ATTR_CJK_FONT_POSTURE );
+ if ( !pPostureItem )
+ pPostureItem = &rSrcSet.Get( ATTR_CJK_FONT_POSTURE );
+ eCjkItalic = pPostureItem->GetValue();
+ pPostureItem = pCondSet->GetItemIfSet( ATTR_CTL_FONT_POSTURE );
+ if ( !pPostureItem )
+ pPostureItem = &rSrcSet.Get( ATTR_CTL_FONT_POSTURE );
+ eCtlItalic = pPostureItem->GetValue();
+
+ lcl_populate(aUnderlineItem, ATTR_FONT_UNDERLINE, rSrcSet, pCondSet);
+ lcl_populate(aOverlineItem, ATTR_FONT_OVERLINE, rSrcSet, pCondSet);
+
+ const SvxWordLineModeItem* pWordLineModeItem = pCondSet->GetItemIfSet( ATTR_FONT_WORDLINE );
+ if ( !pWordLineModeItem )
+ pWordLineModeItem = &rSrcSet.Get( ATTR_FONT_WORDLINE );
+ bWordLine = pWordLineModeItem->GetValue();
+
+ const SvxCrossedOutItem* pCrossedOutItem = pCondSet->GetItemIfSet( ATTR_FONT_CROSSEDOUT );
+ if ( !pCrossedOutItem )
+ pCrossedOutItem = &rSrcSet.Get( ATTR_FONT_CROSSEDOUT );
+ eStrike = pCrossedOutItem->GetValue();
+
+ const SvxContourItem* pContourItem = pCondSet->GetItemIfSet( ATTR_FONT_CONTOUR );
+ if ( !pContourItem )
+ pContourItem = &rSrcSet.Get( ATTR_FONT_CONTOUR );
+ bOutline = pContourItem->GetValue();
+
+ const SvxShadowedItem* pShadowedItem = pCondSet->GetItemIfSet( ATTR_FONT_SHADOWED );
+ if ( !pShadowedItem )
+ pShadowedItem = &rSrcSet.Get( ATTR_FONT_SHADOWED );
+ bShadow = pShadowedItem->GetValue();
+
+ const SvxForbiddenRuleItem* pForbiddenRuleItem = pCondSet->GetItemIfSet( ATTR_FORBIDDEN_RULES );
+ if ( !pForbiddenRuleItem )
+ pForbiddenRuleItem = &rSrcSet.Get( ATTR_FORBIDDEN_RULES );
+ bForbidden = pForbiddenRuleItem->GetValue();
+
+ const SvxEmphasisMarkItem* pEmphasisMarkItem = pCondSet->GetItemIfSet( ATTR_FONT_EMPHASISMARK );
+ if ( !pEmphasisMarkItem )
+ pEmphasisMarkItem = &rSrcSet.Get( ATTR_FONT_EMPHASISMARK );
+ eEmphasis = pEmphasisMarkItem->GetEmphasisMark();
+ const SvxCharReliefItem* pCharReliefItem = pCondSet->GetItemIfSet( ATTR_FONT_RELIEF );
+ if ( !pCharReliefItem )
+ pCharReliefItem = &rSrcSet.Get( ATTR_FONT_RELIEF );
+ eRelief = pCharReliefItem->GetValue();
+
+ const SvxLanguageItem* pLanguageItem = pCondSet->GetItemIfSet( ATTR_FONT_LANGUAGE );
+ if ( !pLanguageItem )
+ pLanguageItem = &rSrcSet.Get( ATTR_FONT_LANGUAGE );
+ eLang = pLanguageItem->GetLanguage();
+ pLanguageItem = pCondSet->GetItemIfSet( ATTR_CJK_FONT_LANGUAGE );
+ if ( !pLanguageItem )
+ pLanguageItem = &rSrcSet.Get( ATTR_CJK_FONT_LANGUAGE );
+ eCjkLang = pLanguageItem->GetLanguage();
+ pLanguageItem = pCondSet->GetItemIfSet( ATTR_CTL_FONT_LANGUAGE );
+ if ( !pLanguageItem )
+ pLanguageItem = &rSrcSet.Get( ATTR_CTL_FONT_LANGUAGE );
+ eCtlLang = pLanguageItem->GetLanguage();
+
+ const ScHyphenateCell* pHyphenateCell = pCondSet->GetItemIfSet( ATTR_HYPHENATE );
+ if ( !pHyphenateCell )
+ pHyphenateCell = &rSrcSet.Get( ATTR_HYPHENATE );
+ bHyphenate = pHyphenateCell->GetValue();
+
+ const SvxFrameDirectionItem* pFrameDirectionItem = pCondSet->GetItemIfSet( ATTR_WRITINGDIR );
+ if ( !pFrameDirectionItem )
+ pFrameDirectionItem = &rSrcSet.Get( ATTR_WRITINGDIR );
+ eDirection = pFrameDirectionItem->GetValue();
}
else // Everything directly from Pattern
{
@@ -728,13 +1149,13 @@ void ScPatternAttr::FillToEditItemSet( SfxItemSet& rEditSet, const SfxItemSet& r
else
{
// tdf#125054 adapt WhichID
- rEditSet.Put( *aColorItem, EE_CHAR_COLOR );
+ rEditSet.PutAsTargetWhich( std::move(aColorItem), EE_CHAR_COLOR );
}
// tdf#125054 adapt WhichID
- rEditSet.Put( *aFontItem, EE_CHAR_FONTINFO );
- rEditSet.Put( *aCjkFontItem, EE_CHAR_FONTINFO_CJK );
- rEditSet.Put( *aCtlFontItem, EE_CHAR_FONTINFO_CTL );
+ rEditSet.PutAsTargetWhich( std::move(aFontItem), EE_CHAR_FONTINFO );
+ rEditSet.PutAsTargetWhich( std::move(aCjkFontItem), EE_CHAR_FONTINFO_CJK );
+ rEditSet.PutAsTargetWhich( std::move(aCtlFontItem), EE_CHAR_FONTINFO_CTL );
rEditSet.Put( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT ) );
rEditSet.Put( SvxFontHeightItem( nCjkHeight, 100, EE_CHAR_FONTHEIGHT_CJK ) );
@@ -744,8 +1165,8 @@ void ScPatternAttr::FillToEditItemSet( SfxItemSet& rEditSet, const SfxItemSet& r
rEditSet.Put( SvxWeightItem ( eCtlWeight, EE_CHAR_WEIGHT_CTL ) );
// tdf#125054 adapt WhichID
- rEditSet.Put( *aUnderlineItem, EE_CHAR_UNDERLINE );
- rEditSet.Put( *aOverlineItem, EE_CHAR_OVERLINE );
+ rEditSet.PutAsTargetWhich( std::move(aUnderlineItem), EE_CHAR_UNDERLINE );
+ rEditSet.PutAsTargetWhich( std::move(aOverlineItem), EE_CHAR_OVERLINE );
rEditSet.Put( SvxWordLineModeItem( bWordLine, EE_CHAR_WLM ) );
rEditSet.Put( SvxCrossedOutItem( eStrike, EE_CHAR_STRIKEOUT ) );
@@ -779,86 +1200,86 @@ void ScPatternAttr::FillEditItemSet( SfxItemSet* pEditSet, const SfxItemSet* pCo
void ScPatternAttr::GetFromEditItemSet( SfxItemSet& rDestSet, const SfxItemSet& rEditSet )
{
- const SfxPoolItem* pItem;
-
- if (rEditSet.GetItemState(EE_CHAR_COLOR,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( *static_cast<const SvxColorItem*>(pItem), ATTR_FONT_COLOR );
-
- if (rEditSet.GetItemState(EE_CHAR_FONTINFO,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( *static_cast<const SvxFontItem*>(pItem), ATTR_FONT );
- if (rEditSet.GetItemState(EE_CHAR_FONTINFO_CJK,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( *static_cast<const SvxFontItem*>(pItem), ATTR_CJK_FONT );
- if (rEditSet.GetItemState(EE_CHAR_FONTINFO_CTL,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( *static_cast<const SvxFontItem*>(pItem), ATTR_CTL_FONT );
-
- if (rEditSet.GetItemState(EE_CHAR_FONTHEIGHT,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( SvxFontHeightItem( convertMm100ToTwip( static_cast<const SvxFontHeightItem*>(pItem)->GetHeight() ),
+ if (const SvxColorItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_COLOR))
+ rDestSet.PutAsTargetWhich( *pItem, ATTR_FONT_COLOR );
+
+ if (const SvxFontItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_FONTINFO))
+ rDestSet.PutAsTargetWhich( *pItem, ATTR_FONT );
+ if (const SvxFontItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_FONTINFO_CJK))
+ rDestSet.PutAsTargetWhich( *pItem, ATTR_CJK_FONT );
+ if (const SvxFontItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_FONTINFO_CTL))
+ rDestSet.PutAsTargetWhich( *pItem, ATTR_CTL_FONT );
+
+ if (const SvxFontHeightItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_FONTHEIGHT))
+ rDestSet.Put( SvxFontHeightItem(o3tl::toTwips(pItem->GetHeight(), o3tl::Length::mm100),
100, ATTR_FONT_HEIGHT ) );
- if (rEditSet.GetItemState(EE_CHAR_FONTHEIGHT_CJK,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( SvxFontHeightItem( convertMm100ToTwip( static_cast<const SvxFontHeightItem*>(pItem)->GetHeight() ),
+ if (const SvxFontHeightItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_FONTHEIGHT_CJK))
+ rDestSet.Put( SvxFontHeightItem(o3tl::toTwips(pItem->GetHeight(), o3tl::Length::mm100),
100, ATTR_CJK_FONT_HEIGHT ) );
- if (rEditSet.GetItemState(EE_CHAR_FONTHEIGHT_CTL,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( SvxFontHeightItem( convertMm100ToTwip( static_cast<const SvxFontHeightItem*>(pItem)->GetHeight() ),
+ if (const SvxFontHeightItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_FONTHEIGHT_CTL))
+ rDestSet.Put( SvxFontHeightItem(o3tl::toTwips(pItem->GetHeight(), o3tl::Length::mm100),
100, ATTR_CTL_FONT_HEIGHT ) );
- if (rEditSet.GetItemState(EE_CHAR_WEIGHT,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( SvxWeightItem( static_cast<const SvxWeightItem*>(pItem)->GetValue(),
+ if (const SvxWeightItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_WEIGHT))
+ rDestSet.Put( SvxWeightItem( pItem->GetValue(),
ATTR_FONT_WEIGHT) );
- if (rEditSet.GetItemState(EE_CHAR_WEIGHT_CJK,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( SvxWeightItem( static_cast<const SvxWeightItem*>(pItem)->GetValue(),
+ if (const SvxWeightItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_WEIGHT_CJK))
+ rDestSet.Put( SvxWeightItem( pItem->GetValue(),
ATTR_CJK_FONT_WEIGHT) );
- if (rEditSet.GetItemState(EE_CHAR_WEIGHT_CTL,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( SvxWeightItem( static_cast<const SvxWeightItem*>(pItem)->GetValue(),
+ if (const SvxWeightItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_WEIGHT_CTL))
+ rDestSet.Put( SvxWeightItem( pItem->GetValue(),
ATTR_CTL_FONT_WEIGHT) );
// SvxTextLineItem contains enum and color
- if (rEditSet.GetItemState(EE_CHAR_UNDERLINE,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( *static_cast<const SvxUnderlineItem*>(pItem), ATTR_FONT_UNDERLINE );
- if (rEditSet.GetItemState(EE_CHAR_OVERLINE,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( *static_cast<const SvxOverlineItem*>(pItem), ATTR_FONT_OVERLINE );
- if (rEditSet.GetItemState(EE_CHAR_WLM,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( SvxWordLineModeItem( static_cast<const SvxWordLineModeItem*>(pItem)->GetValue(),
+ if (const SvxUnderlineItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_UNDERLINE))
+ rDestSet.PutAsTargetWhich( *pItem, ATTR_FONT_UNDERLINE );
+ if (const SvxOverlineItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_OVERLINE))
+ rDestSet.PutAsTargetWhich( *pItem, ATTR_FONT_OVERLINE );
+ if (const SvxWordLineModeItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_WLM))
+ rDestSet.Put( SvxWordLineModeItem( pItem->GetValue(),
ATTR_FONT_WORDLINE) );
- if (rEditSet.GetItemState(EE_CHAR_STRIKEOUT,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( SvxCrossedOutItem( static_cast<const SvxCrossedOutItem*>(pItem)->GetValue(),
+ if (const SvxCrossedOutItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_STRIKEOUT))
+ rDestSet.Put( SvxCrossedOutItem( pItem->GetValue(),
ATTR_FONT_CROSSEDOUT) );
- if (rEditSet.GetItemState(EE_CHAR_ITALIC,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( SvxPostureItem( static_cast<const SvxPostureItem*>(pItem)->GetValue(),
+ if (const SvxPostureItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_ITALIC))
+ rDestSet.Put( SvxPostureItem( pItem->GetValue(),
ATTR_FONT_POSTURE) );
- if (rEditSet.GetItemState(EE_CHAR_ITALIC_CJK,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( SvxPostureItem( static_cast<const SvxPostureItem*>(pItem)->GetValue(),
+ if (const SvxPostureItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_ITALIC_CJK))
+ rDestSet.Put( SvxPostureItem( pItem->GetValue(),
ATTR_CJK_FONT_POSTURE) );
- if (rEditSet.GetItemState(EE_CHAR_ITALIC_CTL,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( SvxPostureItem( static_cast<const SvxPostureItem*>(pItem)->GetValue(),
+ if (const SvxPostureItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_ITALIC_CTL))
+ rDestSet.Put( SvxPostureItem( pItem->GetValue(),
ATTR_CTL_FONT_POSTURE) );
- if (rEditSet.GetItemState(EE_CHAR_OUTLINE,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( SvxContourItem( static_cast<const SvxContourItem*>(pItem)->GetValue(),
+ if (const SvxContourItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_OUTLINE))
+ rDestSet.Put( SvxContourItem( pItem->GetValue(),
ATTR_FONT_CONTOUR) );
- if (rEditSet.GetItemState(EE_CHAR_SHADOW,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( SvxShadowedItem( static_cast<const SvxShadowedItem*>(pItem)->GetValue(),
+ if (const SvxShadowedItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_SHADOW))
+ rDestSet.Put( SvxShadowedItem( pItem->GetValue(),
ATTR_FONT_SHADOWED) );
- if (rEditSet.GetItemState(EE_CHAR_EMPHASISMARK,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( SvxEmphasisMarkItem( static_cast<const SvxEmphasisMarkItem*>(pItem)->GetEmphasisMark(),
+ if (const SvxEmphasisMarkItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_EMPHASISMARK))
+ rDestSet.Put( SvxEmphasisMarkItem( pItem->GetEmphasisMark(),
ATTR_FONT_EMPHASISMARK) );
- if (rEditSet.GetItemState(EE_CHAR_RELIEF,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( SvxCharReliefItem( static_cast<const SvxCharReliefItem*>(pItem)->GetValue(),
+ if (const SvxCharReliefItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_RELIEF))
+ rDestSet.Put( SvxCharReliefItem( pItem->GetValue(),
ATTR_FONT_RELIEF) );
- if (rEditSet.GetItemState(EE_CHAR_LANGUAGE,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( SvxLanguageItem(static_cast<const SvxLanguageItem*>(pItem)->GetValue(), ATTR_FONT_LANGUAGE) );
- if (rEditSet.GetItemState(EE_CHAR_LANGUAGE_CJK,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( SvxLanguageItem(static_cast<const SvxLanguageItem*>(pItem)->GetValue(), ATTR_CJK_FONT_LANGUAGE) );
- if (rEditSet.GetItemState(EE_CHAR_LANGUAGE_CTL,true,&pItem) == SfxItemState::SET)
- rDestSet.Put( SvxLanguageItem(static_cast<const SvxLanguageItem*>(pItem)->GetValue(), ATTR_CTL_FONT_LANGUAGE) );
+ if (const SvxLanguageItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_LANGUAGE))
+ rDestSet.Put( SvxLanguageItem(pItem->GetValue(), ATTR_FONT_LANGUAGE) );
+ if (const SvxLanguageItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_LANGUAGE_CJK))
+ rDestSet.Put( SvxLanguageItem(pItem->GetValue(), ATTR_CJK_FONT_LANGUAGE) );
+ if (const SvxLanguageItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_LANGUAGE_CTL))
+ rDestSet.Put( SvxLanguageItem(pItem->GetValue(), ATTR_CTL_FONT_LANGUAGE) );
+
+ const SvxAdjustItem* pAdjustItem = rEditSet.GetItemIfSet(EE_PARA_JUST);
- if (rEditSet.GetItemState(EE_PARA_JUST,true,&pItem) != SfxItemState::SET)
+ if (!pAdjustItem)
return;
SvxCellHorJustify eVal;
- switch ( static_cast<const SvxAdjustItem*>(pItem)->GetAdjust() )
+ switch ( pAdjustItem->GetAdjust() )
{
case SvxAdjust::Left:
// EditEngine Default is always set in the GetAttribs() ItemSet !
@@ -892,7 +1313,7 @@ void ScPatternAttr::GetFromEditItemSet( const SfxItemSet* pEditSet )
if( !pEditSet )
return;
GetFromEditItemSet( GetItemSet(), *pEditSet );
- mxHashCode.reset();
+ InvalidateCaches();
}
void ScPatternAttr::FillEditParaItems( SfxItemSet* pEditSet ) const
@@ -932,19 +1353,19 @@ void ScPatternAttr::DeleteUnchanged( const ScPatternAttr* pOldAttrs )
if ( eOldState == SfxItemState::SET )
{
// item is set in OldAttrs (or its parent) -> compare pointers
- if ( pThisItem == pOldItem )
+ if (SfxPoolItem::areSame( pThisItem, pOldItem ))
{
rThisSet.ClearItem( nSubWhich );
- mxHashCode.reset();
+ InvalidateCaches();
}
}
- else if ( eOldState != SfxItemState::DONTCARE )
+ else if ( eOldState != SfxItemState::INVALID )
{
// not set in OldAttrs -> compare item value to default item
- if ( *pThisItem == rThisSet.GetPool()->GetDefaultItem( nSubWhich ) )
+ if ( *pThisItem == rThisSet.GetPool()->GetUserOrPoolDefaultItem( nSubWhich ) )
{
rThisSet.ClearItem( nSubWhich );
- mxHashCode.reset();
+ InvalidateCaches();
}
}
}
@@ -965,7 +1386,7 @@ void ScPatternAttr::ClearItems( const sal_uInt16* pWhich )
SfxItemSet& rSet = GetItemSet();
for (sal_uInt16 i=0; pWhich[i]; i++)
rSet.ClearItem(pWhich[i]);
- mxHashCode.reset();
+ InvalidateCaches();
}
static SfxStyleSheetBase* lcl_CopyStyleToPool
@@ -998,11 +1419,11 @@ static SfxStyleSheetBase* lcl_CopyStyleToPool
// number format exchange list has to be handled here, too
// (only called for cell styles)
- const SfxPoolItem* pSrcItem;
+ const SfxUInt32Item* pSrcItem;
if ( pFormatExchangeList &&
- rSrcSet.GetItemState( ATTR_VALUE_FORMAT, false, &pSrcItem ) == SfxItemState::SET )
+ (pSrcItem = rSrcSet.GetItemIfSet( ATTR_VALUE_FORMAT, false )) )
{
- sal_uLong nOldFormat = static_cast<const SfxUInt32Item*>(pSrcItem)->GetValue();
+ sal_uInt32 nOldFormat = pSrcItem->GetValue();
SvNumberFormatterIndexTable::const_iterator it = pFormatExchangeList->find(nOldFormat);
if (it != pFormatExchangeList->end())
{
@@ -1027,15 +1448,13 @@ static SfxStyleSheetBase* lcl_CopyStyleToPool
return pDestStyle;
}
-ScPatternAttr* ScPatternAttr::PutInPool( ScDocument* pDestDoc, ScDocument* pSrcDoc ) const
+CellAttributeHolder ScPatternAttr::MigrateToDocument( ScDocument* pDestDoc, ScDocument* pSrcDoc ) const
{
const SfxItemSet* pSrcSet = &GetItemSet();
-
- ScPatternAttr aDestPattern( pDestDoc->GetPool() );
- SfxItemSet* pDestSet = &aDestPattern.GetItemSet();
+ ScPatternAttr* pDestPattern(new ScPatternAttr(pDestDoc->getCellAttributeHelper()));
+ SfxItemSet* pDestSet(&pDestPattern->GetItemSet());
// Copy cell pattern style to other document:
-
if ( pDestDoc != pSrcDoc )
{
OSL_ENSURE( pStyle, "Missing Pattern-Style! :-/" );
@@ -1048,7 +1467,7 @@ ScPatternAttr* ScPatternAttr::PutInPool( ScDocument* pDestDoc, ScDocument* pSrcD
pDestDoc->GetStyleSheetPool(),
pDestDoc->GetFormatExchangeList() );
- aDestPattern.SetStyleSheet( static_cast<ScStyleSheet*>(pStyleCpy) );
+ pDestPattern->SetStyleSheet( static_cast<ScStyleSheet*>(pStyleCpy) );
}
for ( sal_uInt16 nAttrId = ATTR_PATTERN_START; nAttrId <= ATTR_PATTERN_END; nAttrId++ )
@@ -1063,11 +1482,11 @@ ScPatternAttr* ScPatternAttr::PutInPool( ScDocument* pDestDoc, ScDocument* pSrcD
{
// Copy validity to the new document
- sal_uLong nNewIndex = 0;
+ sal_uInt32 nNewIndex = 0;
ScValidationDataList* pSrcList = pSrcDoc->GetValidationList();
if ( pSrcList )
{
- sal_uLong nOldIndex = static_cast<const SfxUInt32Item*>(pSrcItem)->GetValue();
+ sal_uInt32 nOldIndex = static_cast<const SfxUInt32Item*>(pSrcItem)->GetValue();
const ScValidationData* pOldData = pSrcList->GetData( nOldIndex );
if ( pOldData )
nNewIndex = pDestDoc->AddValidationEntry( *pOldData );
@@ -1078,7 +1497,7 @@ ScPatternAttr* ScPatternAttr::PutInPool( ScDocument* pDestDoc, ScDocument* pSrcD
{
// Number format to Exchange List
- sal_uLong nOldFormat = static_cast<const SfxUInt32Item*>(pSrcItem)->GetValue();
+ sal_uInt32 nOldFormat = static_cast<const SfxUInt32Item*>(pSrcItem)->GetValue();
SvNumberFormatterIndexTable::const_iterator it = pDestDoc->GetFormatExchangeList()->find(nOldFormat);
if (it != pDestDoc->GetFormatExchangeList()->end())
{
@@ -1089,80 +1508,119 @@ ScPatternAttr* ScPatternAttr::PutInPool( ScDocument* pDestDoc, ScDocument* pSrcD
if ( pNewItem )
{
- pDestSet->Put(*pNewItem);
+ pDestSet->Put(std::move(pNewItem));
}
else
pDestSet->Put(*pSrcItem);
}
}
- ScPatternAttr* pPatternAttr = const_cast<ScPatternAttr*>( &pDestDoc->GetPool()->Put(aDestPattern) );
- return pPatternAttr;
+ return CellAttributeHolder(pDestPattern, true);
}
bool ScPatternAttr::IsVisible() const
{
- const SfxItemSet& rSet = GetItemSet();
+ if (!mxVisible.has_value())
+ mxVisible = CalcVisible();
+ return *mxVisible;
+}
- const SfxPoolItem* pItem;
- SfxItemState eState;
+bool ScPatternAttr::CalcVisible() const
+{
+ const SfxItemSet& rSet = GetItemSet();
- eState = rSet.GetItemState( ATTR_BACKGROUND, true, &pItem );
- if ( eState == SfxItemState::SET )
- if ( static_cast<const SvxBrushItem*>(pItem)->GetColor() != COL_TRANSPARENT )
+ if ( const SvxBrushItem* pItem = rSet.GetItemIfSet( ATTR_BACKGROUND ) )
+ if ( pItem->GetColor() != COL_TRANSPARENT )
return true;
- eState = rSet.GetItemState( ATTR_BORDER, true, &pItem );
- if ( eState == SfxItemState::SET )
+ if ( const SvxBoxItem* pBoxItem = rSet.GetItemIfSet( ATTR_BORDER ) )
{
- const SvxBoxItem* pBoxItem = static_cast<const SvxBoxItem*>(pItem);
if ( pBoxItem->GetTop() || pBoxItem->GetBottom() ||
pBoxItem->GetLeft() || pBoxItem->GetRight() )
return true;
}
- eState = rSet.GetItemState( ATTR_BORDER_TLBR, true, &pItem );
- if ( eState == SfxItemState::SET )
- if( static_cast< const SvxLineItem* >( pItem )->GetLine() )
+ if ( const SvxLineItem* pItem = rSet.GetItemIfSet( ATTR_BORDER_TLBR ) )
+ if( pItem->GetLine() )
return true;
- eState = rSet.GetItemState( ATTR_BORDER_BLTR, true, &pItem );
- if ( eState == SfxItemState::SET )
- if( static_cast< const SvxLineItem* >( pItem )->GetLine() )
+ if ( const SvxLineItem* pItem = rSet.GetItemIfSet( ATTR_BORDER_BLTR ) )
+ if( pItem->GetLine() )
return true;
- eState = rSet.GetItemState( ATTR_SHADOW, true, &pItem );
- if ( eState == SfxItemState::SET )
- if ( static_cast<const SvxShadowItem*>(pItem)->GetLocation() != SvxShadowLocation::NONE )
+ if ( const SvxShadowItem* pItem = rSet.GetItemIfSet( ATTR_SHADOW ) )
+ if ( pItem->GetLocation() != SvxShadowLocation::NONE )
return true;
return false;
}
-static bool OneEqual( const SfxItemSet& rSet1, const SfxItemSet& rSet2, sal_uInt16 nId )
-{
- const SfxPoolItem* pItem1 = &rSet1.Get(nId);
- const SfxPoolItem* pItem2 = &rSet2.Get(nId);
- return ( pItem1 == pItem2 || *pItem1 == *pItem2 );
-}
-
bool ScPatternAttr::IsVisibleEqual( const ScPatternAttr& rOther ) const
{
- const SfxItemSet& rThisSet = GetItemSet();
- const SfxItemSet& rOtherSet = rOther.GetItemSet();
+ // This method is hot, so we do an optimised comparison here, by
+ // walking the two itemsets in parallel, avoiding doing repeated searches.
+ auto IsInterestingWhich = [](sal_uInt16 n)
+ {
+ return n == ATTR_BORDER_TLBR || n == ATTR_BORDER_BLTR || n == ATTR_BACKGROUND
+ || n == ATTR_BORDER || n == ATTR_SHADOW;
+ };
+ SfxWhichIter aIter1(GetItemSet());
+ SfxWhichIter aIter2(rOther.GetItemSet());
+ sal_uInt16 nWhich1 = aIter1.FirstWhich();
+ sal_uInt16 nWhich2 = aIter2.FirstWhich();
+ for (;;)
+ {
+ while (nWhich1 != nWhich2)
+ {
+ SfxWhichIter* pIterToIncrement;
+ sal_uInt16* pSmallerWhich;
+ if (nWhich1 == 0 || nWhich1 > nWhich2)
+ {
+ pSmallerWhich = &nWhich2;
+ pIterToIncrement = &aIter2;
+ }
+ else
+ {
+ pSmallerWhich = &nWhich1;
+ pIterToIncrement = &aIter1;
+ }
- return OneEqual( rThisSet, rOtherSet, ATTR_BACKGROUND ) &&
- OneEqual( rThisSet, rOtherSet, ATTR_BORDER ) &&
- OneEqual( rThisSet, rOtherSet, ATTR_BORDER_TLBR ) &&
- OneEqual( rThisSet, rOtherSet, ATTR_BORDER_BLTR ) &&
- OneEqual( rThisSet, rOtherSet, ATTR_SHADOW );
+ if (IsInterestingWhich(*pSmallerWhich))
+ {
+ // the iter with larger which has already passed this point, and has no interesting
+ // item available in the other - so indeed these are unequal
+ return false;
+ }
+ *pSmallerWhich = pIterToIncrement->NextWhich();
+ }
+
+ // Here nWhich1 == nWhich2
+
+ if (!nWhich1 /* && !nWhich2*/)
+ return true;
+
+ if (IsInterestingWhich(nWhich1))
+ {
+ const SfxPoolItem* pItem1 = nullptr;
+ const SfxPoolItem* pItem2 = nullptr;
+ SfxItemState state1 = aIter1.GetItemState(true, &pItem1);
+ SfxItemState state2 = aIter2.GetItemState(true, &pItem2);
+ if (state1 != state2
+ && (state1 < SfxItemState::DEFAULT || state2 < SfxItemState::DEFAULT))
+ return false;
+ if (!SfxPoolItem::areSame(pItem1, pItem2))
+ return false;
+ }
+ nWhich1 = aIter1.NextWhich();
+ nWhich2 = aIter2.NextWhich();
+ }
//TODO: also here only check really visible values !!!
}
const OUString* ScPatternAttr::GetStyleName() const
{
- return pName ? &*pName : ( pStyle ? &pStyle->GetName() : nullptr );
+ return moName ? &*moName : ( pStyle ? &pStyle->GetName() : nullptr );
}
void ScPatternAttr::SetStyleSheet( ScStyleSheet* pNewStyle, bool bClearDirectFormat )
@@ -1182,7 +1640,7 @@ void ScPatternAttr::SetStyleSheet( ScStyleSheet* pNewStyle, bool bClearDirectFor
}
rPatternSet.SetParent(&pNewStyle->GetItemSet());
pStyle = pNewStyle;
- pName.reset();
+ moName.reset();
}
else
{
@@ -1190,13 +1648,15 @@ void ScPatternAttr::SetStyleSheet( ScStyleSheet* pNewStyle, bool bClearDirectFor
GetItemSet().SetParent(nullptr);
pStyle = nullptr;
}
+ InvalidateCaches();
}
-void ScPatternAttr::UpdateStyleSheet(const ScDocument& rDoc)
+bool ScPatternAttr::UpdateStyleSheet(const ScDocument& rDoc)
{
- if (pName)
+ bool bNameChanged = false;
+ if (moName)
{
- pStyle = static_cast<ScStyleSheet*>(rDoc.GetStyleSheetPool()->Find(*pName, SfxStyleFamily::Para));
+ pStyle = static_cast<ScStyleSheet*>(rDoc.GetStyleSheetPool()->Find(*moName, SfxStyleFamily::Para));
// use Standard if Style is not found,
// to avoid empty display in Toolbox-Controller
@@ -1210,11 +1670,16 @@ void ScPatternAttr::UpdateStyleSheet(const ScDocument& rDoc)
if (pStyle)
{
GetItemSet().SetParent(&pStyle->GetItemSet());
- pName.reset();
+ moName.reset();
}
}
else
+ {
pStyle = nullptr;
+ bNameChanged = true;
+ }
+ InvalidateCaches();
+ return bNameChanged;
}
void ScPatternAttr::StyleToName()
@@ -1223,17 +1688,17 @@ void ScPatternAttr::StyleToName()
if ( pStyle )
{
- pName = pStyle->GetName();
+ moName = pStyle->GetName();
pStyle = nullptr;
GetItemSet().SetParent( nullptr );
+ InvalidateCaches();
}
}
bool ScPatternAttr::IsSymbolFont() const
{
- const SfxPoolItem* pItem;
- if( GetItemSet().GetItemState( ATTR_FONT, true, &pItem ) == SfxItemState::SET )
- return static_cast<const SvxFontItem*>(pItem)->GetCharSet() == RTL_TEXTENCODING_SYMBOL;
+ if( const SvxFontItem* pItem = GetItemSet().GetItemIfSet( ATTR_FONT ) )
+ return pItem->GetCharSet() == RTL_TEXTENCODING_SYMBOL;
else
return false;
}
@@ -1252,10 +1717,24 @@ LanguageType getLanguageType(const SfxItemSet& rSet)
}
+sal_uInt32 ScPatternAttr::GetNumberFormatKey() const
+{
+ if (!mxNumberFormatKey.has_value())
+ mxNumberFormatKey = getNumberFormatKey(GetItemSet());
+ return *mxNumberFormatKey;
+}
+
+LanguageType ScPatternAttr::GetLanguageType() const
+{
+ if (!mxLanguageType.has_value())
+ mxLanguageType = getLanguageType(GetItemSet());
+ return *mxLanguageType;
+}
+
sal_uInt32 ScPatternAttr::GetNumberFormat( SvNumberFormatter* pFormatter ) const
{
- sal_uInt32 nFormat = getNumberFormatKey(GetItemSet());
- LanguageType eLang = getLanguageType(GetItemSet());
+ sal_uInt32 nFormat = GetNumberFormatKey();
+ LanguageType eLang = GetLanguageType();
if ( nFormat < SV_COUNTRY_LANGUAGE_OFFSET && eLang == LANGUAGE_SYSTEM )
; // it remains as it is
else if ( pFormatter )
@@ -1263,6 +1742,17 @@ sal_uInt32 ScPatternAttr::GetNumberFormat( SvNumberFormatter* pFormatter ) const
return nFormat;
}
+sal_uInt32 ScPatternAttr::GetNumberFormat( const ScInterpreterContext& rContext ) const
+{
+ sal_uInt32 nFormat = GetNumberFormatKey();
+ LanguageType eLang = GetLanguageType();
+ if ( nFormat < SV_COUNTRY_LANGUAGE_OFFSET && eLang == LANGUAGE_SYSTEM )
+ ; // it remains as it is
+ else
+ nFormat = rContext.NFGetFormatForLanguageIfBuiltIn( nFormat, eLang );
+ return nFormat;
+}
+
// the same if conditional formatting is in play:
sal_uInt32 ScPatternAttr::GetNumberFormat( SvNumberFormatter* pFormatter,
@@ -1274,27 +1764,52 @@ sal_uInt32 ScPatternAttr::GetNumberFormat( SvNumberFormatter* pFormatter,
// Conditional format takes precedence over style and even hard format.
- const SfxPoolItem* pFormItem;
sal_uInt32 nFormat;
- const SfxPoolItem* pLangItem;
LanguageType eLang;
- if (pCondSet->GetItemState(ATTR_VALUE_FORMAT, true, &pFormItem) == SfxItemState::SET )
+ if (pCondSet->GetItemState(ATTR_VALUE_FORMAT) == SfxItemState::SET )
{
nFormat = getNumberFormatKey(*pCondSet);
- if (pCondSet->GetItemState(ATTR_LANGUAGE_FORMAT, true, &pLangItem) == SfxItemState::SET)
+ if (pCondSet->GetItemState(ATTR_LANGUAGE_FORMAT) == SfxItemState::SET)
eLang = getLanguageType(*pCondSet);
else
- eLang = getLanguageType(GetItemSet());
+ eLang = GetLanguageType();
}
else
{
- nFormat = getNumberFormatKey(GetItemSet());
- eLang = getLanguageType(GetItemSet());
+ nFormat = GetNumberFormatKey();
+ eLang = GetLanguageType();
}
return pFormatter->GetFormatForLanguageIfBuiltIn(nFormat, eLang);
}
+sal_uInt32 ScPatternAttr::GetNumberFormat( const ScInterpreterContext& rContext,
+ const SfxItemSet* pCondSet ) const
+{
+ if (!pCondSet)
+ return GetNumberFormat(rContext);
+
+ // Conditional format takes precedence over style and even hard format.
+
+ sal_uInt32 nFormat;
+ LanguageType eLang;
+ if (pCondSet->GetItemState(ATTR_VALUE_FORMAT) == SfxItemState::SET )
+ {
+ nFormat = getNumberFormatKey(*pCondSet);
+ if (pCondSet->GetItemState(ATTR_LANGUAGE_FORMAT) == SfxItemState::SET)
+ eLang = getLanguageType(*pCondSet);
+ else
+ eLang = GetLanguageType();
+ }
+ else
+ {
+ nFormat = GetNumberFormatKey();
+ eLang = GetLanguageType();
+ }
+
+ return rContext.NFGetFormatForLanguageIfBuiltIn(nFormat, eLang);
+}
+
const SfxPoolItem& ScPatternAttr::GetItem( sal_uInt16 nWhich, const SfxItemSet& rItemSet, const SfxItemSet* pCondSet )
{
const SfxPoolItem* pCondItem;
@@ -1353,20 +1868,21 @@ ScRotateDir ScPatternAttr::GetRotateDir( const SfxItemSet* pCondSet ) const
return nRet;
}
-void ScPatternAttr::SetKey(sal_uInt64 nKey)
+void ScPatternAttr::SetPAKey(sal_uInt64 nKey)
{
- mnKey = nKey;
+ mnPAKey = nKey;
}
-sal_uInt64 ScPatternAttr::GetKey() const
+sal_uInt64 ScPatternAttr::GetPAKey() const
{
- return mnKey;
+ return mnPAKey;
}
-void ScPatternAttr::CalcHashCode() const
+void ScPatternAttr::InvalidateCaches()
{
- auto const & rSet = GetItemSet();
- mxHashCode = boost::hash_range(rSet.GetItems_Impl(), rSet.GetItems_Impl() + rSet.Count());
+ mxVisible.reset();
+ mxNumberFormatKey.reset();
+ mxLanguageType.reset();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/pivot2.cxx b/sc/source/core/data/pivot2.cxx
index 7544e6e95c71..c854b452c20e 100644
--- a/sc/source/core/data/pivot2.cxx
+++ b/sc/source/core/data/pivot2.cxx
@@ -18,6 +18,7 @@
*/
#include <pivot.hxx>
+#include <utility>
#if DEBUG_PIVOT_TABLE
using std::cout;
@@ -31,8 +32,8 @@ using std::endl;
ScDPName::ScDPName() : mnDupCount(0)
{}
-ScDPName::ScDPName(const OUString& rName, const OUString& rLayoutName, sal_uInt8 nDupCount) :
- maName(rName), maLayoutName(rLayoutName), mnDupCount(nDupCount)
+ScDPName::ScDPName(OUString aName, OUString aLayoutName, sal_uInt8 nDupCount) :
+ maName(std::move(aName)), maLayoutName(std::move(aLayoutName)), mnDupCount(nDupCount)
{}
// ScDPLabelData
diff --git a/sc/source/core/data/poolcach.cxx b/sc/source/core/data/poolcach.cxx
new file mode 100644
index 000000000000..6db714bb7c12
--- /dev/null
+++ b/sc/source/core/data/poolcach.cxx
@@ -0,0 +1,79 @@
+/* -*- 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 .
+ */
+
+
+#include <svl/itemset.hxx>
+#include <poolcach.hxx>
+#include <tools/debug.hxx>
+#include <patattr.hxx>
+
+ScItemPoolCache::ScItemPoolCache(CellAttributeHelper& _rHelper, const SfxPoolItem& rPutItem)
+: rHelper(_rHelper)
+, pSetToPut(nullptr)
+, aItemToPut(rHelper.GetPool(), &rPutItem)
+{
+}
+
+ScItemPoolCache::ScItemPoolCache(CellAttributeHelper& _rHelper, const SfxItemSet& rPutSet)
+: rHelper(_rHelper)
+, pSetToPut(&rPutSet)
+, aItemToPut()
+{
+}
+
+ScItemPoolCache::~ScItemPoolCache()
+{
+}
+
+const CellAttributeHolder& ScItemPoolCache::ApplyTo(const CellAttributeHolder& rOrigItem)
+{
+ const ScPatternAttr* pAttr(rOrigItem.getScPatternAttr());
+ if (nullptr == pAttr)
+ return rOrigItem;
+
+ DBG_ASSERT(&rHelper.GetPool() == pAttr->GetItemSet().GetPool(), "invalid Pool (!)");
+
+ // Find whether this Transformations ever occurred
+ for (const SfxItemModifyImpl & rMapEntry : m_aCache)
+ {
+ // ptr compare: same used rOrigItem?
+ if (rMapEntry.aOriginal.getScPatternAttr() == pAttr)
+ {
+ return rMapEntry.aModified;
+ }
+ }
+
+ // Insert the new attributes in a new Set
+ ScPatternAttr* pNewItem(new ScPatternAttr(*pAttr));
+
+ if (nullptr != aItemToPut.getItem())
+ {
+ pNewItem->GetItemSet().Put(*aItemToPut.getItem());
+ }
+ else
+ {
+ pNewItem->GetItemSet().Put(*pSetToPut);
+ }
+
+ m_aCache.emplace_back(rOrigItem, CellAttributeHolder(pNewItem, true));
+ return m_aCache.back().aModified;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/poolhelp.cxx b/sc/source/core/data/poolhelp.cxx
index bd27a96c46cb..6eb5e1232da0 100644
--- a/sc/source/core/data/poolhelp.cxx
+++ b/sc/source/core/data/poolhelp.cxx
@@ -18,6 +18,7 @@
*/
#include <comphelper/processfactory.hxx>
+#include <svl/numformat.hxx>
#include <svl/zforlist.hxx>
#include <editeng/editeng.hxx>
@@ -28,10 +29,7 @@
ScPoolHelper::ScPoolHelper( ScDocument& rSourceDoc )
: pDocPool(new ScDocumentPool)
- , m_rSourceDoc(rSourceDoc)
{
- pDocPool->FreezeIdRanges();
-
mxStylePool = new ScStyleSheetPool( *pDocPool, &rSourceDoc );
}
@@ -50,7 +48,6 @@ SfxItemPool* ScPoolHelper::GetEditPool() const
{
pEditPool = EditEngine::CreatePool();
pEditPool->SetDefaultMetric( MapUnit::Map100thMM );
- pEditPool->FreezeIdRanges();
}
return pEditPool.get();
}
@@ -61,7 +58,6 @@ SfxItemPool* ScPoolHelper::GetEnginePool() const
{
pEnginePool = EditEngine::CreatePool();
pEnginePool->SetDefaultMetric( MapUnit::Map100thMM );
- pEnginePool->FreezeIdRanges();
} // ifg ( pEnginePool )
return pEnginePool.get();
}
@@ -91,10 +87,11 @@ std::unique_ptr<SvNumberFormatter> ScPoolHelper::CreateNumberFormatter() const
{
std::unique_ptr<SvNumberFormatter> p;
{
- osl::MutexGuard aGuard(&maMtxCreateNumFormatter);
+ std::scoped_lock aGuard(maMtxCreateNumFormatter);
p.reset(new SvNumberFormatter(comphelper::getProcessComponentContext(), LANGUAGE_SYSTEM));
}
- p->SetColorLink( LINK(&m_rSourceDoc, ScDocument, GetUserDefinedColor) );
+ assert(mxStylePool->GetDocument());
+ p->SetColorLink( LINK(mxStylePool->GetDocument(), ScDocument, GetUserDefinedColor));
p->SetEvalDateFormat(NF_EVALDATEFORMAT_INTL_FORMAT);
sal_uInt16 d,m;
diff --git a/sc/source/core/data/postit.cxx b/sc/source/core/data/postit.cxx
index 882cc8c190bb..67f172a4f945 100644
--- a/sc/source/core/data/postit.cxx
+++ b/sc/source/core/data/postit.cxx
@@ -23,34 +23,33 @@
#include <rtl/ustrbuf.hxx>
#include <sal/log.hxx>
#include <unotools/useroptions.hxx>
-#include <svx/svdpage.hxx>
#include <svx/svdocapt.hxx>
+#include <svx/svdpage.hxx>
#include <editeng/outlobj.hxx>
#include <editeng/editobj.hxx>
-#include <basegfx/polygon/b2dpolygon.hxx>
#include <osl/diagnose.h>
+#include <comphelper/lok.hxx>
-#include <scitems.hxx>
-#include <svx/xfillit0.hxx>
-#include <svx/xlnstit.hxx>
-#include <svx/xlnstwit.hxx>
-#include <svx/xlnstcit.hxx>
-#include <svx/sxcecitm.hxx>
-#include <svx/xflclit.hxx>
-#include <svx/sdshitm.hxx>
#include <svx/sdsxyitm.hxx>
-#include <svx/sdtditm.hxx>
#include <svx/sdtagitm.hxx>
#include <svx/sdtmfitm.hxx>
#include <tools/gen.hxx>
#include <document.hxx>
-#include <docpool.hxx>
-#include <patattr.hxx>
+#include <stlpool.hxx>
+#include <stylehelper.hxx>
#include <drwlayer.hxx>
#include <userdat.hxx>
-#include <detfunc.hxx>
#include <editutil.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <utility>
+#include <strings.hrc>
+
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/text/XTextAppend.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <comphelper/propertyvalue.hxx>
using namespace com::sun::star;
@@ -74,8 +73,8 @@ public:
static void SetBasicCaptionSettings( SdrCaptionObj& rCaption, bool bShown );
/** Stores the cell position of the note in the user data area of the caption. */
static void SetCaptionUserData( SdrCaptionObj& rCaption, const ScAddress& rPos );
- /** Sets all default formatting attributes to the caption object. */
- static void SetDefaultItems( SdrCaptionObj& rCaption, ScDocument& rDoc, const SfxItemSet* pExtraItemSet );
+ /** Sets all hard formatting attributes to the caption object. */
+ static void SetExtraItems( SdrCaptionObj& rCaption, const SfxItemSet& rExtraItemSet );
};
void ScCaptionUtil::SetCaptionLayer( SdrCaptionObj& rCaption, bool bShown )
@@ -87,9 +86,9 @@ void ScCaptionUtil::SetCaptionLayer( SdrCaptionObj& rCaption, bool bShown )
void ScCaptionUtil::SetBasicCaptionSettings( SdrCaptionObj& rCaption, bool bShown )
{
- SetCaptionLayer( rCaption, bShown );
rCaption.SetFixedTail();
rCaption.SetSpecialTextBoxShadow();
+ SetCaptionLayer( rCaption, bShown );
}
void ScCaptionUtil::SetCaptionUserData( SdrCaptionObj& rCaption, const ScAddress& rPos )
@@ -101,60 +100,19 @@ void ScCaptionUtil::SetCaptionUserData( SdrCaptionObj& rCaption, const ScAddress
pObjData->meType = ScDrawObjData::CellNote;
}
-void ScCaptionUtil::SetDefaultItems( SdrCaptionObj& rCaption, ScDocument& rDoc, const SfxItemSet* pExtraItemSet )
+void ScCaptionUtil::SetExtraItems( SdrCaptionObj& rCaption, const SfxItemSet& rExtraItemSet )
{
SfxItemSet aItemSet = rCaption.GetMergedItemSet();
- // caption tail arrow
- ::basegfx::B2DPolygon aTriangle;
- aTriangle.append( ::basegfx::B2DPoint( 10.0, 0.0 ) );
- aTriangle.append( ::basegfx::B2DPoint( 0.0, 30.0 ) );
- aTriangle.append( ::basegfx::B2DPoint( 20.0, 30.0 ) );
- aTriangle.setClosed( true );
- /* Line ends are now created with an empty name. The
- checkForUniqueItem() method then finds a unique name for the item's
- value. */
- aItemSet.Put( XLineStartItem( OUString(), ::basegfx::B2DPolyPolygon( aTriangle ) ) );
- aItemSet.Put( XLineStartWidthItem( 200 ) );
- aItemSet.Put( XLineStartCenterItem( false ) );
- aItemSet.Put( XFillStyleItem( drawing::FillStyle_SOLID ) );
- aItemSet.Put( XFillColorItem( OUString(), ScDetectiveFunc::GetCommentColor() ) );
- aItemSet.Put( SdrCaptionEscDirItem( SdrCaptionEscDir::BestFit ) );
-
- // shadow
- /* SdrShadowItem has sal_False, instead the shadow is set for the
- rectangle only with SetSpecialTextBoxShadow() when the object is
- created (item must be set to adjust objects from older files). */
- aItemSet.Put( makeSdrShadowItem( false ) );
+ aItemSet.Put(rExtraItemSet);
+ // reset shadow visibility (see also ScNoteUtil::CreateNoteFromCaption)
+ aItemSet.ClearItem(SDRATTR_SHADOW);
+ // ... but not distance, as that will fallback to wrong values
+ // if the comment is shown and then opened in older versions:
aItemSet.Put( makeSdrShadowXDistItem( 100 ) );
aItemSet.Put( makeSdrShadowYDistItem( 100 ) );
- // text attributes
- aItemSet.Put( makeSdrTextLeftDistItem( 100 ) );
- aItemSet.Put( makeSdrTextRightDistItem( 100 ) );
- aItemSet.Put( makeSdrTextUpperDistItem( 100 ) );
- aItemSet.Put( makeSdrTextLowerDistItem( 100 ) );
- aItemSet.Put( makeSdrTextAutoGrowWidthItem( false ) );
- aItemSet.Put( makeSdrTextAutoGrowHeightItem( true ) );
- // use the default cell style to be able to modify the caption font
- const ScPatternAttr& rDefPattern = rDoc.GetPool()->GetDefaultItem( ATTR_PATTERN );
- rDefPattern.FillEditItemSet( &aItemSet );
-
- if (pExtraItemSet)
- {
- /* Updates caption item set according to the passed item set while removing shadow items. */
-
- aItemSet.Put(*pExtraItemSet);
- // reset shadow items
- aItemSet.Put( makeSdrShadowItem( false ) );
- aItemSet.Put( makeSdrShadowXDistItem( 100 ) );
- aItemSet.Put( makeSdrShadowYDistItem( 100 ) );
- }
-
rCaption.SetMergedItemSet( aItemSet );
-
- if (pExtraItemSet)
- rCaption.SetSpecialTextBoxShadow();
}
/** Helper for creation and manipulation of caption drawing objects independent
@@ -165,12 +123,12 @@ public:
/** Create a new caption. The caption will not be inserted into the document. */
explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, bool bTailFront );
/** Manipulate an existing caption. */
- explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, const ScCaptionPtr& xCaption );
+ explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, const rtl::Reference<SdrCaptionObj>& xCaption );
/** Returns the drawing layer page of the sheet contained in maPos. */
SdrPage* GetDrawPage();
/** Returns the caption drawing object. */
- ScCaptionPtr & GetCaption() { return mxCaption; }
+ rtl::Reference<SdrCaptionObj> & GetCaption() { return mxCaption; }
/** Moves the caption inside the passed rectangle. Uses page area if 0 is passed. */
void FitCaptionToRect( const tools::Rectangle* pVisRect = nullptr );
@@ -197,7 +155,7 @@ private:
private:
ScDocument& mrDoc;
ScAddress maPos;
- ScCaptionPtr mxCaption;
+ rtl::Reference<SdrCaptionObj> mxCaption;
tools::Rectangle maPageRect;
tools::Rectangle maCellRect;
bool mbNegPage;
@@ -211,7 +169,7 @@ ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, boo
CreateCaption( true/*bShown*/, bTailFront );
}
-ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, const ScCaptionPtr& xCaption ) :
+ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, const rtl::Reference<SdrCaptionObj>& xCaption ) :
mrDoc( rDoc ),
maPos( rPos ),
mxCaption( xCaption )
@@ -378,11 +336,11 @@ void ScCaptionCreator::CreateCaption( bool bShown, bool bTailFront )
// create the caption drawing object
tools::Rectangle aTextRect( Point( 0 , 0 ), Size( SC_NOTECAPTION_WIDTH, SC_NOTECAPTION_HEIGHT ) );
Point aTailPos = CalcTailPos( bTailFront );
- mxCaption.reset(
+ mxCaption =
new SdrCaptionObj(
*mrDoc.GetDrawLayer(), // TTTT should ret a ref?
aTextRect,
- aTailPos));
+ aTailPos);
// basic caption settings
ScCaptionUtil::SetBasicCaptionSettings( *mxCaption, bShown );
}
@@ -397,7 +355,7 @@ void ScCaptionCreator::Initialize()
/* #i98141# SdrPage::GetSize() returns negative width in RTL mode.
The call to Rectangle::Adjust() orders left/right coordinate
accordingly. */
- maPageRect.Justify();
+ maPageRect.Normalize();
}
}
@@ -408,7 +366,7 @@ public:
/** Create a new caption object and inserts it into the document. */
explicit ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScNoteData& rNoteData );
/** Manipulate an existing caption. */
- explicit ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScCaptionPtr& xCaption, bool bShown );
+ explicit ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, rtl::Reference<SdrCaptionObj>& xCaption, bool bShown );
};
ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScNoteData& rNoteData ) :
@@ -432,7 +390,7 @@ ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& r
}
}
-ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScCaptionPtr& xCaption, bool bShown ) :
+ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, rtl::Reference<SdrCaptionObj>& xCaption, bool bShown ) :
ScCaptionCreator( rDoc, rPos, xCaption )
{
SdrPage* pDrawPage = GetDrawPage();
@@ -451,378 +409,13 @@ ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& r
} // namespace
-ScCaptionPtr::ScCaptionPtr() :
- mpHead(nullptr), mpNext(nullptr), mpCaption(nullptr), mbNotOwner(false)
-{
-}
-
-ScCaptionPtr::ScCaptionPtr( SdrCaptionObj* p ) :
- mpHead(nullptr), mpNext(nullptr), mpCaption(p), mbNotOwner(false)
-{
- if (p)
- {
- newHead();
- }
-}
-
-ScCaptionPtr::ScCaptionPtr( const ScCaptionPtr& r ) :
- mpHead(r.mpHead), mpCaption(r.mpCaption), mbNotOwner(false)
-{
- if (r.mpCaption)
- {
- assert(r.mpHead);
- r.incRef();
- // Insert into list.
- mpNext = r.mpNext;
- r.mpNext = this;
- }
- else
- {
- assert(!r.mpHead);
- mpNext = nullptr;
- }
-}
-
-ScCaptionPtr::ScCaptionPtr(ScCaptionPtr&& r) noexcept
- : mpHead(r.mpHead), mpNext(r.mpNext), mpCaption(r.mpCaption), mbNotOwner(false)
-{
- r.replaceInList( this );
- r.mpCaption = nullptr;
- r.mbNotOwner = false;
-}
-
-ScCaptionPtr& ScCaptionPtr::operator=(ScCaptionPtr&& r) noexcept
-{
- assert(this != &r);
-
- mpHead = r.mpHead;
- mpNext = r.mpNext;
- mpCaption = r.mpCaption;
- mbNotOwner = r.mbNotOwner;
-
- r.replaceInList( this );
- r.mpCaption = nullptr;
- r.mbNotOwner = false;
-
- return *this;
-}
-
-ScCaptionPtr& ScCaptionPtr::operator=( const ScCaptionPtr& r )
-{
- if (this == &r)
- return *this;
-
- if (mpCaption == r.mpCaption)
- {
- // Two lists for the same caption is bad.
- assert(!mpCaption || mpHead == r.mpHead);
- assert(!mpCaption); // assigning same caption pointer within same list is weird
- // Nullptr captions are not inserted to the list, so nothing to do here
- // if both are.
- return *this;
- }
-
- // Let's find some weird usage.
- // Assigning without head doesn't make sense unless it is a nullptr caption.
- assert(r.mpHead || !r.mpCaption);
- // A nullptr caption must not be in a list and thus not have a head.
- assert(!r.mpHead || r.mpCaption);
- // Same captions were caught above, so here different heads must be present.
- assert(r.mpHead != mpHead);
-
- r.incRef();
- decRefAndDestroy();
- removeFromList();
-
- mpCaption = r.mpCaption;
- mbNotOwner = r.mbNotOwner;
- // That head is this' master.
- mpHead = r.mpHead;
- // Insert into list.
- mpNext = r.mpNext;
- r.mpNext = this;
-
- return *this;
-}
-
-void ScCaptionPtr::setNotOwner()
-{
- mbNotOwner = true;
-}
-
-ScCaptionPtr::Head::Head( ScCaptionPtr* p ) :
- mpFirst(p), mnRefs(1)
-{
-}
-
-void ScCaptionPtr::newHead()
-{
- assert(!mpHead);
- mpHead = new Head(this);
-}
-
-void ScCaptionPtr::replaceInList(ScCaptionPtr* pNew) noexcept
-{
- if (!mpHead && !mpNext)
- return;
-
- assert(mpHead);
- assert(mpCaption == pNew->mpCaption);
-
- ScCaptionPtr* pThat = mpHead->mpFirst;
- while (pThat && pThat != this && pThat->mpNext != this)
- {
- pThat = pThat->mpNext;
- }
- if (pThat && pThat != this)
- {
- assert(pThat->mpNext == this);
- pThat->mpNext = pNew;
- }
- pNew->mpNext = mpNext;
- if (mpHead->mpFirst == this)
- mpHead->mpFirst = pNew;
-
- mpHead = nullptr;
- mpNext = nullptr;
-}
-
-void ScCaptionPtr::removeFromList()
-{
- if (!mpHead && !mpNext && !mpCaption)
- return;
-
-#if OSL_DEBUG_LEVEL > 0
- oslInterlockedCount nCount = 0;
-#endif
- ScCaptionPtr* pThat = (mpHead ? mpHead->mpFirst : nullptr);
- while (pThat && pThat != this && pThat->mpNext != this)
- {
- // Use the walk to check consistency on the fly.
- assert(pThat->mpHead == mpHead); // all belong to the same
- assert(pThat->mpHead || !pThat->mpNext); // next without head is bad
- assert(pThat->mpCaption == mpCaption);
- pThat = pThat->mpNext;
-#if OSL_DEBUG_LEVEL > 0
- ++nCount;
-#endif
- }
- assert(pThat || !mpHead); // not found only if this was standalone
- if (pThat)
- {
- if (pThat != this)
- {
-#if OSL_DEBUG_LEVEL > 0
- // The while loop above was not executed, and for this
- // (pThat->mpNext) the loop below won't either.
- ++nCount;
-#endif
- pThat->mpNext = mpNext;
- }
-#if OSL_DEBUG_LEVEL > 0
- do
- {
- assert(pThat->mpHead == mpHead); // all belong to the same
- assert(pThat->mpHead || !pThat->mpNext); // next without head is bad
- assert(pThat->mpCaption == mpCaption);
- ++nCount;
- }
- while ((pThat = pThat->mpNext) != nullptr);
-#endif
- }
-#if OSL_DEBUG_LEVEL > 0
- // If part of a list then refs were already decremented.
- assert(nCount == (mpHead ? mpHead->mnRefs + 1 : 0));
-#endif
- if (mpHead && mpHead->mpFirst == this)
- {
- if (mpNext)
- mpHead->mpFirst = mpNext;
- else
- {
- // The only one destroys also head.
- assert(mpHead->mnRefs == 0); // cough
- delete mpHead; // DEAD now
- }
- }
- mpHead = nullptr;
- mpNext = nullptr;
-}
-
-void ScCaptionPtr::reset( SdrCaptionObj* p )
-{
- assert(!p || p != mpCaption);
-#if OSL_DEBUG_LEVEL > 0
- if (p)
- {
- // Check if we end up with a duplicated management in this list.
- ScCaptionPtr* pThat = (mpHead ? mpHead->mpFirst : nullptr);
- while (pThat)
- {
- assert(pThat->mpCaption != p);
- pThat = pThat->mpNext;
- }
- }
-#endif
- decRefAndDestroy();
- removeFromList();
- mpCaption = p;
- mbNotOwner = false;
- if (p)
- {
- newHead();
- }
-}
-
-ScCaptionPtr::~ScCaptionPtr()
-{
- decRefAndDestroy();
- removeFromList();
-}
-
-oslInterlockedCount ScCaptionPtr::getRefs() const
-{
- return mpHead ? mpHead->mnRefs : 0;
-}
-
-void ScCaptionPtr::incRef() const
-{
- if (mpHead)
- osl_atomic_increment(&mpHead->mnRefs);
-}
-
-bool ScCaptionPtr::decRef() const
-{
- return mpHead && mpHead->mnRefs > 0 && !osl_atomic_decrement(&mpHead->mnRefs);
-}
-
-void ScCaptionPtr::decRefAndDestroy()
-{
- if (!decRef())
- return;
-
- assert(mpHead->mpFirst == this); // this must be one and only one
- assert(!mpNext); // this must be one and only one
- assert(mpCaption);
-
-#if 0
- // Quick workaround for when there are still cases where the caption
- // pointer is dangling
- mpCaption = nullptr;
- mbNotOwner = false;
-#else
- // Destroying Draw Undo and some other delete the SdrObject, don't
- // attempt that twice.
- if (mbNotOwner)
- {
- mpCaption = nullptr;
- mbNotOwner = false;
- }
- else
- {
- removeFromDrawPageAndFree( true ); // ignoring Undo
- if (mpCaption)
- {
- // There's no draw page associated so removeFromDrawPageAndFree()
- // didn't do anything, but still we want to delete the caption
- // object. release()/dissolve() also resets mpCaption.
- SdrObject* pObj = release();
- SdrObject::Free( pObj );
- }
- }
-#endif
- delete mpHead;
- mpHead = nullptr;
-}
-
-void ScCaptionPtr::insertToDrawPage( SdrPage& rDrawPage )
-{
- assert(mpHead && mpCaption);
-
- rDrawPage.InsertObject( mpCaption );
-}
-
-void ScCaptionPtr::removeFromDrawPage( SdrPage& rDrawPage )
-{
- assert(mpHead && mpCaption);
- SdrObject* pObj = rDrawPage.RemoveObject( mpCaption->GetOrdNum() );
- assert(pObj == mpCaption); (void)pObj;
-}
-
-void ScCaptionPtr::removeFromDrawPageAndFree( bool bIgnoreUndo )
-{
- assert(mpHead && mpCaption);
- SdrPage* pDrawPage(mpCaption->getSdrPageFromSdrObject());
- SAL_WARN_IF( !pDrawPage, "sc.core", "ScCaptionPtr::removeFromDrawPageAndFree - object without drawing page");
- if (!pDrawPage)
- return;
-
- pDrawPage->RecalcObjOrdNums();
- bool bRecording = false;
- if(!bIgnoreUndo)
- {
- ScDrawLayer* pDrawLayer(dynamic_cast< ScDrawLayer* >(&mpCaption->getSdrModelFromSdrObject()));
- SAL_WARN_IF( !pDrawLayer, "sc.core", "ScCaptionPtr::removeFromDrawPageAndFree - object without drawing layer");
- // create drawing undo action (before removing the object to have valid draw page in undo action)
- bRecording = (pDrawLayer && pDrawLayer->IsRecording());
- if (bRecording)
- pDrawLayer->AddCalcUndo( std::make_unique<SdrUndoDelObj>( *mpCaption ));
- }
- // remove the object from the drawing page, delete if undo is disabled
- removeFromDrawPage( *pDrawPage );
- // If called from outside mnRefs must be 1 to delete. If called from
- // decRefAndDestroy() mnRefs is already 0.
- if (!bRecording && getRefs() <= 1)
- {
- SdrObject* pObj = release();
- SdrObject::Free( pObj );
- }
-}
-
-SdrCaptionObj* ScCaptionPtr::release()
-{
- SdrCaptionObj* pTmp = mpCaption;
- dissolve();
- return pTmp;
-}
-
-void ScCaptionPtr::forget()
-{
- decRef();
- removeFromList();
- mpCaption = nullptr;
- mbNotOwner = false;
-}
-
-void ScCaptionPtr::dissolve()
-{
- ScCaptionPtr::Head* pHead = mpHead;
- ScCaptionPtr* pThat = (mpHead ? mpHead->mpFirst : this);
- while (pThat)
- {
- assert(!pThat->mpNext || pThat->mpHead); // next without head is bad
- assert(pThat->mpHead == pHead); // same head required within one list
- ScCaptionPtr* p = pThat->mpNext;
- pThat->clear();
- pThat = p;
- }
- assert(!mpHead && !mpNext && !mpCaption); // should had been cleared during list walk
- delete pHead;
-}
-
-void ScCaptionPtr::clear()
-{
- mpHead = nullptr;
- mpNext = nullptr;
- mpCaption = nullptr;
- mbNotOwner = false;
-}
-
struct ScCaptionInitData
{
- std::unique_ptr< SfxItemSet > mxItemSet; /// Caption object formatting.
- std::unique_ptr< OutlinerParaObject > mxOutlinerObj; /// Text object with all text portion formatting.
- OUString maSimpleText; /// Simple text without formatting.
+ std::optional< SfxItemSet > moItemSet; /// Caption object formatting.
+ std::optional< OutlinerParaObject > mxOutlinerObj; /// Text object with all text portion formatting.
+ std::unique_ptr< GenerateNoteCaption > mxGenerator; /// Operator to generate Caption Object from import data
+ OUString maStyleName; /// Drawing style associated with the caption object.
+ OUString maSimpleText; /// Simple text without formatting.
Point maCaptionOffset; /// Caption position relative to cell corner.
Size maCaptionSize; /// Size of the caption object.
bool mbDefaultPosSize; /// True = use default position and size for caption.
@@ -856,13 +449,13 @@ ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, const ScPostIt& rNo
maNoteData( rNote.maNoteData )
{
mnPostItId = nPostItId == 0 ? mnLastPostItId++ : nPostItId;
- maNoteData.mxCaption.reset(nullptr);
+ maNoteData.mxCaption.clear();
CreateCaption( rPos, rNote.maNoteData.mxCaption.get() );
}
-ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, const ScNoteData& rNoteData, bool bAlwaysCreateCaption, sal_uInt32 nPostItId ) :
+ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, ScNoteData aNoteData, bool bAlwaysCreateCaption, sal_uInt32 nPostItId ) :
mrDoc( rDoc ),
- maNoteData( rNoteData )
+ maNoteData(std::move( aNoteData ))
{
mnPostItId = nPostItId == 0 ? mnLastPostItId++ : nPostItId;
if( bAlwaysCreateCaption || maNoteData.mbShown )
@@ -876,8 +469,12 @@ ScPostIt::~ScPostIt()
std::unique_ptr<ScPostIt> ScPostIt::Clone( const ScAddress& rOwnPos, ScDocument& rDestDoc, const ScAddress& rDestPos, bool bCloneCaption ) const
{
+ // tdf#117307: Don't clone comment, if it is in the same position
+ if ( (rOwnPos == rDestPos) && !mrDoc.IsClipboard() )
+ bCloneCaption = false;
CreateCaptionFromInitData( rOwnPos );
- return bCloneCaption ? std::make_unique<ScPostIt>( rDestDoc, rDestPos, *this, mnPostItId ) : std::make_unique<ScPostIt>( rDestDoc, rDestPos, maNoteData, false, mnPostItId );
+ sal_uInt32 nPostItId = comphelper::LibreOfficeKit::isActive() ? 0 : mnPostItId;
+ return bCloneCaption ? std::make_unique<ScPostIt>( rDestDoc, rDestPos, *this, nPostItId ) : std::make_unique<ScPostIt>( rDestDoc, rDestPos, maNoteData, false, mnPostItId );
}
void ScPostIt::SetDate( const OUString& rDate )
@@ -892,16 +489,18 @@ void ScPostIt::SetAuthor( const OUString& rAuthor )
void ScPostIt::AutoStamp()
{
- maNoteData.maDate = ScGlobal::getLocaleDataPtr()->getDate( Date( Date::SYSTEM ) );
- maNoteData.maAuthor = SvtUserOptions().GetID();
+ maNoteData.maDate = ScGlobal::getLocaleData().getDate( Date( Date::SYSTEM ) ) + " " +
+ ScGlobal::getLocaleData().getTime(DateTime(DateTime::SYSTEM), false);
+ const OUString aAuthor = SvtUserOptions().GetFullName();
+ maNoteData.maAuthor = !aAuthor.isEmpty() ? aAuthor : ScResId(STR_CHG_UNKNOWN_AUTHOR);
}
const OutlinerParaObject* ScPostIt::GetOutlinerObject() const
{
if( maNoteData.mxCaption )
return maNoteData.mxCaption->GetOutlinerParaObject();
- if( maNoteData.mxInitData )
- return maNoteData.mxInitData->mxOutlinerObj.get();
+ if( maNoteData.mxInitData && maNoteData.mxInitData->mxOutlinerObj )
+ return &*maNoteData.mxInitData->mxOutlinerObj;
return nullptr;
}
@@ -932,15 +531,6 @@ OUString ScPostIt::GetText() const
return OUString();
}
-bool ScPostIt::HasMultiLineText() const
-{
- if( const EditTextObject* pEditObj = GetEditTextObject() )
- return pEditObj->GetParagraphCount() > 1;
- if( maNoteData.mxInitData )
- return maNoteData.mxInitData->maSimpleText.indexOf( '\n' ) >= 0;
- return false;
-}
-
void ScPostIt::SetText( const ScAddress& rPos, const OUString& rText )
{
CreateCaptionFromInitData( rPos );
@@ -967,17 +557,17 @@ void ScPostIt::ForgetCaption( bool bPreserveData )
ScCaptionInitData* pInitData = new ScCaptionInitData;
const OutlinerParaObject* pOPO = GetOutlinerObject();
if (pOPO)
- pInitData->mxOutlinerObj.reset( new OutlinerParaObject(*pOPO));
+ pInitData->mxOutlinerObj = *pOPO;
pInitData->maSimpleText = GetText();
maNoteData.mxInitData.reset(pInitData);
- maNoteData.mxCaption.forget();
+ maNoteData.mxCaption.clear();
}
else
{
/* This function is used in undo actions to give up the responsibility for
the caption object which is handled by separate drawing undo actions. */
- maNoteData.mxCaption.forget();
+ maNoteData.mxCaption.clear();
maNoteData.mxInitData.reset();
}
}
@@ -1049,16 +639,36 @@ void ScPostIt::CreateCaptionFromInitData( const ScAddress& rPos ) const
bool bWasLocked = maNoteData.mxCaption->getSdrModelFromSdrObject().isLocked();
maNoteData.mxCaption->getSdrModelFromSdrObject().setLock(true);
- // transfer ownership of outliner object to caption, or set simple text
- OSL_ENSURE( xInitData->mxOutlinerObj || !xInitData->maSimpleText.isEmpty(),
- "ScPostIt::CreateCaptionFromInitData - need either outliner para object or simple text" );
- if (xInitData->mxOutlinerObj)
- maNoteData.mxCaption->SetOutlinerParaObject( std::move(xInitData->mxOutlinerObj) );
+ if (xInitData->mxGenerator)
+ xInitData->mxGenerator->Generate(*maNoteData.mxCaption);
else
- maNoteData.mxCaption->SetText( xInitData->maSimpleText );
+ {
+ // transfer ownership of outliner object to caption, or set simple text
+ OSL_ENSURE( xInitData->mxOutlinerObj || !xInitData->maSimpleText.isEmpty(),
+ "ScPostIt::CreateCaptionFromInitData - need either outliner para object or simple text" );
+ if (xInitData->mxOutlinerObj)
+ maNoteData.mxCaption->SetOutlinerParaObject( std::move(xInitData->mxOutlinerObj) );
+ else
+ maNoteData.mxCaption->SetText( xInitData->maSimpleText );
+ }
- // copy all items or set default items; reset shadow items
- ScCaptionUtil::SetDefaultItems( *maNoteData.mxCaption, mrDoc, xInitData->mxItemSet.get() );
+ if (!xInitData->maStyleName.isEmpty())
+ {
+ if (auto pStyleSheet = mrDoc.GetStyleSheetPool()->Find(xInitData->maStyleName, SfxStyleFamily::Frame))
+ maNoteData.mxCaption->SetStyleSheet(static_cast<SfxStyleSheet*>(pStyleSheet), true);
+
+ if (xInitData->moItemSet)
+ maNoteData.mxCaption->SetMergedItemSet(*xInitData->moItemSet);
+ }
+ else
+ {
+ if (auto pStyleSheet = mrDoc.GetStyleSheetPool()->Find(ScResId(STR_STYLENAME_NOTE), SfxStyleFamily::Frame))
+ maNoteData.mxCaption->SetStyleSheet(static_cast<SfxStyleSheet*>(pStyleSheet), true);
+
+ // copy all items and reset shadow items
+ if (xInitData->moItemSet)
+ ScCaptionUtil::SetExtraItems(*maNoteData.mxCaption, *xInitData->moItemSet);
+ }
// set position and size of the caption object
if( xInitData->mbDefaultPosSize )
@@ -1088,7 +698,7 @@ void ScPostIt::CreateCaptionFromInitData( const ScAddress& rPos ) const
void ScPostIt::CreateCaption( const ScAddress& rPos, const SdrCaptionObj* pCaption )
{
OSL_ENSURE( !maNoteData.mxCaption, "ScPostIt::CreateCaption - unexpected caption object found" );
- maNoteData.mxCaption.reset(nullptr);
+ maNoteData.mxCaption.clear();
/* #i104915# Never try to create notes in Undo document, leads to
crash due to missing document members (e.g. row height array). */
@@ -1110,8 +720,16 @@ void ScPostIt::CreateCaption( const ScAddress& rPos, const SdrCaptionObj* pCapti
{
// copy edit text object (object must be inserted into page already)
if( OutlinerParaObject* pOPO = pCaption->GetOutlinerParaObject() )
- maNoteData.mxCaption->SetOutlinerParaObject( std::make_unique<OutlinerParaObject>( *pOPO ) );
+ maNoteData.mxCaption->SetOutlinerParaObject( *pOPO );
// copy formatting items (after text has been copied to apply font formatting)
+ if (auto pStyleSheet = pCaption->GetStyleSheet())
+ {
+ auto pPool = mrDoc.GetStyleSheetPool();
+ pPool->CopyStyleFrom(pStyleSheet->GetPool(), pStyleSheet->GetName(), pStyleSheet->GetFamily(), true);
+
+ if (auto pDestStyleSheet = pPool->Find(pStyleSheet->GetName(), pStyleSheet->GetFamily()))
+ maNoteData.mxCaption->SetStyleSheet(static_cast<SfxStyleSheet*>(pDestStyleSheet), true);
+ }
maNoteData.mxCaption->SetMergedItemSetAndBroadcast( pCaption->GetMergedItemSet() );
// move textbox position relative to new cell, copy textbox size
tools::Rectangle aCaptRect = pCaption->GetLogicRect();
@@ -1122,8 +740,14 @@ void ScPostIt::CreateCaption( const ScAddress& rPos, const SdrCaptionObj* pCapti
}
else
{
- // set default formatting and default position
- ScCaptionUtil::SetDefaultItems( *maNoteData.mxCaption, mrDoc, nullptr );
+ if (auto pStyleSheet = mrDoc.GetStyleSheetPool()->Find(ScResId(STR_STYLENAME_NOTE), SfxStyleFamily::Frame))
+ maNoteData.mxCaption->SetStyleSheet(static_cast<SfxStyleSheet*>(pStyleSheet), true);
+ // set default size, undoing sdr::TextProperties::SetStyleSheet's
+ // adjustment that use a wrong min height.
+ tools::Rectangle aCaptRect = maNoteData.mxCaption->GetLogicRect();
+ aCaptRect.SetSize({ SC_NOTECAPTION_WIDTH, SC_NOTECAPTION_HEIGHT });
+ maNoteData.mxCaption->SetLogicRect(aCaptRect);
+ // set default position
aCreator.AutoPlaceCaption();
}
@@ -1144,9 +768,23 @@ void ScPostIt::RemoveCaption()
// TTTT maybe no longer needed - can that still happen?
ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer();
if (pDrawLayer == &maNoteData.mxCaption->getSdrModelFromSdrObject())
- maNoteData.mxCaption.removeFromDrawPageAndFree();
+ {
+ SdrPage* pDrawPage(maNoteData.mxCaption->getSdrPageFromSdrObject());
+ SAL_WARN_IF( !pDrawPage, "sc.core", "ScCaptionPtr::removeFromDrawPageAndFree - object without drawing page");
+ if (pDrawPage)
+ {
+ pDrawPage->RecalcObjOrdNums();
+ // create drawing undo action (before removing the object to have valid draw page in undo action)
+ bool bRecording = (pDrawLayer && pDrawLayer->IsRecording());
+ if (bRecording)
+ pDrawLayer->AddCalcUndo( std::make_unique<SdrUndoDelObj>( *maNoteData.mxCaption ));
+ // remove the object from the drawing page
+ rtl::Reference<SdrObject> pRemovedObj = pDrawPage->RemoveObject( maNoteData.mxCaption->GetOrdNum() );
+ assert(pRemovedObj.get() == maNoteData.mxCaption.get()); (void)pRemovedObj;
+ }
+ }
- SAL_INFO("sc.core","ScPostIt::RemoveCaption - refs: " << maNoteData.mxCaption.getRefs() <<
+ SAL_INFO("sc.core","ScPostIt::RemoveCaption -"
" IsUndo: " << mrDoc.IsUndo() << " IsClip: " << mrDoc.IsClipboard() <<
" Dtor: " << mrDoc.IsInDtorClear());
@@ -1154,29 +792,59 @@ void ScPostIt::RemoveCaption()
if (maNoteData.mxCaption)
{
SAL_INFO("sc.core","ScPostIt::RemoveCaption - forgetting one ref");
- maNoteData.mxCaption.forget();
+ maNoteData.mxCaption.clear();
+ }
+}
+
+static void lcl_FormatAndInsertAuthorAndDatepara(SdrCaptionObj* pCaption, OUStringBuffer& aUserData, bool bUserWithTrackText)
+{
+ uno::Reference<drawing::XShape> xShape = pCaption->getUnoShape();
+ uno::Reference<text::XText> xText(xShape, uno::UNO_QUERY);
+ uno::Reference<text::XTextAppend> xBodyTextAppend(xText, uno::UNO_QUERY);
+
+ if (xBodyTextAppend.is())
+ {
+ uno::Sequence< beans::PropertyValue > aArgs;
+ if (bUserWithTrackText)
+ {
+ xBodyTextAppend->insertTextPortion(aUserData.makeStringAndClear(), aArgs, xText->getStart());
+ }
+ else
+ {
+ xBodyTextAppend->insertTextPortion("\n--------\n", aArgs, xText->getStart());
+ aArgs = {
+ comphelper::makePropertyValue("CharWeight", uno::Any(awt::FontWeight::BOLD)),
+ };
+ xBodyTextAppend->insertTextPortion(aUserData.makeStringAndClear(), aArgs, xText->getStart());
+ }
}
}
-ScCaptionPtr ScNoteUtil::CreateTempCaption(
+rtl::Reference<SdrCaptionObj> ScNoteUtil::CreateTempCaption(
ScDocument& rDoc, const ScAddress& rPos, SdrPage& rDrawPage,
- const OUString& rUserText, const tools::Rectangle& rVisRect, bool bTailFront )
+ std::u16string_view rUserText, const tools::Rectangle& rVisRect, bool bTailFront )
{
+ bool bUserWithTrackText = false;
OUStringBuffer aBuffer( rUserText );
// add plain text of invisible (!) cell note (no formatting etc.)
SdrCaptionObj* pNoteCaption = nullptr;
const ScPostIt* pNote = rDoc.GetNote( rPos );
if( pNote && !pNote->IsCaptionShown() )
{
- if( !aBuffer.isEmpty() )
- aBuffer.append( "\n--------\n" + pNote->GetText() );
+ if (!aBuffer.isEmpty())
+ {
+ bUserWithTrackText = true;
+ aBuffer.append("\n--------\n");
+ }
+ else
+ {
+ aBuffer.append(pNote->GetAuthor()
+ + ", "
+ + pNote->GetDate());
+ }
pNoteCaption = pNote->GetOrCreateCaption( rPos );
}
- // create a caption if any text exists
- if( !pNoteCaption && aBuffer.isEmpty() )
- return ScCaptionPtr();
-
// prepare visible rectangle (add default distance to all borders)
tools::Rectangle aVisRect(
rVisRect.Left() + SC_NOTECAPTION_BORDERDIST_TEMP,
@@ -1188,34 +856,36 @@ ScCaptionPtr ScNoteUtil::CreateTempCaption(
ScCaptionCreator aCreator( rDoc, rPos, bTailFront );
// insert caption into page (needed to set caption text)
- aCreator.GetCaption().insertToDrawPage( rDrawPage );
-
- SdrCaptionObj* pCaption = aCreator.GetCaption().get(); // just for ease of use
+ rtl::Reference<SdrCaptionObj> pCaption = aCreator.GetCaption(); // just for ease of use
+ rDrawPage.InsertObject( pCaption.get() );
- // clone the edit text object, unless user text is present, then set this text
- if( pNoteCaption && rUserText.isEmpty() )
+ // clone the edit text object, then seta and format the Author and date text
+ if (pNoteCaption)
{
if( OutlinerParaObject* pOPO = pNoteCaption->GetOutlinerParaObject() )
- pCaption->SetOutlinerParaObject( std::make_unique<OutlinerParaObject>( *pOPO ) );
+ pCaption->SetOutlinerParaObject( *pOPO );
+ // Setting and formatting rUserText: Author name and date time
+ lcl_FormatAndInsertAuthorAndDatepara(pCaption.get(), aBuffer, bUserWithTrackText);
// set formatting (must be done after setting text) and resize the box to fit the text
- pCaption->SetMergedItemSetAndBroadcast( pNoteCaption->GetMergedItemSet() );
- tools::Rectangle aCaptRect( pCaption->GetLogicRect().TopLeft(), pNoteCaption->GetLogicRect().GetSize() );
- pCaption->SetLogicRect( aCaptRect );
+ if (auto pStyleSheet = pNoteCaption->GetStyleSheet())
+ pCaption->SetStyleSheet(pStyleSheet, true);
+ pCaption->SetMergedItemSetAndBroadcast(pNoteCaption->GetMergedItemSet());
}
else
{
- // if pNoteCaption is null, then aBuffer contains some text
- pCaption->SetText( aBuffer.makeStringAndClear() );
- ScCaptionUtil::SetDefaultItems( *pCaption, rDoc, nullptr );
- // adjust caption size to text size
- tools::Long nMaxWidth = ::std::min< tools::Long >( aVisRect.GetWidth() * 2 / 3, SC_NOTECAPTION_MAXWIDTH_TEMP );
- pCaption->SetMergedItem( makeSdrTextAutoGrowWidthItem( true ) );
- pCaption->SetMergedItem( makeSdrTextMinFrameWidthItem( SC_NOTECAPTION_WIDTH ) );
- pCaption->SetMergedItem( makeSdrTextMaxFrameWidthItem( nMaxWidth ) );
- pCaption->SetMergedItem( makeSdrTextAutoGrowHeightItem( true ) );
- pCaption->AdjustTextFrameWidthAndHeight();
+ pCaption->SetText(aBuffer.makeStringAndClear());
+ if (auto pStyleSheet = rDoc.GetStyleSheetPool()->Find(ScResId(STR_STYLENAME_NOTE), SfxStyleFamily::Frame))
+ pCaption->SetStyleSheet(static_cast<SfxStyleSheet*>(pStyleSheet), true);
}
+ // adjust caption size to text size
+ tools::Long nMaxWidth = ::std::min< tools::Long >( aVisRect.GetWidth() * 2 / 3, SC_NOTECAPTION_MAXWIDTH_TEMP );
+ pCaption->SetMergedItem( makeSdrTextAutoGrowWidthItem( true ) );
+ pCaption->SetMergedItem( makeSdrTextMinFrameWidthItem( SC_NOTECAPTION_WIDTH ) );
+ pCaption->SetMergedItem( makeSdrTextMaxFrameWidthItem( nMaxWidth ) );
+ pCaption->SetMergedItem( makeSdrTextAutoGrowHeightItem( true ) );
+ pCaption->AdjustTextFrameWidthAndHeight();
+
// move caption into visible area
aCreator.AutoPlaceCaption( &aVisRect );
@@ -1224,10 +894,10 @@ ScCaptionPtr ScNoteUtil::CreateTempCaption(
}
ScPostIt* ScNoteUtil::CreateNoteFromCaption(
- ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj* pCaption )
+ ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj* pCaption, bool bHasStyle )
{
ScNoteData aNoteData( true/*bShown*/ );
- aNoteData.mxCaption.reset( pCaption );
+ aNoteData.mxCaption = pCaption;
ScPostIt* pNote = new ScPostIt( rDoc, rPos, aNoteData, false );
pNote->AutoStamp();
@@ -1236,20 +906,26 @@ ScPostIt* ScNoteUtil::CreateNoteFromCaption(
// ScNoteCaptionCreator c'tor updates the caption object to be part of a note
ScNoteCaptionCreator aCreator( rDoc, rPos, aNoteData.mxCaption, true/*bShown*/ );
+ if (!bHasStyle)
+ {
+ if (auto pStyleSheet = rDoc.GetStyleSheetPool()->Find(ScResId(STR_STYLENAME_NOTE), SfxStyleFamily::Frame))
+ aNoteData.mxCaption->SetStyleSheet(static_cast<SfxStyleSheet*>(pStyleSheet), true);
+
+ /* We used to show a shadow despite of the shadow item being set to false.
+ Clear the existing item, so it inherits the true setting from the style.
+ Setting explicitly to true would corrupt the shadow when opened in older versions. */
+ aNoteData.mxCaption->ClearMergedItem(SDRATTR_SHADOW);
+ }
+
return pNote;
}
-ScPostIt* ScNoteUtil::CreateNoteFromObjectData(
- ScDocument& rDoc, const ScAddress& rPos, std::unique_ptr<SfxItemSet> pItemSet,
- OutlinerParaObject* pOutlinerObj, const tools::Rectangle& rCaptionRect,
- bool bShown )
+ScNoteData ScNoteUtil::CreateNoteData(ScDocument& rDoc, const ScAddress& rPos,
+ const tools::Rectangle& rCaptionRect, bool bShown)
{
- OSL_ENSURE( pItemSet && pOutlinerObj, "ScNoteUtil::CreateNoteFromObjectData - item set and outliner object expected" );
ScNoteData aNoteData( bShown );
aNoteData.mxInitData = std::make_shared<ScCaptionInitData>();
ScCaptionInitData& rInitData = *aNoteData.mxInitData;
- rInitData.mxItemSet = std::move(pItemSet);
- rInitData.mxOutlinerObj.reset( pOutlinerObj );
// convert absolute caption position to relative position
rInitData.mbDefaultPosSize = rCaptionRect.IsEmpty();
@@ -1262,13 +938,49 @@ ScPostIt* ScNoteUtil::CreateNoteFromObjectData(
rInitData.maCaptionSize = rCaptionRect.GetSize();
}
+ return aNoteData;
+}
+
+ScPostIt* ScNoteUtil::CreateNoteFromObjectData(
+ ScDocument& rDoc, const ScAddress& rPos, const SfxItemSet& rItemSet, const OUString& rStyleName,
+ const OutlinerParaObject& rOutlinerObj, const tools::Rectangle& rCaptionRect,
+ bool bShown )
+{
+ ScNoteData aNoteData(CreateNoteData(rDoc, rPos, rCaptionRect, bShown));
+ ScCaptionInitData& rInitData = *aNoteData.mxInitData;
+ rInitData.mxOutlinerObj = rOutlinerObj;
+ rInitData.moItemSet.emplace(rItemSet);
+ rInitData.maStyleName = ScStyleNameConversion::ProgrammaticToDisplayName(rStyleName, SfxStyleFamily::Frame);
+
+ return InsertNote(rDoc, rPos, std::move(aNoteData), /*bAlwaysCreateCaption*/false, 0/*nPostItId*/);
+}
+
+ScPostIt* ScNoteUtil::CreateNoteFromGenerator(
+ ScDocument& rDoc, const ScAddress& rPos,
+ std::unique_ptr<GenerateNoteCaption> xGenerator,
+ const tools::Rectangle& rCaptionRect,
+ bool bShown )
+{
+ ScNoteData aNoteData(CreateNoteData(rDoc, rPos, rCaptionRect, bShown));
+ ScCaptionInitData& rInitData = *aNoteData.mxInitData;
+ rInitData.mxGenerator = std::move(xGenerator);
+ // because the Caption is generated on demand, we will need to create the
+ // simple text now to supply any queries for that which don't require
+ // creation of a full Caption
+ rInitData.maSimpleText = rInitData.mxGenerator->GetSimpleText();
+
+ return InsertNote(rDoc, rPos, std::move(aNoteData), /*bAlwaysCreateCaption*/false, 0/*nPostItId*/);
+}
+
+ScPostIt* ScNoteUtil::InsertNote(ScDocument& rDoc, const ScAddress& rPos, ScNoteData&& rNoteData,
+ bool bAlwaysCreateCaption, sal_uInt32 nPostItId)
+{
/* Create the note and insert it into the document. If the note is
visible, the caption object will be created automatically. */
- ScPostIt* pNote = new ScPostIt( rDoc, rPos, aNoteData, /*bAlwaysCreateCaption*/false, 0/*nPostItId*/ );
+ ScPostIt* pNote = new ScPostIt( rDoc, rPos, std::move(rNoteData), bAlwaysCreateCaption, nPostItId );
pNote->AutoStamp();
-
+ //insert takes ownership
rDoc.SetNote(rPos, std::unique_ptr<ScPostIt>(pNote));
-
return pNote;
}
@@ -1283,14 +995,10 @@ ScPostIt* ScNoteUtil::CreateNoteFromString(
aNoteData.mxInitData = std::make_shared<ScCaptionInitData>();
ScCaptionInitData& rInitData = *aNoteData.mxInitData;
rInitData.maSimpleText = rNoteText;
+ rInitData.maStyleName = ScResId(STR_STYLENAME_NOTE);
rInitData.mbDefaultPosSize = true;
- /* Create the note and insert it into the document. If the note is
- visible, the caption object will be created automatically. */
- pNote = new ScPostIt( rDoc, rPos, aNoteData, bAlwaysCreateCaption, nPostItId );
- pNote->AutoStamp();
- //insert takes ownership
- rDoc.SetNote(rPos, std::unique_ptr<ScPostIt>(pNote));
+ pNote = InsertNote(rDoc, rPos, std::move(aNoteData), bAlwaysCreateCaption, nPostItId);
}
return pNote;
}
diff --git a/sc/source/core/data/queryevaluator.cxx b/sc/source/core/data/queryevaluator.cxx
new file mode 100644
index 000000000000..b21c75801a6f
--- /dev/null
+++ b/sc/source/core/data/queryevaluator.cxx
@@ -0,0 +1,897 @@
+/* -*- 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 .
+ */
+
+#include <rtl/math.hxx>
+#include <queryevaluator.hxx>
+
+#include <cellform.hxx>
+#include <cellvalue.hxx>
+#include <document.hxx>
+#include <docoptio.hxx>
+#include <queryparam.hxx>
+#include <table.hxx>
+
+#include <svl/numformat.hxx>
+#include <svl/sharedstringpool.hxx>
+#include <svl/zformat.hxx>
+#include <unotools/collatorwrapper.hxx>
+
+bool ScQueryEvaluator::isPartialTextMatchOp(ScQueryOp eOp)
+{
+ switch (eOp)
+ {
+ // these operators can only be used with textural comparisons.
+ case SC_CONTAINS:
+ case SC_DOES_NOT_CONTAIN:
+ case SC_BEGINS_WITH:
+ case SC_ENDS_WITH:
+ case SC_DOES_NOT_BEGIN_WITH:
+ case SC_DOES_NOT_END_WITH:
+ return true;
+ default:;
+ }
+ return false;
+}
+
+bool ScQueryEvaluator::isTextMatchOp(ScQueryOp eOp)
+{
+ if (isPartialTextMatchOp(eOp))
+ return true;
+
+ switch (eOp)
+ {
+ // these operators can be used for either textural or value comparison.
+ case SC_EQUAL:
+ case SC_NOT_EQUAL:
+ return true;
+ default:;
+ }
+ return false;
+}
+
+bool ScQueryEvaluator::isMatchWholeCellHelper(bool docMatchWholeCell, ScQueryOp eOp)
+{
+ bool bMatchWholeCell = docMatchWholeCell;
+ if (isPartialTextMatchOp(eOp))
+ // may have to do partial textural comparison.
+ bMatchWholeCell = false;
+ return bMatchWholeCell;
+}
+
+bool ScQueryEvaluator::isMatchWholeCell(ScQueryOp eOp) const
+{
+ return isMatchWholeCellHelper(mbMatchWholeCell, eOp);
+}
+
+bool ScQueryEvaluator::isMatchWholeCell(const ScDocument& rDoc, ScQueryOp eOp)
+{
+ return isMatchWholeCellHelper(rDoc.GetDocOptions().IsMatchWholeCell(), eOp);
+}
+
+void ScQueryEvaluator::setupTransliteratorIfNeeded()
+{
+ if (!mpTransliteration)
+ mpTransliteration = &ScGlobal::GetTransliteration(mrParam.bCaseSens);
+}
+
+void ScQueryEvaluator::setupCollatorIfNeeded()
+{
+ if (!mpCollator)
+ mpCollator = &ScGlobal::GetCollator(mrParam.bCaseSens);
+}
+
+ScQueryEvaluator::ScQueryEvaluator(ScDocument& rDoc, const ScTable& rTab,
+ const ScQueryParam& rParam, ScInterpreterContext* pContext,
+ bool* pTestEqualCondition)
+ : mrDoc(rDoc)
+ , mrStrPool(rDoc.GetSharedStringPool())
+ , mrTab(rTab)
+ , mrParam(rParam)
+ , mpTestEqualCondition(pTestEqualCondition)
+ , mpTransliteration(nullptr)
+ , mpCollator(nullptr)
+ , mbMatchWholeCell(rDoc.GetDocOptions().IsMatchWholeCell())
+ , mbCaseSensitive(rParam.bCaseSens)
+ , mpContext(pContext)
+ , mnEntryCount(mrParam.GetEntryCount())
+{
+ if (mnEntryCount <= nFixedBools)
+ {
+ mpPasst = &maBool[0];
+ mpTest = &maTest[0];
+ }
+ else
+ {
+ mpBoolDynamic.reset(new bool[mnEntryCount]);
+ mpTestDynamic.reset(new bool[mnEntryCount]);
+ mpPasst = mpBoolDynamic.get();
+ mpTest = mpTestDynamic.get();
+ }
+}
+
+bool ScQueryEvaluator::isRealWildOrRegExp(const ScQueryEntry& rEntry) const
+{
+ if (mrParam.eSearchType == utl::SearchParam::SearchType::Normal)
+ return false;
+
+ return isTextMatchOp(rEntry.eOp);
+}
+
+bool ScQueryEvaluator::isTestWildOrRegExp(const ScQueryEntry& rEntry) const
+{
+ if (!mpTestEqualCondition)
+ return false;
+
+ if (mrParam.eSearchType == utl::SearchParam::SearchType::Normal)
+ return false;
+
+ return (rEntry.eOp == SC_LESS_EQUAL || rEntry.eOp == SC_GREATER_EQUAL);
+}
+
+bool ScQueryEvaluator::isQueryByValue(ScQueryOp eOp, ScQueryEntry::QueryType eType,
+ const ScRefCellValue& rCell)
+{
+ if (eType == ScQueryEntry::ByString || isPartialTextMatchOp(eOp))
+ return false;
+
+ return isQueryByValueForCell(rCell);
+}
+
+bool ScQueryEvaluator::isQueryByValueForCell(const ScRefCellValue& rCell)
+{
+ if (rCell.getType() == CELLTYPE_FORMULA
+ && rCell.getFormula()->GetErrCode() != FormulaError::NONE)
+ // Error values are compared as string.
+ return false;
+
+ return rCell.hasNumeric();
+}
+
+bool ScQueryEvaluator::isQueryByString(ScQueryOp eOp, ScQueryEntry::QueryType eType,
+ const ScRefCellValue& rCell)
+{
+ if (isTextMatchOp(eOp))
+ return true;
+
+ if (eType != ScQueryEntry::ByString)
+ return false;
+
+ return rCell.hasString();
+}
+
+sal_uInt32 ScQueryEvaluator::getNumFmt(SCCOL nCol, SCROW nRow)
+{
+ sal_uInt32 nNumFmt
+ = (mpContext ? mrTab.GetNumberFormat(*mpContext, ScAddress(nCol, nRow, mrTab.GetTab()))
+ : mrTab.GetNumberFormat(nCol, nRow));
+ if (nNumFmt && (nNumFmt % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
+ // Any General of any locale is irrelevant for rounding.
+ nNumFmt = 0;
+ return nNumFmt;
+}
+
+std::pair<bool, bool> ScQueryEvaluator::compareByValue(const ScRefCellValue& rCell, SCCOL nCol,
+ SCROW nRow, const ScQueryEntry& rEntry,
+ const ScQueryEntry::Item& rItem)
+{
+ bool bOk = false;
+ bool bTestEqual = false;
+ double nCellVal;
+ double fQueryVal = rItem.mfVal;
+ // Defer all number format detection to as late as possible as it's a
+ // bottle neck, even if that complicates the code. Also do not
+ // unnecessarily call ScDocument::RoundValueAsShown() for the same
+ // reason.
+ sal_uInt32 nNumFmt = NUMBERFORMAT_ENTRY_NOT_FOUND;
+
+ switch (rCell.getType())
+ {
+ case CELLTYPE_VALUE:
+ nCellVal = rCell.getDouble();
+ break;
+ case CELLTYPE_FORMULA:
+ nCellVal = rCell.getFormula()->GetValue();
+ break;
+ default:
+ nCellVal = 0.0;
+ }
+ if (rItem.mbRoundForFilter && nCellVal != 0.0)
+ {
+ nNumFmt = getNumFmt(nCol, nRow);
+ if (nNumFmt)
+ {
+ switch (rCell.getType())
+ {
+ case CELLTYPE_VALUE:
+ case CELLTYPE_FORMULA:
+ nCellVal = mrDoc.RoundValueAsShown(nCellVal, nNumFmt, mpContext);
+ break;
+ default:
+ assert(!"can't be");
+ }
+ }
+ }
+
+ /* NOTE: lcl_PrepareQuery() prepares a filter query such that if a
+ * date+time format was queried rEntry.bQueryByDate is not set. In
+ * case other queries wanted to use this mechanism they should do
+ * the same, in other words only if rEntry.nVal is an integer value
+ * rEntry.bQueryByDate should be true and the time fraction be
+ * stripped here. */
+
+ if (rItem.meType == ScQueryEntry::ByDate)
+ {
+ if (nNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND)
+ nNumFmt = getNumFmt(nCol, nRow);
+ if (nNumFmt)
+ {
+ const SvNumberFormatter* pFormatter
+ = mpContext ? mpContext->GetFormatTable() : mrDoc.GetFormatTable();
+ const SvNumberformat* pEntry = pFormatter->GetEntry(nNumFmt);
+ if (pEntry)
+ {
+ SvNumFormatType nNumFmtType = pEntry->GetType();
+ /* NOTE: Omitting the check for absence of
+ * css::util::NumberFormat::TIME would include also date+time formatted
+ * values of the same day. That may be desired in some
+ * cases, querying all time values of a day, but confusing
+ * in other cases. A user can always setup a standard
+ * filter query for x >= date AND x < date+1 */
+ if ((nNumFmtType & SvNumFormatType::DATE) && !(nNumFmtType & SvNumFormatType::TIME))
+ {
+ // The format is of date type. Strip off the time
+ // element.
+ nCellVal = ::rtl::math::approxFloor(nCellVal);
+ }
+ }
+ }
+ }
+
+ switch (rEntry.eOp)
+ {
+ case SC_EQUAL:
+ bOk = ::rtl::math::approxEqual(nCellVal, fQueryVal);
+ break;
+ case SC_LESS:
+ bOk = (nCellVal < fQueryVal) && !::rtl::math::approxEqual(nCellVal, fQueryVal);
+ break;
+ case SC_GREATER:
+ bOk = (nCellVal > fQueryVal) && !::rtl::math::approxEqual(nCellVal, fQueryVal);
+ break;
+ case SC_LESS_EQUAL:
+ bOk = (nCellVal < fQueryVal) || ::rtl::math::approxEqual(nCellVal, fQueryVal);
+ if (bOk && mpTestEqualCondition)
+ bTestEqual = ::rtl::math::approxEqual(nCellVal, fQueryVal);
+ break;
+ case SC_GREATER_EQUAL:
+ bOk = (nCellVal > fQueryVal) || ::rtl::math::approxEqual(nCellVal, fQueryVal);
+ if (bOk && mpTestEqualCondition)
+ bTestEqual = ::rtl::math::approxEqual(nCellVal, fQueryVal);
+ break;
+ case SC_NOT_EQUAL:
+ bOk = !::rtl::math::approxEqual(nCellVal, fQueryVal);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+ return std::pair<bool, bool>(bOk, bTestEqual);
+}
+
+OUString ScQueryEvaluator::getCellString(const ScRefCellValue& rCell, SCROW nRow, SCCOL nCol,
+ const svl::SharedString** sharedString)
+{
+ if (rCell.getType() == CELLTYPE_FORMULA
+ && rCell.getFormula()->GetErrCode() != FormulaError::NONE)
+ {
+ // Error cell is evaluated as string (for now).
+ const FormulaError error = rCell.getFormula()->GetErrCode();
+ auto it = mCachedSharedErrorStrings.find(error);
+ if (it == mCachedSharedErrorStrings.end())
+ {
+ svl::SharedString str = mrStrPool.intern(ScGlobal::GetErrorString(error));
+ auto pos = mCachedSharedErrorStrings.insert({ error, str });
+ assert(pos.second); // inserted
+ it = pos.first;
+ }
+ *sharedString = &it->second;
+ return OUString();
+ }
+ else if (rCell.getType() == CELLTYPE_STRING)
+ {
+ *sharedString = rCell.getSharedString();
+ return OUString();
+ }
+ else
+ {
+ sal_uInt32 nFormat
+ = mpContext ? mrTab.GetNumberFormat(*mpContext, ScAddress(nCol, nRow, mrTab.GetTab()))
+ : mrTab.GetNumberFormat(nCol, nRow);
+ return ScCellFormat::GetInputString(rCell, nFormat, mpContext, mrDoc, sharedString, true);
+ }
+}
+
+bool ScQueryEvaluator::isFastCompareByString(const ScQueryEntry& rEntry) const
+{
+ // If this is true, then there's a fast path in compareByString() which
+ // can be selected using the template argument to get fast code
+ // that will not check the same conditions every time. This makes a difference
+ // in fast lookups that search for an exact value (case sensitive or not).
+ const bool bRealWildOrRegExp = isRealWildOrRegExp(rEntry);
+ const bool bTestWildOrRegExp = isTestWildOrRegExp(rEntry);
+ // SC_EQUAL is part of isTextMatchOp(rEntry)
+ return rEntry.eOp == SC_EQUAL && !bRealWildOrRegExp && !bTestWildOrRegExp
+ && isMatchWholeCell(rEntry.eOp);
+}
+
+// The value is placed inside one parameter: [pValueSource1] or [pValueSource2] but never in both.
+// For the template argument see isFastCompareByString().
+template <bool bFast>
+std::pair<bool, bool> ScQueryEvaluator::compareByString(const ScQueryEntry& rEntry,
+ const ScQueryEntry::Item& rItem,
+ const svl::SharedString* pValueSource1,
+ const OUString* pValueSource2)
+{
+ bool bOk = false;
+ bool bTestEqual = false;
+ bool bMatchWholeCell;
+ if (bFast)
+ bMatchWholeCell = true;
+ else
+ bMatchWholeCell = isMatchWholeCell(rEntry.eOp);
+ const bool bRealWildOrRegExp = !bFast && isRealWildOrRegExp(rEntry);
+ const bool bTestWildOrRegExp = !bFast && isTestWildOrRegExp(rEntry);
+
+ assert(!bFast || pValueSource1 != nullptr); // shared string for fast path
+ // [pValueSource1] or [pValueSource2] but never both of them or none of them
+ assert((pValueSource1 != nullptr) != (pValueSource2 != nullptr));
+
+ if (!bFast && (bRealWildOrRegExp || bTestWildOrRegExp))
+ {
+ const OUString& rValue = pValueSource1 ? pValueSource1->getString() : *pValueSource2;
+
+ sal_Int32 nStart = 0;
+ sal_Int32 nEnd = rValue.getLength();
+
+ // from 614 on, nEnd is behind the found text
+ bool bMatch = false;
+ if (rEntry.eOp == SC_ENDS_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH)
+ {
+ nEnd = 0;
+ nStart = rValue.getLength();
+ bMatch
+ = rEntry.GetSearchTextPtr(mrParam.eSearchType, mrParam.bCaseSens, bMatchWholeCell)
+ ->SearchBackward(rValue, &nStart, &nEnd);
+ }
+ else
+ {
+ bMatch
+ = rEntry.GetSearchTextPtr(mrParam.eSearchType, mrParam.bCaseSens, bMatchWholeCell)
+ ->SearchForward(rValue, &nStart, &nEnd);
+ }
+ if (bMatch && bMatchWholeCell && (nStart != 0 || nEnd != rValue.getLength()))
+ bMatch = false; // RegExp must match entire cell string
+ if (bRealWildOrRegExp)
+ {
+ switch (rEntry.eOp)
+ {
+ case SC_EQUAL:
+ case SC_CONTAINS:
+ bOk = bMatch;
+ break;
+ case SC_NOT_EQUAL:
+ case SC_DOES_NOT_CONTAIN:
+ bOk = !bMatch;
+ break;
+ case SC_BEGINS_WITH:
+ bOk = (bMatch && (nStart == 0));
+ break;
+ case SC_DOES_NOT_BEGIN_WITH:
+ bOk = !(bMatch && (nStart == 0));
+ break;
+ case SC_ENDS_WITH:
+ bOk = (bMatch && (nEnd == rValue.getLength()));
+ break;
+ case SC_DOES_NOT_END_WITH:
+ bOk = !(bMatch && (nEnd == rValue.getLength()));
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ }
+ else
+ bTestEqual = bMatch;
+ }
+ if (bFast || !bRealWildOrRegExp)
+ {
+ // Simple string matching i.e. no regexp match.
+ if (bFast || isTextMatchOp(rEntry.eOp))
+ {
+ // Check this even with bFast.
+ if (rItem.meType != ScQueryEntry::ByString && rItem.maString.isEmpty())
+ {
+ // #i18374# When used from functions (match, countif, sumif, vlookup, hlookup, lookup),
+ // the query value is assigned directly, and the string is empty. In that case,
+ // don't find any string (isEqual would find empty string results in formula cells).
+ bOk = false;
+ if (rEntry.eOp == SC_NOT_EQUAL)
+ bOk = !bOk;
+ }
+ else if (bFast || bMatchWholeCell)
+ {
+ if (bFast || pValueSource1)
+ {
+ // Fast string equality check by comparing string identifiers.
+ // This is the bFast path, all conditions should lead here on bFast == true.
+ if (mrParam.bCaseSens)
+ {
+ bOk = pValueSource1->getData() == rItem.maString.getData();
+ }
+ else
+ {
+ bOk = pValueSource1->getDataIgnoreCase()
+ == rItem.maString.getDataIgnoreCase();
+ }
+ }
+ else // if (pValueSource2)
+ {
+ if (mrParam.bCaseSens)
+ {
+ bOk = (*pValueSource2 == rItem.maString.getString());
+ }
+ else
+ {
+ // fallback
+ const svl::SharedString rSource2(mrStrPool.intern(*pValueSource2));
+ // Fast string equality check by comparing string identifiers.
+ bOk = rSource2.getDataIgnoreCase() == rItem.maString.getDataIgnoreCase();
+ }
+ }
+
+ if (!bFast && rEntry.eOp == SC_NOT_EQUAL)
+ bOk = !bOk;
+ }
+ else
+ {
+ // Where do we find a match (if at all)
+ sal_Int32 nStrPos;
+
+ if (!mbCaseSensitive)
+ { // Common case for vlookup etc.
+ const svl::SharedString rSource(
+ pValueSource1 ? *pValueSource1 : mrStrPool.intern(*pValueSource2));
+
+ const rtl_uString* pQuer = rItem.maString.getDataIgnoreCase();
+ const rtl_uString* pCellStr = rSource.getDataIgnoreCase();
+
+ assert(pCellStr != nullptr);
+ if (pQuer == nullptr)
+ pQuer = svl::SharedString::getEmptyString().getDataIgnoreCase();
+
+ const sal_Int32 nIndex
+ = (rEntry.eOp == SC_ENDS_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH)
+ ? (pCellStr->length - pQuer->length)
+ : 0;
+
+ if (nIndex < 0)
+ nStrPos = -1;
+ else
+ { // OUString::indexOf
+ nStrPos = rtl_ustr_indexOfStr_WithLength(pCellStr->buffer + nIndex,
+ pCellStr->length - nIndex,
+ pQuer->buffer, pQuer->length);
+
+ if (nStrPos >= 0)
+ nStrPos += nIndex;
+ }
+ }
+ else
+ {
+ const OUString& rValue
+ = pValueSource1 ? pValueSource1->getString() : *pValueSource2;
+ const OUString aQueryStr = rItem.maString.getString();
+ const LanguageType nLang
+ = ScGlobal::oSysLocale->GetLanguageTag().getLanguageType();
+ setupTransliteratorIfNeeded();
+ const OUString aCell(mpTransliteration->transliterate(
+ rValue, nLang, 0, rValue.getLength(), nullptr));
+
+ const OUString aQuer(mpTransliteration->transliterate(
+ aQueryStr, nLang, 0, aQueryStr.getLength(), nullptr));
+
+ const sal_Int32 nIndex
+ = (rEntry.eOp == SC_ENDS_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH)
+ ? (aCell.getLength() - aQuer.getLength())
+ : 0;
+ nStrPos = ((nIndex < 0) ? -1 : aCell.indexOf(aQuer, nIndex));
+ }
+ switch (rEntry.eOp)
+ {
+ case SC_EQUAL:
+ case SC_CONTAINS:
+ bOk = (nStrPos != -1);
+ break;
+ case SC_NOT_EQUAL:
+ case SC_DOES_NOT_CONTAIN:
+ bOk = (nStrPos == -1);
+ break;
+ case SC_BEGINS_WITH:
+ bOk = (nStrPos == 0);
+ break;
+ case SC_DOES_NOT_BEGIN_WITH:
+ bOk = (nStrPos != 0);
+ break;
+ case SC_ENDS_WITH:
+ bOk = (nStrPos >= 0);
+ break;
+ case SC_DOES_NOT_END_WITH:
+ bOk = (nStrPos < 0);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ }
+ }
+ else
+ { // use collator here because data was probably sorted
+ const OUString& rValue = pValueSource1 ? pValueSource1->getString() : *pValueSource2;
+ setupCollatorIfNeeded();
+ sal_Int32 nCompare = mpCollator->compareString(rValue, rItem.maString.getString());
+ switch (rEntry.eOp)
+ {
+ case SC_LESS:
+ bOk = (nCompare < 0);
+ break;
+ case SC_GREATER:
+ bOk = (nCompare > 0);
+ break;
+ case SC_LESS_EQUAL:
+ bOk = (nCompare <= 0);
+ if (bOk && mpTestEqualCondition && !bTestEqual)
+ bTestEqual = (nCompare == 0);
+ break;
+ case SC_GREATER_EQUAL:
+ bOk = (nCompare >= 0);
+ if (bOk && mpTestEqualCondition && !bTestEqual)
+ bTestEqual = (nCompare == 0);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ }
+ }
+
+ return std::pair<bool, bool>(bOk, bTestEqual);
+}
+
+std::pair<bool, bool> ScQueryEvaluator::compareByTextColor(SCCOL nCol, SCROW nRow,
+ const ScQueryEntry::Item& rItem)
+{
+ ScAddress aPos(nCol, nRow, mrTab.GetTab());
+ Color color = mrTab.GetCellTextColor(aPos);
+
+ bool bMatch = rItem.maColor == color;
+ return std::pair<bool, bool>(bMatch, false);
+}
+
+std::pair<bool, bool> ScQueryEvaluator::compareByBackgroundColor(SCCOL nCol, SCROW nRow,
+ const ScQueryEntry::Item& rItem)
+{
+ ScAddress aPos(nCol, nRow, mrTab.GetTab());
+ Color color = mrTab.GetCellBackgroundColor(aPos);
+
+ bool bMatch = rItem.maColor == color;
+ return std::pair<bool, bool>(bMatch, false);
+}
+
+// To be called only if both isQueryByValue() and isQueryByString()
+// returned false and range lookup is wanted! In range lookup comparison
+// numbers are less than strings. Nothing else is compared.
+std::pair<bool, bool> ScQueryEvaluator::compareByRangeLookup(const ScRefCellValue& rCell,
+ const ScQueryEntry& rEntry,
+ const ScQueryEntry::Item& rItem)
+{
+ bool bTestEqual = false;
+
+ if (rItem.meType == ScQueryEntry::ByString && rEntry.eOp != SC_LESS
+ && rEntry.eOp != SC_LESS_EQUAL)
+ return std::pair<bool, bool>(false, bTestEqual);
+
+ if (rItem.meType != ScQueryEntry::ByString && rEntry.eOp != SC_GREATER
+ && rEntry.eOp != SC_GREATER_EQUAL)
+ return std::pair<bool, bool>(false, bTestEqual);
+
+ if (rItem.meType == ScQueryEntry::ByString)
+ {
+ if (rCell.getType() == CELLTYPE_FORMULA
+ && rCell.getFormula()->GetErrCode() != FormulaError::NONE)
+ // Error values are compared as string.
+ return std::pair<bool, bool>(false, bTestEqual);
+
+ return std::pair<bool, bool>(rCell.hasNumeric(), bTestEqual);
+ }
+
+ return std::pair<bool, bool>(!rCell.hasNumeric(), bTestEqual);
+}
+
+std::pair<bool, bool> ScQueryEvaluator::processEntry(SCROW nRow, SCCOL nCol, ScRefCellValue& aCell,
+ const ScQueryEntry& rEntry, size_t nEntryIndex)
+{
+ std::pair<bool, bool> aRes(false, false);
+ const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
+ if (rItems.size() == 1 && rItems.front().meType == ScQueryEntry::ByEmpty)
+ {
+ if (rEntry.IsQueryByEmpty())
+ aRes.first = aCell.isEmpty();
+ else
+ {
+ assert(rEntry.IsQueryByNonEmpty());
+ aRes.first = !aCell.isEmpty();
+ }
+ return aRes;
+ }
+ if (rEntry.eOp == SC_EQUAL && rItems.size() >= 10)
+ {
+ // If there are many items to query for (autofilter does this), then try to search
+ // efficiently in those items. So first search all the items of the relevant type,
+ // If that does not find anything, fall back to the generic code.
+ double value = 0;
+ bool valid = true;
+ // For ScQueryEntry::ByValue check that the cell either is a value or is a formula
+ // that has a value and is not an error (those are compared as strings). This
+ // is basically simplified isQueryByValue().
+ if (aCell.getType() == CELLTYPE_VALUE)
+ value = aCell.getDouble();
+ else if (aCell.getType() == CELLTYPE_FORMULA
+ && aCell.getFormula()->GetErrCode() != FormulaError::NONE
+ && aCell.getFormula()->IsValue())
+ {
+ value = aCell.getFormula()->GetValue();
+ }
+ else
+ valid = false;
+ if (valid)
+ {
+ if (rItems.size() >= 100)
+ {
+ // Sort, cache and binary search for the value in items.
+ // Don't bother comparing approximately.
+ if (mCachedSortedItemValues.size() <= nEntryIndex)
+ {
+ mCachedSortedItemValues.resize(nEntryIndex + 1);
+ auto& values = mCachedSortedItemValues[nEntryIndex];
+ values.reserve(rItems.size());
+ for (const auto& rItem : rItems)
+ if (rItem.meType == ScQueryEntry::ByValue)
+ values.push_back(rItem.mfVal);
+ std::sort(values.begin(), values.end());
+ }
+ auto& values = mCachedSortedItemValues[nEntryIndex];
+ auto it = std::lower_bound(values.begin(), values.end(), value);
+ if (it != values.end() && *it == value)
+ return std::make_pair(true, true);
+ }
+ else
+ {
+ for (const auto& rItem : rItems)
+ {
+ // For speed don't bother comparing approximately here, usually there either
+ // will be an exact match or it wouldn't match anyway.
+ if (rItem.meType == ScQueryEntry::ByValue && value == rItem.mfVal)
+ {
+ return std::make_pair(true, true);
+ }
+ }
+ }
+ }
+ }
+ const svl::SharedString* cellSharedString = nullptr;
+ std::optional<OUString> oCellString;
+ const bool bFastCompareByString = isFastCompareByString(rEntry);
+ if (rEntry.eOp == SC_EQUAL && rItems.size() >= 10 && bFastCompareByString)
+ {
+ // The same as above but for strings. Try to optimize the case when
+ // it's a svl::SharedString comparison. That happens when SC_EQUAL is used
+ // and simple matching is used, see compareByString()
+ if (!oCellString)
+ oCellString = getCellString(aCell, nRow, rEntry.nField, &cellSharedString);
+ // Allow also checking ScQueryEntry::ByValue if the cell is not numeric,
+ // as in that case isQueryByNumeric() would be false and isQueryByString() would
+ // be true because of SC_EQUAL making isTextMatchOp() true.
+ bool compareByValue = !isQueryByValueForCell(aCell);
+ // For ScQueryEntry::ByString check that the cell is represented by a shared string,
+ // which means it's either a string cell or a formula error. This is not as
+ // generous as isQueryByString() but it should be enough and better be safe.
+ if (cellSharedString != nullptr)
+ {
+ if (rItems.size() >= 100)
+ {
+ // Sort, cache and binary search for the string in items.
+ // Since each SharedString is identified by pointer value,
+ // sorting by pointer value is enough.
+ if (mCachedSortedItemStrings.size() <= nEntryIndex)
+ {
+ mCachedSortedItemStrings.resize(nEntryIndex + 1);
+ auto& values = mCachedSortedItemStrings[nEntryIndex];
+ values.reserve(rItems.size());
+ for (const auto& rItem : rItems)
+ {
+ if (rItem.meType == ScQueryEntry::ByString
+ || (compareByValue && rItem.meType == ScQueryEntry::ByValue))
+ {
+ values.push_back(mrParam.bCaseSens
+ ? rItem.maString.getData()
+ : rItem.maString.getDataIgnoreCase());
+ }
+ }
+ std::sort(values.begin(), values.end());
+ }
+ auto& values = mCachedSortedItemStrings[nEntryIndex];
+ const rtl_uString* string = mrParam.bCaseSens
+ ? cellSharedString->getData()
+ : cellSharedString->getDataIgnoreCase();
+ auto it = std::lower_bound(values.begin(), values.end(), string);
+ if (it != values.end() && *it == string)
+ return std::make_pair(true, true);
+ }
+ else
+ {
+ for (const auto& rItem : rItems)
+ {
+ if ((rItem.meType == ScQueryEntry::ByString
+ || (compareByValue && rItem.meType == ScQueryEntry::ByValue))
+ && (mrParam.bCaseSens
+ ? cellSharedString->getData() == rItem.maString.getData()
+ : cellSharedString->getDataIgnoreCase()
+ == rItem.maString.getDataIgnoreCase()))
+ {
+ return std::make_pair(true, true);
+ }
+ }
+ }
+ }
+ }
+ // Generic handling.
+ for (const auto& rItem : rItems)
+ {
+ if (rItem.meType == ScQueryEntry::ByTextColor)
+ {
+ std::pair<bool, bool> aThisRes = compareByTextColor(nCol, nRow, rItem);
+ aRes.first |= aThisRes.first;
+ aRes.second |= aThisRes.second;
+ }
+ else if (rItem.meType == ScQueryEntry::ByBackgroundColor)
+ {
+ std::pair<bool, bool> aThisRes = compareByBackgroundColor(nCol, nRow, rItem);
+ aRes.first |= aThisRes.first;
+ aRes.second |= aThisRes.second;
+ }
+ else if (isQueryByValue(rEntry.eOp, rItem.meType, aCell))
+ {
+ std::pair<bool, bool> aThisRes = compareByValue(aCell, nCol, nRow, rEntry, rItem);
+ aRes.first |= aThisRes.first;
+ aRes.second |= aThisRes.second;
+ }
+ else if (isQueryByString(rEntry.eOp, rItem.meType, aCell))
+ {
+ if (!oCellString)
+ oCellString = getCellString(aCell, nRow, rEntry.nField, &cellSharedString);
+ std::pair<bool, bool> aThisRes;
+ if (cellSharedString && bFastCompareByString) // fast
+ aThisRes = compareByString<true>(rEntry, rItem, cellSharedString, nullptr);
+ else if (cellSharedString)
+ aThisRes = compareByString(rEntry, rItem, cellSharedString, nullptr);
+ else
+ aThisRes = compareByString(rEntry, rItem, nullptr, &*oCellString);
+ aRes.first |= aThisRes.first;
+ aRes.second |= aThisRes.second;
+ }
+ else if (mrParam.mbRangeLookup)
+ {
+ std::pair<bool, bool> aThisRes = compareByRangeLookup(aCell, rEntry, rItem);
+ aRes.first |= aThisRes.first;
+ aRes.second |= aThisRes.second;
+ }
+
+ if (aRes.first && (aRes.second || mpTestEqualCondition == nullptr))
+ break;
+ }
+ return aRes;
+}
+
+bool ScQueryEvaluator::ValidQuery(SCROW nRow, const ScRefCellValue* pCell,
+ sc::TableColumnBlockPositionSet* pBlockPos)
+{
+ if (!mrParam.GetEntry(0).bDoQuery)
+ return true;
+
+ tools::Long nPos = -1;
+ ScQueryParam::const_iterator it, itBeg = mrParam.begin(), itEnd = mrParam.end();
+ for (it = itBeg; it != itEnd && it->bDoQuery; ++it)
+ {
+ const ScQueryEntry& rEntry = *it;
+
+ // Short-circuit the test at the end of the loop - if this is SC_AND
+ // and the previous value is false, this value will not be needed.
+ // Disable this if pbTestEqualCondition is present as that one may get set
+ // even if the result is false (that also means pTest doesn't need to be
+ // handled here).
+ if (rEntry.eConnect == SC_AND && mpTestEqualCondition == nullptr && nPos != -1
+ && !mpPasst[nPos])
+ {
+ continue;
+ }
+
+ SCCOL nCol = static_cast<SCCOL>(rEntry.nField);
+
+ // We can only handle one single direct query passed as a known pCell,
+ // subsequent queries have to obtain the cell.
+ ScRefCellValue aCell;
+ if (pCell && it == itBeg)
+ aCell = *pCell;
+ else if (pBlockPos)
+ { // hinted mdds access
+ aCell = const_cast<ScTable&>(mrTab).GetCellValue(
+ nCol, *pBlockPos->getBlockPosition(nCol), nRow);
+ }
+ else
+ aCell = mrTab.GetCellValue(nCol, nRow);
+
+ std::pair<bool, bool> aRes = processEntry(nRow, nCol, aCell, rEntry, it - itBeg);
+
+ if (nPos == -1)
+ {
+ nPos++;
+ mpPasst[nPos] = aRes.first;
+ mpTest[nPos] = aRes.second;
+ }
+ else
+ {
+ if (rEntry.eConnect == SC_AND)
+ {
+ mpPasst[nPos] = mpPasst[nPos] && aRes.first;
+ mpTest[nPos] = mpTest[nPos] && aRes.second;
+ }
+ else
+ {
+ nPos++;
+ mpPasst[nPos] = aRes.first;
+ mpTest[nPos] = aRes.second;
+ }
+ }
+ }
+
+ for (tools::Long j = 1; j <= nPos; j++)
+ {
+ mpPasst[0] = mpPasst[0] || mpPasst[j];
+ mpTest[0] = mpTest[0] || mpTest[j];
+ }
+
+ bool bRet = mpPasst[0];
+ if (mpTestEqualCondition)
+ *mpTestEqualCondition = mpTest[0];
+
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/queryiter.cxx b/sc/source/core/data/queryiter.cxx
new file mode 100644
index 000000000000..7e2ba3851f08
--- /dev/null
+++ b/sc/source/core/data/queryiter.cxx
@@ -0,0 +1,1624 @@
+/* -*- 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 .
+ */
+
+#include <queryiter.hxx>
+#include <rtl/math.hxx>
+
+#include <comphelper/flagguard.hxx>
+#include <o3tl/safeint.hxx>
+#include <svl/numformat.hxx>
+
+#include <global.hxx>
+#include <document.hxx>
+#include <table.hxx>
+#include <column.hxx>
+#include <formulacell.hxx>
+#include <cellform.hxx>
+#include <queryparam.hxx>
+#include <queryentry.hxx>
+#include <cellvalue.hxx>
+#include <queryevaluator.hxx>
+#include <rangecache.hxx>
+#include <refdata.hxx>
+
+#include <svl/sharedstring.hxx>
+#include <unotools/collatorwrapper.hxx>
+
+#include <limits>
+#include <vector>
+
+template< ScQueryCellIteratorAccess accessType, ScQueryCellIteratorType queryType >
+ScQueryCellIteratorBase< accessType, queryType >::ScQueryCellIteratorBase(ScDocument& rDocument,
+ ScInterpreterContext& rContext, SCTAB nTable, const ScQueryParam& rParam, bool bMod, bool bReverse )
+ : AccessBase( rDocument, rContext, rParam, bReverse )
+ , nStopOnMismatch( nStopOnMismatchDisabled )
+ , nTestEqualCondition( nTestEqualConditionDisabled )
+ , nSortedBinarySearch( nBinarySearchDisabled )
+ , bAdvanceQuery( false )
+ , bIgnoreMismatchOnLeadingStrings( false )
+ , nSearchOpCode( SC_OPCODE_NONE )
+ , nBestFitCol(SCCOL_MAX)
+ , nBestFitRow(SCROW_MAX)
+{
+ nTab = nTable;
+ nCol = !bReverse ? maParam.nCol1 : maParam.nCol2;
+ nRow = !bReverse ? maParam.nRow1 : maParam.nRow2;
+ SCSIZE i;
+ if (!bMod) // Or else it's already inserted
+ return;
+
+ SCSIZE nCount = maParam.GetEntryCount();
+ for (i = 0; (i < nCount) && (maParam.GetEntry(i).bDoQuery); ++i)
+ {
+ ScQueryEntry& rEntry = maParam.GetEntry(i);
+ ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
+ sal_uInt32 nIndex = 0;
+ bool bNumber = mrContext.NFIsNumberFormat(
+ rItem.maString.getString(), nIndex, rItem.mfVal);
+ rItem.meType = bNumber ? ScQueryEntry::ByValue : ScQueryEntry::ByString;
+ }
+}
+
+template< ScQueryCellIteratorAccess accessType, ScQueryCellIteratorType queryType >
+void ScQueryCellIteratorBase< accessType, queryType >::PerformQuery()
+{
+ assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT");
+ const ScQueryEntry& rEntry = maParam.GetEntry(0);
+ const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
+
+ const bool bSingleQueryItem = rEntry.GetQueryItems().size() == 1;
+ SCCOLROW nFirstQueryField = rEntry.nField;
+ bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings &&
+ rItem.meType != ScQueryEntry::ByString;
+ bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
+ !maParam.bHasHeader && rItem.meType == ScQueryEntry::ByString &&
+ ((maParam.bByRow && nRow == maParam.nRow1) ||
+ (!maParam.bByRow && nCol == maParam.nCol1));
+ bool bTestEqualCondition = false;
+ ScQueryEvaluator queryEvaluator(rDoc, *rDoc.maTabs[nTab], maParam, &mrContext,
+ (nTestEqualCondition ? &bTestEqualCondition : nullptr));
+ if( queryType == ScQueryCellIteratorType::CountIf )
+ {
+ // These are not used for COUNTIF, so should not be set, make the compiler
+ // explicitly aware of it so that the relevant parts are optimized away.
+ assert( !bAllStringIgnore );
+ assert( !bIgnoreMismatchOnLeadingStrings );
+ assert( nStopOnMismatch == nStopOnMismatchDisabled );
+ assert( nTestEqualCondition == nTestEqualConditionDisabled );
+ bAllStringIgnore = false;
+ bIgnoreMismatchOnLeadingStrings = false;
+ nStopOnMismatch = nStopOnMismatchDisabled;
+ nTestEqualCondition = nTestEqualConditionDisabled;
+ // This one is always set.
+ assert( bAdvanceQuery );
+ bAdvanceQuery = true;
+ }
+
+ const ScColumn* pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
+ while (true)
+ {
+ bool bNextColumn = maCurPos.first == pCol->maCells.end();
+ if (!bNextColumn)
+ {
+ if ((!mbReverseSearch && nRow > maParam.nRow2) || (mbReverseSearch && nRow < maParam.nRow1))
+ bNextColumn = true;
+ }
+
+ if (bNextColumn)
+ {
+ do
+ {
+ if (!mbReverseSearch)
+ {
+ ++nCol;
+ if (nCol > maParam.nCol2 || nCol >= rDoc.maTabs[nTab]->GetAllocatedColumnsCount())
+ return;
+ }
+ else
+ {
+ --nCol;
+ if (nCol < maParam.nCol1 || nCol < static_cast<SCCOL>(0))
+ return;
+ }
+ if ( bAdvanceQuery )
+ {
+ AdvanceQueryParamEntryField();
+ nFirstQueryField = rEntry.nField;
+ }
+ pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
+ }
+ while (!rItem.mbMatchEmpty && pCol->IsEmptyData());
+
+ InitPos();
+
+ bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
+ !maParam.bHasHeader && rItem.meType == ScQueryEntry::ByString &&
+ maParam.bByRow;
+ }
+
+ if (maCurPos.first->type == sc::element_type_empty)
+ {
+ if (rItem.mbMatchEmpty && bSingleQueryItem)
+ {
+ // This shortcut, instead of determining if any SC_OR query
+ // exists or this query is SC_AND'ed (which wouldn't make
+ // sense, but..) and evaluating them in ValidQuery(), is
+ // possible only because the interpreter is the only caller
+ // that sets mbMatchEmpty and there is only one item in those
+ // cases.
+ // XXX this would have to be reworked if other filters used it
+ // in different manners and evaluation would have to be done in
+ // ValidQuery().
+ if(HandleItemFound())
+ return;
+ !mbReverseSearch ? IncPos() : DecPos();
+ continue;
+ }
+ else
+ {
+ !mbReverseSearch ? IncBlock() : DecBlock();
+ continue;
+ }
+ }
+
+ ScRefCellValue aCell = sc::toRefCell(maCurPos.first, maCurPos.second);
+
+ if (bAllStringIgnore && aCell.hasString())
+ !mbReverseSearch ? IncPos() : DecPos();
+ else
+ {
+ if ( queryEvaluator.ValidQuery( nRow,
+ (nCol == static_cast<SCCOL>(nFirstQueryField) ? &aCell : nullptr)))
+ {
+ if ( nTestEqualCondition && bTestEqualCondition )
+ nTestEqualCondition |= nTestEqualConditionMatched;
+ if ( aCell.isEmpty())
+ return;
+
+ // XLookUp/XMatch: Forward/asc/backward/desc search for best fit value, except if we have an exact match
+ if ((nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH) &&
+ (rEntry.eOp == SC_LESS_EQUAL || rEntry.eOp == SC_GREATER_EQUAL) &&
+ (nBestFitCol != nCol || nBestFitRow != nRow))
+ {
+ bool bNumSearch = rItem.meType == ScQueryEntry::ByValue && aCell.hasNumeric();
+ bool bStringSearch = rItem.meType == ScQueryEntry::ByString && aCell.hasString();
+ if (bNumSearch || bStringSearch)
+ {
+ if (nTestEqualCondition == nTestEqualConditionFulfilled || (nBestFitCol == SCCOL_MAX && nBestFitRow == SCROW_MAX))
+ HandleBestFitItemFound(nCol, nRow);
+ else
+ {
+ ScAddress aBFAddr(nBestFitCol, nBestFitRow, nTab);
+ ScRefCellValue aBFCell(rDoc, aBFAddr);
+ ScQueryParam aParamTmp(maParam);
+ ScQueryEntry& rEntryTmp = aParamTmp.GetEntry(0);
+
+ if (rEntry.eOp == SC_LESS_EQUAL)
+ rEntryTmp.eOp = SC_GREATER;
+ else if (rEntry.eOp == SC_GREATER_EQUAL)
+ rEntryTmp.eOp = SC_LESS;
+
+ ScQueryEntry::Item& rItemTmp = rEntryTmp.GetQueryItem();
+ if (bNumSearch)
+ rItemTmp.mfVal = aBFCell.getValue();
+ else if (bStringSearch)
+ rItemTmp.maString = svl::SharedString(aBFCell.getString(&rDoc));
+
+ ScQueryEvaluator queryEvaluatorTmp(rDoc, *rDoc.maTabs[nTab], aParamTmp, &mrContext, nullptr);
+ if (queryEvaluatorTmp.ValidQuery(nRow, (nCol == static_cast<SCCOL>(nFirstQueryField) ? &aCell : nullptr)))
+ HandleBestFitItemFound(nCol, nRow);
+ else
+ {
+ !mbReverseSearch ? IncPos() : DecPos();
+ continue;
+ }
+ }
+ }
+ else
+ {
+ !mbReverseSearch ? IncPos() : DecPos();
+ continue;
+ }
+ }
+ if (HandleItemFound())
+ return;
+ !mbReverseSearch ? IncPos() : DecPos();
+ continue;
+ }
+ else if ( nStopOnMismatch )
+ {
+ // Yes, even a mismatch may have a fulfilled equal
+ // condition if regular expressions were involved and
+ // SC_LESS_EQUAL or SC_GREATER_EQUAL were queried.
+ if ( nTestEqualCondition && bTestEqualCondition )
+ {
+ nTestEqualCondition |= nTestEqualConditionMatched;
+ nStopOnMismatch |= nStopOnMismatchOccurred;
+ return;
+ }
+ bool bStop;
+ if (bFirstStringIgnore)
+ {
+ if (aCell.hasString())
+ {
+ !mbReverseSearch ? IncPos() : DecPos();
+ bStop = false;
+ }
+ else
+ bStop = true;
+ }
+ else
+ bStop = true;
+ if (bStop)
+ {
+ nStopOnMismatch |= nStopOnMismatchOccurred;
+ return;
+ }
+ }
+ else
+ !mbReverseSearch ? IncPos() : DecPos();
+ }
+ bFirstStringIgnore = false;
+ }
+}
+
+template< ScQueryCellIteratorAccess accessType, ScQueryCellIteratorType queryType >
+void ScQueryCellIteratorBase< accessType, queryType >::InitPos()
+{
+ if constexpr( accessType != ScQueryCellIteratorAccess::SortedCache )
+ AccessBase::InitPos();
+ else
+ {
+ // This should be all in AccessBase::InitPos(), but that one can't call
+ // BinarySearch(), so do it this way instead.
+ AccessBase::InitPosStart();
+ ScQueryOp& op = maParam.GetEntry(0).eOp;
+ SCROW beforeRow = -1;
+ SCROW lastRow = -1;
+ if( op == SC_EQUAL )
+ {
+ if( BinarySearch( nCol ))
+ {
+ // BinarySearch() searches for the last item that matches. Now we
+ // also need to find the first item where to start. Find the last
+ // non-matching position using SC_LESS and the start position
+ // is the one after it.
+ lastRow = nRow;
+ // BinarySearch() looks for the first match for XLOOKUP/XMATCH
+ if (nSearchOpCode != SC_OPCODE_X_LOOKUP && nSearchOpCode != SC_OPCODE_X_MATCH)
+ {
+ ScQueryOp saveOp = op;
+ op = SC_LESS;
+ if( BinarySearch( nCol, true ))
+ beforeRow = nRow;
+ // If BinarySearch() returns false, there was no match, which means
+ // there's no value smaller. In that case BinarySearch() has set
+ // the position to the first row in the range.
+ op = saveOp; // back to SC_EQUAL
+ }
+ }
+ else if( maParam.GetEntry(0).GetQueryItem().mbMatchEmpty
+ && rDoc.IsEmptyData(nCol, maParam.nRow1, nCol, maParam.nRow2, nTab))
+ {
+ // BinarySearch() returns false in case it's all empty data,
+ // handle that specially.
+ beforeRow = -1;
+ lastRow = maParam.nRow2;
+ }
+ }
+ else
+ { // The range is from the start up to and including the last matching.
+ if( BinarySearch( nCol ))
+ lastRow = nRow;
+ }
+ AccessBase::InitPosFinish(beforeRow, lastRow,
+ (nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH));
+ }
+}
+
+template< ScQueryCellIteratorAccess accessType, ScQueryCellIteratorType queryType >
+void ScQueryCellIteratorBase< accessType, queryType >::AdvanceQueryParamEntryField()
+{
+ SCSIZE nEntries = maParam.GetEntryCount();
+ for ( SCSIZE j = 0; j < nEntries; j++ )
+ {
+ ScQueryEntry& rEntry = maParam.GetEntry( j );
+ if ( rEntry.bDoQuery )
+ {
+ if (!mbReverseSearch && rEntry.nField < rDoc.MaxCol())
+ rEntry.nField++;
+ else if (mbReverseSearch && rEntry.nField > static_cast<SCCOLROW>(0))
+ rEntry.nField--;
+ else
+ {
+ assert(!"AdvanceQueryParamEntryField: ++rEntry.nField > MAXCOL || --rEntry.nField < 0");
+ }
+ }
+ else
+ break; // for
+ }
+}
+
+namespace {
+
+template<typename Iter>
+void incBlock(std::pair<Iter, size_t>& rPos)
+{
+ // Move to the next block.
+ ++rPos.first;
+ rPos.second = 0;
+}
+
+template<typename Iter>
+void decBlock(std::pair<Iter, size_t>& rPos)
+{
+ // Move to the last element of the previous block.
+ --rPos.first;
+ rPos.second = rPos.first->size - 1;
+}
+
+}
+
+template< ScQueryCellIteratorAccess accessType, ScQueryCellIteratorType queryType >
+bool ScQueryCellIteratorBase< accessType, queryType >::BinarySearch( SCCOL col, bool forEqual )
+{
+ assert(maParam.GetEntry(0).bDoQuery && !maParam.GetEntry(1).bDoQuery
+ && maParam.GetEntry(0).GetQueryItems().size() == 1 );
+ assert(maParam.eSearchType == utl::SearchParam::SearchType::Normal);
+ assert(maParam.GetEntry(0).GetQueryItem().meType == ScQueryEntry::ByString
+ || maParam.GetEntry(0).GetQueryItem().meType == ScQueryEntry::ByValue);
+ assert(maParam.bByRow);
+ assert(maParam.GetEntry(0).eOp == SC_LESS || maParam.GetEntry(0).eOp == SC_LESS_EQUAL
+ || maParam.GetEntry(0).eOp == SC_GREATER || maParam.GetEntry(0).eOp == SC_GREATER_EQUAL
+ || maParam.GetEntry(0).eOp == SC_EQUAL);
+
+ // TODO: This will be extremely slow with mdds::multi_type_vector.
+
+ assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT");
+ nCol = col;
+ nRow = maParam.nRow1;
+
+ if (nCol >= rDoc.maTabs[nTab]->GetAllocatedColumnsCount())
+ return false;
+
+ const ScColumn* pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
+ if (pCol->IsEmptyData())
+ return false;
+
+ CollatorWrapper& rCollator = ScGlobal::GetCollator(maParam.bCaseSens);
+ const ScQueryEntry& rEntry = maParam.GetEntry(0);
+ const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
+ bool bAscending = rEntry.eOp == SC_LESS || rEntry.eOp == SC_LESS_EQUAL || rEntry.eOp == SC_EQUAL;
+ bool bByString = rItem.meType == ScQueryEntry::ByString;
+ bool bForceStr = bByString && ( rEntry.eOp == SC_EQUAL || forEqual );
+ bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings && !bByString;
+ bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
+ !maParam.bHasHeader && bByString;
+
+ if (maParam.bHasHeader)
+ ++nRow;
+
+ if (bFirstStringIgnore)
+ {
+ sc::CellStoreType::const_position_type aPos = pCol->maCells.position(nRow);
+ if (aPos.first->type == sc::element_type_string || aPos.first->type == sc::element_type_edittext)
+ {
+ ScRefCellValue aCell = sc::toRefCell(aPos.first, aPos.second);
+ sal_uInt32 nFormat = pCol->GetNumberFormat(mrContext, nRow);
+ OUString aCellStr = ScCellFormat::GetInputString(aCell, nFormat, &mrContext, rDoc);
+ sal_Int32 nTmp = rCollator.compareString(aCellStr, rEntry.GetQueryItem().maString.getString());
+ if ((rEntry.eOp == SC_LESS_EQUAL && nTmp > 0) ||
+ (rEntry.eOp == SC_GREATER_EQUAL && nTmp < 0) ||
+ (rEntry.eOp == SC_EQUAL && nTmp != 0) ||
+ (rEntry.eOp == SC_LESS && nTmp >= 0) ||
+ (rEntry.eOp == SC_GREATER && nTmp <= 0))
+ ++nRow;
+ }
+ }
+
+ // Skip leading empty block, if any.
+ sc::CellStoreType::const_position_type startPos = pCol->maCells.position(nRow);
+ if (startPos.first->type == sc::element_type_empty)
+ incBlock(startPos);
+ if(bAllStringIgnore)
+ {
+ // Skip all leading string or empty blocks.
+ while (startPos.first != pCol->maCells.end()
+ && (startPos.first->type == sc::element_type_string ||
+ startPos.first->type == sc::element_type_edittext ||
+ startPos.first->type == sc::element_type_empty))
+ {
+ incBlock(startPos);
+ }
+ }
+ if(startPos.first == pCol->maCells.end())
+ return false;
+ nRow = startPos.first->position + startPos.second;
+ if (nRow > maParam.nRow2)
+ return false;
+
+ auto aIndexer = MakeBinarySearchIndexer(pCol->maCells, nRow, maParam.nRow2);
+ if (!aIndexer.isValid())
+ return false;
+
+ size_t nLo = aIndexer.getLowIndex();
+ size_t nHi = aIndexer.getHighIndex();
+ BinarySearchCellType aCellData;
+
+ // Bookkeeping values for breaking up the binary search in case the data
+ // range isn't strictly sorted.
+ size_t nLastInRange = nLo;
+ double fLastInRangeValue = bAscending ?
+ -(::std::numeric_limits<double>::max()) :
+ ::std::numeric_limits<double>::max();
+ OUString aLastInRangeString;
+ if (!bAscending)
+ aLastInRangeString = OUString(u'\xFFFF');
+
+ aCellData = aIndexer.getCell(nLastInRange);
+ ScRefCellValue aCell = aCellData.first;
+ if (bForceStr || aCell.hasString())
+ {
+ sal_uInt32 nFormat = pCol->GetNumberFormat(mrContext, aCellData.second);
+ aLastInRangeString = ScCellFormat::GetInputString(aCell, nFormat, &mrContext, rDoc);
+ }
+ else
+ {
+ switch (aCell.getType())
+ {
+ case CELLTYPE_VALUE :
+ fLastInRangeValue = aCell.getDouble();
+ break;
+ case CELLTYPE_FORMULA :
+ fLastInRangeValue = aCell.getFormula()->GetValue();
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+
+ sal_Int32 nRes = 0;
+ std::optional<size_t> found;
+ bool bDone = false;
+ bool orderBroken = false;
+ while (nLo <= nHi && !bDone)
+ {
+ size_t nMid = (nLo+nHi)/2;
+ size_t i = nMid;
+
+ aCellData = aIndexer.getCell(i);
+ aCell = aCellData.first;
+ bool bStr = bForceStr || aCell.hasString();
+ nRes = 0;
+
+ // compares are content<query:-1, content>query:1
+ // Cell value comparison similar to ScTable::ValidQuery()
+ if (!bStr && !bByString)
+ {
+ double nCellVal;
+ switch (aCell.getType())
+ {
+ case CELLTYPE_VALUE :
+ case CELLTYPE_FORMULA :
+ nCellVal = aCell.getValue();
+ break;
+ default:
+ nCellVal = 0.0;
+ }
+ if ((nCellVal < rItem.mfVal) && !::rtl::math::approxEqual(
+ nCellVal, rItem.mfVal))
+ {
+ nRes = -1;
+ if (bAscending)
+ {
+ if (fLastInRangeValue <= nCellVal)
+ {
+ if ((nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH) &&
+ nSortedBinarySearch != nSearchbDesc && fLastInRangeValue == nCellVal &&
+ aIndexer.getLowIndex() != i)
+ bDone = true;
+ else
+ {
+ fLastInRangeValue = nCellVal;
+ nLastInRange = i;
+ }
+ }
+ else if (fLastInRangeValue >= nCellVal)
+ {
+ // not strictly sorted, continue with GetThis()
+ orderBroken = true;
+ bDone = true;
+ }
+ }
+ }
+ else if ((nCellVal > rItem.mfVal) && !::rtl::math::approxEqual(
+ nCellVal, rItem.mfVal))
+ {
+ nRes = 1;
+ if (!bAscending)
+ {
+ if (fLastInRangeValue >= nCellVal)
+ {
+ fLastInRangeValue = nCellVal;
+ nLastInRange = i;
+ }
+ else if (fLastInRangeValue <= nCellVal)
+ {
+ // not strictly sorted, continue with GetThis()
+ orderBroken = true;
+ bDone = true;
+ }
+ }
+ }
+ }
+ else if (bStr && bByString)
+ {
+ sal_uInt32 nFormat = pCol->GetNumberFormat(mrContext, aCellData.second);
+ OUString aCellStr = ScCellFormat::GetInputString(aCell, nFormat, &mrContext, rDoc);
+
+ nRes = rCollator.compareString(aCellStr, rEntry.GetQueryItem().maString.getString());
+ if (nRes < 0 && bAscending)
+ {
+ sal_Int32 nTmp = rCollator.compareString( aLastInRangeString,
+ aCellStr);
+ if (nTmp <= 0)
+ {
+ if ((nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH) &&
+ nSortedBinarySearch != nSearchbDesc && nTmp == 0 &&
+ aIndexer.getLowIndex() != i)
+ bDone = true;
+ else
+ {
+ aLastInRangeString = aCellStr;
+ nLastInRange = i;
+ }
+ }
+ else if (nTmp > 0)
+ {
+ // not strictly sorted, continue with GetThis()
+ orderBroken = true;
+ bDone = true;
+ }
+ }
+ else if (nRes > 0 && !bAscending)
+ {
+ sal_Int32 nTmp = rCollator.compareString( aLastInRangeString,
+ aCellStr);
+ if (nTmp >= 0)
+ {
+ aLastInRangeString = aCellStr;
+ nLastInRange = i;
+ }
+ else if (nTmp < 0)
+ {
+ // not strictly sorted, continue with GetThis()
+ orderBroken = true;
+ bDone = true;
+ }
+ }
+ }
+ else if (!bStr && bByString)
+ {
+ nRes = -1; // numeric < string
+ if (bAscending)
+ nLastInRange = i;
+ }
+ else // if (bStr && !bByString)
+ {
+ nRes = 1; // string > numeric
+ if (!bAscending)
+ nLastInRange = i;
+ }
+ if (nRes < 0)
+ {
+ if (bAscending)
+ nLo = nMid + 1;
+ else // assumed to be SC_GREATER_EQUAL
+ {
+ if (nMid > 0)
+ nHi = nMid - 1;
+ else
+ bDone = true;
+ }
+ }
+ else if (nRes > 0)
+ {
+ if (bAscending)
+ {
+ if (nMid > 0)
+ nHi = nMid - 1;
+ else
+ bDone = true;
+ }
+ else // assumed to be SC_GREATER_EQUAL
+ nLo = nMid + 1;
+ }
+ else
+ {
+ if(rEntry.eOp == SC_LESS_EQUAL || rEntry.eOp == SC_GREATER_EQUAL || rEntry.eOp == SC_EQUAL)
+ {
+ found = i;
+ nLastInRange = i;
+ if ((nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH) &&
+ (nSortedBinarySearch == nSearchbAscd && (rEntry.eOp == SC_LESS_EQUAL || rEntry.eOp == SC_EQUAL)))
+ bDone = true;
+ else // But keep searching to find the last matching one.
+ nLo = nMid + 1;
+ }
+ else if (bAscending)
+ {
+ if (nMid > 0)
+ nHi = nMid - 1;
+ else
+ bDone = true;
+ }
+ else
+ {
+ if (nMid > 0)
+ nHi = nMid - 1;
+ else
+ bDone = true;
+ }
+ }
+ }
+
+ bool isInRange;
+ if (orderBroken)
+ {
+ // Reset position to the first row in range and force caller
+ // to search from start.
+ nLo = aIndexer.getLowIndex();
+ isInRange = false;
+ }
+ else if (found)
+ {
+ nLo = *found;
+ isInRange = true;
+ }
+ else
+ {
+ // Not nothing was found and the search position is at the start,
+ // then the possible match would need to be before the data range.
+ // In that case return false to force the caller to search from the start
+ // and detect this.
+ isInRange = nLo != aIndexer.getLowIndex();
+ // If nothing was found, that is either because there is no value
+ // that would match exactly, or the data range is not properly sorted
+ // and we failed to detect (doing so reliably would require a linear scan).
+ // Set the position to the last one that was in matching range (i.e. before
+ // where the exact match would be), and leave sorting it out to GetThis()
+ // or whatever the caller uses.
+ nLo = nLastInRange;
+ }
+
+ aCellData = aIndexer.getCell(nLo);
+ if (nLo <= nHi && aCellData.second <= maParam.nRow2)
+ {
+ nRow = aCellData.second;
+ maCurPos = aIndexer.getPosition(nLo);
+ return isInRange;
+ }
+ else
+ {
+ nRow = maParam.nRow2 + 1;
+ // Set current position to the last possible row.
+ maCurPos.first = pCol->maCells.end();
+ --maCurPos.first;
+ maCurPos.second = maCurPos.first->size - 1;
+ return false;
+ }
+}
+
+
+template< ScQueryCellIteratorAccess accessType >
+bool ScQueryCellIterator< accessType >::FindEqualOrSortedLastInRange( SCCOL& nFoundCol,
+ SCROW& nFoundRow )
+{
+ // Set and automatically reset mpParam->mbRangeLookup when returning.
+ comphelper::FlagRestorationGuard aRangeLookupResetter( maParam.mbRangeLookup, true );
+
+ nFoundCol = rDoc.MaxCol()+1;
+ nFoundRow = rDoc.MaxRow()+1;
+
+ if ((nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH) &&
+ nSortedBinarySearch == nBinarySearchDisabled)
+ SetStopOnMismatch( false ); // assume not sorted keys for XLookup/XMatch
+ else
+ SetStopOnMismatch( true ); // assume sorted keys
+
+ SetTestEqualCondition( true );
+ bIgnoreMismatchOnLeadingStrings = true;
+
+ bool bLiteral = maParam.eSearchType == utl::SearchParam::SearchType::Normal &&
+ maParam.GetEntry(0).GetQueryItem().meType == ScQueryEntry::ByString;
+ bool bBinary = maParam.bByRow &&
+ (bLiteral || maParam.GetEntry(0).GetQueryItem().meType == ScQueryEntry::ByValue) &&
+ (maParam.GetEntry(0).eOp == SC_LESS_EQUAL || maParam.GetEntry(0).eOp == SC_GREATER_EQUAL);
+
+ // assume not sorted properly if we are using XLookup/XMatch with forward or backward search
+ if (bBinary && (nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH) &&
+ nSortedBinarySearch == nBinarySearchDisabled)
+ bBinary = false;
+
+ bool bFound = false;
+ if (bBinary)
+ {
+ if (BinarySearch( maParam.nCol1 ))
+ {
+ // BinarySearch() already positions correctly and only needs real
+ // query comparisons afterwards, skip the verification check below.
+ maParam.mbRangeLookup = false;
+ bFound = GetThis();
+ }
+ else // Not sorted properly, or before the range (in which case GetFirst() will be simple).
+ bFound = GetFirst();
+ }
+ else
+ {
+ bFound = GetFirst();
+ }
+ if (bFound)
+ {
+ // First equal entry or last smaller than (greater than) entry.
+ PositionType aPosSave;
+ bool bNext = false;
+ SCSIZE nEntries = maParam.GetEntryCount();
+ std::vector<SCCOL> aFoundFieldPositions(nEntries);
+ do
+ {
+ nFoundCol = GetCol();
+ nFoundRow = GetRow();
+ aPosSave = maCurPos;
+ // If we might need to rewind below, save the position to rewind to
+ // rather than calculate it as a diff between nCol and nFoundCol as
+ // PerformQuery can return early if nCol is greater than
+ // maParam.nCol2 or AllocatedColumns
+ if (maParam.mbRangeLookup && bAdvanceQuery)
+ {
+ for (SCSIZE j=0; j < nEntries; ++j)
+ {
+ ScQueryEntry& rEntry = maParam.GetEntry( j );
+ if (rEntry.bDoQuery)
+ aFoundFieldPositions[j] = maParam.GetEntry(j).nField;
+ else
+ break; // for
+ }
+ }
+ if (IsEqualConditionFulfilled())
+ break;
+ bNext = GetNext();
+ }
+ while (bNext);
+
+ // There may be no pNext but equal condition fulfilled if regular
+ // expressions are involved. Keep the found entry and proceed.
+ if (!bNext && !IsEqualConditionFulfilled())
+ {
+ // Step back to last in range and adjust position markers for
+ // GetNumberFormat() or similar.
+ bool bColDiff = nCol != nFoundCol;
+ nCol = nFoundCol;
+ nRow = nFoundRow;
+ maCurPos = aPosSave;
+ if (maParam.mbRangeLookup)
+ {
+ // Verify that the found entry does not only fulfill the range
+ // lookup but also the real query, i.e. not numeric was found
+ // if query is ByString and vice versa.
+ maParam.mbRangeLookup = false;
+ // Step back the last field advance if GetNext() did one.
+ if (bAdvanceQuery && bColDiff)
+ {
+ for (SCSIZE j=0; j < nEntries; ++j)
+ {
+ ScQueryEntry& rEntry = maParam.GetEntry( j );
+ if (rEntry.bDoQuery)
+ {
+ rEntry.nField = aFoundFieldPositions[j];
+ assert(rEntry.nField >= 0);
+ }
+ else
+ break; // for
+ }
+ }
+ // Check it.
+ if (!GetThis())
+ {
+ nFoundCol = rDoc.MaxCol()+1;
+ nFoundRow = rDoc.MaxRow()+1;
+ }
+ }
+ }
+ }
+ if (IsEqualConditionFulfilled() && (nSearchOpCode != SC_OPCODE_X_LOOKUP &&
+ nSearchOpCode != SC_OPCODE_X_MATCH))
+ {
+ // Position on last equal entry, except for XLOOKUP,
+ // which looking for the first equal entry
+ SCSIZE nEntries = maParam.GetEntryCount();
+ for ( SCSIZE j = 0; j < nEntries; j++ )
+ {
+ ScQueryEntry& rEntry = maParam.GetEntry( j );
+ if ( rEntry.bDoQuery )
+ {
+ switch ( rEntry.eOp )
+ {
+ case SC_LESS_EQUAL :
+ case SC_GREATER_EQUAL :
+ rEntry.eOp = SC_EQUAL;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ else
+ break; // for
+ }
+ PositionType aPosSave;
+ bIgnoreMismatchOnLeadingStrings = false;
+ SetTestEqualCondition( false );
+ do
+ {
+ nFoundCol = GetCol();
+ nFoundRow = GetRow();
+ aPosSave = maCurPos;
+ } while (GetNext());
+
+ // Step back conditions are the same as above
+ nCol = nFoundCol;
+ nRow = nFoundRow;
+ maCurPos = aPosSave;
+ return true;
+ }
+ if ( (maParam.eSearchType != utl::SearchParam::SearchType::Normal) &&
+ StoppedOnMismatch() )
+ {
+ // Assume found entry to be the last value less than respectively
+ // greater than the query. But keep on searching for an equal match.
+ SCSIZE nEntries = maParam.GetEntryCount();
+ for ( SCSIZE j = 0; j < nEntries; j++ )
+ {
+ ScQueryEntry& rEntry = maParam.GetEntry( j );
+ if ( rEntry.bDoQuery )
+ {
+ switch ( rEntry.eOp )
+ {
+ case SC_LESS_EQUAL :
+ case SC_GREATER_EQUAL :
+ rEntry.eOp = SC_EQUAL;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ else
+ break; // for
+ }
+ SetStopOnMismatch( false );
+ SetTestEqualCondition( false );
+ if (GetNext())
+ {
+ // Last of a consecutive area, avoid searching the entire parameter
+ // range as it is a real performance bottleneck in case of regular
+ // expressions.
+ PositionType aPosSave;
+ do
+ {
+ nFoundCol = GetCol();
+ nFoundRow = GetRow();
+ aPosSave = maCurPos;
+ SetStopOnMismatch( true );
+ } while (GetNext());
+ nCol = nFoundCol;
+ nRow = nFoundRow;
+ maCurPos = aPosSave;
+ }
+ }
+ return (nFoundCol <= rDoc.MaxCol()) && (nFoundRow <= rDoc.MaxRow());
+}
+
+// Direct linear cell access using mdds.
+
+ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::Direct >
+ ::ScQueryCellIteratorAccessSpecific( ScDocument& rDocument,
+ ScInterpreterContext& rContext, const ScQueryParam& rParam, bool bReverseSearch )
+ : maParam( rParam )
+ , rDoc( rDocument )
+ , mrContext( rContext )
+ , mbReverseSearch( bReverseSearch )
+{
+ // coverity[uninit_member] - this just contains data, subclass will initialize some of it
+}
+
+void ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::Direct >::InitPos()
+{
+ if (!mbReverseSearch)
+ {
+ nRow = maParam.nRow1;
+ if (maParam.bHasHeader && maParam.bByRow)
+ ++nRow;
+ }
+ else
+ {
+ nRow = maParam.nRow2;
+ }
+ const ScColumn& rCol = rDoc.maTabs[nTab]->CreateColumnIfNotExists(nCol);
+ maCurPos = rCol.maCells.position(nRow);
+}
+
+void ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::Direct >::IncPos()
+{
+ if (maCurPos.second + 1 < maCurPos.first->size)
+ {
+ // Move within the same block.
+ ++maCurPos.second;
+ ++nRow;
+ }
+ else
+ // Move to the next block.
+ IncBlock();
+}
+
+void ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::Direct >::DecPos()
+{
+ if (maCurPos.second > 0)
+ {
+ // Move within the same block.
+ --maCurPos.second;
+ --nRow;
+ }
+ else
+ // Move to the prev block.
+ DecBlock();
+}
+
+void ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::Direct >::IncBlock()
+{
+ ++maCurPos.first;
+ maCurPos.second = 0;
+
+ nRow = maCurPos.first->position;
+}
+
+void ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::Direct >::DecBlock()
+{
+ // Set current position to the last possible row.
+ const ScColumn& rCol = rDoc.maTabs[nTab]->CreateColumnIfNotExists(nCol);
+ if (maCurPos.first != rCol.maCells.begin())
+ {
+ --maCurPos.first;
+ maCurPos.second = maCurPos.first->size - 1;
+
+ nRow = maCurPos.first->position + maCurPos.second;
+ }
+ else
+ {
+ // No rows, set to end. This will make PerformQuery() go to next column.
+ nRow = maParam.nRow1 - 1;
+ maCurPos.first = rCol.maCells.end();
+ maCurPos.second = 0;
+ }
+}
+
+/**
+ * This class sequentially indexes non-empty cells in order, from the top of
+ * the block where the start row position is, to the bottom of the block
+ * where the end row position is. It skips all empty blocks that may be
+ * present in between.
+ *
+ * The index value is an offset from the first element of the first block
+ * disregarding all empty cell blocks.
+ */
+class ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::Direct >::NonEmptyCellIndexer
+{
+ typedef std::map<size_t, sc::CellStoreType::const_iterator> BlockMapType;
+
+ BlockMapType maBlockMap;
+
+ const sc::CellStoreType& mrCells;
+
+ size_t mnLowIndex;
+ size_t mnHighIndex;
+
+ bool mbValid;
+
+public:
+ /**
+ * @param rCells cell storage container
+ * @param nStartRow logical start row position
+ * @param nEndRow logical end row position, inclusive.
+ */
+ NonEmptyCellIndexer(
+ const sc::CellStoreType& rCells, SCROW nStartRow, SCROW nEndRow) :
+ mrCells(rCells), mnLowIndex(0), mnHighIndex(0), mbValid(true)
+ {
+ // Find the low position.
+
+ sc::CellStoreType::const_position_type aLoPos = mrCells.position(nStartRow);
+ assert(aLoPos.first->type != sc::element_type_empty);
+ assert(aLoPos.first != rCells.end());
+
+ SCROW nFirstRow = aLoPos.first->position;
+ SCROW nLastRow = aLoPos.first->position + aLoPos.first->size - 1;
+
+ if (nFirstRow > nEndRow)
+ {
+ // Both start and end row positions are within the leading skipped
+ // blocks.
+ mbValid = false;
+ return;
+ }
+
+ // Calculate the index of the low position.
+ if (nFirstRow < nStartRow)
+ mnLowIndex = nStartRow - nFirstRow;
+ else
+ {
+ // Start row is within the skipped block(s). Set it to the first
+ // element of the low block.
+ mnLowIndex = 0;
+ }
+
+ if (nEndRow < nLastRow)
+ {
+ assert(nEndRow >= nFirstRow);
+ mnHighIndex = nEndRow - nFirstRow;
+
+ maBlockMap.emplace(aLoPos.first->size, aLoPos.first);
+ return;
+ }
+
+ // Find the high position.
+
+ sc::CellStoreType::const_position_type aHiPos = mrCells.position(aLoPos.first, nEndRow);
+ if (aHiPos.first->type == sc::element_type_empty)
+ {
+ // Move to the last position of the previous block.
+ decBlock(aHiPos);
+
+ // Check the row position of the end of the previous block, and make sure it's valid.
+ SCROW nBlockEndRow = aHiPos.first->position + aHiPos.first->size - 1;
+ if (nBlockEndRow < nStartRow)
+ {
+ mbValid = false;
+ return;
+ }
+ }
+
+ // Tag the start and end blocks, and all blocks in between in order
+ // but skip all empty blocks.
+
+ size_t nPos = 0;
+ sc::CellStoreType::const_iterator itBlk = aLoPos.first;
+ while (itBlk != aHiPos.first)
+ {
+ if (itBlk->type == sc::element_type_empty)
+ {
+ ++itBlk;
+ continue;
+ }
+
+ nPos += itBlk->size;
+ maBlockMap.emplace(nPos, itBlk);
+ ++itBlk;
+
+ if (itBlk->type == sc::element_type_empty)
+ ++itBlk;
+
+ assert(itBlk != mrCells.end());
+ }
+
+ assert(itBlk == aHiPos.first);
+ nPos += itBlk->size;
+ maBlockMap.emplace(nPos, itBlk);
+
+ // Calculate the high index.
+ BlockMapType::const_reverse_iterator ri = maBlockMap.rbegin();
+ mnHighIndex = ri->first;
+ mnHighIndex -= ri->second->size;
+ mnHighIndex += aHiPos.second;
+ }
+
+ sc::CellStoreType::const_position_type getPosition( size_t nIndex ) const
+ {
+ assert(mbValid);
+ assert(mnLowIndex <= nIndex);
+ assert(nIndex <= mnHighIndex);
+
+ sc::CellStoreType::const_position_type aRet(mrCells.end(), 0);
+
+ BlockMapType::const_iterator it = maBlockMap.upper_bound(nIndex);
+ if (it == maBlockMap.end())
+ return aRet;
+
+ sc::CellStoreType::const_iterator itBlk = it->second;
+ size_t nBlkIndex = it->first - itBlk->size; // index of the first element of the block.
+ assert(nBlkIndex <= nIndex);
+ assert(nIndex < it->first);
+
+ size_t nOffset = nIndex - nBlkIndex;
+ aRet.first = itBlk;
+ aRet.second = nOffset;
+ return aRet;
+ }
+
+ BinarySearchCellType getCell( size_t nIndex ) const
+ {
+ BinarySearchCellType aRet;
+ aRet.second = -1;
+
+ sc::CellStoreType::const_position_type aPos = getPosition(nIndex);
+ if (aPos.first == mrCells.end())
+ return aRet;
+
+ aRet.first = sc::toRefCell(aPos.first, aPos.second);
+ aRet.second = aPos.first->position + aPos.second;
+ return aRet;
+ }
+
+ size_t getLowIndex() const { return mnLowIndex; }
+
+ size_t getHighIndex() const { return mnHighIndex; }
+
+ bool isValid() const { return mbValid; }
+};
+
+ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::Direct >::NonEmptyCellIndexer
+ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::Direct >::MakeBinarySearchIndexer(
+ const sc::CellStoreType& rCells, SCROW nStartRow, SCROW nEndRow )
+{
+ return NonEmptyCellIndexer(rCells, nStartRow, nEndRow);
+}
+
+// Sorted access using ScSortedRangeCache.
+
+ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::SortedCache >
+ ::ScQueryCellIteratorAccessSpecific( ScDocument& rDocument,
+ ScInterpreterContext& rContext, const ScQueryParam& rParam, bool bReverseSearch )
+ : maParam( rParam )
+ , rDoc( rDocument )
+ , mrContext( rContext )
+ , mbReverseSearch( bReverseSearch )
+{
+ // coverity[uninit_member] - this just contains data, subclass will initialize some of it
+}
+
+void ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::SortedCache >::SetSortedRangeCache(
+ const ScSortedRangeCache& cache)
+{
+ sortedCache = &cache;
+}
+
+// The idea in iterating using the sorted cache is that the iteration is instead done
+// over indexes of the sorted cache (which is a stable sort of the cell contents) in the range
+// that fits the query condition and then that is mapped to rows. This will result in iterating
+// over only matching rows in their sorted order (and for equal rows in their row order).
+void ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::SortedCache >::InitPosStart()
+{
+ ScRange aSortedRangeRange( nCol, maParam.nRow1, nTab, nCol, maParam.nRow2, nTab );
+ // We want all matching values first in the sort order,
+ SetSortedRangeCache( rDoc.GetSortedRangeCache( aSortedRangeRange, maParam, &mrContext ));
+ // InitPosFinish() needs to be called after this, ScQueryCellIteratorBase::InitPos()
+ // will handle that
+}
+
+void ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::SortedCache >::InitPosFinish(
+ SCROW beforeRow, SCROW lastRow, bool bFirstMatch )
+{
+ pColumn = &rDoc.maTabs[nTab]->CreateColumnIfNotExists(nCol);
+ if(lastRow >= 0)
+ {
+ sortedCachePos = beforeRow >= 0 ? sortedCache->indexForRow(beforeRow) + 1 : 0;
+ sortedCachePosLast = sortedCache->indexForRow(lastRow);
+ if(sortedCachePos <= sortedCachePosLast)
+ {
+ if (!bFirstMatch)
+ nRow = sortedCache->rowForIndex(sortedCachePos);
+ else
+ nRow = sortedCache->rowForIndex(sortedCachePosLast);
+ maCurPos = pColumn->maCells.position(nRow);
+ return;
+ }
+ }
+ // No rows, set to end.
+ sortedCachePos = sortedCachePosLast = 0;
+ maCurPos.first = pColumn->maCells.end();
+ maCurPos.second = 0;
+}
+
+template<bool fast>
+bool ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::SortedCache >::IncPosImpl()
+{
+ if(sortedCachePos < sortedCachePosLast)
+ {
+ ++sortedCachePos;
+ nRow = sortedCache->rowForIndex(sortedCachePos);
+#ifndef DBG_UTIL
+ if constexpr (!fast)
+#endif
+ {
+ // Avoid mdds position() call if row is in the same block.
+ if(maCurPos.first != pColumn->maCells.end() && o3tl::make_unsigned(nRow) >= maCurPos.first->position
+ && o3tl::make_unsigned(nRow) < maCurPos.first->position + maCurPos.first->size)
+ maCurPos.second = nRow - maCurPos.first->position;
+ else
+ maCurPos = pColumn->maCells.position(nRow);
+ }
+ return true;
+ }
+ else
+ {
+ // This will make PerformQuery() go to next column.
+ // Necessary even in fast mode, as GetNext() will call GetThis() in this case.
+ maCurPos.first = pColumn->maCells.end();
+ maCurPos.second = 0;
+ return false;
+ }
+}
+
+template
+bool ScQueryCellIteratorAccessSpecific<ScQueryCellIteratorAccess::SortedCache>::IncPosImpl<false>();
+template
+bool ScQueryCellIteratorAccessSpecific<ScQueryCellIteratorAccess::SortedCache>::IncPosImpl<true>();
+
+// Helper that allows binary search of unsorted cells using ScSortedRangeCache.
+// Rows in the given range are kept in a sorted vector and that vector is binary-searched.
+class ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::SortedCache >::SortedCacheIndexer
+{
+ std::vector<SCROW> mSortedRowsCopy;
+ const std::vector<SCROW>& mSortedRows;
+ const sc::CellStoreType& mCells;
+ size_t mLowIndex;
+ size_t mHighIndex;
+ bool mValid;
+
+ const std::vector<SCROW>& makeSortedRows( const ScSortedRangeCache* cache, SCROW startRow, SCROW endRow )
+ {
+ // Keep a reference to rows from the cache if equal, otherwise make a copy.
+ if(startRow == cache->getRange().aStart.Row() && endRow == cache->getRange().aEnd.Row())
+ return cache->sortedRows();
+ else
+ {
+ mSortedRowsCopy.reserve( cache->sortedRows().size());
+ for( SCROW row : cache->sortedRows())
+ if( row >= startRow && row <= endRow )
+ mSortedRowsCopy.emplace_back( row );
+ return mSortedRowsCopy;
+ }
+ }
+
+public:
+ SortedCacheIndexer( const sc::CellStoreType& cells, SCROW startRow, SCROW endRow,
+ const ScSortedRangeCache* cache )
+ : mSortedRows( makeSortedRows( cache, startRow, endRow ))
+ , mCells( cells )
+ , mValid( false )
+ {
+ if(mSortedRows.empty())
+ {
+ // coverity[uninit_member] - these are initialized only if valid
+ return;
+ }
+ mLowIndex = 0;
+ mHighIndex = mSortedRows.size() - 1;
+ mValid = true;
+ }
+
+ sc::CellStoreType::const_position_type getPosition( size_t nIndex ) const
+ {
+ // TODO optimize?
+ SCROW row = mSortedRows[ nIndex ];
+ return mCells.position(row);
+ }
+
+ BinarySearchCellType getCell( size_t nIndex ) const
+ {
+ BinarySearchCellType aRet;
+ aRet.second = -1;
+
+ sc::CellStoreType::const_position_type aPos = getPosition(nIndex);
+ if (aPos.first == mCells.end())
+ return aRet;
+
+ aRet.first = sc::toRefCell(aPos.first, aPos.second);
+ aRet.second = aPos.first->position + aPos.second;
+ return aRet;
+ }
+
+ size_t getLowIndex() const { return mLowIndex; }
+
+ size_t getHighIndex() const { return mHighIndex; }
+
+ bool isValid() const { return mValid; }
+};
+
+ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::SortedCache >::SortedCacheIndexer
+ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::SortedCache >::MakeBinarySearchIndexer(
+ const sc::CellStoreType& rCells, SCROW nStartRow, SCROW nEndRow)
+{
+ return SortedCacheIndexer(rCells, nStartRow, nEndRow, sortedCache);
+}
+
+static bool CanBeUsedForSorterCache(ScDocument& /*rDoc*/, const ScQueryParam& /*rParam*/,
+ SCTAB /*nTab*/, const ScFormulaCell* /*cell*/, const ScComplexRefData* /*refData*/,
+ ScInterpreterContext& /*context*/)
+{
+#if 1
+ /* TODO: tdf#151958 broken by string query of binary search on sorted
+ * cache, use the direct query instead for releases and fix SortedCache
+ * implementation after. Not only COUNTIF() is broken, but also COUNTIFS(),
+ * and maybe lcl_LookupQuery() for VLOOKUP() etc. as well. Just disable
+ * this for now.
+ * Can't just return false because below would be unreachable code. Can't
+ * just #if/#else/#endif either because parameters would be unused. Crap
+ * this and comment out parameter names. */
+ return false;
+#else
+ if(!rParam.GetEntry(0).bDoQuery || rParam.GetEntry(1).bDoQuery
+ || rParam.GetEntry(0).GetQueryItems().size() != 1 )
+ return false;
+ if(rParam.eSearchType != utl::SearchParam::SearchType::Normal)
+ return false;
+ if(rParam.GetEntry(0).GetQueryItem().meType != ScQueryEntry::ByValue
+ && rParam.GetEntry(0).GetQueryItem().meType != ScQueryEntry::ByString)
+ return false;
+ if(!rParam.bByRow)
+ return false;
+ if(rParam.bHasHeader)
+ return false;
+ if(rParam.mbRangeLookup)
+ return false;
+ if(rParam.GetEntry(0).GetQueryItem().meType == ScQueryEntry::ByString
+ && !ScQueryEvaluator::isMatchWholeCell(rDoc, rParam.GetEntry(0).eOp))
+ return false; // substring matching cannot be sorted
+ if(rParam.GetEntry(0).eOp != SC_LESS && rParam.GetEntry(0).eOp != SC_LESS_EQUAL
+ && rParam.GetEntry(0).eOp != SC_GREATER && rParam.GetEntry(0).eOp != SC_GREATER_EQUAL
+ && rParam.GetEntry(0).eOp != SC_EQUAL)
+ return false;
+ // For unittests allow inefficient caching, in order for the code to be checked.
+ static bool inUnitTest = getenv("LO_TESTNAME") != nullptr;
+ if(refData == nullptr || refData->Ref1.IsRowRel() || refData->Ref2.IsRowRel())
+ {
+ // If this is not a range, then a cache is not worth it. If rows are relative, then each
+ // computation will use a different area, so the cache wouldn't be reused. Tab/cols are
+ // not a problem, because formula group computations are done for the same tab/col.
+ if(!inUnitTest)
+ return false;
+ }
+ if(rParam.nRow2 - rParam.nRow1 < 10)
+ {
+ if(!inUnitTest)
+ return false;
+ }
+ if( !cell )
+ return false;
+ if( !cell->GetCellGroup() || cell->GetCellGroup()->mnLength < 10 )
+ {
+ if(!inUnitTest)
+ return false;
+ }
+ // Check that all the relevant caches would be valid (may not be the case when mixing
+ // numeric and string cells for ByValue lookups).
+ for(SCCOL col : rDoc.GetAllocatedColumnsRange(nTab, rParam.nCol1, rParam.nCol2))
+ {
+ ScRange aSortedRangeRange( col, rParam.nRow1, nTab, col, rParam.nRow2, nTab);
+ if( aSortedRangeRange.Contains( cell->aPos ))
+ return false; // self-referencing, can't create cache
+ ScSortedRangeCache& cache = rDoc.GetSortedRangeCache( aSortedRangeRange, rParam, &context );
+ if(!cache.isValid())
+ return false;
+ }
+ return true;
+#endif
+}
+
+// Generic query implementation.
+
+bool ScQueryCellIteratorTypeSpecific< ScQueryCellIteratorType::Generic >::HandleItemFound()
+{
+ getThisResult = true;
+ return true; // Return from PerformQuery().
+}
+
+template< ScQueryCellIteratorAccess accessType >
+bool ScQueryCellIterator< accessType >::GetThis()
+{
+ getThisResult = false;
+ PerformQuery();
+ return getThisResult;
+}
+
+template< ScQueryCellIteratorAccess accessType >
+bool ScQueryCellIterator< accessType >::GetFirst()
+{
+ assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT");
+ if (!mbReverseSearch)
+ nCol = maParam.nCol1;
+ else
+ nCol = maParam.nCol2;
+ InitPos();
+ return GetThis();
+}
+
+template< ScQueryCellIteratorAccess accessType >
+bool ScQueryCellIterator< accessType >::GetNext()
+{
+ if (!mbReverseSearch)
+ IncPos();
+ else
+ DecPos();
+ if ( nStopOnMismatch )
+ nStopOnMismatch = nStopOnMismatchEnabled;
+ if ( nTestEqualCondition )
+ nTestEqualCondition = nTestEqualConditionEnabled;
+ return GetThis();
+}
+
+template<>
+bool ScQueryCellIterator< ScQueryCellIteratorAccess::SortedCache >::GetNext()
+{
+ assert( !nStopOnMismatch );
+ assert( !nTestEqualCondition );
+ // When searching using sorted cache, we should always find cells that match,
+ // because InitPos()/IncPos() select only such rows, so skip GetThis() (and thus
+ // the somewhat expensive PerformQuery) as long as we're not at the end
+ // of a column. As an optimization IncPosFast() returns true if not at the end,
+ // in which case in non-DBG_UTIL mode it doesn't even bother to set maCurPos.
+ if( IncPosFast())
+ {
+#ifdef DBG_UTIL
+ assert(GetThis());
+#endif
+ return true;
+ }
+ return GetThis();
+}
+
+bool ScQueryCellIteratorSortedCache::CanBeUsed(ScDocument& rDoc, const ScQueryParam& rParam,
+ SCTAB nTab, const ScFormulaCell* cell, const ScComplexRefData* refData,
+ ScInterpreterContext& context)
+{
+ return CanBeUsedForSorterCache(rDoc, rParam, nTab, cell, refData, context);
+}
+
+// Countifs implementation.
+
+bool ScQueryCellIteratorTypeSpecific< ScQueryCellIteratorType::CountIf >::HandleItemFound()
+{
+ ++countIfCount;
+ return false; // Continue searching.
+}
+
+template< ScQueryCellIteratorAccess accessType >
+sal_uInt64 ScCountIfCellIterator< accessType >::GetCount()
+{
+ // Keep Entry.nField in iterator on column change
+ SetAdvanceQueryParamEntryField( true );
+ assert(nTab < rDoc.GetTableCount() && "try to access index out of bounds, FIX IT");
+ maParam.nCol1 = rDoc.ClampToAllocatedColumns(nTab, maParam.nCol1);
+ maParam.nCol2 = rDoc.ClampToAllocatedColumns(nTab, maParam.nCol2);
+ nCol = maParam.nCol1;
+ InitPos();
+ countIfCount = 0;
+ PerformQuery();
+ return countIfCount;
+}
+
+
+bool ScCountIfCellIteratorSortedCache::CanBeUsed(ScDocument& rDoc, const ScQueryParam& rParam,
+ SCTAB nTab, const ScFormulaCell* cell, const ScComplexRefData* refData,
+ ScInterpreterContext& context)
+{
+ return CanBeUsedForSorterCache(rDoc, rParam, nTab, cell, refData, context);
+}
+
+template<>
+sal_uInt64 ScCountIfCellIterator< ScQueryCellIteratorAccess::SortedCache >::GetCount()
+{
+ // Keep Entry.nField in iterator on column change
+ SetAdvanceQueryParamEntryField( true );
+ assert(nTab < rDoc.GetTableCount() && "try to access index out of bounds, FIX IT");
+ sal_uInt64 count = 0;
+ // Each column must be sorted separately.
+ for(SCCOL col : rDoc.GetAllocatedColumnsRange(nTab, maParam.nCol1, maParam.nCol2))
+ {
+ nCol = col;
+ nRow = maParam.nRow1;
+ ScRange aSortedRangeRange( col, maParam.nRow1, nTab, col, maParam.nRow2, nTab);
+ ScQueryOp& op = maParam.GetEntry(0).eOp;
+ SetSortedRangeCache( rDoc.GetSortedRangeCache( aSortedRangeRange, maParam, &mrContext ));
+ if( op == SC_EQUAL )
+ {
+ // BinarySearch() searches for the last item that matches. Therefore first
+ // find the last non-matching position using SC_LESS and then find the last
+ // matching position using SC_EQUAL.
+ ScQueryOp saveOp = op;
+ op = SC_LESS;
+ if( BinarySearch( nCol, true ))
+ {
+ op = saveOp; // back to SC_EQUAL
+ size_t lastNonMatching = sortedCache->indexForRow(nRow);
+ if( BinarySearch( nCol ))
+ {
+ size_t lastMatching = sortedCache->indexForRow(nRow);
+ assert(lastMatching >= lastNonMatching);
+ count += lastMatching - lastNonMatching;
+ }
+ else
+ {
+ // BinarySearch() should at least find the same result as the SC_LESS
+ // call, so this should not happen.
+ assert(false);
+ }
+ }
+ else
+ {
+ // BinarySearch() returning false means that all values are larger,
+ // so try to find matching ones and count those up to and including
+ // the found one.
+ op = saveOp; // back to SC_EQUAL
+ if( BinarySearch( nCol ))
+ {
+ size_t lastMatching = sortedCache->indexForRow(nRow) + 1;
+ count += lastMatching;
+ }
+ else if( maParam.GetEntry(0).GetQueryItem().mbMatchEmpty
+ && rDoc.IsEmptyData(col, maParam.nRow1, col, maParam.nRow2, nTab))
+ {
+ // BinarySearch() returns false in case it's all empty data,
+ // handle that specially.
+ count += maParam.nRow2 - maParam.nRow1 + 1;
+ }
+ }
+ }
+ else
+ {
+ // BinarySearch() searches for the last item that matches. Therefore everything
+ // up to and including the found row matches the condition.
+ if( BinarySearch( nCol ))
+ count += sortedCache->indexForRow(nRow) + 1;
+ }
+ }
+ if( maParam.GetEntry(0).GetQueryItem().mbMatchEmpty
+ && maParam.nCol2 >= rDoc.GetAllocatedColumnsCount( nTab ))
+ {
+ const sal_uInt64 nRows = maParam.nRow2 - maParam.nRow1 + 1;
+ count += (maParam.nCol2 - rDoc.GetAllocatedColumnsCount(nTab)) * nRows;
+ }
+ return count;
+}
+
+template class ScQueryCellIterator< ScQueryCellIteratorAccess::Direct >;
+template class ScQueryCellIterator< ScQueryCellIteratorAccess::SortedCache >;
+template class ScCountIfCellIterator< ScQueryCellIteratorAccess::Direct >;
+template class ScCountIfCellIterator< ScQueryCellIteratorAccess::SortedCache >;
+
+// gcc for some reason needs these too
+template class ScQueryCellIteratorBase< ScQueryCellIteratorAccess::Direct, ScQueryCellIteratorType::Generic >;
+template class ScQueryCellIteratorBase< ScQueryCellIteratorAccess::SortedCache, ScQueryCellIteratorType::Generic >;
+template class ScQueryCellIteratorBase< ScQueryCellIteratorAccess::Direct, ScQueryCellIteratorType::CountIf >;
+template class ScQueryCellIteratorBase< ScQueryCellIteratorAccess::SortedCache, ScQueryCellIteratorType::CountIf >;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/refupdatecontext.cxx b/sc/source/core/data/refupdatecontext.cxx
index 8faf1f105505..0ce3f175e48f 100644
--- a/sc/source/core/data/refupdatecontext.cxx
+++ b/sc/source/core/data/refupdatecontext.cxx
@@ -96,7 +96,8 @@ ColumnBlockPosition* RefUpdateContext::getBlockPosition(SCTAB nTab, SCCOL nCol)
return mpBlockPos ? mpBlockPos->getBlockPosition(nTab, nCol) : nullptr;
}
-RefUpdateResult::RefUpdateResult() : mbValueChanged(false), mbReferenceModified(false), mbNameModified(false) {}
+RefUpdateResult::RefUpdateResult()
+ : mbValueChanged(false), mbReferenceModified(false), mbNameModified(false), mnTab(-1) {}
RefUpdateInsertTabContext::RefUpdateInsertTabContext(ScDocument& rDoc, SCTAB nInsertPos, SCTAB nSheets) :
mrDoc(rDoc), mnInsertPos(nInsertPos), mnSheets(nSheets) {}
diff --git a/sc/source/core/data/segmenttree.cxx b/sc/source/core/data/segmenttree.cxx
index 60003fb924b3..7ae8eba29e16 100644
--- a/sc/source/core/data/segmenttree.cxx
+++ b/sc/source/core/data/segmenttree.cxx
@@ -23,6 +23,7 @@
#include <sal/log.hxx>
#include <algorithm>
#include <limits>
+#include <string_view>
#include <global.hxx>
using ::std::numeric_limits;
@@ -49,7 +50,7 @@ public:
bool setValue(SCCOLROW nPos1, SCCOLROW nPos2, ValueType nValue);
void setValueIf(SCCOLROW nPos1, SCCOLROW nPos2, ValueType nValue, const std::function<bool(ValueType)>& rPredicate);
ValueType getValue(SCCOLROW nPos);
- ExtValueType getSumValue(SCCOLROW nPos1, SCCOLROW nPos2);
+ sal_uInt64 getSumValue(SCCOLROW nPos1, SCCOLROW nPos2);
bool getRangeData(SCCOLROW nPos, RangeData& rData);
bool getRangeDataLeaf(SCCOLROW nPos, RangeData& rData);
void removeSegment(SCCOLROW nPos1, SCCOLROW nPos2);
@@ -143,8 +144,7 @@ typename ScFlatSegmentsImpl<ValueType_, ExtValueType_>::ValueType ScFlatSegments
}
template<typename ValueType_, typename ExtValueType_>
-typename ScFlatSegmentsImpl<ValueType_, ExtValueType_>::ExtValueType
-ScFlatSegmentsImpl<ValueType_, ExtValueType_>::getSumValue(SCCOLROW nPos1, SCCOLROW nPos2)
+sal_uInt64 ScFlatSegmentsImpl<ValueType_, ExtValueType_>::getSumValue(SCCOLROW nPos1, SCCOLROW nPos2)
{
if (mbTreeSearchEnabled)
{
@@ -161,17 +161,17 @@ ScFlatSegmentsImpl<ValueType_, ExtValueType_>::getSumValue(SCCOLROW nPos1, SCCOL
return 0;
aData.mnPos2 = aData.mnPos2-1; // end point is not inclusive.
- sal_uInt32 nValue = 0;
+ sal_uInt64 nValue = 0;
SCROW nCurPos = nPos1;
SCROW nEndPos = aData.mnPos2;
while (nEndPos <= nPos2)
{
- sal_uInt32 nRes;
- if (o3tl::checked_multiply<sal_uInt32>(aData.mnValue, nEndPos - nCurPos + 1, nRes))
+ sal_uInt64 nRes;
+ if (o3tl::checked_multiply<sal_uInt64>(aData.mnValue, nEndPos - nCurPos + 1, nRes))
{
SAL_WARN("sc.core", "row height overflow");
- nRes = SAL_MAX_INT32;
+ nRes = SAL_MAX_INT64;
}
nValue = o3tl::saturating_add(nValue, nRes);
nCurPos = nEndPos + 1;
@@ -185,11 +185,11 @@ ScFlatSegmentsImpl<ValueType_, ExtValueType_>::getSumValue(SCCOLROW nPos1, SCCOL
if (nCurPos <= nPos2)
{
nEndPos = ::std::min(nEndPos, nPos2);
- sal_uInt32 nRes;
- if (o3tl::checked_multiply<sal_uInt32>(aData.mnValue, nEndPos - nCurPos + 1, nRes))
+ sal_uInt64 nRes;
+ if (o3tl::checked_multiply<sal_uInt64>(aData.mnValue, nEndPos - nCurPos + 1, nRes))
{
SAL_WARN("sc.core", "row height overflow");
- nRes = SAL_MAX_INT32;
+ nRes = SAL_MAX_INT64;
}
nValue = o3tl::saturating_add(nValue, nRes);
}
@@ -201,17 +201,17 @@ ScFlatSegmentsImpl<ValueType_, ExtValueType_>::getSumValue(SCCOLROW nPos1, SCCOL
if (!getRangeDataLeaf(nPos1, aData))
return 0;
- sal_uInt32 nValue = 0;
+ sal_uInt64 nValue = 0;
SCROW nCurPos = nPos1;
SCROW nEndPos = aData.mnPos2;
while (nEndPos <= nPos2)
{
- sal_uInt32 nRes;
- if (o3tl::checked_multiply<sal_uInt32>(aData.mnValue, nEndPos - nCurPos + 1, nRes))
+ sal_uInt64 nRes;
+ if (o3tl::checked_multiply<sal_uInt64>(aData.mnValue, nEndPos - nCurPos + 1, nRes))
{
SAL_WARN("sc.core", "row height overflow");
- nRes = SAL_MAX_INT32;
+ nRes = SAL_MAX_INT64;
}
nValue = o3tl::saturating_add(nValue, nRes);
nCurPos = nEndPos + 1;
@@ -223,11 +223,11 @@ ScFlatSegmentsImpl<ValueType_, ExtValueType_>::getSumValue(SCCOLROW nPos1, SCCOL
if (nCurPos <= nPos2)
{
nEndPos = ::std::min(nEndPos, nPos2);
- sal_uInt32 nRes;
- if (o3tl::checked_multiply<sal_uInt32>(aData.mnValue, nEndPos - nCurPos + 1, nRes))
+ sal_uInt64 nRes;
+ if (o3tl::checked_multiply<sal_uInt64>(aData.mnValue, nEndPos - nCurPos + 1, nRes))
{
SAL_WARN("sc.core", "row height overflow");
- nRes = SAL_MAX_INT32;
+ nRes = SAL_MAX_INT64;
}
nValue = o3tl::saturating_add(nValue, nRes);
}
@@ -250,7 +250,7 @@ bool ScFlatSegmentsImpl<ValueType_, ExtValueType_>::getRangeData(SCCOLROW nPos,
auto [it,found] = maSegments.search_tree(nPos, rData.mnValue, &rData.mnPos1, &rData.mnPos2);
if (!found)
return false;
- maItr = it; // cache the iterator to speed up ForwardIterator.
+ maItr = std::move(it); // cache the iterator to speed up ForwardIterator.
rData.mnPos2 = rData.mnPos2-1; // end point is not inclusive.
return true;
}
@@ -499,7 +499,7 @@ OString ScFlatBoolRowSegments::dumpAsString()
while (getRangeData(nRow, aRange))
{
if (!nRow)
- aSegment = (aRange.mbValue ? OStringLiteral("1") : OStringLiteral("0")) + OString::Concat(":");
+ aSegment = (aRange.mbValue ? std::string_view("1") : std::string_view("0")) + OString::Concat(":");
else
aSegment.clear();
@@ -644,7 +644,7 @@ sal_uInt16 ScFlatUInt16RowSegments::getValue(SCROW nRow)
return mpImpl->getValue(static_cast<SCCOLROW>(nRow));
}
-sal_uInt32 ScFlatUInt16RowSegments::getSumValue(SCROW nRow1, SCROW nRow2)
+sal_uInt64 ScFlatUInt16RowSegments::getSumValue(SCROW nRow1, SCROW nRow2)
{
return mpImpl->getSumValue(static_cast<SCCOLROW>(nRow1), static_cast<SCCOLROW>(nRow2));
}
diff --git a/sc/source/core/data/simpleformulacalc.cxx b/sc/source/core/data/simpleformulacalc.cxx
index 5959d08318d2..cd2559e9f22f 100644
--- a/sc/source/core/data/simpleformulacalc.cxx
+++ b/sc/source/core/data/simpleformulacalc.cxx
@@ -10,12 +10,13 @@
#include <memory>
#include <simpleformulacalc.hxx>
#include <document.hxx>
+#include <docsh.hxx>
#include <tokenarray.hxx>
#include <interpre.hxx>
#include <compiler.hxx>
#include <sfx2/linkmgr.hxx>
-#define DISPLAY_LEN 15
+#define DISPLAY_LEN 66
ScSimpleFormulaCalculator::ScSimpleFormulaCalculator( ScDocument& rDoc, const ScAddress& rAddr,
const OUString& rFormula, bool bMatrixFormula, formula::FormulaGrammar::Grammar eGram )
@@ -64,12 +65,15 @@ void ScSimpleFormulaCalculator::Calculate()
if (mbLimitString)
{
- size_t n = aStr.getLength();
- for (size_t i = DISPLAY_LEN; i < n; ++i)
+ const sal_Unicode cCol = ScCompiler::GetNativeSymbol(ocArrayColSep)[0];
+ const sal_Unicode cRow = ScCompiler::GetNativeSymbol(ocArrayRowSep)[0];
+ const sal_Int32 n = aStr.getLength();
+ for (sal_Int32 i = DISPLAY_LEN; i < n; ++i)
{
- if (aStr[i] == ',' || aStr[i] == ';')
+ const sal_Unicode c = aStr[i];
+ if (c == cCol || c == cRow)
{
- aStr.truncate(i);
+ aStr.truncate(i+1);
aStr.append("...");
break;
}
diff --git a/sc/source/core/data/sortparam.cxx b/sc/source/core/data/sortparam.cxx
index cd98dd07a982..37e44794a4df 100644
--- a/sc/source/core/data/sortparam.cxx
+++ b/sc/source/core/data/sortparam.cxx
@@ -33,11 +33,14 @@ ScSortParam::ScSortParam()
}
ScSortParam::ScSortParam( const ScSortParam& r ) :
- nCol1(r.nCol1),nRow1(r.nRow1),nCol2(r.nCol2),nRow2(r.nRow2),nUserIndex(r.nUserIndex),
+ nCol1(r.nCol1),nRow1(r.nRow1),nCol2(r.nCol2),nRow2(r.nRow2),
+ nSourceTab(r.nSourceTab),
+ aDataAreaExtras(r.aDataAreaExtras),
+ nUserIndex(r.nUserIndex),
bHasHeader(r.bHasHeader),bByRow(r.bByRow),bCaseSens(r.bCaseSens),
- bNaturalSort(r.bNaturalSort),bIncludeComments(r.bIncludeComments),
- bIncludeGraphicObjects(r.bIncludeGraphicObjects),bUserDef(r.bUserDef),
- bIncludePattern(r.bIncludePattern),bInplace(r.bInplace),
+ bNaturalSort(r.bNaturalSort),
+ bUserDef(r.bUserDef),
+ bInplace(r.bInplace),
nDestTab(r.nDestTab),nDestCol(r.nDestCol),nDestRow(r.nDestRow),
maKeyState( r.maKeyState ),
aCollatorLocale( r.aCollatorLocale ), aCollatorAlgorithm( r.aCollatorAlgorithm ),
@@ -53,19 +56,22 @@ void ScSortParam::Clear()
nCol1=nCol2=nDestCol = 0;
nRow1=nRow2=nDestRow = 0;
+ nSourceTab = 0;
+ aDataAreaExtras = ScDataAreaExtras();
+ aDataAreaExtras.mbCellDrawObjects = true;
+ aDataAreaExtras.mbCellFormats = true;
nCompatHeader = 2;
nDestTab = 0;
nUserIndex = 0;
bHasHeader=bCaseSens=bUserDef=bNaturalSort = false;
- bIncludeComments = false;
- bIncludeGraphicObjects = true;
- bByRow=bIncludePattern=bInplace = true;
+ bByRow = bInplace = true;
aCollatorLocale = css::lang::Locale();
aCollatorAlgorithm.clear();
aKeyState.bDoSort = false;
aKeyState.nField = 0;
aKeyState.bAscending = true;
+ aKeyState.aColorSortMode = ScColorSortMode::None;
// Initialize to default size
maKeyState.assign( DEFSORT, aKeyState );
@@ -77,15 +83,14 @@ ScSortParam& ScSortParam::operator=( const ScSortParam& r )
nRow1 = r.nRow1;
nCol2 = r.nCol2;
nRow2 = r.nRow2;
+ nSourceTab = r.nSourceTab;
+ aDataAreaExtras = r.aDataAreaExtras;
nUserIndex = r.nUserIndex;
bHasHeader = r.bHasHeader;
bByRow = r.bByRow;
bCaseSens = r.bCaseSens;
bNaturalSort = r.bNaturalSort;
- bIncludeComments= r.bIncludeComments;
- bIncludeGraphicObjects = r.bIncludeGraphicObjects;
bUserDef = r.bUserDef;
- bIncludePattern = r.bIncludePattern;
bInplace = r.bInplace;
nDestTab = r.nDestTab;
nDestCol = r.nDestCol;
@@ -123,15 +128,14 @@ bool ScSortParam::operator==( const ScSortParam& rOther ) const
&& (nRow1 == rOther.nRow1)
&& (nCol2 == rOther.nCol2)
&& (nRow2 == rOther.nRow2)
+ && (nSourceTab == rOther.nSourceTab)
+ && (aDataAreaExtras == rOther.aDataAreaExtras)
&& (bHasHeader == rOther.bHasHeader)
&& (bByRow == rOther.bByRow)
&& (bCaseSens == rOther.bCaseSens)
&& (bNaturalSort == rOther.bNaturalSort)
- && (bIncludeComments== rOther.bIncludeComments)
- && (bIncludeGraphicObjects == rOther.bIncludeGraphicObjects)
&& (bUserDef == rOther.bUserDef)
&& (nUserIndex == rOther.nUserIndex)
- && (bIncludePattern == rOther.bIncludePattern)
&& (bInplace == rOther.bInplace)
&& (nDestTab == rOther.nDestTab)
&& (nDestCol == rOther.nDestCol)
@@ -155,15 +159,20 @@ bool ScSortParam::operator==( const ScSortParam& rOther ) const
}
ScSortParam::ScSortParam( const ScSubTotalParam& rSub, const ScSortParam& rOld ) :
- nCol1(rSub.nCol1),nRow1(rSub.nRow1),nCol2(rSub.nCol2),nRow2(rSub.nRow2),nUserIndex(rSub.nUserIndex),
+ nCol1(rSub.nCol1),nRow1(rSub.nRow1),nCol2(rSub.nCol2),nRow2(rSub.nRow2),
+ nSourceTab(0),
+ aDataAreaExtras(rOld.aDataAreaExtras),
+ nUserIndex(rSub.nUserIndex),
bHasHeader(true),bByRow(true),bCaseSens(rSub.bCaseSens),bNaturalSort(rOld.bNaturalSort),
- bIncludeComments(rOld.bIncludeComments),bIncludeGraphicObjects(rOld.bIncludeGraphicObjects),
- bUserDef(rSub.bUserDef),bIncludePattern(rSub.bIncludePattern),
+ bUserDef(rSub.bUserDef),
bInplace(true),
nDestTab(0),nDestCol(0),nDestRow(0),
aCollatorLocale( rOld.aCollatorLocale ), aCollatorAlgorithm( rOld.aCollatorAlgorithm ),
nCompatHeader( rOld.nCompatHeader )
{
+ aDataAreaExtras.mbCellFormats = rSub.bIncludePattern;
+ aDataAreaExtras.resetArea();
+
sal_uInt16 i;
// first the groups from the partial results
@@ -175,6 +184,7 @@ ScSortParam::ScSortParam( const ScSubTotalParam& rSub, const ScSortParam& rOld )
key.bDoSort = true;
key.nField = rSub.nField[i];
key.bAscending = rSub.bAscending;
+ key.aColorSortMode = ScColorSortMode::None;
maKeyState.push_back(key);
}
@@ -193,24 +203,30 @@ ScSortParam::ScSortParam( const ScSubTotalParam& rSub, const ScSortParam& rOld )
key.bDoSort = true;
key.nField = nThisField;
key.bAscending = rOld.maKeyState[i].bAscending;
+ key.aColorSortMode = ScColorSortMode::None;
maKeyState.push_back(key);
}
}
}
ScSortParam::ScSortParam( const ScQueryParam& rParam, SCCOL nCol ) :
- nCol1(nCol),nRow1(rParam.nRow1),nCol2(nCol),nRow2(rParam.nRow2),nUserIndex(0),
+ nCol1(nCol),nRow1(rParam.nRow1),nCol2(nCol),nRow2(rParam.nRow2),
+ nSourceTab(rParam.nTab),
+ nUserIndex(0),
bHasHeader(rParam.bHasHeader),bByRow(true),bCaseSens(rParam.bCaseSens),
- bNaturalSort(false),bIncludeComments(false),bIncludeGraphicObjects(true),
+ bNaturalSort(false),
//TODO: what about Locale and Algorithm?
- bUserDef(false),bIncludePattern(false),
+ bUserDef(false),
bInplace(true),
nDestTab(0),nDestCol(0),nDestRow(0), nCompatHeader(2)
{
+ aDataAreaExtras.mbCellDrawObjects = true;
+
ScSortKeyState aKeyState;
aKeyState.bDoSort = true;
aKeyState.nField = nCol;
aKeyState.bAscending = true;
+ aKeyState.aColorSortMode = ScColorSortMode::None;
maKeyState.push_back( aKeyState );
diff --git a/sc/source/core/data/stlpool.cxx b/sc/source/core/data/stlpool.cxx
index 3939978633f3..2f9ee31d5d14 100644
--- a/sc/source/core/data/stlpool.cxx
+++ b/sc/source/core/data/stlpool.cxx
@@ -24,7 +24,6 @@
#include <editeng/borderline.hxx>
#include <editeng/boxitem.hxx>
#include <editeng/brushitem.hxx>
-#include <editeng/editdata.hxx>
#include <editeng/editeng.hxx>
#include <editeng/editobj.hxx>
#include <editeng/flditem.hxx>
@@ -101,7 +100,7 @@ rtl::Reference<SfxStyleSheetBase> ScStyleSheetPool::Create( const OUString& rN
SfxStyleSearchBits nMaskP )
{
rtl::Reference<ScStyleSheet> pSheet = new ScStyleSheet( rName, *this, eFamily, nMaskP );
- if ( eFamily == SfxStyleFamily::Para && ScResId(STR_STYLENAME_STANDARD) != rName )
+ if ( eFamily != SfxStyleFamily::Page && ScResId(STR_STYLENAME_STANDARD) != rName )
pSheet->SetParent( ScResId(STR_STYLENAME_STANDARD) );
return pSheet;
@@ -120,13 +119,15 @@ void ScStyleSheetPool::Remove( SfxStyleSheetBase* pStyle )
OSL_ENSURE( SfxStyleSearchBits::UserDefined & pStyle->GetMask(),
"SfxStyleSearchBits::UserDefined not set!" );
- static_cast<ScDocumentPool&>(rPool).StyleDeleted(static_cast<ScStyleSheet*>(pStyle));
+ assert(nullptr != pDoc);
+ pDoc->getCellAttributeHelper().CellStyleDeleted(static_cast<ScStyleSheet&>(*pStyle));
SfxStyleSheetPool::Remove(pStyle);
}
}
-void ScStyleSheetPool::CopyStyleFrom( ScStyleSheetPool* pSrcPool,
- const OUString& rName, SfxStyleFamily eFamily )
+void ScStyleSheetPool::CopyStyleFrom( SfxStyleSheetBasePool* pSrcPool,
+ const OUString& rName, SfxStyleFamily eFamily,
+ bool bNewStyleHierarchy )
{
// this is the Dest-Pool
@@ -136,39 +137,40 @@ void ScStyleSheetPool::CopyStyleFrom( ScStyleSheetPool* pSrcPool,
const SfxItemSet& rSourceSet = pStyleSheet->GetItemSet();
SfxStyleSheetBase* pDestSheet = Find( rName, eFamily );
+ if (pDestSheet && bNewStyleHierarchy)
+ return;
if (!pDestSheet)
- pDestSheet = &Make( rName, eFamily );
+ pDestSheet = &Make( rName, eFamily, pStyleSheet->GetMask() );
SfxItemSet& rDestSet = pDestSheet->GetItemSet();
- rDestSet.PutExtended( rSourceSet, SfxItemState::DONTCARE, SfxItemState::DEFAULT );
+ rDestSet.PutExtended( rSourceSet, SfxItemState::INVALID, SfxItemState::DEFAULT );
- const SfxPoolItem* pItem;
if ( eFamily == SfxStyleFamily::Page )
{
// Set-Items
- if ( rSourceSet.GetItemState( ATTR_PAGE_HEADERSET, false, &pItem ) == SfxItemState::SET )
+ if ( const SvxSetItem* pSetItem = rSourceSet.GetItemIfSet( ATTR_PAGE_HEADERSET, false ) )
{
- const SfxItemSet& rSrcSub = static_cast<const SvxSetItem*>(pItem)->GetItemSet();
+ const SfxItemSet& rSrcSub = pSetItem->GetItemSet();
SfxItemSet aDestSub( *rDestSet.GetPool(), rSrcSub.GetRanges() );
- aDestSub.PutExtended( rSrcSub, SfxItemState::DONTCARE, SfxItemState::DEFAULT );
- rDestSet.Put( SvxSetItem( ATTR_PAGE_HEADERSET, aDestSub ) );
+ aDestSub.PutExtended( rSrcSub, SfxItemState::INVALID, SfxItemState::DEFAULT );
}
- if ( rSourceSet.GetItemState( ATTR_PAGE_FOOTERSET, false, &pItem ) == SfxItemState::SET )
+ if ( const SvxSetItem* pSetItem = rSourceSet.GetItemIfSet( ATTR_PAGE_FOOTERSET, false ) )
{
- const SfxItemSet& rSrcSub = static_cast<const SvxSetItem*>(pItem)->GetItemSet();
+ const SfxItemSet& rSrcSub = pSetItem->GetItemSet();
SfxItemSet aDestSub( *rDestSet.GetPool(), rSrcSub.GetRanges() );
- aDestSub.PutExtended( rSrcSub, SfxItemState::DONTCARE, SfxItemState::DEFAULT );
+ aDestSub.PutExtended( rSrcSub, SfxItemState::INVALID, SfxItemState::DEFAULT );
rDestSet.Put( SvxSetItem( ATTR_PAGE_FOOTERSET, aDestSub ) );
}
}
- else // cell styles
+ else if ( eFamily == SfxStyleFamily::Para )
{
// number format exchange list has to be handled here, too
+ const SfxUInt32Item* pItem;
if ( pDoc && pDoc->GetFormatExchangeList() &&
- rSourceSet.GetItemState( ATTR_VALUE_FORMAT, false, &pItem ) == SfxItemState::SET )
+ (pItem = rSourceSet.GetItemIfSet( ATTR_VALUE_FORMAT, false )) )
{
- sal_uLong nOldFormat = static_cast<const SfxUInt32Item*>(pItem)->GetValue();
+ sal_uInt32 nOldFormat = pItem->GetValue();
SvNumberFormatterIndexTable::const_iterator it = pDoc->GetFormatExchangeList()->find(nOldFormat);
if (it != pDoc->GetFormatExchangeList()->end())
{
@@ -177,19 +179,50 @@ void ScStyleSheetPool::CopyStyleFrom( ScStyleSheetPool* pSrcPool,
}
}
}
+
+ const OUString aParentName = pStyleSheet->GetParent();
+ if (!bNewStyleHierarchy || aParentName.isEmpty())
+ return;
+
+ CopyStyleFrom(pSrcPool, aParentName, eFamily, bNewStyleHierarchy);
+ pDestSheet->SetParent(aParentName);
}
-// Standard templates
+void ScStyleSheetPool::CopyUsedGraphicStylesFrom(SfxStyleSheetBasePool* pSrcPool)
+{
+ // this is the Dest-Pool
+
+ std::vector<std::pair<SfxStyleSheetBase*, OUString>> aNewStyles;
+
+ auto pSrcSheet = pSrcPool->First(SfxStyleFamily::Frame);
+ while (pSrcSheet)
+ {
+ if (pSrcSheet->IsUsed() && !Find(pSrcSheet->GetName(), pSrcSheet->GetFamily()))
+ {
+ auto pDestSheet = &Make(pSrcSheet->GetName(), pSrcSheet->GetFamily(), pSrcSheet->GetMask());
+ aNewStyles.emplace_back(pDestSheet, pSrcSheet->GetParent());
+
+ SfxItemSet& rDestSet = pDestSheet->GetItemSet();
+ rDestSet.Put(pSrcSheet->GetItemSet());
+ }
+
+ pSrcSheet = pSrcPool->Next();
+ }
-#define SCSTR(id) ScResId(id)
+ for (const auto& style : aNewStyles)
+ style.first->SetParent(style.second);
+}
+
+// Standard templates
void ScStyleSheetPool::CopyStdStylesFrom( ScStyleSheetPool* pSrcPool )
{
// Copy Default styles
- CopyStyleFrom( pSrcPool, SCSTR(STR_STYLENAME_STANDARD), SfxStyleFamily::Para );
- CopyStyleFrom( pSrcPool, SCSTR(STR_STYLENAME_STANDARD), SfxStyleFamily::Page );
- CopyStyleFrom( pSrcPool, SCSTR(STR_STYLENAME_REPORT), SfxStyleFamily::Page );
+ CopyStyleFrom( pSrcPool, ScResId(STR_STYLENAME_STANDARD), SfxStyleFamily::Para );
+ CopyStyleFrom( pSrcPool, ScResId(STR_STYLENAME_STANDARD), SfxStyleFamily::Frame );
+ CopyStyleFrom( pSrcPool, ScResId(STR_STYLENAME_STANDARD), SfxStyleFamily::Page );
+ CopyStyleFrom( pSrcPool, ScResId(STR_STYLENAME_REPORT), SfxStyleFamily::Page );
}
static void lcl_CheckFont( SfxItemSet& rSet, LanguageType eLang, DefaultFontType nFontType, sal_uInt16 nItemId )
@@ -218,13 +251,13 @@ void ScStyleSheetPool::CreateStandardStyles()
SfxItemSet* pSet = nullptr;
SfxItemSet* pHFSet = nullptr;
ScEditEngineDefaulter aEdEngine( EditEngine::CreatePool().get(), true );
- aEdEngine.SetUpdateMode( false );
+ aEdEngine.SetUpdateLayout( false );
std::unique_ptr<EditTextObject> pEmptyTxtObj = aEdEngine.CreateTextObject();
std::unique_ptr<EditTextObject> pTxtObj;
ScPageHFItem aHeaderItem( ATTR_PAGE_HEADERRIGHT );
ScPageHFItem aFooterItem( ATTR_PAGE_FOOTERRIGHT );
ScStyleSheet* pSheet = nullptr;
- ::editeng::SvxBorderLine aBorderLine ( &aColBlack, DEF_LINE_WIDTH_2 );
+ ::editeng::SvxBorderLine aBorderLine ( &aColBlack, SvxBorderLineWidth::Medium );
SvxBoxItem aBoxItem ( ATTR_BORDER );
SvxBoxInfoItem aBoxInfoItem ( ATTR_BORDER_INNER );
@@ -284,7 +317,7 @@ void ScStyleSheetPool::CreateStandardStyles()
// Header:
// [empty][\sheet\][empty]
- aEdEngine.SetTextCurrentDefaults(EMPTY_OUSTRING);
+ aEdEngine.SetTextCurrentDefaults(OUString());
aEdEngine.QuickInsertField( SvxFieldItem(SvxTableField(), EE_FEATURE_FIELD), ESelection() );
pTxtObj = aEdEngine.CreateTextObject();
aHeaderItem.SetLeftArea ( *pEmptyTxtObj );
@@ -295,7 +328,7 @@ void ScStyleSheetPool::CreateStandardStyles()
// Footer:
// [empty][Page \STR_PAGE\][empty]
- aStr = SCSTR( STR_PAGE ) + " ";
+ aStr = ScResId( STR_PAGE ) + " ";
aEdEngine.SetTextCurrentDefaults( aStr );
nStrLen = aStr.getLength();
aEdEngine.QuickInsertField( SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD), ESelection(0,nStrLen,0,nStrLen) );
@@ -307,7 +340,7 @@ void ScStyleSheetPool::CreateStandardStyles()
// 2. Report
- pSheet = static_cast<ScStyleSheet*>( &Make( SCSTR( STR_STYLENAME_REPORT ),
+ pSheet = static_cast<ScStyleSheet*>( &Make( ScResId( STR_STYLENAME_REPORT ),
SfxStyleFamily::Page,
SfxStyleSearchBits::ScStandard ) );
pSet = &pSheet->GetItemSet();
@@ -360,7 +393,7 @@ void ScStyleSheetPool::CreateStandardStyles()
// Footer:
// [empty][Page: \PAGE\ / \PAGE\][empty]
- aStr = SCSTR( STR_PAGE ) + " ";
+ aStr = ScResId( STR_PAGE ) + " ";
nStrLen = aStr.getLength();
aStr += " / ";
sal_Int32 nStrLen2 = aStr.getLength();
@@ -381,7 +414,7 @@ namespace {
struct CaseInsensitiveNamePredicate : svl::StyleSheetPredicate
{
CaseInsensitiveNamePredicate(const OUString& rName, SfxStyleFamily eFam)
- : mUppercaseName(ScGlobal::getCharClassPtr()->uppercase(rName)), mFamily(eFam)
+ : mUppercaseName(ScGlobal::getCharClass().uppercase(rName)), mFamily(eFam)
{
}
@@ -390,7 +423,7 @@ struct CaseInsensitiveNamePredicate : svl::StyleSheetPredicate
{
if (rStyleSheet.GetFamily() == mFamily)
{
- OUString aUpName = ScGlobal::getCharClassPtr()->uppercase(rStyleSheet.GetName());
+ OUString aUpName = ScGlobal::getCharClass().uppercase(rStyleSheet.GetName());
if (mUppercaseName == aUpName)
{
return true;
@@ -411,14 +444,30 @@ ScStyleSheet* ScStyleSheetPool::FindCaseIns( const OUString& rName, SfxStyleFami
CaseInsensitiveNamePredicate aPredicate(rName, eFam);
std::vector<sal_Int32> aFoundPositions = GetIndexedStyleSheets().FindPositionsByPredicate(aPredicate);
+ ScStyleSheet* first = nullptr; // first case insensitive match found
for (const auto& rPos : aFoundPositions)
{
SfxStyleSheetBase *pFound = GetStyleSheetByPositionInIndex(rPos);
// we do not know what kind of sheets we have.
if (pFound->isScStyleSheet())
- return static_cast<ScStyleSheet*>(pFound);
+ {
+ if (pFound->GetName() == rName) // exact case sensitive match
+ return static_cast<ScStyleSheet*>(pFound);
+ if (!first)
+ first = static_cast<ScStyleSheet*>(pFound);
+ }
}
- return nullptr;
+ return first;
+}
+
+ScStyleSheet* ScStyleSheetPool::FindAutoStyle(const OUString& rName)
+{
+ ScStyleSheet* pStyleSheet = FindCaseIns(rName, SfxStyleFamily::Para);
+ if (!pStyleSheet)
+ if (auto pFound = Find(ScResId(STR_STYLENAME_STANDARD), SfxStyleFamily::Para))
+ if (pFound->isScStyleSheet()) // we do not know what kind of sheets we have
+ pStyleSheet = static_cast<ScStyleSheet*>(pFound);
+ return pStyleSheet;
}
void ScStyleSheetPool::setAllParaStandard()
diff --git a/sc/source/core/data/stlsheet.cxx b/sc/source/core/data/stlsheet.cxx
index 20f4399dd98b..dc9e7715f6e2 100644
--- a/sc/source/core/data/stlsheet.cxx
+++ b/sc/source/core/data/stlsheet.cxx
@@ -26,6 +26,10 @@
#include <editeng/frmdiritem.hxx>
#include <editeng/lrspitem.hxx>
#include <svx/pageitem.hxx>
+#include <svx/svddef.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/xdef.hxx>
+#include <editeng/eeitem.hxx>
#include <editeng/paperinf.hxx>
#include <editeng/shaditem.hxx>
#include <editeng/sizeitem.hxx>
@@ -33,6 +37,7 @@
#include <editeng/xmlcnitm.hxx>
#include <svl/itempool.hxx>
#include <svl/itemset.hxx>
+#include <svl/numformat.hxx>
#include <svl/hint.hxx>
#include <o3tl/unit_conversion.hxx>
#include <attrib.hxx>
@@ -76,6 +81,7 @@ bool ScStyleSheet::HasParentSupport () const
switch ( GetFamily() )
{
case SfxStyleFamily::Para: bHasParentSupport = true; break;
+ case SfxStyleFamily::Frame: bHasParentSupport = true; break;
case SfxStyleFamily::Page: bHasParentSupport = false; break;
default:
{
@@ -112,7 +118,7 @@ bool ScStyleSheet::SetParent( const OUString& rParentName )
// RepaintRange checks the document's IsVisible flag and locked repaints.
ScDocument* pDoc = static_cast<ScStyleSheetPool*>(GetPool())->GetDocument();
if (pDoc)
- pDoc->RepaintRange( ScRange( 0,0,0, MAXCOL,MAXROW,MAXTAB ) );
+ pDoc->RepaintRange( ScRange( 0,0,0, pDoc->MaxCol(),pDoc->MaxRow(),MAXTAB ) );
}
}
@@ -137,14 +143,12 @@ SfxItemSet& ScStyleSheet::GetItemSet()
// (== Standard page template)
SfxItemPool& rItemPool = GetPool()->GetPool();
- pSet = new SfxItemSet(
- rItemPool,
- svl::Items<
+ pSet = new SfxItemSetFixed<
ATTR_USERDEF, ATTR_USERDEF,
ATTR_WRITINGDIR, ATTR_WRITINGDIR,
ATTR_BACKGROUND, ATTR_BACKGROUND,
ATTR_BORDER, ATTR_SHADOW,
- ATTR_LRSPACE, ATTR_PAGE_SCALETO>{} );
+ ATTR_LRSPACE, ATTR_PAGE_SCALETO>(rItemPool);
// If being loaded also the set is then filled in from the file,
// so the defaults do not need to be set.
@@ -159,7 +163,7 @@ SfxItemSet& ScStyleSheet::GetItemSet()
SvxSizeItem aPaperSizeItem( ATTR_PAGE_SIZE, SvxPaperInfo::GetDefaultPaperSize() );
SvxSetItem aHFSetItem(
- rItemPool.GetDefaultItem(ATTR_PAGE_HEADERSET) );
+ rItemPool.GetUserOrPoolDefaultItem(ATTR_PAGE_HEADERSET) );
SfxItemSet& rHFSet = aHFSetItem.GetItemSet();
SvxSizeItem aHFSizeItem( // 0,5 cm + distance
@@ -172,7 +176,6 @@ SfxItemSet& ScStyleSheet::GetItemSet()
SvxLRSpaceItem aLRSpaceItem( TWO_CM, // nLeft
TWO_CM, // nRight
- TWO_CM, // nTLeft
0, // nFirstLineOffset
ATTR_LRSPACE );
SvxULSpaceItem aULSpaceItem( TWO_CM, // nUp
@@ -189,7 +192,7 @@ SfxItemSet& ScStyleSheet::GetItemSet()
rHFSet.Put( aBoxInfoItem );
rHFSet.Put( aHFSizeItem );
rHFSet.Put( aHFDistItem );
- rHFSet.Put( SvxLRSpaceItem( 0,0,0,0, ATTR_LRSPACE ) ); // Set border to Null
+ rHFSet.Put( SvxLRSpaceItem(0, 0, 0, ATTR_LRSPACE) ); // Set border to Null
aHFSetItem.SetWhich(ATTR_PAGE_HEADERSET);
pSet->Put( aHFSetItem );
@@ -207,21 +210,39 @@ SfxItemSet& ScStyleSheet::GetItemSet()
SvxFrameDirection::Horizontal_RL_TB : SvxFrameDirection::Horizontal_LR_TB;
pSet->Put( SvxFrameDirectionItem( eDirection, ATTR_WRITINGDIR ) );
- rItemPool.SetPoolDefaultItem( aPageItem );
- rItemPool.SetPoolDefaultItem( aPaperSizeItem );
- rItemPool.SetPoolDefaultItem( aLRSpaceItem );
- rItemPool.SetPoolDefaultItem( aULSpaceItem );
- rItemPool.SetPoolDefaultItem( SfxUInt16Item( ATTR_PAGE_SCALE, 100 ) );
+ rItemPool.SetUserDefaultItem( aPageItem );
+ rItemPool.SetUserDefaultItem( aPaperSizeItem );
+ rItemPool.SetUserDefaultItem( aLRSpaceItem );
+ rItemPool.SetUserDefaultItem( aULSpaceItem );
+ rItemPool.SetUserDefaultItem( SfxUInt16Item( ATTR_PAGE_SCALE, 100 ) );
ScPageScaleToItem aScaleToItem;
- rItemPool.SetPoolDefaultItem( aScaleToItem );
- rItemPool.SetPoolDefaultItem( SfxUInt16Item( ATTR_PAGE_SCALETOPAGES, 0 ) );
+ rItemPool.SetUserDefaultItem( aScaleToItem );
+ rItemPool.SetUserDefaultItem( SfxUInt16Item( ATTR_PAGE_SCALETOPAGES, 0 ) );
}
}
break;
+ case SfxStyleFamily::Frame:
+ {
+ SfxItemPool* pItemPool = &GetPool()->GetPool();
+ if (dynamic_cast<SdrItemPool*>(pItemPool) == nullptr)
+ pItemPool = pItemPool->GetSecondaryPool();
+ assert(pItemPool);
+
+ pSet = new SfxItemSetFixed<
+ XATTR_LINE_FIRST, XATTR_LINE_LAST,
+ XATTR_FILL_FIRST, XATTR_FILL_LAST,
+ SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST,
+ SDRATTR_TEXT_MINFRAMEHEIGHT, SDRATTR_TEXT_WORDWRAP,
+ SDRATTR_EDGE_FIRST, SDRATTR_MEASURE_LAST,
+ SDRATTR_3D_FIRST, SDRATTR_3D_LAST,
+ EE_PARA_START, EE_CHAR_END>(*pItemPool);
+ }
+ break;
+
case SfxStyleFamily::Para:
default:
- pSet = new SfxItemSet( GetPool()->GetPool(), svl::Items<ATTR_PATTERN_START, ATTR_PATTERN_END>{} );
+ pSet = new SfxItemSetFixed<ATTR_PATTERN_START, ATTR_PATTERN_END>( GetPool()->GetPool() );
break;
}
bMySet = true;
@@ -251,25 +272,56 @@ SfxItemSet& ScStyleSheet::GetItemSet()
bool ScStyleSheet::IsUsed() const
{
- if ( GetFamily() == SfxStyleFamily::Para )
+ switch (GetFamily())
{
- // Always query the document to let it decide if a rescan is necessary,
- // and store the state.
- ScDocument* pDoc = static_cast<ScStyleSheetPool*>(m_pPool)->GetDocument();
- if ( pDoc && pDoc->IsStyleSheetUsed( *this ) )
- eUsage = Usage::USED;
- else
- eUsage = Usage::NOTUSED;
- return eUsage == Usage::USED;
+ case SfxStyleFamily::Para:
+ {
+ // Always query the document to let it decide if a rescan is necessary,
+ // and store the state.
+ ScDocument* pDoc = static_cast<ScStyleSheetPool*>(m_pPool)->GetDocument();
+ if ( pDoc && pDoc->IsStyleSheetUsed( *this ) )
+ eUsage = Usage::USED;
+ else
+ eUsage = Usage::NOTUSED;
+ return eUsage == Usage::USED;
+ }
+ case SfxStyleFamily::Page:
+ {
+ // tdf#108188 - verify that the page style is actually used
+ ScDocument* pDoc = static_cast<ScStyleSheetPool*>(m_pPool)->GetDocument();
+ if (pDoc && pDoc->IsPageStyleInUse(GetName(), nullptr))
+ eUsage = Usage::USED;
+ else
+ eUsage = Usage::NOTUSED;
+ return eUsage == Usage::USED;
+ }
+ case SfxStyleFamily::Frame:
+ {
+ ForAllListeners([this] (SfxListener* pListener)
+ {
+ auto pUser(dynamic_cast<svl::StyleSheetUser*>(pListener));
+ if (pUser && pUser->isUsedByModel())
+ {
+ eUsage = Usage::USED;
+ return true; // break loop
+ }
+ else
+ eUsage = Usage::NOTUSED;
+ return false;
+ });
+ return eUsage == Usage::USED;
+ }
+ default:
+ return true;
}
- else
- return true;
}
-void ScStyleSheet::Notify( SfxBroadcaster&, const SfxHint& rHint )
+void ScStyleSheet::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
{
if ( rHint.GetId() == SfxHintId::Dying )
GetItemSet().SetParent( nullptr );
+ if (GetFamily() == SfxStyleFamily::Frame)
+ SfxStyleSheet::Notify(rBC, rHint);
}
// Avoid creating a Style "Standard" if this is not the Standard-Name;
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 40aeab42cfa2..c7539a154204 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -17,6 +17,7 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
+#include <sal/types.h>
#include <scitems.hxx>
#include <editeng/justifyitem.hxx>
#include <o3tl/safeint.hxx>
@@ -28,6 +29,7 @@
#include <patattr.hxx>
#include <table.hxx>
#include <document.hxx>
+#include <docsh.hxx>
#include <drwlayer.hxx>
#include <olinetab.hxx>
#include <global.hxx>
@@ -37,6 +39,8 @@
#include <markdata.hxx>
#include <progress.hxx>
#include <prnsave.hxx>
+#include <printopt.hxx>
+#include <scmod.hxx>
#include <tabprotection.hxx>
#include <sheetevents.hxx>
#include <segmenttree.hxx>
@@ -109,7 +113,7 @@ void GetOptimalHeightsInColumn(
const SCROW nMinStart = nPos;
- sal_uLong nWeightedCount = nProgressStart + rCol.back().GetWeightedCount(nStartRow, nEndRow);
+ sal_uInt64 nWeightedCount = nProgressStart + rCol.back().GetWeightedCount(nStartRow, nEndRow);
const SCCOL maxCol = rCol.size() - 1; // last col done already above
for (SCCOL nCol=0; nCol<maxCol; nCol++)
{
@@ -244,6 +248,7 @@ ScTable::ScTable( ScDocument& rDoc, SCTAB nNewTab, const OUString& rNewName,
nRepeatEndX( SCCOL_REPEAT_NONE ),
nRepeatStartY( SCROW_REPEAT_NONE ),
nRepeatEndY( SCROW_REPEAT_NONE ),
+ mnOptimalMinRowHeight(0),
mpRowHeights( static_cast<ScFlatUInt16RowSegments*>(nullptr) ),
mpHiddenCols(new ScFlatBoolColSegments(rDoc.MaxCol())),
mpHiddenRows(new ScFlatBoolRowSegments(rDoc.MaxRow())),
@@ -269,7 +274,6 @@ ScTable::ScTable( ScDocument& rDoc, SCTAB nNewTab, const OUString& rNewName,
bTableAreaValid(false),
bTableAreaVisibleValid(false),
bVisible(true),
- bStreamValid(false),
bPendingRowHeights(false),
bCalcNotification(false),
bGlobalKeepQuery(false),
@@ -277,8 +281,9 @@ ScTable::ScTable( ScDocument& rDoc, SCTAB nNewTab, const OUString& rNewName,
bActiveScenario(false),
mbPageBreaksValid(false),
mbForceBreaks(false),
- aDefaultColAttrArray(static_cast<SCCOL>(-1), nNewTab, rDoc, nullptr)
+ bStreamValid(false)
{
+ aDefaultColData.InitAttrArray(new ScAttrArray(static_cast<SCCOL>(-1), nNewTab, rDoc, nullptr));
if (bColInfo)
{
mpColWidth.reset( new ScCompressedArray<SCCOL, sal_uInt16>( rDocument.MaxCol()+1, STD_COL_WIDTH ) );
@@ -287,7 +292,7 @@ ScTable::ScTable( ScDocument& rDoc, SCTAB nNewTab, const OUString& rNewName,
if (bRowInfo)
{
- mpRowHeights.reset(new ScFlatUInt16RowSegments(rDocument.MaxRow(), ScGlobal::nStdRowHeight));
+ mpRowHeights.reset(new ScFlatUInt16RowSegments(rDocument.MaxRow(), GetOptimalMinRowHeight()));
pRowFlags.reset(new ScBitMaskCompressedArray<SCROW, CRFlags>( rDocument.MaxRow(), CRFlags::NONE));
}
@@ -305,7 +310,8 @@ ScTable::ScTable( ScDocument& rDoc, SCTAB nNewTab, const OUString& rNewName,
{
pDrawLayer->ScRenamePage( nTab, aName );
sal_uLong const nx = o3tl::convert((rDocument.MaxCol()+1) * STD_COL_WIDTH, o3tl::Length::twip, o3tl::Length::mm100);
- sal_uLong ny = o3tl::convert((rDocument.MaxRow()+1) * ScGlobal::nStdRowHeight, o3tl::Length::twip, o3tl::Length::mm10);
+ sal_uLong ny = o3tl::convert((rDocument.MaxRow() + 1) * GetOptimalMinRowHeight(),
+ o3tl::Length::twip, o3tl::Length::mm10);
pDrawLayer->SetPageSize( static_cast<sal_uInt16>(nTab), Size( nx, ny ), false );
}
}
@@ -318,7 +324,7 @@ ScTable::~ScTable() COVERITY_NOEXCEPT_FALSE
{
if (!rDocument.IsInDtorClear())
{
- for (SCCOL nCol = 0; nCol < (aCol.size() - 1); ++nCol)
+ for (SCCOL nCol = 0; nCol < aCol.size(); ++nCol)
{
aCol[nCol].FreeNotes();
}
@@ -335,8 +341,8 @@ ScTable::~ScTable() COVERITY_NOEXCEPT_FALSE
pSheetEvents.reset();
pOutlineTable.reset();
pSearchText.reset();
- pRepeatColRange.reset();
- pRepeatRowRange.reset();
+ moRepeatColRange.reset();
+ moRepeatRowRange.reset();
pScenarioRanges.reset();
mpRangeName.reset();
pDBDataNoName.reset();
@@ -359,7 +365,7 @@ void ScTable::SetName( const OUString& rNewName )
const OUString& ScTable::GetUpperName() const
{
if (aUpperName.isEmpty() && !aName.isEmpty())
- aUpperName = ScGlobal::getCharClassPtr()->uppercase(aName);
+ aUpperName = ScGlobal::getCharClass().uppercase(aName);
return aUpperName;
}
@@ -411,7 +417,7 @@ void ScTable::SetScenario( bool bFlag )
void ScTable::SetLink( ScLinkMode nMode,
const OUString& rDoc, const OUString& rFlt, const OUString& rOpt,
- const OUString& rTab, sal_uLong nRefreshDelay )
+ const OUString& rTab, sal_Int32 nRefreshDelay )
{
nLinkMode = nMode;
aLinkDoc = rDoc; // File
@@ -455,7 +461,7 @@ tools::Long ScTable::GetNeededSize( SCCOL nCol, SCROW nRow,
bool ScTable::SetOptimalHeight(
sc::RowHeightContext& rCxt, SCROW nStartRow, SCROW nEndRow, bool bApi,
- ScProgress* pOuterProgress, sal_uLong nProgressStart )
+ ScProgress* pOuterProgress, sal_uInt64 nProgressStart )
{
assert(nStartRow <= nEndRow);
@@ -488,7 +494,7 @@ bool ScTable::SetOptimalHeight(
void ScTable::SetOptimalHeightOnly(
sc::RowHeightContext& rCxt, SCROW nStartRow, SCROW nEndRow,
- ScProgress* pOuterProgress, sal_uLong nProgressStart )
+ ScProgress* pOuterProgress, sal_uInt64 nProgressStart )
{
OSL_ENSURE( rCxt.getExtraHeight() == 0 || rCxt.isForceAutoSize(),
"automatic OptimalHeight with Extra" );
@@ -516,7 +522,7 @@ bool ScTable::GetCellArea( SCCOL& rEndCol, SCROW& rEndRow ) const
SCCOL nMaxX = 0;
SCROW nMaxY = 0;
for (SCCOL i=0; i<aCol.size(); i++)
- {
+ {
if (!aCol[i].IsEmptyData())
{
bFound = true;
@@ -539,7 +545,21 @@ bool ScTable::GetCellArea( SCCOL& rEndCol, SCROW& rEndRow ) const
nMaxX = i;
}
}
- }
+ if (aCol[i].HasSparklines())
+ {
+ SCROW maxSparklineRow = aCol[i].GetSparklinesMaxRow();
+ if (maxSparklineRow >= nMaxY)
+ {
+ bFound = true;
+ nMaxY = maxSparklineRow;
+ }
+ if (i > nMaxX)
+ {
+ bFound = true;
+ nMaxX = i;
+ }
+ }
+ }
rEndCol = nMaxX;
rEndRow = nMaxY;
@@ -581,6 +601,8 @@ bool ScTable::GetPrintArea( SCCOL& rEndCol, SCROW& rEndRow, bool bNotes, bool bC
SCROW nMaxY = 0;
SCCOL i;
+ bool bSkipEmpty = SC_MOD()->GetPrintOptions().GetSkipEmpty();
+
for (i=0; i<aCol.size(); i++) // Test data
{
if (bCalcHiddens || !rDocument.ColHidden(i, nTab))
@@ -608,6 +630,20 @@ bool ScTable::GetPrintArea( SCCOL& rEndCol, SCROW& rEndRow, bool bNotes, bool bC
nMaxX = i;
}
}
+ if (aCol[i].HasSparklines())
+ {
+ SCROW maxSparklineRow = aCol[i].GetSparklinesMaxRow();
+ if (maxSparklineRow >= nMaxY)
+ {
+ bFound = true;
+ nMaxY = maxSparklineRow;
+ }
+ if (i > nMaxX)
+ {
+ bFound = true;
+ nMaxX = i;
+ }
+ }
}
}
@@ -618,7 +654,7 @@ bool ScTable::GetPrintArea( SCCOL& rEndCol, SCROW& rEndRow, bool bNotes, bool bC
if (bCalcHiddens || !rDocument.ColHidden(i, nTab))
{
SCROW nLastRow;
- if (aCol[i].GetLastVisibleAttr( nLastRow ))
+ if (aCol[i].GetLastVisibleAttr( nLastRow, bSkipEmpty ))
{
bFound = true;
nMaxX = i;
@@ -631,7 +667,7 @@ bool ScTable::GetPrintArea( SCCOL& rEndCol, SCROW& rEndRow, bool bNotes, bool bC
if (nMaxX == rDocument.MaxCol()) // omit attribute at the right
{
--nMaxX;
- while ( nMaxX>0 && aCol[nMaxX].IsVisibleAttrEqual(aCol[nMaxX+1]) )
+ while ( nMaxX>0 && aCol[nMaxX].IsVisibleAttrEqual(aCol[nMaxX+1], 0, rDocument.MaxRow()) )
--nMaxX;
}
@@ -645,7 +681,7 @@ bool ScTable::GetPrintArea( SCCOL& rEndCol, SCROW& rEndRow, bool bNotes, bool bC
while ( nAttrStartX < (aCol.size()-1) )
{
SCCOL nAttrEndX = nAttrStartX;
- while ( nAttrEndX < (aCol.size()-1) && aCol[nAttrStartX].IsVisibleAttrEqual(aCol[nAttrEndX+1]) )
+ while ( nAttrEndX < (aCol.size()-1) && aCol[nAttrStartX].IsVisibleAttrEqual(aCol[nAttrEndX+1], 0, rDocument.MaxRow()) )
++nAttrEndX;
if ( nAttrEndX + 1 - nAttrStartX >= SC_COLUMNS_STOP )
{
@@ -654,7 +690,7 @@ bool ScTable::GetPrintArea( SCCOL& rEndCol, SCROW& rEndRow, bool bNotes, bool bC
// also don't include default-formatted columns before that
SCROW nDummyRow;
- while ( nMaxX > nMaxDataX && !aCol[nMaxX].GetLastVisibleAttr( nDummyRow ) )
+ while ( nMaxX > nMaxDataX && !aCol[nMaxX].GetLastVisibleAttr( nDummyRow, bSkipEmpty ) )
--nMaxX;
break;
}
@@ -692,11 +728,19 @@ bool ScTable::GetPrintAreaHor( SCROW nStartRow, SCROW nEndRow,
for (i=0; i<aCol.size(); i++) // test the data
{
- if (!aCol[i].IsEmptyBlock( nStartRow, nEndRow )) //TODO: bNotes ??????
+ if (!aCol[i].IsEmptyData( nStartRow, nEndRow )) //TODO: bNotes ??????
{
bFound = true;
- if (i>nMaxX)
+ if (i > nMaxX)
+ nMaxX = i;
+ }
+ else if (aCol[i].HasSparklines())
+ {
+ if (i > nMaxX)
+ {
+ bFound = true;
nMaxX = i;
+ }
}
}
@@ -707,16 +751,16 @@ bool ScTable::GetPrintAreaHor( SCROW nStartRow, SCROW nEndRow,
bool ScTable::GetPrintAreaVer( SCCOL nStartCol, SCCOL nEndCol,
SCROW& rEndRow, bool bNotes ) const
{
- nStartCol = std::min<SCCOL>( nStartCol, aCol.size()-1 );
- nEndCol = std::min<SCCOL>( nEndCol, aCol.size()-1 );
bool bFound = false;
SCROW nMaxY = 0;
SCCOL i;
- for (i=nStartCol; i<=nEndCol; i++) // Test attribute
+ bool bSkipEmpty = SC_MOD()->GetPrintOptions().GetSkipEmpty();
+
+ for (i=nStartCol; i<=nEndCol && i < aCol.size(); i++) // Test attribute
{
SCROW nLastRow;
- if (aCol[i].GetLastVisibleAttr( nLastRow ))
+ if (aCol[i].GetLastVisibleAttr( nLastRow, bSkipEmpty ))
{
bFound = true;
if (nLastRow > nMaxY)
@@ -724,7 +768,7 @@ bool ScTable::GetPrintAreaVer( SCCOL nStartCol, SCCOL nEndCol,
}
}
- for (i=nStartCol; i<=nEndCol; i++) // Test data
+ for (i=nStartCol; i<=nEndCol && i < aCol.size(); i++) // Test data
{
if (!aCol[i].IsEmptyData())
{
@@ -742,6 +786,15 @@ bool ScTable::GetPrintAreaVer( SCCOL nStartCol, SCCOL nEndCol,
nMaxY = maxNoteRow;
}
}
+ if (aCol[i].HasSparklines())
+ {
+ SCROW maxNoteRow = aCol[i].GetSparklinesMaxRow();
+ if (maxNoteRow > nMaxY)
+ {
+ bFound = true;
+ nMaxY = maxNoteRow;
+ }
+ }
}
rEndRow = nMaxY;
@@ -770,10 +823,10 @@ bool ScTable::GetDataStart( SCCOL& rStartCol, SCROW& rStartRow ) const
if (nMinX == 0) // omit attribute at the right
{
- if ( aCol.size() > 1 && aCol[0].IsVisibleAttrEqual(aCol[1]) ) // no single ones
+ if ( aCol.size() > 1 && aCol[0].IsVisibleAttrEqual(aCol[1], 0, rDocument.MaxRow())) // no single ones
{
++nMinX;
- while ( nMinX<(aCol.size()-1) && aCol[nMinX].IsVisibleAttrEqual(aCol[nMinX-1]) )
+ while ( nMinX<(aCol.size()-1) && aCol[nMinX].IsVisibleAttrEqual(aCol[nMinX-1], 0, rDocument.MaxRow()))
++nMinX;
}
}
@@ -804,6 +857,20 @@ bool ScTable::GetDataStart( SCCOL& rStartCol, SCROW& rStartRow ) const
nMinX = i;
}
}
+ if (aCol[i].HasSparklines())
+ {
+ SCROW minSparkline = aCol[i].GetSparklinesMinRow();
+ if (minSparkline <= nMinY)
+ {
+ bFound = true;
+ nMinY = minSparkline;
+ }
+ if (i < nMinX)
+ {
+ bFound = true;
+ nMinX = i;
+ }
+ }
}
rStartCol = nMinX;
rStartRow = nMinY;
@@ -847,7 +914,7 @@ void ScTable::GetDataArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, S
if (nEnd<rDocument.MaxRow()) ++nEnd;
if (rEndCol < (aCol.size()-1))
- if (!aCol[rEndCol+1].IsEmptyBlock(nStart,nEnd))
+ if (!aCol[rEndCol+1].IsEmptyData(nStart,nEnd))
{
assert( int( blockPos.size()) == rEndCol + 1 );
++rEndCol;
@@ -858,7 +925,7 @@ void ScTable::GetDataArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, S
}
if (rStartCol > 0)
- if (!aCol[rStartCol-1].IsEmptyBlock(nStart,nEnd))
+ if (!aCol[rStartCol-1].IsEmptyData(nStart,nEnd))
{
--rStartCol;
bChanged = true;
@@ -901,11 +968,11 @@ void ScTable::GetDataArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, S
if ( !bIncludeOld && !bOnlyDown )
{
if ( !bLeft )
- while ( rStartCol < rEndCol && rStartCol < (aCol.size()-1) && aCol[rStartCol].IsEmptyBlock(rStartRow,rEndRow) )
+ while ( rStartCol < rEndCol && rStartCol < (aCol.size()-1) && aCol[rStartCol].IsEmptyData(rStartRow,rEndRow) )
++rStartCol;
if ( !bRight )
- while ( rEndCol > 0 && rStartCol < rEndCol && aCol[rEndCol].IsEmptyBlock(rStartRow,rEndRow) )
+ while ( rEndCol > 0 && rStartCol < rEndCol && aCol[rEndCol].IsEmptyData(rStartRow,rEndRow) )
--rEndCol;
if ( !bTop && rStartRow < rDocument.MaxRow() && rStartRow < rEndRow )
@@ -976,7 +1043,7 @@ bool ScTable::GetDataAreaSubrange( ScRange& rRange ) const
bool ScTable::ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rStartRow,
SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly, bool bStickyTopRow, bool bStickyLeftCol,
- bool bConsiderCellNotes, bool bConsiderCellDrawObjects, bool bConsiderCellFormats ) const
+ ScDataAreaExtras* pDataAreaExtras ) const
{
rStartCol = std::min<SCCOL>( rStartCol, aCol.size()-1 );
// check for rEndCol is done below.
@@ -1008,16 +1075,20 @@ bool ScTable::ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rS
while (rStartCol < rEndCol)
{
- if (aCol[rEndCol].IsEmptyBlock( rStartRow, rEndRow))
+ if (aCol[rEndCol].IsEmptyData( rStartRow, rEndRow))
{
- if (bConsiderCellNotes && !aCol[rEndCol].IsNotesEmptyBlock( rStartRow, rEndRow ))
- break;
-
- if (bConsiderCellDrawObjects && !aCol[rEndCol].IsDrawObjectsEmptyBlock( rStartRow, rEndRow ))
- break;
-
- if (bConsiderCellFormats && aCol[rEndCol].HasVisibleAttrIn(rStartRow, rEndRow))
- break;
+ if (pDataAreaExtras && pDataAreaExtras->mnEndCol < rEndCol)
+ {
+ // Check in order of likeliness.
+ if ( (pDataAreaExtras->mbCellFormats
+ && aCol[rEndCol].GetPatternCount( rStartRow, rEndRow) > 1
+ && aCol[rEndCol].HasVisibleAttrIn( rStartRow, rEndRow)) ||
+ (pDataAreaExtras->mbCellNotes
+ && !aCol[rEndCol].IsNotesEmptyBlock( rStartRow, rEndRow)) ||
+ (pDataAreaExtras->mbCellDrawObjects
+ && !aCol[rEndCol].IsDrawObjectsEmptyBlock( rStartRow, rEndRow)))
+ pDataAreaExtras->mnEndCol = rEndCol;
+ }
--rEndCol;
o_bShrunk = true;
@@ -1030,16 +1101,20 @@ bool ScTable::ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rS
{
while (rStartCol < rEndCol)
{
- if (aCol[rStartCol].IsEmptyBlock( rStartRow, rEndRow))
+ if (aCol[rStartCol].IsEmptyData( rStartRow, rEndRow))
{
- if (bConsiderCellNotes && !aCol[rStartCol].IsNotesEmptyBlock( rStartRow, rEndRow ))
- break;
-
- if (bConsiderCellDrawObjects && !aCol[rStartCol].IsDrawObjectsEmptyBlock( rStartRow, rEndRow ))
- break;
-
- if (bConsiderCellFormats && aCol[rEndCol].HasVisibleAttrIn(rStartRow, rEndRow))
- break;
+ if (pDataAreaExtras && pDataAreaExtras->mnStartCol > rStartCol)
+ {
+ // Check in order of likeliness.
+ if ( (pDataAreaExtras->mbCellFormats
+ && aCol[rStartCol].GetPatternCount( rStartRow, rEndRow) > 1
+ && aCol[rStartCol].HasVisibleAttrIn( rStartRow, rEndRow)) ||
+ (pDataAreaExtras->mbCellNotes
+ && !aCol[rStartCol].IsNotesEmptyBlock( rStartRow, rEndRow)) ||
+ (pDataAreaExtras->mbCellDrawObjects
+ && !aCol[rStartCol].IsDrawObjectsEmptyBlock( rStartRow, rEndRow)))
+ pDataAreaExtras->mnStartCol = rStartCol;
+ }
++rStartCol;
o_bShrunk = true;
@@ -1051,6 +1126,18 @@ bool ScTable::ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rS
if (!bColumnsOnly)
{
+ while (rStartRow < rEndRow)
+ {
+ SCROW nLastDataRow = GetLastDataRow(rStartCol, rEndCol, rEndRow, pDataAreaExtras);
+ if (0 <= nLastDataRow && nLastDataRow < rEndRow)
+ {
+ rEndRow = std::max( rStartRow, nLastDataRow);
+ o_bShrunk = true;
+ }
+ else
+ break; // while
+ }
+
if (!bStickyTopRow)
{
while (rStartRow < rEndRow)
@@ -1058,8 +1145,7 @@ bool ScTable::ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rS
bool bFound = false;
for (SCCOL i=rStartCol; i<=rEndCol && !bFound; i++)
{
- if (aCol[i].HasDataAt(rStartRow, bConsiderCellNotes, bConsiderCellDrawObjects,
- bConsiderCellFormats))
+ if (aCol[i].HasDataAt(rStartRow, pDataAreaExtras))
bFound = true;
}
if (!bFound)
@@ -1071,29 +1157,15 @@ bool ScTable::ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rS
break; // while
}
}
-
- while (rStartRow < rEndRow)
- {
- SCROW nLastDataRow = GetLastDataRow(rStartCol, rEndCol, rEndRow, bConsiderCellNotes,
- bConsiderCellDrawObjects, bConsiderCellFormats);
- if (0 <= nLastDataRow && nLastDataRow < rEndRow)
- {
- rEndRow = std::max( rStartRow, nLastDataRow);
- o_bShrunk = true;
- }
- else
- break; // while
- }
}
return rStartCol != rEndCol || (bColumnsOnly ?
- !aCol[rStartCol].IsEmptyBlock( rStartRow, rEndRow) :
+ !aCol[rStartCol].IsEmptyData( rStartRow, rEndRow) :
(rStartRow != rEndRow ||
- aCol[rStartCol].HasDataAt( rStartRow, bConsiderCellNotes, bConsiderCellDrawObjects, bConsiderCellFormats )));
+ aCol[rStartCol].HasDataAt( rStartRow, pDataAreaExtras)));
}
-SCROW ScTable::GetLastDataRow( SCCOL nCol1, SCCOL nCol2, SCROW nLastRow, bool bConsiderCellNotes,
- bool bConsiderCellDrawObjects, bool bConsiderCellFormats ) const
+SCROW ScTable::GetLastDataRow( SCCOL nCol1, SCCOL nCol2, SCROW nLastRow, ScDataAreaExtras* pDataAreaExtras ) const
{
if ( !IsColValid( nCol1 ) || !ValidCol( nCol2 ) )
return -1;
@@ -1103,8 +1175,7 @@ SCROW ScTable::GetLastDataRow( SCCOL nCol1, SCCOL nCol2, SCROW nLastRow, bool bC
SCROW nNewLastRow = 0;
for (SCCOL i = nCol1; i <= nCol2; ++i)
{
- SCROW nThis = aCol[i].GetLastDataPos(nLastRow, bConsiderCellNotes, bConsiderCellDrawObjects,
- bConsiderCellFormats);
+ SCROW nThis = aCol[i].GetLastDataPos(nLastRow, pDataAreaExtras);
if (nNewLastRow < nThis)
nNewLastRow = nThis;
}
@@ -1112,6 +1183,15 @@ SCROW ScTable::GetLastDataRow( SCCOL nCol1, SCCOL nCol2, SCROW nLastRow, bool bC
return nNewLastRow;
}
+bool ScTable::IsEmptyData( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow ) const
+{
+ for( SCCOL col : GetAllocatedColumnsRange( nStartCol, nEndCol ))
+ if( !aCol[col].IsEmptyData( nStartRow, nEndRow ))
+ return false;
+ return true;
+}
+
SCSIZE ScTable::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow,
SCCOL nEndCol, SCROW nEndRow, ScDirection eDir ) const
{
@@ -1139,7 +1219,7 @@ SCSIZE ScTable::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow,
{
nCol = nEndCol;
while ((nCol >= nStartCol) &&
- aCol[nCol].IsEmptyBlock(nStartRow, nEndRow))
+ aCol[nCol].IsEmptyData(nStartRow, nEndRow))
{
nCount++;
nCol--;
@@ -1149,7 +1229,7 @@ SCSIZE ScTable::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow,
else
{
nCol = nStartCol;
- while ((nCol <= nEndCol) && aCol[nCol].IsEmptyBlock(nStartRow, nEndRow))
+ while ((nCol <= nEndCol) && aCol[nCol].IsEmptyData(nStartRow, nEndRow))
{
nCount++;
nCol++;
@@ -1171,11 +1251,10 @@ bool ScTable::IsEmptyLine( SCROW nRow, SCCOL nStartCol, SCCOL nEndCol ) const
nEndCol = std::min<SCCOL>( nEndCol, aCol.size()-1 );
- bool bFound = false;
- for (SCCOL i=nStartCol; i<=nEndCol && !bFound; i++)
+ for (SCCOL i=nStartCol; i<=nEndCol; i++)
if (aCol[i].HasDataAt(nRow))
- bFound = true;
- return !bFound;
+ return false;
+ return true;
}
void ScTable::LimitChartArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow ) const
@@ -1183,10 +1262,10 @@ void ScTable::LimitChartArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol
rStartCol = std::min<SCCOL>( rStartCol, aCol.size()-1 );
rEndCol = std::min<SCCOL>( rEndCol, aCol.size()-1 );
- while ( rStartCol<rEndCol && aCol[rStartCol].IsEmptyBlock(rStartRow,rEndRow) )
+ while ( rStartCol<rEndCol && aCol[rStartCol].IsEmptyData(rStartRow,rEndRow) )
++rStartCol;
- while ( rStartCol<rEndCol && aCol[rEndCol].IsEmptyBlock(rStartRow,rEndRow) )
+ while ( rStartCol<rEndCol && aCol[rEndCol].IsEmptyData(rStartRow,rEndRow) )
--rEndCol;
while ( rStartRow<rEndRow && IsEmptyLine(rStartRow, rStartCol, rEndCol) )
@@ -1260,14 +1339,14 @@ SCCOL ScTable::FindNextVisibleColWithContent( SCCOL nCol, bool bRight, SCROW nRo
}
else
{
- // If nCol is in the unallocated range [nLastCol+1, rDocument.MaxCol()], then move it directly to nLastCol
+ if(nCol == 0)
+ return 0;
+
+ // If nCol is in the unallocated range [nLastCol+1, rDocument.MaxCol()], then move it directly after nLastCol
// as there is no data in the unallocated range. This also makes the search faster and avoids
// the need for more range checks in the loop below.
if ( nCol > nLastCol )
- nCol = nLastCol;
-
- if(nCol == 0)
- return 0;
+ nCol = nLastCol + 1;
do
{
@@ -1445,9 +1524,9 @@ void ScTable::GetNextPos( SCCOL& rCol, SCROW& rRow, SCCOL nMovX, SCROW nMovY,
{
ScRange aRange( ScAddress::UNINITIALIZED);
if (rMark.IsMarked())
- rMark.GetMarkArea( aRange);
+ aRange = rMark.GetMarkArea();
else if (rMark.IsMultiMarked())
- rMark.GetMultiMarkArea( aRange);
+ aRange = rMark.GetMultiMarkArea();
else
{
// Covered by assert() above, but for NDEBUG build.
@@ -1609,7 +1688,7 @@ void ScTable::GetNextPos( SCCOL& rCol, SCROW& rRow, SCCOL nMovX, SCROW nMovY,
nNextRow = rMark.GetNextMarked( nCol, nNextRow, bUp );
if ( bUnprotected )
nNextRow = ( nCol <= nLastCol ) ? aCol[nCol].GetNextUnprotected( nNextRow, bUp ) :
- aDefaultColAttrArray.GetNextUnprotected( nNextRow, bUp );
+ aDefaultColData.GetNextUnprotected( nNextRow, bUp );
pNextRows[nCol - nStartCol] = nNextRow;
if (bUp)
@@ -1748,19 +1827,6 @@ void ScTable::UpdateReference(
sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, bool bIncludeDraw, bool bUpdateNoteCaptionPos )
{
bool bUpdated = false;
- SCCOL i;
- SCCOL iMax;
- if (rCxt.meMode == URM_COPY )
- {
- i = rCxt.maRange.aStart.Col();
- iMax = rCxt.maRange.aEnd.Col();
- }
- else
- {
- i = 0;
- iMax = rDocument.MaxCol();
- }
-
UpdateRefMode eUpdateRefMode = rCxt.meMode;
SCCOL nDx = rCxt.mnColDelta;
SCROW nDy = rCxt.mnRowDelta;
@@ -1773,8 +1839,19 @@ void ScTable::UpdateReference(
if (mpRangeName)
mpRangeName->UpdateReference(rCxt, nTab);
- for ( ; i<=iMax; i++)
- bUpdated |= CreateColumnIfNotExists(i).UpdateReference(rCxt, pUndoDoc);
+ if (rCxt.meMode == URM_COPY )
+ {
+ for( SCCOL col : GetAllocatedColumnsRange( rCxt.maRange.aStart.Col(), rCxt.maRange.aEnd.Col()))
+ bUpdated |= aCol[col].UpdateReference(rCxt, pUndoDoc);
+ }
+ else
+ {
+ for (SCCOL col : GetAllocatedColumnsRange(0, rDocument.MaxCol()))
+ bUpdated |= aCol[col].UpdateReference(rCxt, pUndoDoc);
+ // When deleting row(s), delete same row from the default attribute
+ if (nDy < 0)
+ aDefaultColData.DeleteRow(nRow1+nDy, -nDy);
+ }
if ( bIncludeDraw )
UpdateDrawRef( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz, bUpdateNoteCaptionPos );
@@ -1807,12 +1884,12 @@ void ScTable::UpdateReference(
}
}
- if ( pRepeatColRange )
+ if ( moRepeatColRange )
{
- nSCol = pRepeatColRange->aStart.Col();
- nSRow = pRepeatColRange->aStart.Row();
- nECol = pRepeatColRange->aEnd.Col();
- nERow = pRepeatColRange->aEnd.Row();
+ nSCol = moRepeatColRange->aStart.Col();
+ nSRow = moRepeatColRange->aStart.Row();
+ nECol = moRepeatColRange->aEnd.Col();
+ nERow = moRepeatColRange->aEnd.Row();
// do not try to modify sheet index of repeat range
if ( ScRefUpdate::Update( &rDocument, eUpdateRefMode,
@@ -1820,19 +1897,19 @@ void ScTable::UpdateReference(
nDx,nDy,0,
nSCol,nSRow,nSTab, nECol,nERow,nETab ) )
{
- *pRepeatColRange = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 );
+ *moRepeatColRange = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 );
bRecalcPages = true;
nRepeatStartX = nSCol; // for UpdatePageBreaks
nRepeatEndX = nECol;
}
}
- if ( pRepeatRowRange )
+ if ( moRepeatRowRange )
{
- nSCol = pRepeatRowRange->aStart.Col();
- nSRow = pRepeatRowRange->aStart.Row();
- nECol = pRepeatRowRange->aEnd.Col();
- nERow = pRepeatRowRange->aEnd.Row();
+ nSCol = moRepeatRowRange->aStart.Col();
+ nSRow = moRepeatRowRange->aStart.Row();
+ nECol = moRepeatRowRange->aEnd.Col();
+ nERow = moRepeatRowRange->aEnd.Row();
// do not try to modify sheet index of repeat range
if ( ScRefUpdate::Update( &rDocument, eUpdateRefMode,
@@ -1840,7 +1917,7 @@ void ScTable::UpdateReference(
nDx,nDy,0,
nSCol,nSRow,nSTab, nECol,nERow,nETab ) )
{
- *pRepeatRowRange = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 );
+ *moRepeatRowRange = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 );
bRecalcPages = true;
nRepeatStartY = nSRow; // for UpdatePageBreaks
nRepeatEndY = nERow;
@@ -2015,17 +2092,19 @@ void ScTable::ExtendPrintArea( OutputDevice* pDev,
else
{
// These columns are visible. Check for empty columns.
- for (SCCOL j = i; j <= nLastCol; ++j)
+ SCCOL nEmptyCount = 0;
+ SCCOL j = i;
+ for (; j <= nLastCol; ++j)
{
if ( j >= aCol.size() )
- {
- aSkipCols.setTrue( j, rDocument.MaxCol() );
break;
- }
- if (aCol[j].GetCellCount() == 0)
- // empty
- aSkipCols.setTrue(j,j);
+ if (aCol[j].IsCellCountZero()) // empty
+ nEmptyCount++;
}
+ if (nEmptyCount)
+ aSkipCols.setTrue(i,i+nEmptyCount);
+ if ( j >= aCol.size() )
+ aSkipCols.setTrue( j, rDocument.MaxCol() );
}
i = nLastCol;
}
@@ -2186,35 +2265,35 @@ void ScTable::CopyPrintRange(const ScTable& rTable)
bPrintEntireSheet = rTable.bPrintEntireSheet;
- pRepeatColRange.reset();
- if (rTable.pRepeatColRange)
+ moRepeatColRange.reset();
+ if (rTable.moRepeatColRange)
{
- pRepeatColRange.reset(new ScRange(*rTable.pRepeatColRange));
- pRepeatColRange->aStart.SetTab(nTab);
- pRepeatColRange->aEnd.SetTab(nTab);
+ moRepeatColRange.emplace(*rTable.moRepeatColRange);
+ moRepeatColRange->aStart.SetTab(nTab);
+ moRepeatColRange->aEnd.SetTab(nTab);
}
- pRepeatRowRange.reset();
- if (rTable.pRepeatRowRange)
+ moRepeatRowRange.reset();
+ if (rTable.moRepeatRowRange)
{
- pRepeatRowRange.reset(new ScRange(*rTable.pRepeatRowRange));
- pRepeatRowRange->aStart.SetTab(nTab);
- pRepeatRowRange->aEnd.SetTab(nTab);
+ moRepeatRowRange.emplace(*rTable.moRepeatRowRange);
+ moRepeatRowRange->aStart.SetTab(nTab);
+ moRepeatRowRange->aEnd.SetTab(nTab);
}
}
-void ScTable::SetRepeatColRange( std::unique_ptr<ScRange> pNew )
+void ScTable::SetRepeatColRange( std::optional<ScRange> oNew )
{
- pRepeatColRange = std::move(pNew);
+ moRepeatColRange = std::move(oNew);
SetStreamValid(false);
InvalidatePageBreaks();
}
-void ScTable::SetRepeatRowRange( std::unique_ptr<ScRange> pNew )
+void ScTable::SetRepeatRowRange( std::optional<ScRange> oNew )
{
- pRepeatRowRange = std::move(pNew);
+ moRepeatRowRange = std::move(oNew);
SetStreamValid(false);
@@ -2231,6 +2310,26 @@ void ScTable::ClearPrintRanges()
InvalidatePageBreaks(); // #i117952# forget page breaks for an old print range
}
+void ScTable::ClearPrintNamedRanges()
+{
+ // tdf#100034 Clearing print ranges also requires to remove all print named ranges
+ // Iterate over all named ranges to determine which are print areas to be removed
+ if (mpRangeName)
+ {
+ std::vector<ScRangeData*> aRangesToRemove;
+ for (auto it = mpRangeName->begin(); it != mpRangeName->end(); it++)
+ {
+ ScRangeData* pData = it->second.get();
+ if (pData->HasType(ScRangeData::Type::PrintArea))
+ aRangesToRemove.push_back(pData);
+ }
+
+ // Effectively remove all named ranges that refer to print ranges
+ for (auto pItem : aRangesToRemove)
+ mpRangeName->erase(*pItem);
+ }
+}
+
void ScTable::AddPrintRange( const ScRange& rNew )
{
bPrintEntireSheet = false;
@@ -2258,18 +2357,16 @@ const ScRange* ScTable::GetPrintRange(sal_uInt16 nPos) const
void ScTable::FillPrintSaver( ScPrintSaverTab& rSaveTab ) const
{
- rSaveTab.SetAreas( aPrintRanges, bPrintEntireSheet );
- rSaveTab.SetRepeat( pRepeatColRange.get(), pRepeatRowRange.get() );
+ rSaveTab.SetAreas( std::vector(aPrintRanges), bPrintEntireSheet );
+ rSaveTab.SetRepeat( moRepeatColRange, moRepeatRowRange );
}
void ScTable::RestorePrintRanges( const ScPrintSaverTab& rSaveTab )
{
aPrintRanges = rSaveTab.GetPrintRanges();
bPrintEntireSheet = rSaveTab.IsEntireSheet();
- auto p = rSaveTab.GetRepeatCol();
- SetRepeatColRange( std::unique_ptr<ScRange>(p ? new ScRange(*p) : nullptr) );
- p = rSaveTab.GetRepeatRow();
- SetRepeatRowRange( std::unique_ptr<ScRange>(p ? new ScRange(*p) : nullptr) );
+ SetRepeatColRange( rSaveTab.GetRepeatCol() );
+ SetRepeatRowRange( rSaveTab.GetRepeatRow() );
InvalidatePageBreaks(); // #i117952# forget page breaks for an old print range
UpdatePageBreaks(nullptr);
@@ -2284,10 +2381,6 @@ ScTable::VisibleDataCellIterator::VisibleDataCellIterator(const ScDocument& rDoc
{
}
-ScTable::VisibleDataCellIterator::~VisibleDataCellIterator()
-{
-}
-
ScRefCellValue ScTable::VisibleDataCellIterator::reset(SCROW nRow)
{
if (nRow > mrDocument.MaxRow())
@@ -2375,7 +2468,7 @@ void ScTable::SetAnonymousDBData(std::unique_ptr<ScDBData> pDBData)
pDBDataNoName = std::move(pDBData);
}
-sal_uLong ScTable::AddCondFormat( std::unique_ptr<ScConditionalFormat> pNew )
+sal_uInt32 ScTable::AddCondFormat( std::unique_ptr<ScConditionalFormat> pNew )
{
if(!mpCondFormatList)
mpCondFormatList.reset(new ScConditionalFormatList());
@@ -2446,7 +2539,7 @@ formula::FormulaTokenRef ScTable::ResolveStaticReference( SCCOL nCol1, SCROW nRo
return formula::FormulaTokenRef();
}
- return formula::FormulaTokenRef(new ScMatrixToken(pMat));
+ return formula::FormulaTokenRef(new ScMatrixToken(std::move(pMat)));
}
formula::VectorRefArray ScTable::FetchVectorRefArray( SCCOL nCol, SCROW nRow1, SCROW nRow2 )
@@ -2469,7 +2562,7 @@ void ScTable::AssertNoInterpretNeeded( SCCOL nCol, SCROW nRow1, SCROW nRow2 )
}
#endif
-bool ScTable::HandleRefArrayForParallelism( SCCOL nCol, SCROW nRow1, SCROW nRow2, const ScFormulaCellGroupRef& mxGroup )
+bool ScTable::HandleRefArrayForParallelism( SCCOL nCol, SCROW nRow1, SCROW nRow2, const ScFormulaCellGroupRef& mxGroup, ScAddress* pDirtiedAddress )
{
if (nRow2 < nRow1)
return false;
@@ -2482,7 +2575,7 @@ bool ScTable::HandleRefArrayForParallelism( SCCOL nCol, SCROW nRow1, SCROW nRow2
mpFilteredCols->makeReady();
mpFilteredRows->makeReady();
- return aCol[nCol].HandleRefArrayForParallelism(nRow1, nRow2, mxGroup);
+ return aCol[nCol].HandleRefArrayForParallelism(nRow1, nRow2, mxGroup, pDirtiedAddress);
}
ScRefCellValue ScTable::GetRefCellValue( SCCOL nCol, SCROW nRow )
@@ -2518,11 +2611,18 @@ void ScTable::DeleteBroadcasters(
aCol[nCol].DeleteBroadcasters(rBlockPos, nRow1, nRow2);
}
+void ScTable::DeleteEmptyBroadcasters()
+{
+ for( auto& col : aCol )
+ col->DeleteEmptyBroadcasters();
+}
+
void ScTable::FillMatrix( ScMatrix& rMat, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, svl::SharedStringPool* pPool ) const
{
size_t nMatCol = 0;
+ nCol2 = ClampToAllocatedColumns(nCol2);
for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol, ++nMatCol)
- CreateColumnIfNotExists(nCol).FillMatrix(rMat, nMatCol, nRow1, nRow2, pPool);
+ aCol[nCol].FillMatrix(rMat, nMatCol, nRow1, nRow2, pPool);
}
void ScTable::InterpretDirtyCells( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
@@ -2532,6 +2632,16 @@ void ScTable::InterpretDirtyCells( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW
aCol[nCol].InterpretDirtyCells(nRow1, nRow2);
}
+bool ScTable::InterpretCellsIfNeeded( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
+{
+ nCol2 = ClampToAllocatedColumns(nCol2);
+ bool allInterpreted = true;
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+ if(!aCol[nCol].InterpretCellsIfNeeded(nRow1, nRow2))
+ allInterpreted = false;
+ return allInterpreted;
+}
+
void ScTable::SetFormulaResults( SCCOL nCol, SCROW nRow, const double* pResults, size_t nLen )
{
if (!ValidCol(nCol))
@@ -2607,35 +2717,38 @@ const ScConditionalFormatList* ScTable::GetCondFormList() const
return mpCondFormatList.get();
}
-ScColumnsRange ScTable::GetColumnsRange(SCCOL nColBegin, SCCOL nColEnd) const
+ScColumnsRange ScTable::GetWritableColumnsRange(SCCOL nColBegin, SCCOL nColEnd)
+{
+ // because the range is inclusive, some code will pass nColEnd<nColBegin to indicate an empty range
+ if (nColEnd < nColBegin)
+ return ScColumnsRange(-1, -1);
+ assert( nColEnd >= 0 && nColEnd <= GetDoc().MaxCol());
+ CreateColumnIfNotExists(nColEnd);
+ return GetColumnsRange(nColBegin, nColEnd);
+}
+
+ScColumnsRange ScTable::GetAllocatedColumnsRange(SCCOL nColBegin, SCCOL nColEnd) const
{
- ScColContainer::ScColumnVector::const_iterator beginIter;
- ScColContainer::ScColumnVector::const_iterator endIter;
+ if (nColBegin >= aCol.size())
+ return ScColumnsRange(-1, -1);
+ // clamp end of range to available columns
+ if (nColEnd >= aCol.size())
+ nColEnd = aCol.size() - 1;
+ return GetColumnsRange(nColBegin, nColEnd);
+}
+ScColumnsRange ScTable::GetColumnsRange(SCCOL nColBegin, SCCOL nColEnd) const
+{
// because the range is inclusive, some code will pass nColEnd<nColBegin to indicate an empty range
if (nColEnd < nColBegin)
- {
- beginIter = aCol.end();
- endIter = aCol.end();
- }
- else if (nColBegin >= aCol.size())
- {
- beginIter = aCol.end();
- endIter = aCol.end();
- }
- else
- {
- // clamp end of range to available columns
- if (nColEnd >= aCol.size())
- nColEnd = aCol.size() - 1;
- beginIter = aCol.begin() + nColBegin;
- endIter = aCol.begin() + nColEnd + 1;
- }
- return ScColumnsRange(ScColumnsRange::Iterator(beginIter), ScColumnsRange::Iterator(endIter));
+ return ScColumnsRange(-1, -1);
+ assert( nColBegin >= 0 && nColBegin <= GetDoc().MaxCol());
+ assert( nColEnd >= 0 && nColEnd <= GetDoc().MaxCol());
+ return ScColumnsRange(nColBegin, nColEnd + 1); // change inclusive end to past-end
}
// out-of-line the cold part of the CreateColumnIfNotExists function
-void ScTable::CreateColumnIfNotExistsImpl( const SCCOL nScCol ) const
+void ScTable::CreateColumnIfNotExistsImpl( const SCCOL nScCol )
{
// When doing multi-threaded load of, e.g. XLS files, we can hit this, which calls
// into SfxItemPool::Put, in parallel with other code that calls into SfxItemPool::Put,
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index af36f60f0d9e..aa51bec2d727 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -50,7 +50,6 @@
#include <rowheightcontext.hxx>
#include <listenercontext.hxx>
#include <compressedarray.hxx>
-#include <brdcst.hxx>
#include <refdata.hxx>
#include <docsh.hxx>
@@ -60,7 +59,8 @@
#include <o3tl/safeint.hxx>
#include <o3tl/unit_conversion.hxx>
#include <osl/diagnose.h>
-#include <svl/poolcach.hxx>
+#include <sal/log.hxx>
+#include <poolcach.hxx>
#include <unotools/charclass.hxx>
#include <math.h>
@@ -134,15 +134,20 @@ void ScTable::SetCalcNotification( bool bSet )
bool ScTable::TestInsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize ) const
{
- bool bTest = true;
-
if ( nStartCol==0 && nEndCol==rDocument.MaxCol() && pOutlineTable )
- bTest = pOutlineTable->TestInsertRow(nSize);
+ if (!pOutlineTable->TestInsertRow(nSize))
+ return false;
+
+ SCCOL maxCol = ClampToAllocatedColumns(nEndCol);
+ for (SCCOL i=nStartCol; i<=maxCol; i++)
+ if (!aCol[i].TestInsertRow(nStartRow, nSize))
+ return false;
- for (SCCOL i=nStartCol; (i<=nEndCol) && bTest; i++)
- bTest = CreateColumnIfNotExists(i).TestInsertRow(nStartRow, nSize);
+ if( maxCol != nEndCol )
+ if (!aDefaultColData.TestInsertRow(nSize))
+ return false;
- return bTest;
+ return true;
}
void ScTable::InsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize )
@@ -181,8 +186,9 @@ void ScTable::InsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE
}
}
- for (SCCOL j=nStartCol; j<=nEndCol; j++)
+ for (SCCOL j : GetAllocatedColumnsRange(nStartCol, nEndCol))
aCol[j].InsertRow( nStartRow, nSize );
+ aDefaultColData.InsertRow( nStartRow, nSize );
mpCondFormatList->InsertRow(nTab, nStartCol, nEndCol, nStartRow, nSize);
@@ -235,7 +241,7 @@ void ScTable::DeleteRow(
{ // scope for bulk broadcast
ScBulkBroadcast aBulkBroadcast( rDocument.GetBASM(), SfxHintId::ScDataChanged);
- for (SCCOL j=nStartCol; j<=nEndCol; j++)
+ for (SCCOL j=nStartCol; j<=ClampToAllocatedColumns(nEndCol); j++)
aCol[j].DeleteRow(nStartRow, nSize, pGroupPos);
}
@@ -260,7 +266,7 @@ bool ScTable::TestInsertCol( SCROW nStartRow, SCROW nEndRow, SCSIZE nSize ) cons
&& ! pOutlineTable->TestInsertCol(nSize) )
return false;
- auto range = GetColumnsRange( rDocument.MaxCol() - static_cast<SCCOL>(nSize) + 1, rDocument.MaxCol() );
+ auto range = GetAllocatedColumnsRange( rDocument.MaxCol() - static_cast<SCCOL>(nSize) + 1, rDocument.MaxCol() );
for (auto it = range.rbegin(); it != range.rend(); ++it )
if (! aCol[*it].TestInsertCol(nStartRow, nEndRow))
return false;
@@ -303,11 +309,13 @@ void ScTable::InsertCol(
}
}
+ // Make sure there are enough columns at the end.
+ CreateColumnIfNotExists(std::min<SCCOL>(rDocument.MaxCol(), std::max(nStartCol, aCol.size()) + nSize - 1 ));
if ((nStartRow == 0) && (nEndRow == rDocument.MaxRow()))
{
- for (SCSIZE i=0; i < nSize; i++)
- for (SCCOL nCol = aCol.size() - 1; nCol > nStartCol; nCol--)
- aCol[nCol].SwapCol(aCol[nCol-1]);
+ // Move existing columns back, this will swap last empty columns in the inserted place.
+ for (SCCOL nCol = aCol.size() - 1 - nSize; nCol >= nStartCol; --nCol)
+ aCol[nCol].SwapCol(aCol[nCol+nSize]);
}
else
{
@@ -385,14 +393,16 @@ void ScTable::DeleteCol(
}
}
- for (SCSIZE i = 0; i < nSize; i++)
- aCol[nStartCol + i].DeleteArea(nStartRow, nEndRow, InsertDeleteFlags::ALL, false);
+ for (SCCOL col = nStartCol; col <= ClampToAllocatedColumns(nStartCol + nSize - 1); ++col)
+ aCol[col].DeleteArea(nStartRow, nEndRow, InsertDeleteFlags::ALL, false);
if ((nStartRow == 0) && (nEndRow == rDocument.MaxRow()))
{
- for (SCSIZE i=0; i < nSize; i++)
- for (SCCOL nCol = nStartCol; nCol < aCol.size() - 1; nCol++)
- aCol[nCol].SwapCol(aCol[nCol+1]);
+ for (SCCOL nCol = nStartCol + nSize; nCol < aCol.size(); ++nCol)
+ aCol[nCol].SwapCol(aCol[nCol - nSize]);
+ // When delete column(s), initialize the last columns from the default attributes
+ for (SCCOL nCol = aCol.size() < static_cast<SCCOL>(nSize) ? 0 : aCol.size() - nSize; nCol < aCol.size(); ++nCol)
+ aCol[nCol].Init(nCol, aCol[nCol].GetTab(), rDocument, false);
}
else
{
@@ -429,7 +439,7 @@ void ScTable::DeleteArea(
if ( IsProtected() && (nDelFlag & InsertDeleteFlags::ATTRIB) )
{
- ScPatternAttr aPattern(rDocument.GetPool());
+ ScPatternAttr aPattern(rDocument.getCellAttributeHelper());
aPattern.GetItemSet().Put( ScProtectionAttr( false ) );
ApplyPatternArea( nCol1, nRow1, nCol2, nRow2, aPattern );
}
@@ -466,11 +476,10 @@ void ScTable::DeleteSelection( InsertDeleteFlags nDelFlag, const ScMarkData& rMa
if ( IsProtected() && (nDelFlag & InsertDeleteFlags::ATTRIB) )
{
- ScDocumentPool* pPool = rDocument.GetPool();
- SfxItemSet aSet( *pPool, svl::Items<ATTR_PATTERN_START, ATTR_PATTERN_END>{} );
+ SfxItemSetFixed<ATTR_PATTERN_START, ATTR_PATTERN_END> aSet(*rDocument.GetPool());
aSet.Put( ScProtectionAttr( false ) );
- SfxItemPoolCache aCache( pPool, &aSet );
- ApplySelectionCache( &aCache, rMark );
+ ScItemPoolCache aCache(rDocument.getCellAttributeHelper(), aSet );
+ ApplySelectionCache( aCache, rMark );
}
// TODO: In the future we may want to check if the table has been
@@ -493,6 +502,7 @@ void ScTable::CopyToClip(
nCol2 = ClampToAllocatedColumns(nCol2);
+ pTable->CreateColumnIfNotExists(nCol2); // prevent repeated resizing
for ( SCCOL i = nCol1; i <= nCol2; i++)
aCol[i].CopyToClip(rCxt, nRow1, nRow2, pTable->CreateColumnIfNotExists(i)); // notes are handled at column level
@@ -522,7 +532,10 @@ void ScTable::CopyToClip(
for (SCCOL i = nCol1; i <= nCol2; i++)
pTable->aCol[i].RemoveProtected(nRow1, nRow2);
+ mpCondFormatList->startRendering();
+ mpCondFormatList->updateValues();
pTable->mpCondFormatList.reset(new ScConditionalFormatList(pTable->rDocument, *mpCondFormatList));
+ mpCondFormatList->endRendering();
}
void ScTable::CopyToClip(
@@ -561,8 +574,8 @@ void ScTable::CopyStaticToDocument(
rDestCol.maCells.set_empty(nRow1, nRow2);
for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
{
- sal_uInt32 nNumFmt = aDefaultColAttrArray.GetPattern(nRow)->GetNumberFormat(
- rDocument.GetNonThreadedContext().GetFormatTable());
+ sal_uInt32 nNumFmt = aDefaultColData.GetPattern(nRow)->GetNumberFormat(
+ rDocument.GetNonThreadedContext());
SvNumberFormatterMergeMap::const_iterator itNum = rMap.find(nNumFmt);
if (itNum != rMap.end())
nNumFmt = itNum->second;
@@ -625,6 +638,9 @@ void ScTable::CopyConditionalFormat( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCRO
{
ScRange aOldRange( nCol1 - nDx, nRow1 - nDy, pTable->nTab, nCol2 - nDx, nRow2 - nDy, pTable->nTab);
ScRange aNewRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab );
+ // Don't deduplicate when undoing or creating an Undo document! It would disallow correct undo
+ bool bUndoContext = rDocument.IsUndo() || pTable->rDocument.IsUndo();
+ // Note that Undo documents use same pool as the original document
bool bSameDoc = rDocument.GetStyleSheetPool() == pTable->rDocument.GetStyleSheetPool();
for(const auto& rxCondFormat : *pTable->mpCondFormatList)
@@ -645,17 +661,17 @@ void ScTable::CopyConditionalFormat( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCRO
aRefCxt.mnTabDelta = nTab - pTable->nTab;
pNewFormat->UpdateReference(aRefCxt, true);
- if (bSameDoc && pTable->nTab == nTab && CheckAndDeduplicateCondFormat(rDocument, mpCondFormatList->GetFormat(rxCondFormat->GetKey()), pNewFormat.get(), nTab))
+ if (!bUndoContext && bSameDoc && pTable->nTab == nTab && CheckAndDeduplicateCondFormat(rDocument, mpCondFormatList->GetFormat(rxCondFormat->GetKey()), pNewFormat.get(), nTab))
{
continue;
}
- sal_uLong nMax = 0;
+ sal_uInt32 nMax = 0;
bool bDuplicate = false;
for(const auto& rxCond : *mpCondFormatList)
{
// Check if there is the same format in the destination
// If there is, then simply expand its range
- if (CheckAndDeduplicateCondFormat(rDocument, rxCond.get(), pNewFormat.get(), nTab))
+ if (!bUndoContext && CheckAndDeduplicateCondFormat(rDocument, rxCond.get(), pNewFormat.get(), nTab))
{
bDuplicate = true;
break;
@@ -688,13 +704,8 @@ void ScTable::CopyConditionalFormat( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCRO
aStyleName = static_cast<const ScCondDateFormatEntry*>(pEntry)->GetStyleName();
if(!aStyleName.isEmpty())
- {
- if(rDocument.GetStyleSheetPool()->Find(aStyleName, SfxStyleFamily::Para))
- continue;
-
rDocument.GetStyleSheetPool()->CopyStyleFrom(
- pTable->rDocument.GetStyleSheetPool(), aStyleName, SfxStyleFamily::Para );
- }
+ pTable->rDocument.GetStyleSheetPool(), aStyleName, SfxStyleFamily::Para, true );
}
}
@@ -765,7 +776,7 @@ void ScTable::CopyFromClip(
// Do not set protected cell in a protected sheet
if (IsProtected() && (rCxt.getInsertFlag() & InsertDeleteFlags::ATTRIB))
{
- ScPatternAttr aPattern(rDocument.GetPool());
+ ScPatternAttr aPattern(rDocument.getCellAttributeHelper());
aPattern.GetItemSet().Put( ScProtectionAttr( false ) );
ApplyPatternArea( nCol1, nRow1, nCol2, nRow2, aPattern );
}
@@ -778,8 +789,8 @@ void ScTable::MixData(
sc::MixDocContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
ScPasteFunc nFunction, bool bSkipEmpty, const ScTable* pSrcTab )
{
- for (SCCOL i=nCol1; i<=nCol2; i++)
- aCol[i].MixData(rCxt, nRow1, nRow2, nFunction, bSkipEmpty, pSrcTab->aCol[i]);
+ for (SCCOL nCol : pSrcTab->GetAllocatedColumnsRange(nCol1, nCol2))
+ aCol[nCol].MixData(rCxt, nRow1, nRow2, nFunction, bSkipEmpty, pSrcTab->aCol[nCol]);
}
// Selection form this document
@@ -964,10 +975,10 @@ public:
{
mnFilteredRows++;
continue;
-}
+ }
if (mbAsLink && mnFlags == InsertDeleteFlags::ALL)
-{
+ {
// with InsertDeleteFlags::ALL, also create links (formulas) for empty cells
setLink(nRow);
continue;
@@ -983,7 +994,7 @@ void ScTable::TransposeClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
{
bool bWasCut = rDocument.IsCutMode();
- for (SCCOL nCol=nCol1; nCol<=nCol2; nCol++)
+ for (SCCOL nCol : GetWritableColumnsRange(nCol1, nCol2))
{
std::vector<SCROW> aFilteredRows;
@@ -1011,7 +1022,7 @@ void ScTable::TransposeClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
static void lcl_SetTransposedPatternInRows(ScTable* pTransClip, SCROW nAttrRow1, SCROW nAttrRow2,
SCCOL nCol1, SCROW nRow1, SCROW nCombinedStartRow, SCCOL nCol,
- const ScPatternAttr& rPatternAttr, bool bIncludeFiltered,
+ const CellAttributeHolder& rPatternHolder, bool bIncludeFiltered,
const std::vector<SCROW>& rFilteredRows,
SCROW nRowDestOffset)
{
@@ -1035,7 +1046,7 @@ static void lcl_SetTransposedPatternInRows(ScTable* pTransClip, SCROW nAttrRow1,
pTransClip->SetPattern(
static_cast<SCCOL>(nCol1 + nRow - nRow1 - nFilteredRowAdjustment + nRowDestOffset),
- static_cast<SCROW>(nCombinedStartRow + nCol - nCol1), rPatternAttr);
+ static_cast<SCROW>(nCombinedStartRow + nCol - nCol1), rPatternHolder);
}
}
@@ -1043,13 +1054,14 @@ void ScTable::TransposeColPatterns(ScTable* pTransClip, SCCOL nCol1, SCCOL nCol,
SCROW nRow2, SCROW nCombinedStartRow, bool bIncludeFiltered,
const std::vector<SCROW>& rFilteredRows, SCROW nRowDestOffset)
{
- SCROW nAttrRow1 = {}; // spurious -Werror=maybe-uninitialized
- SCROW nAttrRow2 = {}; // spurious -Werror=maybe-uninitialized
- const ScPatternAttr* pPattern;
- std::unique_ptr<ScAttrIterator> pAttrIter(aCol[nCol].CreateAttrIterator( nRow1, nRow2 ));
- while ( (pPattern = pAttrIter->Next( nAttrRow1, nAttrRow2 )) != nullptr )
- {
- if ( !IsDefaultItem( pPattern ) )
+ SCROW nAttrRow1 = {}; // spurious -Werror=maybe-uninitialized
+ SCROW nAttrRow2 = {}; // spurious -Werror=maybe-uninitialized
+ const ScPatternAttr* pPattern;
+ ScAttrIterator aAttrIter(aCol[nCol].CreateAttrIterator( nRow1, nRow2 ));
+ while ( (pPattern = aAttrIter.Next( nAttrRow1, nAttrRow2 )) != nullptr )
+ {
+ // ptr compare OK, was so before
+ if (&rDocument.getCellAttributeHelper().getDefaultCellAttribute() != pPattern)
{
const SfxItemSet& rSet = pPattern->GetItemSet();
if ( rSet.GetItemState( ATTR_MERGE, false ) == SfxItemState::DEFAULT &&
@@ -1058,8 +1070,9 @@ void ScTable::TransposeColPatterns(ScTable* pTransClip, SCCOL nCol1, SCCOL nCol,
{
// Set pattern in cells from nAttrRow1 to nAttrRow2
// no borders or merge items involved - use pattern as-is
+ const CellAttributeHolder aPatternHolder(pPattern);
lcl_SetTransposedPatternInRows(pTransClip, nAttrRow1, nAttrRow2, nCol1, nRow1,
- nCombinedStartRow, nCol, *pPattern,
+ nCombinedStartRow, nCol, aPatternHolder,
bIncludeFiltered, rFilteredRows, nRowDestOffset);
}
else
@@ -1102,8 +1115,9 @@ void ScTable::TransposeColPatterns(ScTable* pTransClip, SCCOL nCol1, SCCOL nCol,
}
// Set pattern in cells from nAttrRow1 to nAttrRow2
+ const CellAttributeHolder aPatternHolder(&aNewPattern);
lcl_SetTransposedPatternInRows(pTransClip, nAttrRow1, nAttrRow2, nCol1, nRow1,
- nCombinedStartRow, nCol, aNewPattern,
+ nCombinedStartRow, nCol, aPatternHolder,
bIncludeFiltered, rFilteredRows, nRowDestOffset);
}
}
@@ -1274,7 +1288,7 @@ void ScTable::DetachFormulaCells(
{
nCol2 = ClampToAllocatedColumns(nCol2);
for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
- aCol[nCol].DetachFormulaCells(rCxt, nRow1, nRow2, nullptr);
+ aCol[nCol].DetachFormulaCells(rCxt, nRow1, nRow2);
}
void ScTable::SetDirtyFromClip(
@@ -1308,13 +1322,28 @@ void ScTable::CopyToTable(
if (!ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2))
return;
- bool bIsUndoDoc = pDestTab->rDocument.IsUndo();
+ const bool bToUndoDoc = pDestTab->rDocument.IsUndo();
+ const bool bFromUndoDoc = rDocument.IsUndo();
+
+ if (bToUndoDoc && (nFlags & InsertDeleteFlags::ATTRIB) && nCol2 >= aCol.size())
+ {
+ // tdf#154044: Copy also the default column data
+ aDefaultColData.AttrArray().CopyArea(nRow1, nRow2, 0,
+ pDestTab->aDefaultColData.AttrArray());
+ }
- if (bIsUndoDoc && (nFlags & InsertDeleteFlags::CONTENTS))
+ if ((bToUndoDoc || bFromUndoDoc) && (nFlags & InsertDeleteFlags::CONTENTS) && mpRangeName)
{
// Copying formulas may create sheet-local named expressions on the
// destination sheet. Add existing to Undo first.
+ // During Undo restore the previous named expressions.
pDestTab->SetRangeName( std::unique_ptr<ScRangeName>( new ScRangeName( *GetRangeName())));
+ if (!pDestTab->rDocument.IsClipOrUndo())
+ {
+ ScDocShell* pDocSh = pDestTab->rDocument.GetDocumentShell();
+ if (pDocSh)
+ pDocSh->SetAreasChangedNeedBroadcast();
+ }
}
if (nFlags != InsertDeleteFlags::NONE)
@@ -1325,15 +1354,26 @@ void ScTable::CopyToTable(
// can lead to repetitive splitting and rejoining of the same formula group, which can get
// quadratically expensive with large groups. So do the grouping just once at the end.
sc::DelayFormulaGroupingSwitch delayGrouping( pDestTab->rDocument, true );
+ pDestTab->CreateColumnIfNotExists(ClampToAllocatedColumns(nCol2)); // avoid repeated resizing
for (SCCOL i = nCol1; i <= ClampToAllocatedColumns(nCol2); i++)
- aCol[i].CopyToColumn(rCxt, nRow1, nRow2, bIsUndoDoc ? nFlags : nTempFlags, bMarked,
+ aCol[i].CopyToColumn(rCxt, nRow1, nRow2, bToUndoDoc ? nFlags : nTempFlags, bMarked,
pDestTab->CreateColumnIfNotExists(i), pMarkData, bAsLink, bGlobalNamesToLocal);
+ // tdf#154044: Restore from the default column data
+ if (bFromUndoDoc && (nFlags & InsertDeleteFlags::ATTRIB) && nCol2 >= aCol.size())
+ {
+ aDefaultColData.AttrArray().CopyArea(nRow1, nRow2, 0,
+ pDestTab->aDefaultColData.AttrArray());
+ SCCOL nMaxSetDefault = pDestTab->ClampToAllocatedColumns(nCol2);
+ for (SCCOL i = aCol.size(); i <= nMaxSetDefault; i++)
+ aDefaultColData.AttrArray().CopyArea(nRow1, nRow2, 0,
+ pDestTab->aCol[i].AttrArray());
+ }
}
if (!bColRowFlags) // Column widths/Row heights/Flags
return;
- if(bIsUndoDoc && (nFlags & InsertDeleteFlags::ATTRIB))
+ if (bToUndoDoc && (nFlags & InsertDeleteFlags::ATTRIB))
{
pDestTab->mpCondFormatList.reset(new ScConditionalFormatList(pDestTab->rDocument, *mpCondFormatList));
}
@@ -1380,7 +1420,7 @@ void ScTable::CopyToTable(
++destTabColWidthIt;
++thisTabColWidthIt;
}
- pDestTab->SetColManualBreaks( maColManualBreaks);
+ pDestTab->SetColManualBreaks( std::set(maColManualBreaks) );
}
if (bHeight)
@@ -1425,7 +1465,7 @@ void ScTable::CopyToTable(
pDestTab->SetRowFiltered(i, nLastRow, bFiltered);
i = nLastRow;
}
- pDestTab->SetRowManualBreaks( maRowManualBreaks);
+ pDestTab->SetRowManualBreaks( std::set(maRowManualBreaks) );
}
}
@@ -1441,13 +1481,30 @@ void ScTable::CopyToTable(
if(nFlags & InsertDeleteFlags::OUTLINE) // also only when bColRowFlags
pDestTab->SetOutlineTable( pOutlineTable.get() );
- if (!bIsUndoDoc && bCopyCaptions && (nFlags & (InsertDeleteFlags::NOTE | InsertDeleteFlags::ADDNOTES)))
+ if (nFlags & InsertDeleteFlags::SPARKLINES)
+ {
+ CopySparklinesToTable(nCol1, nRow1, nCol2, nRow2, pDestTab);
+ }
+
+ if (!bToUndoDoc && bCopyCaptions && (nFlags & (InsertDeleteFlags::NOTE | InsertDeleteFlags::ADDNOTES)))
{
bool bCloneCaption = (nFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE;
CopyCaptionsToTable( nCol1, nRow1, nCol2, nRow2, pDestTab, bCloneCaption);
}
}
+void ScTable::CopySparklinesToTable(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScTable* pDestTab)
+{
+ if (!ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2))
+ return;
+
+ nCol2 = ClampToAllocatedColumns(nCol2);
+ for (SCCOL i = nCol1; i <= nCol2; i++)
+ {
+ aCol[i].CopyCellSparklinesToDocument(nRow1, nRow2, pDestTab->CreateColumnIfNotExists(i));
+ }
+}
+
void ScTable::CopyCaptionsToTable( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScTable* pDestTab,
bool bCloneCaption )
{
@@ -1458,7 +1515,7 @@ void ScTable::CopyCaptionsToTable( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW
for (SCCOL i = nCol1; i <= nCol2; i++)
{
aCol[i].CopyCellNotesToDocument(nRow1, nRow2, pDestTab->CreateColumnIfNotExists(i), bCloneCaption);
- pDestTab->aCol[i].UpdateNoteCaptions(nRow1, nRow2);
+ pDestTab->aCol[i].UpdateNoteCaptions(nRow1, nRow2, false /* address unchanged from initial create */);
}
}
@@ -1480,7 +1537,7 @@ void ScTable::UndoToTable(
pDestTab->SetRangeName( std::unique_ptr<ScRangeName>( new ScRangeName( *GetRangeName())));
if (!pDestTab->rDocument.IsClipOrUndo())
{
- ScDocShell* pDocSh = static_cast<ScDocShell*>(pDestTab->rDocument.GetDocumentShell());
+ ScDocShell* pDocSh = pDestTab->rDocument.GetDocumentShell();
if (pDocSh)
pDocSh->SetAreasChangedNeedBroadcast();
}
@@ -1505,26 +1562,26 @@ void ScTable::UndoToTable(
if (bWidth)
{
pDestTab->mpColWidth->CopyFrom(*mpColWidth, nCol1, nCol2);
- pDestTab->SetColManualBreaks( maColManualBreaks);
+ pDestTab->SetColManualBreaks( std::set(maColManualBreaks) );
}
if (bHeight)
{
pDestTab->CopyRowHeight(*this, nRow1, nRow2, 0);
- pDestTab->SetRowManualBreaks( maRowManualBreaks);
+ pDestTab->SetRowManualBreaks( std::set(maRowManualBreaks) );
}
}
void ScTable::CopyUpdated( const ScTable* pPosTab, ScTable* pDestTab ) const
{
- pPosTab->CreateColumnIfNotExists(aCol.size()-1);
pDestTab->CreateColumnIfNotExists(aCol.size()-1);
for (SCCOL i=0; i < aCol.size(); i++)
- aCol[i].CopyUpdated( pPosTab->aCol[i], pDestTab->aCol[i] );
+ aCol[i].CopyUpdated( pPosTab->FetchColumn(i), pDestTab->aCol[i] );
}
void ScTable::InvalidateTableArea()
{
bTableAreaValid = false;
+ bTableAreaVisibleValid = false;
}
void ScTable::InvalidatePageBreaks()
@@ -1532,7 +1589,7 @@ void ScTable::InvalidatePageBreaks()
mbPageBreaksValid = false;
}
-void ScTable::CopyScenarioTo( const ScTable* pDestTab ) const
+void ScTable::CopyScenarioTo( ScTable* pDestTab ) const
{
OSL_ENSURE( bScenario, "bScenario == FALSE" );
@@ -1739,12 +1796,12 @@ void ScTable::SetRawString( SCCOL nCol, SCROW nRow, const svl::SharedString& rSt
CreateColumnIfNotExists(nCol).SetRawString(nRow, rStr);
}
-void ScTable::GetString( SCCOL nCol, SCROW nRow, OUString& rString, const ScInterpreterContext* pContext ) const
+OUString ScTable::GetString( SCCOL nCol, SCROW nRow, ScInterpreterContext* pContext ) const
{
if (ValidColRow(nCol,nRow) && nCol < GetAllocatedColumnsCount())
- aCol[nCol].GetString( nRow, rString, pContext );
+ return aCol[nCol].GetString( nRow, pContext );
else
- rString.clear();
+ return OUString();
}
double* ScTable::GetValueCell( SCCOL nCol, SCROW nRow )
@@ -1755,12 +1812,12 @@ double* ScTable::GetValueCell( SCCOL nCol, SCROW nRow )
return CreateColumnIfNotExists(nCol).GetValueCell(nRow);
}
-void ScTable::GetInputString( SCCOL nCol, SCROW nRow, OUString& rString ) const
+OUString ScTable::GetInputString( SCCOL nCol, SCROW nRow, bool bForceSystemLocale ) const
{
if (ValidColRow(nCol, nRow) && nCol < GetAllocatedColumnsCount())
- aCol[nCol].GetInputString( nRow, rString );
+ return aCol[nCol].GetInputString( nRow, bForceSystemLocale );
else
- rString.clear();
+ return OUString();
}
double ScTable::GetValue( SCCOL nCol, SCROW nRow ) const
@@ -1786,12 +1843,12 @@ void ScTable::RemoveEditTextCharAttribs( SCCOL nCol, SCROW nRow, const ScPattern
return aCol[nCol].RemoveEditTextCharAttribs(nRow, rAttr);
}
-void ScTable::GetFormula( SCCOL nCol, SCROW nRow, OUString& rFormula ) const
+OUString ScTable::GetFormula( SCCOL nCol, SCROW nRow ) const
{
if (ValidColRow(nCol, nRow) && nCol < GetAllocatedColumnsCount())
- aCol[nCol].GetFormula( nRow, rFormula );
+ return aCol[nCol].GetFormula( nRow );
else
- rFormula.clear();
+ return OUString();
}
const ScFormulaCell* ScTable::GetFormulaCell( SCCOL nCol, SCROW nRow ) const
@@ -1804,11 +1861,56 @@ const ScFormulaCell* ScTable::GetFormulaCell( SCCOL nCol, SCROW nRow ) const
ScFormulaCell* ScTable::GetFormulaCell( SCCOL nCol, SCROW nRow )
{
- if (!ValidColRow(nCol, nRow))
+ if (!ValidColRow(nCol, nRow) || nCol >= GetAllocatedColumnsCount())
+ return nullptr;
+
+ return aCol[nCol].GetFormulaCell(nRow);
+}
+
+// Sparklines
+
+std::shared_ptr<sc::Sparkline> ScTable::GetSparkline(SCCOL nCol, SCROW nRow)
+{
+ if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
+ return std::shared_ptr<sc::Sparkline>();
+
+ sc::SparklineCell* pSparklineCell = aCol[nCol].GetSparklineCell(nRow);
+ if (!pSparklineCell)
+ return std::shared_ptr<sc::Sparkline>();
+
+ return pSparklineCell->getSparkline();
+}
+
+sc::Sparkline* ScTable::CreateSparkline(SCCOL nCol, SCROW nRow, std::shared_ptr<sc::SparklineGroup> const& pSparklineGroup)
+{
+ if (!ValidCol(nCol))
return nullptr;
- return CreateColumnIfNotExists(nCol).GetFormulaCell(nRow);
+
+ ScColumn& rColumn = CreateColumnIfNotExists(nCol);
+
+ std::shared_ptr<sc::Sparkline> pSparkline(new sc::Sparkline(nCol, nRow, pSparklineGroup));
+ rColumn.CreateSparklineCell(nRow, pSparkline);
+
+ return pSparkline.get();
+}
+
+bool ScTable::DeleteSparkline(SCCOL nCol, SCROW nRow)
+{
+ if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
+ return false;
+
+ aCol[nCol].DeleteSparkline(nRow);
+
+ return true;
+}
+
+sc::SparklineList& ScTable::GetSparklineList()
+{
+ return maSparklineList;
}
+// Notes
+
std::unique_ptr<ScPostIt> ScTable::ReleaseNote( SCCOL nCol, SCROW nRow )
{
if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
@@ -1817,6 +1919,21 @@ std::unique_ptr<ScPostIt> ScTable::ReleaseNote( SCCOL nCol, SCROW nRow )
return aCol[nCol].ReleaseNote(nRow);
}
+ScPostIt* ScTable::GetNote( SCCOL nCol, SCROW nRow )
+{
+ if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
+ return nullptr;
+ return aCol[nCol].GetCellNote(nRow);
+}
+
+void ScTable::SetNote( SCCOL nCol, SCROW nRow, std::unique_ptr<ScPostIt> pNote )
+{
+ if (!ValidColRow(nCol, nRow))
+ return;
+
+ CreateColumnIfNotExists(nCol).SetCellNote(nRow, std::move(pNote));
+}
+
size_t ScTable::GetNoteCount( SCCOL nCol ) const
{
if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
@@ -1848,6 +1965,21 @@ void ScTable::ForgetNoteCaptions( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW n
aCol[i].ForgetNoteCaptions(nRow1, nRow2, bPreserveData);
}
+void ScTable::CommentNotifyAddressChange( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
+{
+ // Only in use in kit mode for now, but looks to me a good idea to revisit why (since OOo times)
+ // on deleting/inserting a column that we generate all the captions, while on deleting/inserting
+ // a row we do not. Presumably we should skip generating captions if we don't have to.
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ if (!ValidCol(nCol1) || !ValidCol(nCol2))
+ return;
+ if ( nCol2 >= aCol.size() ) nCol2 = aCol.size() - 1;
+ for (SCCOL i = nCol1; i <= nCol2; ++i)
+ aCol[i].CommentNotifyAddressChange(nRow1, nRow2);
+}
+
void ScTable::GetAllNoteEntries( std::vector<sc::NoteEntry>& rNotes ) const
{
for (SCCOL nCol = 0; nCol < aCol.size(); ++nCol)
@@ -1934,6 +2066,14 @@ ScRefCellValue ScTable::GetCellValue( SCCOL nCol, SCROW nRow ) const
return aCol[nCol].GetCellValue(nRow);
}
+ScRefCellValue ScTable::GetCellValue( SCCOL nCol, sc::ColumnBlockPosition& rBlockPos, SCROW nRow )
+{
+ if (!ValidColRow(nCol, nRow) || nCol >= GetAllocatedColumnsCount())
+ return ScRefCellValue();
+
+ return aCol[nCol].GetCellValue(rBlockPos, nRow);
+}
+
void ScTable::GetFirstDataPos(SCCOL& rCol, SCROW& rRow) const
{
rCol = 0;
@@ -2022,41 +2162,34 @@ void ScTable::SetAllFormulasDirty( const sc::SetFormulaDirtyContext& rCxt )
void ScTable::SetDirty( const ScRange& rRange, ScColumn::BroadcastMode eMode )
{
- bool bOldAutoCalc = rDocument.GetAutoCalc();
- rDocument.SetAutoCalc( false ); // avoid multiple recalculations
+ sc::AutoCalcSwitch aSwitch(rDocument, false);
SCCOL nCol2 = rRange.aEnd.Col();
nCol2 = ClampToAllocatedColumns(nCol2);
for (SCCOL i=rRange.aStart.Col(); i<=nCol2; i++)
aCol[i].SetDirty(rRange.aStart.Row(), rRange.aEnd.Row(), eMode);
- rDocument.SetAutoCalc( bOldAutoCalc );
}
void ScTable::SetTableOpDirty( const ScRange& rRange )
{
- bool bOldAutoCalc = rDocument.GetAutoCalc();
- rDocument.SetAutoCalc( false ); // no multiple recalculation
+ sc::AutoCalcSwitch aSwitch(rDocument, false);
const SCCOL nCol2 = ClampToAllocatedColumns(rRange.aEnd.Col());
for (SCCOL i=rRange.aStart.Col(); i<=nCol2; i++)
aCol[i].SetTableOpDirty( rRange );
- rDocument.SetAutoCalc( bOldAutoCalc );
}
void ScTable::SetDirtyAfterLoad()
{
- bool bOldAutoCalc = rDocument.GetAutoCalc();
- rDocument.SetAutoCalc( false ); // avoid multiple recalculations
+ sc::AutoCalcSwitch aSwitch(rDocument, false);
for (SCCOL i=0; i < aCol.size(); i++)
aCol[i].SetDirtyAfterLoad();
- rDocument.SetAutoCalc( bOldAutoCalc );
}
void ScTable::SetDirtyIfPostponed()
{
- bool bOldAutoCalc = rDocument.GetAutoCalc();
- rDocument.SetAutoCalc( false ); // avoid multiple recalculations
+ sc::AutoCalcSwitch aSwitch(rDocument, false);
+ ScBulkBroadcast aBulkBroadcast( rDocument.GetBASM(), SfxHintId::ScDataChanged);
for (SCCOL i=0; i < aCol.size(); i++)
aCol[i].SetDirtyIfPostponed();
- rDocument.SetAutoCalc( bOldAutoCalc );
}
void ScTable::BroadcastRecalcOnRefMove()
@@ -2066,14 +2199,13 @@ void ScTable::BroadcastRecalcOnRefMove()
aCol[i].BroadcastRecalcOnRefMove();
}
-bool ScTable::BroadcastBroadcasters( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScHint& rHint )
+bool ScTable::BroadcastBroadcasters( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SfxHintId nHint )
{
bool bBroadcasted = false;
sc::AutoCalcSwitch aSwitch(rDocument, false);
- rHint.GetAddress().SetTab(nTab);
nCol2 = ClampToAllocatedColumns(nCol2);
for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
- bBroadcasted |= aCol[nCol].BroadcastBroadcasters( nRow1, nRow2, rHint);
+ bBroadcasted |= aCol[nCol].BroadcastBroadcasters( nRow1, nRow2, nHint);
return bBroadcasted;
}
@@ -2146,30 +2278,28 @@ void ScTable::ResetChanged( const ScRange& rRange )
const SfxPoolItem* ScTable::GetAttr( SCCOL nCol, SCROW nRow, sal_uInt16 nWhich ) const
{
- if (ValidColRow(nCol, nRow) && nCol < GetAllocatedColumnsCount())
- return &aCol[nCol].GetAttr( nRow, nWhich );
- else
+ if (!ValidColRow(nCol, nRow))
+ return nullptr;
+ return &GetColumnData(nCol).GetAttr( nRow, nWhich );
+}
+
+const SfxPoolItem* ScTable::GetAttr( SCCOL nCol, SCROW nRow, sal_uInt16 nWhich, SCROW& nStartRow, SCROW& nEndRow ) const
+{
+ if (!ValidColRow(nCol, nRow))
return nullptr;
+ return &GetColumnData(nCol).GetAttr( nRow, nWhich, nStartRow, nEndRow );
}
sal_uInt32 ScTable::GetNumberFormat( const ScInterpreterContext& rContext, const ScAddress& rPos ) const
{
if (ValidColRow(rPos.Col(), rPos.Row()))
- {
- if (rPos.Col() < GetAllocatedColumnsCount())
- return aCol[rPos.Col()].GetNumberFormat(rContext, rPos.Row());
- return aDefaultColAttrArray.GetPattern(rPos.Row())
- ->GetNumberFormat(rContext.GetFormatTable());
- }
+ return GetColumnData(rPos.Col()).GetNumberFormat(rContext, rPos.Row());
return 0;
}
sal_uInt32 ScTable::GetNumberFormat( SCCOL nCol, SCROW nRow ) const
{
- if (ValidColRow(nCol,nRow))
- return CreateColumnIfNotExists(nCol).GetNumberFormat(rDocument.GetNonThreadedContext(), nRow);
- else
- return 0;
+ return GetNumberFormat(rDocument.GetNonThreadedContext(), ScAddress(nCol, nRow, nTab));
}
sal_uInt32 ScTable::GetNumberFormat( SCCOL nCol, SCROW nStartRow, SCROW nEndRow ) const
@@ -2177,7 +2307,7 @@ sal_uInt32 ScTable::GetNumberFormat( SCCOL nCol, SCROW nStartRow, SCROW nEndRow
if (!ValidCol(nCol) || !ValidRow(nStartRow) || !ValidRow(nEndRow))
return 0;
- return CreateColumnIfNotExists(nCol).GetNumberFormat(nStartRow, nEndRow);
+ return GetColumnData(nCol).GetNumberFormat(nStartRow, nEndRow);
}
void ScTable::SetNumberFormat( SCCOL nCol, SCROW nRow, sal_uInt32 nNumberFormat )
@@ -2190,35 +2320,31 @@ void ScTable::SetNumberFormat( SCCOL nCol, SCROW nRow, sal_uInt32 nNumberFormat
const ScPatternAttr* ScTable::GetPattern( SCCOL nCol, SCROW nRow ) const
{
- if (ValidColRow(nCol,nRow))
- return CreateColumnIfNotExists(nCol).GetPattern( nRow );
- else
- {
- OSL_FAIL("wrong column or row");
- return rDocument.GetDefPattern(); // for safety
- }
+ if (!ValidColRow(nCol,nRow))
+ return nullptr;
+ return GetColumnData(nCol).GetPattern( nRow );
}
const ScPatternAttr* ScTable::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow ) const
{
- if ( ValidColRow( nCol, nStartRow ) && ValidRow( nEndRow ) && (nStartRow <= nEndRow)
- && nCol < GetAllocatedColumnsCount())
- return aCol[nCol].GetMostUsedPattern( nStartRow, nEndRow );
- else
- return nullptr;
+ if ( ValidColRow( nCol, nStartRow ) && ValidRow( nEndRow ) && (nStartRow <= nEndRow))
+ return GetColumnData(nCol).GetMostUsedPattern( nStartRow, nEndRow );
+ return nullptr;
}
bool ScTable::HasAttrib( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, HasAttrFlags nMask ) const
{
- if ( nCol1 >= aCol.size() )
- return false;
- if ( nCol2 >= aCol.size() )
- nCol2 = aCol.size() - 1; // Rows above range, doesn't contains flags
+ for(SCCOL nCol = nCol1; nCol <= nCol2 && nCol < aCol.size(); ++nCol )
+ if( aCol[nCol].HasAttrib( nRow1, nRow2, nMask ))
+ return true;
+ if( nCol2 >= aCol.size())
+ return aDefaultColData.HasAttrib( nRow1, nRow2, nMask );
+ return false;
+}
- bool bFound = false;
- for (SCCOL i=nCol1; i<=nCol2 && !bFound; i++)
- bFound |= aCol[i].HasAttrib( nRow1, nRow2, nMask );
- return bFound;
+bool ScTable::HasAttrib( SCCOL nCol, SCROW nRow, HasAttrFlags nMask, SCROW* nStartRow, SCROW* nEndRow ) const
+{
+ return GetColumnData(nCol).HasAttrib( nRow, nMask, nStartRow, nEndRow );
}
bool ScTable::HasAttribSelection( const ScMarkData& rMark, HasAttrFlags nMask ) const
@@ -2245,13 +2371,10 @@ bool ScTable::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
OSL_FAIL("ScTable::ExtendMerge: invalid column number");
return false;
}
- if ( nStartCol >= aCol.size() )
- {
- OSL_FAIL("ScTable::ExtendMerge: invalid nStartCol");
- return false;
- }
+ if( rEndCol >= aCol.size())
+ assert( !aDefaultColData.GetAttr( nStartRow, ATTR_MERGE ).IsMerged());
bool bFound = false;
- SCCOL nOldEndX = std::min( rEndCol, static_cast<SCCOL>(aCol.size()-1) );
+ SCCOL nOldEndX = ClampToAllocatedColumns(rEndCol);
SCROW nOldEndY = rEndRow;
for (SCCOL i=nStartCol; i<=nOldEndX; i++)
bFound |= aCol[i].ExtendMerge( i, nStartRow, nOldEndY, rEndCol, rEndRow, bRefresh );
@@ -2273,7 +2396,7 @@ void ScTable::SetMergedCells( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2
ApplyFlags(nCol1+1, nRow1+1, nCol2, nRow2, ScMF::Hor | ScMF::Ver);
}
-bool ScTable::IsBlockEmpty( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, bool bIgnoreNotes ) const
+bool ScTable::IsBlockEmpty( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) const
{
if (!(ValidCol(nCol1) && ValidCol(nCol2)))
{
@@ -2284,8 +2407,12 @@ bool ScTable::IsBlockEmpty( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
bool bEmpty = true;
for (SCCOL i=nCol1; i<=nCol2 && bEmpty; i++)
{
- bEmpty = aCol[i].IsEmptyBlock( nRow1, nRow2 );
- if (!bIgnoreNotes && bEmpty)
+ bEmpty = aCol[i].IsEmptyData( nRow1, nRow2 );
+ if (bEmpty)
+ {
+ bEmpty = aCol[i].IsSparklinesEmptyBlock(nRow1, nRow2);
+ }
+ if (bEmpty)
{
bEmpty = aCol[i].IsNotesEmptyBlock(nRow1, nRow2);
}
@@ -2315,7 +2442,7 @@ SCSIZE ScTable::FillMaxRot( RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nX1, SCCO
{
Degree100 nRotVal = pPattern->
GetItem( ATTR_ROTATE_VALUE, pCondSet ).GetValue();
- double nRealOrient = nRotVal.get() * F_PI18000; // 1/100 degree
+ double nRealOrient = toRadians(nRotVal);
double nCos = cos( nRealOrient );
double nSin = sin( nRealOrient );
//TODO: limit !!!
@@ -2386,14 +2513,12 @@ void ScTable::FindMaxRotCol( RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nX1, SCC
const ScPatternAttr* pPattern = aIter.GetNext( nAttrCol, nAttrRow1, nAttrRow2 );
while ( pPattern )
{
- const SfxPoolItem* pCondItem;
- if ( pPattern->GetItemSet().GetItemState( ATTR_CONDITIONAL, true, &pCondItem )
- == SfxItemState::SET )
+ if ( const ScCondFormatItem* pCondItem = pPattern->GetItemSet().GetItemIfSet( ATTR_CONDITIONAL ) )
{
// Run through all formats, so that each cell does not have to be
// handled individually
- const ScCondFormatIndexes& rCondFormatData = static_cast<const ScCondFormatItem*>(pCondItem)->GetCondFormatData();
+ const ScCondFormatIndexes& rCondFormatData = pCondItem->GetCondFormatData();
ScStyleSheetPool* pStylePool = rDocument.GetStyleSheetPool();
if (mpCondFormatList && pStylePool && !rCondFormatData.empty())
{
@@ -2538,13 +2663,14 @@ bool ScTable::HasBlockMatrixFragment( const SCCOL nCol1, SCROW nRow1, const SCCO
bool ScTable::HasSelectionMatrixFragment( const ScMarkData& rMark ) const
{
std::vector<sc::ColRowSpan> aSpans = rMark.GetMarkedColSpans();
+ ScRangeList rangeList = rMark.GetMarkedRanges();
for (const sc::ColRowSpan & aSpan : aSpans)
{
SCCOL nEndCol = ClampToAllocatedColumns(aSpan.mnEnd);
for ( SCCOLROW j=aSpan.mnStart; j<=nEndCol; j++ )
{
- if ( aCol[j].HasSelectionMatrixFragment(rMark) )
+ if ( aCol[j].HasSelectionMatrixFragment(rMark, rangeList) )
return true;
}
}
@@ -2562,8 +2688,6 @@ bool ScTable::IsBlockEditable( SCCOL nCol1, SCROW nRow1, SCCOL nCol2,
*pOnlyNotBecauseOfMatrix = false;
return false;
}
- nCol1 = ClampToAllocatedColumns(nCol1);
- nCol2 = ClampToAllocatedColumns(nCol2);
bool bIsEditable = true;
if ( nLockCount )
@@ -2740,9 +2864,10 @@ void ScTable::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkDa
for (const sc::ColRowSpan & rSpan : aSpans)
{
- for (SCCOLROW i = rSpan.mnStart; i <= rSpan.mnEnd; ++i)
+ SCCOL maxCol = ClampToAllocatedColumns(rSpan.mnEnd);
+ for (SCCOL i = rSpan.mnStart; i <= maxCol; ++i)
{
- CreateColumnIfNotExists(i).MergeSelectionPattern( rState, rMark, bDeep );
+ aCol[i].MergeSelectionPattern( rState, rMark, bDeep );
}
}
}
@@ -2750,9 +2875,11 @@ void ScTable::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkDa
void ScTable::MergePatternArea( ScMergePatternState& rState, SCCOL nCol1, SCROW nRow1,
SCCOL nCol2, SCROW nRow2, bool bDeep ) const
{
- nCol2 = ClampToAllocatedColumns(nCol2);
- for (SCCOL i=nCol1; i<=nCol2; i++)
+ const SCCOL nEndCol = ClampToAllocatedColumns(nCol2);
+ for (SCCOL i=nCol1; i<=nEndCol; i++)
aCol[i].MergePatternArea( rState, nRow1, nRow2, bDeep );
+ if (nEndCol != nCol2)
+ aDefaultColData.MergePatternArea( rState, nRow1, nRow2, bDeep );
}
void ScTable::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner, ScLineFlags& rFlags,
@@ -2776,7 +2903,7 @@ void ScTable::ApplyBlockFrame(const SvxBoxItem& rLineOuter, const SvxBoxInfoItem
{
PutInOrder(nStartCol, nEndCol);
PutInOrder(nStartRow, nEndRow);
- nEndCol = ClampToAllocatedColumns(nEndCol);
+ CreateColumnIfNotExists(nEndCol);
for (SCCOL i=nStartCol; i<=nEndCol; i++)
aCol[i].ApplyBlockFrame(rLineOuter, pLineInner,
nStartRow, nEndRow, (i==nStartCol), nEndCol-i);
@@ -2793,15 +2920,65 @@ void ScTable::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol,
const ScPatternAttr& rAttr, ScEditDataArray* pDataArray,
bool* const pIsChanged )
{
- if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
+ if (!ValidColRow(nStartCol, nStartRow) || !ValidColRow(nEndCol, nEndRow))
+ return;
+ PutInOrder(nStartCol, nEndCol);
+ PutInOrder(nStartRow, nEndRow);
+ SCCOL maxCol = nEndCol;
+ if( nEndCol == GetDoc().MaxCol())
{
- PutInOrder(nStartCol, nEndCol);
- PutInOrder(nStartRow, nEndRow);
- for (SCCOL i = nStartCol; i <= nEndCol; i++)
- CreateColumnIfNotExists(i).ApplyPatternArea(nStartRow, nEndRow, rAttr, pDataArray, pIsChanged);
+ // For the same unallocated columns until the end we can change just the default.
+ maxCol = std::max( nStartCol, aCol.size()) - 1;
+ if( maxCol >= 0 )
+ CreateColumnIfNotExists(maxCol); // Allocate needed different columns before changing the default.
+ aDefaultColData.ApplyPatternArea(nStartRow, nEndRow, rAttr, pDataArray, pIsChanged);
+ }
+ for (SCCOL i = nStartCol; i <= maxCol; i++)
+ CreateColumnIfNotExists(i).ApplyPatternArea(nStartRow, nEndRow, rAttr, pDataArray, pIsChanged);
+}
+
+namespace
+{
+ std::vector<ScAttrEntry> duplicateScAttrEntries(const std::vector<ScAttrEntry>& rOrigData)
+ {
+ // this can now just be copied, will do the right thing with the
+ // ref-counted ScAttrEntry instances
+ std::vector<ScAttrEntry> aData(rOrigData);
+ return aData;
+ }
+}
+
+void ScTable::SetAttrEntries( SCCOL nStartCol, SCCOL nEndCol, std::vector<ScAttrEntry> && vNewData)
+{
+ if (!ValidCol(nStartCol) || !ValidCol(nEndCol))
+ return;
+ if ( nEndCol == rDocument.MaxCol() )
+ {
+ if ( nStartCol < aCol.size() )
+ {
+ // If we would like set all columns to same attrs, then change only attrs for not existing columns
+ nEndCol = aCol.size() - 1;
+ for (SCCOL i = nStartCol; i <= nEndCol; i++)
+ aCol[i].SetAttrEntries(duplicateScAttrEntries(vNewData));
+ aDefaultColData.SetAttrEntries(std::move(vNewData));
+ }
+ else
+ {
+ CreateColumnIfNotExists( nStartCol - 1 );
+ aDefaultColData.SetAttrEntries(std::move(vNewData));
+ }
+ }
+ else
+ {
+ CreateColumnIfNotExists( nEndCol );
+ for (SCCOL i = nStartCol; i < nEndCol; i++) // all but last need a copy
+ aCol[i].SetAttrEntries(duplicateScAttrEntries(vNewData));
+ aCol[nEndCol].SetAttrEntries( std::move(vNewData));
}
}
+
+
void ScTable::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
const ScPatternAttr& rPattern, SvNumFormatType nNewType )
{
@@ -2849,7 +3026,7 @@ void ScTable::RemoveCondFormatData( const ScRangeList& rRangeList, sal_uInt32 nI
void ScTable::SetPatternAreaCondFormat( SCCOL nCol, SCROW nStartRow, SCROW nEndRow,
const ScPatternAttr& rAttr, const ScCondFormatIndexes& rCondFormatIndexes )
{
- aCol[nCol].SetPatternArea( nStartRow, nEndRow, rAttr);
+ CreateColumnIfNotExists(nCol).SetPatternArea( nStartRow, nEndRow, CellAttributeHolder(&rAttr));
for (const auto& rIndex : rCondFormatIndexes)
{
@@ -2885,12 +3062,12 @@ void ScTable::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, S
nEndCol = aCol.size() - 1;
for (SCCOL i = nStartCol; i <= nEndCol; i++)
aCol[i].ApplyStyleArea(nStartRow, nEndRow, rStyle);
- aDefaultColAttrArray.ApplyStyleArea(nStartRow, nEndRow, rStyle );
+ aDefaultColData.ApplyStyleArea(nStartRow, nEndRow, rStyle );
}
else
{
CreateColumnIfNotExists( nStartCol - 1 );
- aDefaultColAttrArray.ApplyStyleArea(nStartRow, nEndRow, rStyle );
+ aDefaultColData.ApplyStyleArea(nStartRow, nEndRow, rStyle );
}
}
else
@@ -2903,8 +3080,8 @@ void ScTable::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, S
void ScTable::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
{
- for (SCCOL i=0; i < aCol.size(); i++)
- aCol[i].ApplySelectionStyle( rStyle, rMark );
+ ApplyWithAllocation(rMark, [&rStyle](ScColumnData& applyTo, SCROW nTop, SCROW nBottom)
+ { applyTo.ApplySelectionStyle(rStyle, nTop, nBottom); });
}
void ScTable::ApplySelectionLineStyle( const ScMarkData& rMark,
@@ -2921,10 +3098,7 @@ const ScStyleSheet* ScTable::GetStyle( SCCOL nCol, SCROW nRow ) const
{
if ( !ValidColRow( nCol, nRow ) )
return nullptr;
- if ( nCol < aCol.size() )
- return aCol[nCol].GetStyle( nRow );
- else
- return aDefaultColAttrArray.GetPattern( nRow )->GetStyleSheet();
+ return GetColumnData(nCol).GetStyle( nRow );
}
const ScStyleSheet* ScTable::GetSelectionStyle( const ScMarkData& rMark, bool& rFound ) const
@@ -3045,20 +3219,19 @@ bool ScTable::RemoveFlags( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCRO
void ScTable::SetPattern( const ScAddress& rPos, const ScPatternAttr& rAttr )
{
if (ValidColRow(rPos.Col(),rPos.Row()))
- aCol[rPos.Col()].SetPattern( rPos.Row(), rAttr );
+ CreateColumnIfNotExists(rPos.Col()).SetPattern(rPos.Row(), rAttr);
}
-const ScPatternAttr* ScTable::SetPattern( SCCOL nCol, SCROW nRow, std::unique_ptr<ScPatternAttr> pAttr )
+void ScTable::SetPattern( SCCOL nCol, SCROW nRow, const CellAttributeHolder& rHolder )
{
if (ValidColRow(nCol,nRow))
- return aCol[nCol].SetPattern( nRow, std::move(pAttr) );
- return nullptr;
+ CreateColumnIfNotExists(nCol).SetPattern(nRow, rHolder);
}
void ScTable::SetPattern( SCCOL nCol, SCROW nRow, const ScPatternAttr& rAttr )
{
if (ValidColRow(nCol,nRow))
- aCol[nCol].SetPattern( nRow, rAttr );
+ CreateColumnIfNotExists(nCol).SetPattern(nRow, rAttr);
}
void ScTable::ApplyAttr( SCCOL nCol, SCROW nRow, const SfxPoolItem& rAttr )
@@ -3067,23 +3240,24 @@ void ScTable::ApplyAttr( SCCOL nCol, SCROW nRow, const SfxPoolItem& rAttr )
CreateColumnIfNotExists(nCol).ApplyAttr( nRow, rAttr );
}
-void ScTable::ApplySelectionCache( SfxItemPoolCache* pCache, const ScMarkData& rMark,
+void ScTable::ApplySelectionCache( ScItemPoolCache& rCache, const ScMarkData& rMark,
ScEditDataArray* pDataArray, bool* const pIsChanged )
{
- for (SCCOL i=0; i < aCol.size(); i++)
- aCol[i].ApplySelectionCache( pCache, rMark, pDataArray, pIsChanged );
+ ApplyWithAllocation(
+ rMark, [&rCache, pDataArray, pIsChanged](ScColumnData& applyTo, SCROW nTop, SCROW nBottom)
+ { applyTo.ApplySelectionCache(rCache, nTop, nBottom, pDataArray, pIsChanged); });
}
void ScTable::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark )
{
- for (SCCOL i=0; i < aCol.size(); i++)
- aCol[i].ChangeSelectionIndent( bIncrement, rMark );
+ ApplyWithAllocation(rMark, [&bIncrement](ScColumnData& applyTo, SCROW nTop, SCROW nBottom)
+ { applyTo.ChangeSelectionIndent(bIncrement, nTop, nBottom); });
}
void ScTable::ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark )
{
- for (SCCOL i=0; i < aCol.size(); i++)
- aCol[i].ClearSelectionItems( pWhich, rMark );
+ ApplyWithAllocation(rMark, [pWhich](ScColumnData& applyTo, SCROW nTop, SCROW nBottom)
+ { applyTo.ClearSelectionItems(pWhich, nTop, nBottom); });
}
// Column widths / Row heights
@@ -3128,7 +3302,7 @@ void ScTable::SetRowHeight( SCROW nRow, sal_uInt16 nNewHeight )
if (!nNewHeight)
{
OSL_FAIL("SetRowHeight: Row height zero");
- nNewHeight = ScGlobal::nStdRowHeight;
+ nNewHeight = GetOptimalMinRowHeight();
}
sal_uInt16 nOldHeight = mpRowHeights->getValue(nRow);
@@ -3191,7 +3365,7 @@ bool ScTable::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, sal_uInt16 nNew
if (!nNewHeight)
{
OSL_FAIL("SetRowHeight: Row height zero");
- nNewHeight = ScGlobal::nStdRowHeight;
+ nNewHeight = GetOptimalMinRowHeight();
}
bool bSingle = false; // true = process every row for its own
@@ -3244,7 +3418,7 @@ void ScTable::SetRowHeightOnly( SCROW nStartRow, SCROW nEndRow, sal_uInt16 nNewH
return;
if (!nNewHeight)
- nNewHeight = ScGlobal::nStdRowHeight;
+ nNewHeight = GetOptimalMinRowHeight();
mpRowHeights->setValue(nStartRow, nEndRow, nNewHeight);
}
@@ -3279,12 +3453,12 @@ sal_uInt16 ScTable::GetColWidth( SCCOL nCol, bool bHiddenAsZero ) const
return sal_uInt16(STD_COL_WIDTH);
}
-sal_uLong ScTable::GetColWidth( SCCOL nStartCol, SCCOL nEndCol ) const
+tools::Long ScTable::GetColWidth( SCCOL nStartCol, SCCOL nEndCol ) const
{
if (!ValidCol(nStartCol) || !ValidCol(nEndCol) || nStartCol > nEndCol)
return 0;
- sal_uLong nW = 0;
+ tools::Long nW = 0;
bool bHidden = false;
SCCOL nLastHiddenCol = -1;
auto colWidthIt = mpColWidth->begin() + nStartCol;
@@ -3400,17 +3574,17 @@ sal_uInt16 ScTable::GetRowHeight( SCROW nRow, SCROW* pStartRow, SCROW* pEndRow,
*pStartRow = nRow;
if (pEndRow)
*pEndRow = nRow;
- return ScGlobal::nStdRowHeight;
+ return GetOptimalMinRowHeight();
}
}
-sal_uLong ScTable::GetRowHeight( SCROW nStartRow, SCROW nEndRow, bool bHiddenAsZero ) const
+tools::Long ScTable::GetRowHeight( SCROW nStartRow, SCROW nEndRow, bool bHiddenAsZero ) const
{
OSL_ENSURE(ValidRow(nStartRow) && ValidRow(nEndRow),"wrong row number");
if (ValidRow(nStartRow) && ValidRow(nEndRow) && mpRowHeights)
{
- sal_uLong nHeight = 0;
+ tools::Long nHeight = 0;
SCROW nRow = nStartRow;
while (nRow <= nEndRow)
{
@@ -3426,16 +3600,16 @@ sal_uLong ScTable::GetRowHeight( SCROW nStartRow, SCROW nEndRow, bool bHiddenAsZ
return nHeight;
}
else
- return (nEndRow - nStartRow + 1) * static_cast<sal_uLong>(ScGlobal::nStdRowHeight);
+ return (nEndRow - nStartRow + 1) * static_cast<tools::Long>(GetOptimalMinRowHeight());
}
-sal_uLong ScTable::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow, double fScale, const sal_uLong* pnMaxHeight ) const
+tools::Long ScTable::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow, double fScale ) const
{
OSL_ENSURE(ValidRow(nStartRow) && ValidRow(nEndRow),"wrong row number");
if (ValidRow(nStartRow) && ValidRow(nEndRow) && mpRowHeights)
{
- sal_uLong nHeight = 0;
+ tools::Long nHeight = 0;
SCROW nRow = nStartRow;
while (nRow <= nEndRow)
{
@@ -3456,21 +3630,8 @@ sal_uLong ScTable::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow, double fS
SCROW nSegmentEnd = std::min( nLastRow, aSegmentIter.getLastPos() );
// round-down a single height value, multiply resulting (pixel) values
- const sal_uLong nOneHeight = static_cast<sal_uLong>( nRowVal * fScale );
- // sometimes scaling results in zero height
- if (nOneHeight)
- {
- SCROW nRowsInSegment = nSegmentEnd + 1 - nRow;
- if (pnMaxHeight)
- {
- nRowsInSegment = std::min(nRowsInSegment, static_cast<SCROW>(*pnMaxHeight / nOneHeight + 1));
- nHeight += nOneHeight * nRowsInSegment;
- if (nHeight > *pnMaxHeight)
- return nHeight;
- }
- else
- nHeight += nOneHeight * nRowsInSegment;
- }
+ tools::Long nOneHeight = static_cast<tools::Long>( nRowVal * fScale );
+ nHeight += nOneHeight * ( nSegmentEnd + 1 - nRow );
nRow = nSegmentEnd + 1;
}
@@ -3480,17 +3641,7 @@ sal_uLong ScTable::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow, double fS
return nHeight;
}
else
- {
- const sal_uLong nOneHeight = static_cast<sal_uLong>(ScGlobal::nStdRowHeight * fScale);
- SCROW nRowsInSegment = nEndRow - nStartRow + 1;
- if (pnMaxHeight)
- {
- nRowsInSegment = std::min(nRowsInSegment, static_cast<SCROW>(*pnMaxHeight / nOneHeight + 1));
- return nOneHeight * nRowsInSegment;
- }
- else
- return static_cast<sal_uLong>(nRowsInSegment * nOneHeight);
- }
+ return static_cast<tools::Long>((nEndRow - nStartRow + 1) * GetOptimalMinRowHeight() * fScale);
}
sal_uInt16 ScTable::GetOriginalHeight( SCROW nRow ) const // non-0 even if hidden
@@ -3500,7 +3651,7 @@ sal_uInt16 ScTable::GetOriginalHeight( SCROW nRow ) const // non-0 even if
if (ValidRow(nRow) && mpRowHeights)
return mpRowHeights->getValue(nRow);
else
- return ScGlobal::nStdRowHeight;
+ return GetOptimalMinRowHeight();
}
// Column/Row -Flags
@@ -3664,6 +3815,8 @@ void ScTable::ShowRows(SCROW nRow1, SCROW nRow2, bool bShow)
bool ScTable::IsDataFiltered(SCCOL nColStart, SCROW nRowStart, SCCOL nColEnd, SCROW nRowEnd) const
{
+ assert(nColStart <= nColEnd && nRowStart <= nRowEnd
+ && "range must be normalized to obtain a valid result");
for (SCROW i = nRowStart; i <= nRowEnd; ++i)
{
if (RowHidden(i))
@@ -3679,8 +3832,9 @@ bool ScTable::IsDataFiltered(SCCOL nColStart, SCROW nRowStart, SCCOL nColEnd, SC
bool ScTable::IsDataFiltered(const ScRange& rRange) const
{
- return IsDataFiltered(rRange.aStart.Col(), rRange.aStart.Row(),
- rRange.aEnd.Col(), rRange.aEnd.Row());
+ ScRange aNormalized(rRange.aStart, rRange.aEnd);
+ return IsDataFiltered(aNormalized.aStart.Col(), aNormalized.aStart.Row(),
+ aNormalized.aEnd.Col(), aNormalized.aEnd.Row());
}
void ScTable::SetRowFlags( SCROW nRow, CRFlags nNewFlags )
@@ -3749,22 +3903,21 @@ SCROW ScTable::GetLastFlaggedRow() const
return nLastFound;
}
-SCCOL ScTable::GetLastChangedCol() const
+SCCOL ScTable::GetLastChangedColFlagsWidth() const
{
if ( !mpColFlags )
return 0;
SCCOL nLastFound = 0;
- const auto nColSize = aCol.size();
auto colWidthIt = mpColWidth->begin() + 1;
- for (SCCOL nCol = 1; nCol < nColSize; (++nCol < nColSize) ? ++colWidthIt : (void)false)
+ for (SCCOL nCol = 1; nCol <= GetDoc().MaxCol(); (++nCol <= GetDoc().MaxCol()) ? ++colWidthIt : (void)false)
if ((mpColFlags->GetValue(nCol) & CRFlags::All) || (*colWidthIt != STD_COL_WIDTH))
nLastFound = nCol;
return nLastFound;
}
-SCROW ScTable::GetLastChangedRow() const
+SCROW ScTable::GetLastChangedRowFlagsWidth() const
{
if ( !pRowFlags )
return 0;
@@ -3774,7 +3927,7 @@ SCROW ScTable::GetLastChangedRow() const
// Find the last row position where the height is NOT the standard row
// height.
// KOHEI: Test this to make sure it does what it's supposed to.
- SCROW nLastHeight = mpRowHeights->findLastTrue(ScGlobal::nStdRowHeight);
+ SCROW nLastHeight = mpRowHeights->findLastTrue(GetOptimalMinRowHeight());
if (!ValidRow(nLastHeight))
nLastHeight = 0;
@@ -3938,10 +4091,10 @@ void ScTable::DoAutoOutline( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SC
{
ScRefCellValue aCell = aCol[nCol].GetCellValue(nRow);
- if (aCell.meType != CELLTYPE_FORMULA)
+ if (aCell.getType() != CELLTYPE_FORMULA)
continue;
- if (!aCell.mpFormula->HasRefListExpressibleAsOneReference(aRef))
+ if (!aCell.getFormula()->HasRefListExpressibleAsOneReference(aRef))
continue;
if ( aRef.aStart.Col() == nCol && aRef.aEnd.Col() == nCol &&
@@ -3993,7 +4146,7 @@ void ScTable::CopyData( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW n
ScCellValue aCell;
aCell.assign(rDocument, ScAddress(nCol, nRow, nTab));
- if (aCell.meType == CELLTYPE_FORMULA)
+ if (aCell.getType() == CELLTYPE_FORMULA)
{
sc::RefUpdateContext aCxt(rDocument);
aCxt.meMode = URM_COPY;
@@ -4001,8 +4154,8 @@ void ScTable::CopyData( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW n
aCxt.mnColDelta = nDestCol - nStartCol;
aCxt.mnRowDelta = nDestRow - nStartRow;
aCxt.mnTabDelta = nDestTab - nTab;
- aCell.mpFormula->UpdateReference(aCxt);
- aCell.mpFormula->aPos = aDest;
+ aCell.getFormula()->UpdateReference(aCxt);
+ aCell.getFormula()->aPos = aDest;
}
if (bThisTab)
@@ -4044,10 +4197,9 @@ bool ScTable::RefVisible(const ScFormulaCell* pCell)
return true; // somehow different
}
-void ScTable::GetUpperCellString(SCCOL nCol, SCROW nRow, OUString& rStr)
+OUString ScTable::GetUpperCellString(SCCOL nCol, SCROW nRow)
{
- GetInputString(nCol, nRow, rStr);
- rStr = ScGlobal::getCharClassPtr()->uppercase(rStr.trim());
+ return ScGlobal::getCharClass().uppercase(GetInputString(nCol, nRow).trim());
}
// Calculate the size of the sheet and set the size on DrawPage
@@ -4096,9 +4248,9 @@ ScRangeName* ScTable::GetRangeName() const
return mpRangeName.get();
}
-sal_uLong ScTable::GetRowOffset( SCROW nRow, bool bHiddenAsZero ) const
+tools::Long ScTable::GetRowOffset( SCROW nRow, bool bHiddenAsZero ) const
{
- sal_uLong n = 0;
+ tools::Long n = 0;
if ( mpHiddenRows && mpRowHeights )
{
if (nRow == 0)
@@ -4108,7 +4260,7 @@ sal_uLong ScTable::GetRowOffset( SCROW nRow, bool bHiddenAsZero ) const
n = GetTotalRowHeight(0, nRow-1, bHiddenAsZero);
#if OSL_DEBUG_LEVEL > 0
- if (n == ::std::numeric_limits<tools::ULong>::max())
+ if (n == ::std::numeric_limits<tools::Long>::max())
OSL_FAIL("ScTable::GetRowOffset: row heights overflow");
#endif
}
@@ -4119,15 +4271,15 @@ sal_uLong ScTable::GetRowOffset( SCROW nRow, bool bHiddenAsZero ) const
return n;
}
-SCROW ScTable::GetRowForHeight(sal_uLong nHeight) const
+SCROW ScTable::GetRowForHeight(tools::Long nHeight) const
{
- sal_uLong nSum = 0;
+ tools::Long nSum = 0;
ScFlatBoolRowSegments::RangeData aData;
ScFlatUInt16RowSegments::RangeData aRowHeightRange;
aRowHeightRange.mnRow2 = -1;
- aRowHeightRange.mnValue = 0; // silence MSVC C4701
+ aRowHeightRange.mnValue = 1; // silence MSVC C4701
for (SCROW nRow = 0; nRow <= rDocument.MaxRow(); ++nRow)
{
@@ -4155,8 +4307,8 @@ SCROW ScTable::GetRowForHeight(sal_uLong nHeight) const
SCROW nCommon = nLastCommon - nRow + 1;
// how much further to go ?
- sal_uLong nPixelsLeft = nHeight - nSum;
- sal_uLong nCommonPixels = static_cast<sal_uLong>(aRowHeightRange.mnValue) * nCommon;
+ tools::Long nPixelsLeft = nHeight - nSum;
+ tools::Long nCommonPixels = static_cast<tools::Long>(aRowHeightRange.mnValue) * nCommon;
// are we in the zone ?
if (nCommonPixels > nPixelsLeft)
@@ -4186,9 +4338,9 @@ SCROW ScTable::GetRowForHeight(sal_uLong nHeight) const
return -1;
}
-sal_uLong ScTable::GetColOffset( SCCOL nCol, bool bHiddenAsZero ) const
+tools::Long ScTable::GetColOffset( SCCOL nCol, bool bHiddenAsZero ) const
{
- sal_uLong n = 0;
+ tools::Long n = 0;
if ( mpColWidth )
{
auto colWidthIt = mpColWidth->begin();
diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index 47d1ea2b852d..4e06aca8231a 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -19,15 +19,11 @@
#include <comphelper/processfactory.hxx>
#include <comphelper/random.hxx>
-#include <editeng/brushitem.hxx>
-#include <editeng/colritem.hxx>
-#include <unotools/textsearch.hxx>
+#include <svl/numformat.hxx>
#include <svl/zforlist.hxx>
#include <svl/zformat.hxx>
-#include <unotools/charclass.hxx>
#include <unotools/collatorwrapper.hxx>
#include <stdlib.h>
-#include <unotools/transliterationwrapper.hxx>
#include <com/sun/star/i18n/KParseTokens.hpp>
#include <com/sun/star/i18n/KParseType.hpp>
#include <sal/log.hxx>
@@ -44,16 +40,13 @@
#include <stlpool.hxx>
#include <patattr.hxx>
#include <subtotal.hxx>
-#include <docoptio.hxx>
#include <markdata.hxx>
#include <rangelst.hxx>
#include <userlist.hxx>
#include <progress.hxx>
-#include <cellform.hxx>
#include <queryparam.hxx>
#include <queryentry.hxx>
#include <subtotalparam.hxx>
-#include <docpool.hxx>
#include <cellvalue.hxx>
#include <tokenarray.hxx>
#include <mtvcellfunc.hxx>
@@ -67,6 +60,8 @@
#include <bcaslot.hxx>
#include <reordermap.hxx>
#include <drwlayer.hxx>
+#include <queryevaluator.hxx>
+#include <scopetools.hxx>
#include <svl/sharedstringpool.hxx>
@@ -110,7 +105,7 @@ static bool SplitString( const OUString &sWhole,
sal_Int32 nPos = 0;
while (nPos < sWhole.getLength())
{
- const sal_uInt16 nType = ScGlobal::getCharClassPtr()->getCharacterType( sWhole, nPos);
+ const sal_uInt16 nType = ScGlobal::getCharClass().getCharacterType( sWhole, nPos);
if (nType & KCharacterType::DIGIT)
break;
sWhole.iterateCodePoints( &nPos );
@@ -121,8 +116,8 @@ static bool SplitString( const OUString &sWhole,
return false;
// Get numeral element
- const OUString& sUser = ScGlobal::getLocaleDataPtr()->getNumDecimalSep();
- ParseResult aPRNum = ScGlobal::getCharClassPtr()->parsePredefinedToken(
+ const OUString& sUser = ScGlobal::getLocaleData().getNumDecimalSep();
+ ParseResult aPRNum = ScGlobal::getCharClass().parsePredefinedToken(
KParseType::ANY_NUMBER, sWhole, nPos,
KParseTokens::ANY_NUMBER, "", KParseTokens::ANY_NUMBER, sUser );
@@ -222,190 +217,26 @@ static short Compare( const OUString &sInput1, const OUString &sInput2,
}
-namespace {
-
-struct ScSortInfo final
-{
- ScRefCellValue maCell;
- SCCOLROW nOrg;
-};
-
-}
-
-class ScSortInfoArray
-{
-public:
-
- struct Cell
- {
- ScRefCellValue maCell;
- const sc::CellTextAttr* mpAttr;
- const ScPostIt* mpNote;
- std::vector<SdrObject*> maDrawObjects;
- const ScPatternAttr* mpPattern;
-
- Cell() : mpAttr(nullptr), mpNote(nullptr), maDrawObjects(), mpPattern(nullptr) {}
- };
-
- struct Row
- {
- std::vector<Cell> maCells;
-
- bool mbHidden:1;
- bool mbFiltered:1;
-
- explicit Row( size_t nColSize ) : maCells(nColSize, Cell()), mbHidden(false), mbFiltered(false) {}
- };
-
- typedef std::vector<Row> RowsType;
-
-private:
- std::unique_ptr<RowsType> mpRows; /// row-wise data table for sort by row operation.
-
- std::vector<std::unique_ptr<ScSortInfo[]>> mvppInfo;
- SCCOLROW nStart;
- SCCOLROW mnLastIndex; /// index of last non-empty cell position.
-
- std::vector<SCCOLROW> maOrderIndices;
- bool mbKeepQuery;
- bool mbUpdateRefs;
-
-public:
- ScSortInfoArray(const ScSortInfoArray&) = delete;
- const ScSortInfoArray& operator=(const ScSortInfoArray&) = delete;
-
- ScSortInfoArray( sal_uInt16 nSorts, SCCOLROW nInd1, SCCOLROW nInd2 ) :
- mvppInfo(nSorts),
- nStart( nInd1 ),
- mnLastIndex(nInd2),
- mbKeepQuery(false),
- mbUpdateRefs(false)
- {
- SCSIZE nCount( nInd2 - nInd1 + 1 );
- if (nSorts)
- {
- for ( sal_uInt16 nSort = 0; nSort < nSorts; nSort++ )
- {
- mvppInfo[nSort].reset(new ScSortInfo[nCount]);
- }
- }
-
- for (size_t i = 0; i < nCount; ++i)
- maOrderIndices.push_back(i+nStart);
- }
-
- void SetKeepQuery( bool b ) { mbKeepQuery = b; }
-
- bool IsKeepQuery() const { return mbKeepQuery; }
-
- void SetUpdateRefs( bool b ) { mbUpdateRefs = b; }
-
- bool IsUpdateRefs() const { return mbUpdateRefs; }
-
- /**
- * Call this only during normal sorting, not from reordering.
- */
- std::unique_ptr<ScSortInfo[]> const & GetFirstArray() const
- {
- return mvppInfo[0];
- }
-
- /**
- * Call this only during normal sorting, not from reordering.
- */
- ScSortInfo & Get( sal_uInt16 nSort, SCCOLROW nInd )
- {
- return mvppInfo[nSort][ nInd - nStart ];
- }
-
- /**
- * Call this only during normal sorting, not from reordering.
- */
- void Swap( SCCOLROW nInd1, SCCOLROW nInd2 )
- {
- if (nInd1 == nInd2) // avoid self-move-assign
- return;
- SCSIZE n1 = static_cast<SCSIZE>(nInd1 - nStart);
- SCSIZE n2 = static_cast<SCSIZE>(nInd2 - nStart);
- for ( sal_uInt16 nSort = 0; nSort < static_cast<sal_uInt16>(mvppInfo.size()); nSort++ )
- {
- auto & ppInfo = mvppInfo[nSort];
- std::swap(ppInfo[n1], ppInfo[n2]);
- }
-
- std::swap(maOrderIndices[n1], maOrderIndices[n2]);
-
- if (mpRows)
- {
- // Swap rows in data table.
- RowsType& rRows = *mpRows;
- std::swap(rRows[n1], rRows[n2]);
- }
- }
-
- void SetOrderIndices( const std::vector<SCCOLROW>& rIndices )
- {
- maOrderIndices = rIndices;
- }
-
- /**
- * @param rIndices indices are actual row positions on the sheet, not an
- * offset from the top row.
- */
- void ReorderByRow( const std::vector<SCCOLROW>& rIndices )
- {
- if (!mpRows)
- return;
-
- RowsType& rRows = *mpRows;
-
- std::vector<SCCOLROW> aOrderIndices2;
- aOrderIndices2.reserve(rIndices.size());
-
- RowsType aRows2;
- aRows2.reserve(rRows.size());
-
- for (const auto& rIndex : rIndices)
- {
- size_t nPos = rIndex - nStart; // switch to an offset to top row.
- aRows2.push_back(rRows[nPos]);
- aOrderIndices2.push_back(maOrderIndices[nPos]);
- }
-
- rRows.swap(aRows2);
- maOrderIndices.swap(aOrderIndices2);
- }
-
- sal_uInt16 GetUsedSorts() const { return mvppInfo.size(); }
-
- SCCOLROW GetStart() const { return nStart; }
- SCCOLROW GetLast() const { return mnLastIndex; }
-
- const std::vector<SCCOLROW>& GetOrderIndices() const { return maOrderIndices; }
-
- RowsType& InitDataRows( size_t nRowSize, size_t nColSize )
- {
- mpRows.reset(new RowsType);
- mpRows->resize(nRowSize, Row(nColSize));
- return *mpRows;
- }
-
- RowsType* GetDataRows()
- {
- return mpRows.get();
- }
-};
+// Assume that we can handle 512MB, which with a ~100 bytes
+// ScSortInfoArray::Cell element for 500MB are about 5 million cells plus
+// overhead in one chunk.
+constexpr sal_Int32 kSortCellsChunk = 500 * 1024 * 1024 / sizeof(ScSortInfoArray::Cell);
namespace {
void initDataRows(
ScSortInfoArray& rArray, ScTable& rTab, ScColContainer& rCols,
SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
- bool bPattern, bool bHiddenFiltered )
+ bool bHiddenFiltered, bool bPattern, bool bCellNotes, bool bCellDrawObjects, bool bOnlyDataAreaExtras )
{
// Fill row-wise data table.
ScSortInfoArray::RowsType& rRows = rArray.InitDataRows(nRow2-nRow1+1, nCol2-nCol1+1);
+ const std::vector<SCCOLROW>& rOrderIndices = rArray.GetOrderIndices();
+ assert(!bOnlyDataAreaExtras || (rOrderIndices.size() == static_cast<size_t>(nRow2 - nRow1 + 1)
+ && nRow1 == rArray.GetStart()));
+
+ ScDrawLayer* pDrawLayer = (bCellDrawObjects ? rTab.GetDoc().GetDrawLayer() : nullptr);
for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
{
ScColumn& rCol = rCols[nCol];
@@ -416,26 +247,30 @@ void initDataRows(
sc::ColumnBlockConstPosition aBlockPos;
rCol.InitBlockPosition(aBlockPos);
std::map<SCROW, std::vector<SdrObject*>> aRowDrawObjects;
- ScDrawLayer* pDrawLayer = rTab.GetDoc().GetDrawLayer();
if (pDrawLayer)
aRowDrawObjects = pDrawLayer->GetObjectsAnchoredToRange(rTab.GetTab(), nCol, nRow1, nRow2);
- for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
+ for (SCROW nR = nRow1; nR <= nRow2; ++nR)
{
- ScSortInfoArray::Row& rRow = rRows[nRow-nRow1];
+ const SCROW nRow = (bOnlyDataAreaExtras ? rOrderIndices[nR - rArray.GetStart()] : nR);
+ ScSortInfoArray::Row& rRow = rRows[nR-nRow1];
ScSortInfoArray::Cell& rCell = rRow.maCells[nCol-nCol1];
- rCell.maCell = rCol.GetCellValue(aBlockPos, nRow);
- rCell.mpAttr = rCol.GetCellTextAttr(aBlockPos, nRow);
- rCell.mpNote = rCol.GetCellNote(aBlockPos, nRow);
+ if (!bOnlyDataAreaExtras)
+ {
+ rCell.maCell = rCol.GetCellValue(aBlockPos, nRow);
+ rCell.mpAttr = rCol.GetCellTextAttr(aBlockPos, nRow);
+ }
+ if (bCellNotes)
+ rCell.mpNote = rCol.GetCellNote(aBlockPos, nRow);
if (pDrawLayer)
rCell.maDrawObjects = aRowDrawObjects[nRow];
if (!bUniformPattern && bPattern)
- rCell.mpPattern = rCol.GetPattern(nRow);
+ rCell.maPattern.setScPatternAttr(rCol.GetPattern(nRow));
}
}
- if (bHiddenFiltered)
+ if (!bOnlyDataAreaExtras && bHiddenFiltered)
{
for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
{
@@ -464,9 +299,9 @@ std::unique_ptr<ScSortInfoArray> ScTable::CreateSortInfoArray( const sc::Reorder
pArray->SetKeepQuery(rParam.mbHiddenFiltered);
pArray->SetUpdateRefs(rParam.mbUpdateRefs);
- initDataRows(
- *pArray, *this, aCol, nCol1, nRow1, nCol2, nRow2,
- rParam.mbPattern, rParam.mbHiddenFiltered);
+ CreateColumnIfNotExists(nCol2);
+ initDataRows( *pArray, *this, aCol, nCol1, nRow1, nCol2, nRow2, rParam.mbHiddenFiltered,
+ rParam.maDataAreaExtras.mbCellFormats, true, true, false);
}
else
{
@@ -508,9 +343,9 @@ std::unique_ptr<ScSortInfoArray> ScTable::CreateSortInfoArray(
}
}
- initDataRows(
- *pArray, *this, aCol, rSortParam.nCol1, nInd1, rSortParam.nCol2, nInd2,
- rSortParam.bIncludePattern, bKeepQuery);
+ CreateColumnIfNotExists(rSortParam.nCol2);
+ initDataRows( *pArray, *this, aCol, rSortParam.nCol1, nInd1, rSortParam.nCol2, nInd2, bKeepQuery,
+ rSortParam.aDataAreaExtras.mbCellFormats, true, true, false);
}
else
{
@@ -533,7 +368,7 @@ namespace {
struct SortedColumn
{
- typedef mdds::flat_segment_tree<SCROW, const ScPatternAttr*> PatRangeType;
+ typedef mdds::flat_segment_tree<SCROW, CellAttributeHolder> PatRangeType;
sc::CellStoreType maCells;
sc::CellTextAttrStoreType maCellTextAttrs;
@@ -552,13 +387,12 @@ struct SortedColumn
maCellTextAttrs(nTopEmptyRows),
maBroadcasters(nTopEmptyRows),
maCellNotes(nTopEmptyRows),
- maCellDrawObjects(),
maPatterns(0, rSheetLimits.GetMaxRowCount(), nullptr),
miPatternPos(maPatterns.begin()) {}
- void setPattern( SCROW nRow, const ScPatternAttr* pPat )
+ void setPattern( SCROW nRow, const CellAttributeHolder& rPat )
{
- miPatternPos = maPatterns.insert(miPatternPos, nRow, nRow+1, pPat).first;
+ miPatternPos = maPatterns.insert(miPatternPos, nRow, nRow+1, rPat).first;
}
};
@@ -602,18 +436,18 @@ struct PatternSpan
{
SCROW mnRow1;
SCROW mnRow2;
- const ScPatternAttr* mpPattern;
+ CellAttributeHolder maPattern;
- PatternSpan( SCROW nRow1, SCROW nRow2, const ScPatternAttr* pPat ) :
- mnRow1(nRow1), mnRow2(nRow2), mpPattern(pPat) {}
+ PatternSpan( SCROW nRow1, SCROW nRow2, const CellAttributeHolder& rPat ) :
+ mnRow1(nRow1), mnRow2(nRow2), maPattern(rPat) {}
};
}
bool ScTable::IsSortCollatorGlobal() const
{
- return pSortCollator == ScGlobal::GetCollator() ||
- pSortCollator == ScGlobal::GetCaseCollator();
+ return pSortCollator == &ScGlobal::GetCollator() ||
+ pSortCollator == &ScGlobal::GetCaseCollator();
}
void ScTable::InitSortCollator( const ScSortParam& rPar )
@@ -628,8 +462,7 @@ void ScTable::InitSortCollator( const ScSortParam& rPar )
else
{ // SYSTEM
DestroySortCollator();
- pSortCollator = (rPar.bCaseSens ? ScGlobal::GetCaseCollator() :
- ScGlobal::GetCollator());
+ pSortCollator = &ScGlobal::GetCollator(rPar.bCaseSens);
}
}
@@ -676,8 +509,11 @@ void fillSortedColumnArray(
std::vector<std::unique_ptr<SortedColumn>>& rSortedCols,
SortedRowFlags& rRowFlags,
std::vector<SvtListener*>& rCellListeners,
- ScSortInfoArray* pArray, SCTAB nTab, SCCOL nCol1, SCCOL nCol2, ScProgress* pProgress, const ScTable* pTable )
+ ScSortInfoArray* pArray, SCTAB nTab, SCCOL nCol1, SCCOL nCol2, ScProgress* pProgress, const ScTable* pTable,
+ bool bOnlyDataAreaExtras )
{
+ assert(!bOnlyDataAreaExtras || !pArray->IsUpdateRefs());
+
SCROW nRow1 = pArray->GetStart();
ScSortInfoArray::RowsType* pRows = pArray->GetDataRows();
std::vector<SCCOLROW> aOrderIndices = pArray->GetOrderIndices();
@@ -696,72 +532,83 @@ void fillSortedColumnArray(
for (size_t i = 0; i < pRows->size(); ++i)
{
+ const SCROW nRow = nRow1 + i;
+
ScSortInfoArray::Row& rRow = (*pRows)[i];
for (size_t j = 0; j < rRow.maCells.size(); ++j)
{
- ScAddress aCellPos(nCol1 + j, nRow1 + i, nTab);
-
ScSortInfoArray::Cell& rCell = rRow.maCells[j];
- sc::CellStoreType& rCellStore = aSortedCols.at(j)->maCells;
- switch (rCell.maCell.meType)
+ // If bOnlyDataAreaExtras,
+ // sc::CellStoreType aSortedCols.at(j)->maCells
+ // and
+ // sc::CellTextAttrStoreType aSortedCols.at(j)->maCellTextAttrs
+ // are by definition all empty mdds::multi_type_vector, so nothing
+ // needs to be done to push *all* empty.
+
+ if (!bOnlyDataAreaExtras)
{
- case CELLTYPE_STRING:
- assert(rCell.mpAttr);
- rCellStore.push_back(*rCell.maCell.mpString);
- break;
- case CELLTYPE_VALUE:
- assert(rCell.mpAttr);
- rCellStore.push_back(rCell.maCell.mfValue);
- break;
- case CELLTYPE_EDIT:
- assert(rCell.mpAttr);
- rCellStore.push_back(rCell.maCell.mpEditText->Clone().release());
- break;
- case CELLTYPE_FORMULA:
+ sc::CellStoreType& rCellStore = aSortedCols.at(j)->maCells;
+ switch (rCell.maCell.getType())
{
- assert(rCell.mpAttr);
- ScAddress aOldPos = rCell.maCell.mpFormula->aPos;
-
- ScFormulaCell* pNew = rCell.maCell.mpFormula->Clone( aCellPos );
- if (pArray->IsUpdateRefs())
- {
- pNew->CopyAllBroadcasters(*rCell.maCell.mpFormula);
- pNew->GetCode()->AdjustReferenceOnMovedOrigin(aOldPos, aCellPos);
- }
- else
- {
- pNew->GetCode()->AdjustReferenceOnMovedOriginIfOtherSheet(aOldPos, aCellPos);
- }
-
- if (!rCellListeners.empty())
- {
- // Original source cells will be deleted during
- // sc::CellStoreType::transfer(), SvtListener is a base
- // class, so we need to replace it.
- auto it( ::std::find( rCellListeners.begin(), rCellListeners.end(), rCell.maCell.mpFormula));
- if (it != rCellListeners.end())
- *it = pNew;
- }
-
- rCellStore.push_back(pNew);
+ case CELLTYPE_STRING:
+ assert(rCell.mpAttr);
+ rCellStore.push_back(*rCell.maCell.getSharedString());
+ break;
+ case CELLTYPE_VALUE:
+ assert(rCell.mpAttr);
+ rCellStore.push_back(rCell.maCell.getDouble());
+ break;
+ case CELLTYPE_EDIT:
+ assert(rCell.mpAttr);
+ rCellStore.push_back(rCell.maCell.getEditText()->Clone().release());
+ break;
+ case CELLTYPE_FORMULA:
+ {
+ assert(rCell.mpAttr);
+ ScAddress aOldPos = rCell.maCell.getFormula()->aPos;
+
+ const ScAddress aCellPos(nCol1 + j, nRow, nTab);
+ ScFormulaCell* pNew = rCell.maCell.getFormula()->Clone( aCellPos );
+ if (pArray->IsUpdateRefs())
+ {
+ pNew->CopyAllBroadcasters(*rCell.maCell.getFormula());
+ pNew->GetCode()->AdjustReferenceOnMovedOrigin(aOldPos, aCellPos);
+ }
+ else
+ {
+ pNew->GetCode()->AdjustReferenceOnMovedOriginIfOtherSheet(aOldPos, aCellPos);
+ }
+
+ if (!rCellListeners.empty())
+ {
+ // Original source cells will be deleted during
+ // sc::CellStoreType::transfer(), SvtListener is a base
+ // class, so we need to replace it.
+ auto it( ::std::find( rCellListeners.begin(), rCellListeners.end(), rCell.maCell.getFormula()));
+ if (it != rCellListeners.end())
+ *it = pNew;
+ }
+
+ rCellStore.push_back(pNew);
+ }
+ break;
+ default:
+ //assert(!rCell.mpAttr);
+ // This assert doesn't hold, for example
+ // CopyCellsFromClipHandler may omit copying cells during
+ // PasteSpecial for which CopyTextAttrsFromClipHandler
+ // still copies a CellTextAttr. So if that really is not
+ // expected then fix it there.
+ rCellStore.push_back_empty();
}
- break;
- default:
- //assert(!rCell.mpAttr);
- // This assert doesn't hold, for example
- // CopyCellsFromClipHandler may omit copying cells during
- // PasteSpecial for which CopyTextAttrsFromClipHandler
- // still copies a CellTextAttr. So if that really is not
- // expected then fix it there.
- rCellStore.push_back_empty();
- }
- sc::CellTextAttrStoreType& rAttrStore = aSortedCols.at(j)->maCellTextAttrs;
- if (rCell.mpAttr)
- rAttrStore.push_back(*rCell.mpAttr);
- else
- rAttrStore.push_back_empty();
+ sc::CellTextAttrStoreType& rAttrStore = aSortedCols.at(j)->maCellTextAttrs;
+ if (rCell.mpAttr)
+ rAttrStore.push_back(*rCell.mpAttr);
+ else
+ rAttrStore.push_back_empty();
+ }
if (pArray->IsUpdateRefs())
{
@@ -787,14 +634,13 @@ void fillSortedColumnArray(
// Add cell anchored images
aSortedCols.at(j)->maCellDrawObjects.push_back(rCell.maDrawObjects);
- if (rCell.mpPattern)
- aSortedCols.at(j)->setPattern(aCellPos.Row(), rCell.mpPattern);
+ if (rCell.maPattern)
+ aSortedCols.at(j)->setPattern(nRow, rCell.maPattern);
}
- if (pArray->IsKeepQuery())
+ if (!bOnlyDataAreaExtras && pArray->IsKeepQuery())
{
// Hidden and filtered flags are first converted to segments.
- SCROW nRow = nRow1 + i;
aRowFlags.setRowHidden(nRow, rRow.mbHidden);
aRowFlags.setRowFiltered(nRow, rRow.mbFiltered);
}
@@ -874,6 +720,53 @@ public:
}
+void ScTable::SortReorderAreaExtrasByRow( ScSortInfoArray* pArray,
+ SCCOL nDataCol1, SCCOL nDataCol2,
+ const ScDataAreaExtras& rDataAreaExtras, ScProgress* pProgress )
+{
+ const SCROW nRow1 = pArray->GetStart();
+ const SCROW nLastRow = pArray->GetLast();
+ const SCCOL nChunkCols = std::max<SCCOL>( 1, kSortCellsChunk / (nLastRow - nRow1 + 1));
+ // Before data area.
+ for (SCCOL nCol = rDataAreaExtras.mnStartCol; nCol < nDataCol1; nCol += nChunkCols)
+ {
+ const SCCOL nEndCol = std::min<SCCOL>( nCol + nChunkCols - 1, nDataCol1 - 1);
+ CreateColumnIfNotExists(nEndCol);
+ initDataRows( *pArray, *this, aCol, nCol, nRow1, nEndCol, nLastRow, false,
+ rDataAreaExtras.mbCellFormats, rDataAreaExtras.mbCellNotes, rDataAreaExtras.mbCellDrawObjects, true);
+ SortReorderByRow( pArray, nCol, nEndCol, pProgress, true);
+ }
+ // Behind data area.
+ for (SCCOL nCol = nDataCol2 + 1; nCol <= rDataAreaExtras.mnEndCol; nCol += nChunkCols)
+ {
+ const SCCOL nEndCol = std::min<SCCOL>( nCol + nChunkCols - 1, rDataAreaExtras.mnEndCol);
+ CreateColumnIfNotExists(nEndCol);
+ initDataRows( *pArray, *this, aCol, nCol, nRow1, nEndCol, nLastRow, false,
+ rDataAreaExtras.mbCellFormats, rDataAreaExtras.mbCellNotes, rDataAreaExtras.mbCellDrawObjects, true);
+ SortReorderByRow( pArray, nCol, nEndCol, pProgress, true);
+ }
+}
+
+void ScTable::SortReorderAreaExtrasByColumn( const ScSortInfoArray* pArray,
+ SCROW nDataRow1, SCROW nDataRow2, const ScDataAreaExtras& rDataAreaExtras, ScProgress* pProgress )
+{
+ const SCCOL nCol1 = static_cast<SCCOL>(pArray->GetStart());
+ const SCCOL nLastCol = static_cast<SCCOL>(pArray->GetLast());
+ const SCROW nChunkRows = std::max<SCROW>( 1, kSortCellsChunk / (nLastCol - nCol1 + 1));
+ // Above data area.
+ for (SCROW nRow = rDataAreaExtras.mnStartRow; nRow < nDataRow1; nRow += nChunkRows)
+ {
+ const SCROW nEndRow = std::min<SCROW>( nRow + nChunkRows - 1, nDataRow1 - 1);
+ SortReorderByColumn( pArray, nRow, nEndRow, rDataAreaExtras.mbCellFormats, pProgress);
+ }
+ // Below data area.
+ for (SCROW nRow = nDataRow2 + 1; nRow <= rDataAreaExtras.mnEndRow; nRow += nChunkRows)
+ {
+ const SCROW nEndRow = std::min<SCROW>( nRow + nChunkRows - 1, rDataAreaExtras.mnEndRow);
+ SortReorderByColumn( pArray, nRow, nEndRow, rDataAreaExtras.mbCellFormats, pProgress);
+ }
+}
+
void ScTable::SortReorderByColumn(
const ScSortInfoArray* pArray, SCROW nRow1, SCROW nRow2, bool bPattern, ScProgress* pProgress )
{
@@ -975,8 +868,10 @@ void ScTable::SortReorderByColumn(
// once.
std::sort(aListeners.begin(), aListeners.end());
aListeners.erase(std::unique(aListeners.begin(), aListeners.end()), aListeners.end());
- ReorderNotifier<sc::RefColReorderHint, sc::ColRowReorderMapType, SCCOL> aFunc(aColMap, nTab, nRow1, nRow2);
- std::for_each(aListeners.begin(), aListeners.end(), aFunc);
+ {
+ ReorderNotifier<sc::RefColReorderHint, sc::ColRowReorderMapType, SCCOL> aFunc(aColMap, nTab, nRow1, nRow2);
+ std::for_each(aListeners.begin(), aListeners.end(), std::move(aFunc));
+ }
// Re-start area listeners on the reordered columns.
{
@@ -1016,14 +911,20 @@ void ScTable::SortReorderByColumn(
}
}
-void ScTable::SortReorderByRow(
- ScSortInfoArray* pArray, SCCOL nCol1, SCCOL nCol2, ScProgress* pProgress )
+void ScTable::SortReorderByRow( ScSortInfoArray* pArray, SCCOL nCol1, SCCOL nCol2,
+ ScProgress* pProgress, bool bOnlyDataAreaExtras )
{
assert(!pArray->IsUpdateRefs());
if (nCol2 < nCol1)
return;
+ // bOnlyDataAreaExtras:
+ // Data area extras by definition do not have any cell content so no
+ // formula cells either, so that handling doesn't need to be executed.
+ // However, there may be listeners of formulas listening to broadcasters of
+ // empty cells.
+
SCROW nRow1 = pArray->GetStart();
SCROW nRow2 = pArray->GetLast();
@@ -1033,6 +934,7 @@ void ScTable::SortReorderByRow(
// When the update ref mode is disabled, we need to detach all formula
// cells in the sorted range before reordering, and re-start them
// afterward.
+ if (!bOnlyDataAreaExtras)
{
sc::EndListeningContext aCxt(rDocument);
DetachFormulaCells(aCxt, nCol1, nRow1, nCol2, nRow2);
@@ -1058,33 +960,41 @@ void ScTable::SortReorderByRow(
}
// Split formula groups at the sort range boundaries (if applicable).
- std::vector<SCROW> aRowBounds;
- aRowBounds.reserve(2);
- aRowBounds.push_back(nRow1);
- aRowBounds.push_back(nRow2+1);
- for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
- SplitFormulaGroups(nCol, aRowBounds);
+ if (!bOnlyDataAreaExtras)
+ {
+ std::vector<SCROW> aRowBounds
+ {
+ nRow1,
+ nRow2+1
+ };
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+ SplitFormulaGroups(nCol, aRowBounds);
+ }
// Cells in the data rows only reference values in the document. Make
// a copy before updating the document.
std::vector<std::unique_ptr<SortedColumn>> aSortedCols; // storage for copied cells.
SortedRowFlags aRowFlags(GetDoc().GetSheetLimits());
- fillSortedColumnArray(aSortedCols, aRowFlags, aCellListeners, pArray, nTab, nCol1, nCol2, pProgress, this);
+ fillSortedColumnArray(aSortedCols, aRowFlags, aCellListeners, pArray, nTab, nCol1, nCol2,
+ pProgress, this, bOnlyDataAreaExtras);
for (size_t i = 0, n = aSortedCols.size(); i < n; ++i)
{
SCCOL nThisCol = i + nCol1;
+ if (!bOnlyDataAreaExtras)
{
- sc::CellStoreType& rDest = aCol[nThisCol].maCells;
- sc::CellStoreType& rSrc = aSortedCols[i]->maCells;
- rSrc.transfer(nRow1, nRow2, rDest, nRow1);
- }
+ {
+ sc::CellStoreType& rDest = aCol[nThisCol].maCells;
+ sc::CellStoreType& rSrc = aSortedCols[i]->maCells;
+ rSrc.transfer(nRow1, nRow2, rDest, nRow1);
+ }
- {
- sc::CellTextAttrStoreType& rDest = aCol[nThisCol].maCellTextAttrs;
- sc::CellTextAttrStoreType& rSrc = aSortedCols[i]->maCellTextAttrs;
- rSrc.transfer(nRow1, nRow2, rDest, nRow1);
+ {
+ sc::CellTextAttrStoreType& rDest = aCol[nThisCol].maCellTextAttrs;
+ sc::CellTextAttrStoreType& rSrc = aSortedCols[i]->maCellTextAttrs;
+ rSrc.transfer(nRow1, nRow2, rDest, nRow1);
+ }
}
{
@@ -1103,26 +1013,19 @@ void ScTable::SortReorderByRow(
{
// Get all row spans where the pattern is not NULL.
std::vector<PatternSpan> aSpans =
- sc::toSpanArrayWithValue<SCROW,const ScPatternAttr*,PatternSpan>(
+ sc::toSpanArrayWithValue<SCROW, CellAttributeHolder, PatternSpan>(
aSortedCols[i]->maPatterns);
for (const auto& rSpan : aSpans)
{
- assert(rSpan.mpPattern); // should never be NULL.
- rDocument.GetPool()->Put(*rSpan.mpPattern);
- }
-
- for (const auto& rSpan : aSpans)
- {
- aCol[nThisCol].SetPatternArea(rSpan.mnRow1, rSpan.mnRow2, *rSpan.mpPattern);
- rDocument.GetPool()->Remove(*rSpan.mpPattern);
+ aCol[nThisCol].SetPatternArea(rSpan.mnRow1, rSpan.mnRow2, rSpan.maPattern);
}
}
aCol[nThisCol].CellStorageModified();
}
- if (pArray->IsKeepQuery())
+ if (!bOnlyDataAreaExtras && pArray->IsKeepQuery())
{
aRowFlags.maRowsHidden.build_tree();
aRowFlags.maRowsFiltered.build_tree();
@@ -1150,13 +1053,16 @@ void ScTable::SortReorderByRow(
l->Notify(aHint);
}
- // Re-group columns in the sorted range too.
- for (SCCOL i = nCol1; i <= nCol2; ++i)
- aCol[i].RegroupFormulaCells();
-
+ if (!bOnlyDataAreaExtras)
{
- sc::StartListeningContext aCxt(rDocument);
- AttachFormulaCells(aCxt, nCol1, nRow1, nCol2, nRow2);
+ // Re-group columns in the sorted range too.
+ for (SCCOL i = nCol1; i <= nCol2; ++i)
+ aCol[i].RegroupFormulaCells();
+
+ {
+ sc::StartListeningContext aCxt(rDocument);
+ AttachFormulaCells(aCxt, nCol1, nRow1, nCol2, nRow2);
+ }
}
}
@@ -1243,10 +1149,11 @@ void ScTable::SortReorderByRowRefUpdate(
}
// Split formula groups at the sort range boundaries (if applicable).
- std::vector<SCROW> aRowBounds;
- aRowBounds.reserve(2);
- aRowBounds.push_back(nRow1);
- aRowBounds.push_back(nRow2+1);
+ std::vector<SCROW> aRowBounds
+ {
+ nRow1,
+ nRow2+1
+ };
for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
SplitFormulaGroups(nCol, aRowBounds);
@@ -1255,7 +1162,7 @@ void ScTable::SortReorderByRowRefUpdate(
std::vector<std::unique_ptr<SortedColumn>> aSortedCols; // storage for copied cells.
SortedRowFlags aRowFlags(GetDoc().GetSheetLimits());
std::vector<SvtListener*> aListenersDummy;
- fillSortedColumnArray(aSortedCols, aRowFlags, aListenersDummy, pArray, nTab, nCol1, nCol2, pProgress, this);
+ fillSortedColumnArray(aSortedCols, aRowFlags, aListenersDummy, pArray, nTab, nCol1, nCol2, pProgress, this, false);
for (size_t i = 0, n = aSortedCols.size(); i < n; ++i)
{
@@ -1300,19 +1207,12 @@ void ScTable::SortReorderByRowRefUpdate(
{
// Get all row spans where the pattern is not NULL.
std::vector<PatternSpan> aSpans =
- sc::toSpanArrayWithValue<SCROW,const ScPatternAttr*,PatternSpan>(
+ sc::toSpanArrayWithValue<SCROW, CellAttributeHolder, PatternSpan>(
aSortedCols[i]->maPatterns);
for (const auto& rSpan : aSpans)
{
- assert(rSpan.mpPattern); // should never be NULL.
- rDocument.GetPool()->Put(*rSpan.mpPattern);
- }
-
- for (const auto& rSpan : aSpans)
- {
- aCol[nThisCol].SetPatternArea(rSpan.mnRow1, rSpan.mnRow2, *rSpan.mpPattern);
- rDocument.GetPool()->Remove(*rSpan.mpPattern);
+ aCol[nThisCol].SetPatternArea(rSpan.mnRow1, rSpan.mnRow2, rSpan.maPattern);
}
}
@@ -1401,8 +1301,10 @@ void ScTable::SortReorderByRowRefUpdate(
}
// Notify the listeners to update their references.
- ReorderNotifier<sc::RefRowReorderHint, sc::ColRowReorderMapType, SCROW> aFunc(aRowMap, nTab, nCol1, nCol2);
- std::for_each(aListeners.begin(), aListeners.end(), aFunc);
+ {
+ ReorderNotifier<sc::RefRowReorderHint, sc::ColRowReorderMapType, SCROW> aFunc(aRowMap, nTab, nCol1, nCol2);
+ std::for_each(aListeners.begin(), aListeners.end(), std::move(aFunc));
+ }
// Re-group formulas in affected columns.
for (const auto& [rTab, rCols] : rGroupTabs)
@@ -1442,7 +1344,38 @@ short ScTable::CompareCell(
{
short nRes = 0;
- CellType eType1 = rCell1.meType, eType2 = rCell2.meType;
+ CellType eType1 = rCell1.getType(), eType2 = rCell2.getType();
+
+ // tdf#95520 Sort by color - selected color goes on top, everything else according to compare function
+ if (aSortParam.maKeyState[nSort].aColorSortMode == ScColorSortMode::TextColor
+ || aSortParam.maKeyState[nSort].aColorSortMode == ScColorSortMode::BackgroundColor)
+ {
+ ScAddress aPos1(nCell1Col, nCell1Row, GetTab());
+ ScAddress aPos2(nCell2Col, nCell2Row, GetTab());
+ Color aTheChosenColor = aSortParam.maKeyState[nSort].aColorSortColor;
+ Color aColor1;
+ Color aColor2;
+ if (aSortParam.maKeyState[nSort].aColorSortMode == ScColorSortMode::TextColor)
+ {
+ aColor1 = GetCellTextColor(aPos1);
+ aColor2 = GetCellTextColor(aPos2);
+ }
+ else
+ {
+ aColor1 = GetCellBackgroundColor(aPos1);
+ aColor2 = GetCellBackgroundColor(aPos2);
+ }
+ if (aTheChosenColor == aColor1)
+ return -1;
+ if (aTheChosenColor == aColor2)
+ return 1;
+ if (aColor1 == aColor2)
+ return 0;
+ if (aColor1 > aColor2)
+ return 1;
+ if (aColor1 < aColor2)
+ return -1;
+ }
if (!rCell1.isEmpty())
{
@@ -1452,12 +1385,12 @@ short ScTable::CompareCell(
bool bStr1 = ( eType1 != CELLTYPE_VALUE );
if (eType1 == CELLTYPE_FORMULA)
{
- if (rCell1.mpFormula->GetErrCode() != FormulaError::NONE)
+ if (rCell1.getFormula()->GetErrCode() != FormulaError::NONE)
{
bErr1 = true;
bStr1 = false;
}
- else if (rCell1.mpFormula->IsValue())
+ else if (rCell1.getFormula()->IsValue())
{
bStr1 = false;
}
@@ -1467,12 +1400,12 @@ short ScTable::CompareCell(
bool bStr2 = ( eType2 != CELLTYPE_VALUE );
if (eType2 == CELLTYPE_FORMULA)
{
- if (rCell2.mpFormula->GetErrCode() != FormulaError::NONE)
+ if (rCell2.getFormula()->GetErrCode() != FormulaError::NONE)
{
bErr2 = true;
bStr2 = false;
}
- else if (rCell2.mpFormula->IsValue())
+ else if (rCell2.getFormula()->IsValue())
{
bStr2 = false;
}
@@ -1483,13 +1416,13 @@ short ScTable::CompareCell(
OUString aStr1;
OUString aStr2;
if (eType1 == CELLTYPE_STRING)
- aStr1 = rCell1.mpString->getString();
+ aStr1 = rCell1.getSharedString()->getString();
else
- GetString(nCell1Col, nCell1Row, aStr1);
+ aStr1 = GetString(nCell1Col, nCell1Row);
if (eType2 == CELLTYPE_STRING)
- aStr2 = rCell2.mpString->getString();
+ aStr2 = rCell2.getSharedString()->getString();
else
- GetString(nCell2Col, nCell2Row, aStr2);
+ aStr2 = GetString(nCell2Col, nCell2Row);
bool bUserDef = aSortParam.bUserDef; // custom sort order
bool bNaturalSort = aSortParam.bNaturalSort; // natural sort
@@ -1651,9 +1584,13 @@ short ScTable::Compare(SCCOLROW nIndex1, SCCOLROW nIndex2) const
do
{
SCCOL nCol = static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField);
- ScRefCellValue aCell1 = aCol[nCol].GetCellValue(nIndex1);
- ScRefCellValue aCell2 = aCol[nCol].GetCellValue(nIndex2);
- nRes = CompareCell(nSort, aCell1, nCol, nIndex1, aCell2, nCol, nIndex2);
+ nRes = 0;
+ if(nCol < GetAllocatedColumnsCount())
+ {
+ ScRefCellValue aCell1 = aCol[nCol].GetCellValue(nIndex1);
+ ScRefCellValue aCell2 = aCol[nCol].GetCellValue(nIndex2);
+ nRes = CompareCell(nSort, aCell1, nCol, nIndex1, aCell2, nCol, nIndex2);
+ }
} while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.maKeyState[nSort].bDoSort );
}
else
@@ -1661,8 +1598,12 @@ short ScTable::Compare(SCCOLROW nIndex1, SCCOLROW nIndex2) const
do
{
SCROW nRow = aSortParam.maKeyState[nSort].nField;
- ScRefCellValue aCell1 = aCol[nIndex1].GetCellValue(nRow);
- ScRefCellValue aCell2 = aCol[nIndex2].GetCellValue(nRow);
+ ScRefCellValue aCell1;
+ ScRefCellValue aCell2;
+ if(nIndex1 < GetAllocatedColumnsCount())
+ aCell1 = aCol[nIndex1].GetCellValue(nRow);
+ if(nIndex2 < GetAllocatedColumnsCount())
+ aCell2 = aCol[nIndex2].GetCellValue(nRow);
nRes = CompareCell( nSort, aCell1, static_cast<SCCOL>(nIndex1),
nRow, aCell2, static_cast<SCCOL>(nIndex2), nRow );
} while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.maKeyState[nSort].bDoSort );
@@ -1695,14 +1636,15 @@ void ScTable::Sort(
const ScSortParam& rSortParam, bool bKeepQuery, bool bUpdateRefs,
ScProgress* pProgress, sc::ReorderParam* pUndo )
{
+ sc::DelayDeletingBroadcasters delayDeletingBroadcasters(GetDoc());
InitSortCollator( rSortParam );
bGlobalKeepQuery = bKeepQuery;
if (pUndo)
{
// Copy over the basic sort parameters.
+ pUndo->maDataAreaExtras = rSortParam.aDataAreaExtras;
pUndo->mbByRow = rSortParam.bByRow;
- pUndo->mbPattern = rSortParam.bIncludePattern;
pUndo->mbHiddenFiltered = bKeepQuery;
pUndo->mbUpdateRefs = bUpdateRefs;
pUndo->mbHasHeaders = rSortParam.bHasHeader;
@@ -1713,14 +1655,15 @@ void ScTable::Sort(
aSortParam = rSortParam; // must be assigned before calling IsSorted()
if (rSortParam.bByRow)
{
- SCROW nLastRow = rSortParam.nRow2;
- SCROW nRow1 = (rSortParam.bHasHeader ? rSortParam.nRow1 + 1 : rSortParam.nRow1);
+ const SCROW nLastRow = rSortParam.nRow2;
+ const SCROW nRow1 = (rSortParam.bHasHeader ? rSortParam.nRow1 + 1 : rSortParam.nRow1);
if (nRow1 < nLastRow && !IsSorted(nRow1, nLastRow))
{
if(pProgress)
pProgress->SetState( 0, nLastRow-nRow1 );
- std::unique_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(aSortParam, nRow1, nLastRow, bKeepQuery, bUpdateRefs));
+ std::unique_ptr<ScSortInfoArray> pArray( CreateSortInfoArray(
+ aSortParam, nRow1, nLastRow, bKeepQuery, bUpdateRefs));
if ( nLastRow - nRow1 > 255 )
DecoladeRow(pArray.get(), nRow1, nLastRow);
@@ -1729,32 +1672,46 @@ void ScTable::Sort(
if (pArray->IsUpdateRefs())
SortReorderByRowRefUpdate(pArray.get(), aSortParam.nCol1, aSortParam.nCol2, pProgress);
else
- SortReorderByRow(pArray.get(), aSortParam.nCol1, aSortParam.nCol2, pProgress);
+ {
+ SortReorderByRow(pArray.get(), aSortParam.nCol1, aSortParam.nCol2, pProgress, false);
+ if (rSortParam.aDataAreaExtras.anyExtrasWanted())
+ SortReorderAreaExtrasByRow( pArray.get(), aSortParam.nCol1, aSortParam.nCol2,
+ rSortParam.aDataAreaExtras, pProgress);
+ }
if (pUndo)
{
+ // Stored is the first data row without header row.
pUndo->maSortRange = ScRange(rSortParam.nCol1, nRow1, nTab, rSortParam.nCol2, nLastRow, nTab);
+ pUndo->maDataAreaExtras.mnStartRow = nRow1;
pUndo->maOrderIndices = pArray->GetOrderIndices();
}
}
}
else
{
- SCCOL nLastCol = rSortParam.nCol2;
- SCCOL nCol1 = (rSortParam.bHasHeader ? rSortParam.nCol1 + 1 : rSortParam.nCol1);
+ const SCCOL nLastCol = rSortParam.nCol2;
+ const SCCOL nCol1 = (rSortParam.bHasHeader ? rSortParam.nCol1 + 1 : rSortParam.nCol1);
if (nCol1 < nLastCol && !IsSorted(nCol1, nLastCol))
{
if(pProgress)
pProgress->SetState( 0, nLastCol-nCol1 );
- std::unique_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(aSortParam, nCol1, nLastCol, bKeepQuery, bUpdateRefs));
+ std::unique_ptr<ScSortInfoArray> pArray( CreateSortInfoArray(
+ aSortParam, nCol1, nLastCol, bKeepQuery, bUpdateRefs));
QuickSort(pArray.get(), nCol1, nLastCol);
- SortReorderByColumn(pArray.get(), aSortParam.nRow1, aSortParam.nRow2, aSortParam.bIncludePattern, pProgress);
+ SortReorderByColumn(pArray.get(), rSortParam.nRow1, rSortParam.nRow2,
+ rSortParam.aDataAreaExtras.mbCellFormats, pProgress);
+ if (rSortParam.aDataAreaExtras.anyExtrasWanted() && !pArray->IsUpdateRefs())
+ SortReorderAreaExtrasByColumn( pArray.get(),
+ rSortParam.nRow1, rSortParam.nRow2, rSortParam.aDataAreaExtras, pProgress);
if (pUndo)
{
+ // Stored is the first data column without header column.
pUndo->maSortRange = ScRange(nCol1, aSortParam.nRow1, nTab, nLastCol, aSortParam.nRow2, nTab);
+ pUndo->maDataAreaExtras.mnStartCol = nCol1;
pUndo->maOrderIndices = pArray->GetOrderIndices();
}
}
@@ -1779,16 +1736,26 @@ void ScTable::Reorder( const sc::ReorderParam& rParam )
SortReorderByRowRefUpdate(
pArray.get(), rParam.maSortRange.aStart.Col(), rParam.maSortRange.aEnd.Col(), nullptr);
else
- SortReorderByRow(
- pArray.get(), rParam.maSortRange.aStart.Col(), rParam.maSortRange.aEnd.Col(), nullptr);
+ {
+ SortReorderByRow( pArray.get(),
+ rParam.maSortRange.aStart.Col(), rParam.maSortRange.aEnd.Col(), nullptr, false);
+ if (rParam.maDataAreaExtras.anyExtrasWanted())
+ SortReorderAreaExtrasByRow( pArray.get(),
+ rParam.maSortRange.aStart.Col(), rParam.maSortRange.aEnd.Col(),
+ rParam.maDataAreaExtras, nullptr);
+ }
}
else
{
// Ordering by column is much simpler. Just set the order indices and we are done.
- pArray->SetOrderIndices(rParam.maOrderIndices);
+ pArray->SetOrderIndices(std::vector(rParam.maOrderIndices));
SortReorderByColumn(
pArray.get(), rParam.maSortRange.aStart.Row(), rParam.maSortRange.aEnd.Row(),
- rParam.mbPattern, nullptr);
+ rParam.maDataAreaExtras.mbCellFormats, nullptr);
+ if (rParam.maDataAreaExtras.anyExtrasWanted() && !pArray->IsUpdateRefs())
+ SortReorderAreaExtrasByColumn( pArray.get(),
+ rParam.maSortRange.aStart.Row(), rParam.maSortRange.aEnd.Row(),
+ rParam.maDataAreaExtras, nullptr);
}
}
@@ -1811,12 +1778,12 @@ public:
SCCOL nStartCol = mrParam.nCol1;
SCCOL nEndCol = mrParam.nCol2;
- for (SCCOL nCol : mrTab.GetColumnsRange(0, nStartCol - 1))
+ for (SCCOL nCol : mrTab.GetAllocatedColumnsRange(0, nStartCol - 1))
{
if (mrTab.HasData(nCol, nRow))
return true;
}
- for (SCCOL nCol : mrTab.GetColumnsRange(nEndCol + 1, mrTab.GetDoc().MaxCol()))
+ for (SCCOL nCol : mrTab.GetAllocatedColumnsRange(nEndCol + 1, mrTab.GetDoc().MaxCol()))
{
if (mrTab.HasData(nCol, nRow))
return true;
@@ -1893,11 +1860,11 @@ static void lcl_RemoveNumberFormat( ScTable* pTab, SCCOL nCol, SCROW nRow )
if ( pPattern->GetItemSet().GetItemState( ATTR_VALUE_FORMAT, false )
== SfxItemState::SET )
{
- auto pNewPattern = std::make_unique<ScPatternAttr>( *pPattern );
+ ScPatternAttr* pNewPattern(new ScPatternAttr( *pPattern ));
SfxItemSet& rSet = pNewPattern->GetItemSet();
rSet.ClearItem( ATTR_VALUE_FORMAT );
rSet.ClearItem( ATTR_LANGUAGE_FORMAT );
- pTab->SetPattern( nCol, nRow, std::move(pNewPattern) );
+ pTab->SetPattern( nCol, nRow, CellAttributeHolder(pNewPattern, true) );
}
}
@@ -1914,7 +1881,7 @@ struct RowEntry
}
-static const char* lcl_GetSubTotalStrId(int id)
+static TranslateId lcl_GetSubTotalStrId(int id)
{
switch ( id )
{
@@ -1937,6 +1904,30 @@ static const char* lcl_GetSubTotalStrId(int id)
}
}
+// Gets the string used for "Grand" results
+static TranslateId lcl_GetGrandSubTotalStrId(int id)
+{
+ switch ( id )
+ {
+ case SUBTOTAL_FUNC_AVE: return STR_TABLE_GRAND_AVG;
+ case SUBTOTAL_FUNC_CNT:
+ case SUBTOTAL_FUNC_CNT2: return STR_TABLE_GRAND_COUNT;
+ case SUBTOTAL_FUNC_MAX: return STR_TABLE_GRAND_MAX;
+ case SUBTOTAL_FUNC_MIN: return STR_TABLE_GRAND_MIN;
+ case SUBTOTAL_FUNC_PROD: return STR_TABLE_GRAND_PRODUCT;
+ case SUBTOTAL_FUNC_STD:
+ case SUBTOTAL_FUNC_STDP: return STR_TABLE_GRAND_STDDEV;
+ case SUBTOTAL_FUNC_SUM: return STR_TABLE_GRAND_SUM;
+ case SUBTOTAL_FUNC_VAR:
+ case SUBTOTAL_FUNC_VARP: return STR_TABLE_GRAND_VAR;
+ default:
+ {
+ return STR_EMPTYDATA;
+ // added to avoid warnings
+ }
+ }
+}
+
// new intermediate results
// rParam.nRow2 is changed!
@@ -2004,9 +1995,9 @@ bool ScTable::DoSubTotals( ScSubTotalParam& rParam )
{
for (i=0; i<=aRowEntry.nGroupNo; i++)
{
- GetString( nGroupCol[i], nStartRow, aSubString );
+ aSubString = GetString( nGroupCol[i], nStartRow );
if ( bIgnoreCase )
- aCompString[i] = ScGlobal::getCharClassPtr()->uppercase( aSubString );
+ aCompString[i] = ScGlobal::getCharClass().uppercase( aSubString );
else
aCompString[i] = aSubString;
} // aSubString stays on the last
@@ -2024,9 +2015,9 @@ bool ScTable::DoSubTotals( ScSubTotalParam& rParam )
OUString aString;
for (i=0; i<=aRowEntry.nGroupNo && !bChanged; i++)
{
- GetString( nGroupCol[i], nRow, aString );
+ aString = GetString( nGroupCol[i], nRow );
if (bIgnoreCase)
- aString = ScGlobal::getCharClassPtr()->uppercase(aString);
+ aString = ScGlobal::getCharClass().uppercase(aString);
// when sorting, blanks are separate group
// otherwise blank cells are allowed below
bChanged = ( ( !aString.isEmpty() || rParam.bDoSort ) &&
@@ -2072,7 +2063,7 @@ bool ScTable::DoSubTotals( ScSubTotalParam& rParam )
if (aOutString.isEmpty())
aOutString = ScResId( STR_EMPTYDATA );
aOutString += " ";
- const char* pStrId = STR_TABLE_ERGEBNIS;
+ TranslateId pStrId = STR_TABLE_ERGEBNIS;
if ( nResCount == 1 )
pStrId = lcl_GetSubTotalStrId(pResFunc[0]);
aOutString += ScResId(pStrId);
@@ -2084,9 +2075,9 @@ bool ScTable::DoSubTotals( ScSubTotalParam& rParam )
aRowEntry.nSubStartRow = nRow;
for (i=0; i<=aRowEntry.nGroupNo; i++)
{
- GetString( nGroupCol[i], nRow, aSubString );
+ aSubString = GetString( nGroupCol[i], nRow );
if ( bIgnoreCase )
- aCompString[i] = ScGlobal::getCharClassPtr()->uppercase( aSubString );
+ aCompString[i] = ScGlobal::getCharClass().uppercase( aSubString );
else
aCompString[i] = aSubString;
}
@@ -2143,7 +2134,7 @@ bool ScTable::DoSubTotals( ScSubTotalParam& rParam )
DBShowRow(aRowEntry.nDestRow, true);
// insert label
- OUString label = ScResId(STR_TABLE_GRAND) + " " + ScResId(lcl_GetSubTotalStrId(pResFunc[0]));
+ OUString label = ScResId(lcl_GetGrandSubTotalStrId(pResFunc[0]));
SetString(nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, nTab, label);
ApplyStyle(nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, pStyle);
}
@@ -2202,701 +2193,6 @@ bool ScTable::DoSubTotals( ScSubTotalParam& rParam )
return bSpaceLeft;
}
-namespace {
-
-class QueryEvaluator
-{
- ScDocument& mrDoc;
- svl::SharedStringPool& mrStrPool;
- const ScTable& mrTab;
- const ScQueryParam& mrParam;
- bool mpTestEqualCondition;
- utl::TransliterationWrapper* mpTransliteration;
- CollatorWrapper* mpCollator;
- const bool mbMatchWholeCell;
- const bool mbCaseSensitive;
-
- static bool isPartialTextMatchOp(const ScQueryEntry& rEntry)
- {
- switch (rEntry.eOp)
- {
- // these operators can only be used with textural comparisons.
- case SC_CONTAINS:
- case SC_DOES_NOT_CONTAIN:
- case SC_BEGINS_WITH:
- case SC_ENDS_WITH:
- case SC_DOES_NOT_BEGIN_WITH:
- case SC_DOES_NOT_END_WITH:
- return true;
- default:
- ;
- }
- return false;
- }
-
- static bool isTextMatchOp(const ScQueryEntry& rEntry)
- {
- if (isPartialTextMatchOp(rEntry))
- return true;
-
- switch (rEntry.eOp)
- {
- // these operators can be used for either textural or value comparison.
- case SC_EQUAL:
- case SC_NOT_EQUAL:
- return true;
- default:
- ;
- }
- return false;
- }
-
- bool isRealWildOrRegExp(const ScQueryEntry& rEntry) const
- {
- if (mrParam.eSearchType == utl::SearchParam::SearchType::Normal)
- return false;
-
- return isTextMatchOp(rEntry);
- }
-
- bool isTestWildOrRegExp(const ScQueryEntry& rEntry) const
- {
- if (!mpTestEqualCondition)
- return false;
-
- if (mrParam.eSearchType == utl::SearchParam::SearchType::Normal)
- return false;
-
- return (rEntry.eOp == SC_LESS_EQUAL || rEntry.eOp == SC_GREATER_EQUAL);
- }
-
- void setupTransliteratorIfNeeded()
- {
- if (!mpTransliteration)
- mpTransliteration = mrParam.bCaseSens ? ScGlobal::GetCaseTransliteration() : ScGlobal::GetpTransliteration();
- }
-
- void setupCollatorIfNeeded()
- {
- if (!mpCollator)
- mpCollator = mrParam.bCaseSens ? ScGlobal::GetCaseCollator() : ScGlobal::GetCollator();
- }
-
-public:
- QueryEvaluator(ScDocument& rDoc, const ScTable& rTab, const ScQueryParam& rParam,
- bool pTestEqualCondition) :
- mrDoc(rDoc),
- mrStrPool(rDoc.GetSharedStringPool()),
- mrTab(rTab),
- mrParam(rParam),
- mpTestEqualCondition(pTestEqualCondition),
- mpTransliteration(nullptr),
- mpCollator(nullptr),
- mbMatchWholeCell(rDoc.GetDocOptions().IsMatchWholeCell()),
- mbCaseSensitive( rParam.bCaseSens )
- {
- }
-
- bool isQueryByValue(
- const ScQueryEntry::Item& rItem, SCCOL nCol, SCROW nRow, ScRefCellValue& rCell)
- {
- if (rItem.meType == ScQueryEntry::ByString)
- return false;
-
- if (!rCell.isEmpty())
- {
- if (rCell.meType == CELLTYPE_FORMULA && rCell.mpFormula->GetErrCode() != FormulaError::NONE)
- // Error values are compared as string.
- return false;
-
- return rCell.hasNumeric();
- }
-
- return mrTab.HasValueData(nCol, nRow);
- }
-
- bool isQueryByString(
- const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem,
- SCCOL nCol, SCROW nRow, const ScRefCellValue& rCell)
- {
- if (isTextMatchOp(rEntry))
- return true;
-
- if (rItem.meType != ScQueryEntry::ByString)
- return false;
-
- if (!rCell.isEmpty())
- return rCell.hasString();
-
- return mrTab.HasStringData(nCol, nRow);
- }
-
- std::pair<bool,bool> compareByValue(
- const ScRefCellValue& rCell, SCCOL nCol, SCROW nRow,
- const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem,
- const ScInterpreterContext* pContext)
- {
- bool bOk = false;
- bool bTestEqual = false;
- double nCellVal;
- if (!rCell.isEmpty())
- {
- switch (rCell.meType)
- {
- case CELLTYPE_VALUE :
- nCellVal = rCell.mfValue;
- break;
- case CELLTYPE_FORMULA :
- nCellVal = rCell.mpFormula->GetValue();
- break;
- default:
- nCellVal = 0.0;
- }
-
- }
- else
- nCellVal = mrTab.GetValue(nCol, nRow);
-
- /* NOTE: lcl_PrepareQuery() prepares a filter query such that if a
- * date+time format was queried rEntry.bQueryByDate is not set. In
- * case other queries wanted to use this mechanism they should do
- * the same, in other words only if rEntry.nVal is an integer value
- * rEntry.bQueryByDate should be true and the time fraction be
- * stripped here. */
- if (rItem.meType == ScQueryEntry::ByDate)
- {
- sal_uInt32 nNumFmt = pContext ? mrTab.GetNumberFormat(*pContext, ScAddress(nCol, nRow, mrTab.GetTab())) :
- mrTab.GetNumberFormat(nCol, nRow);
- SvNumberFormatter* pFormatter = pContext ? pContext->GetFormatTable() : mrDoc.GetFormatTable();
- const SvNumberformat* pEntry = pFormatter->GetEntry(nNumFmt);
- if (pEntry)
- {
- SvNumFormatType nNumFmtType = pEntry->GetType();
- /* NOTE: Omitting the check for absence of
- * css::util::NumberFormat::TIME would include also date+time formatted
- * values of the same day. That may be desired in some
- * cases, querying all time values of a day, but confusing
- * in other cases. A user can always setup a standard
- * filter query for x >= date AND x < date+1 */
- if ((nNumFmtType & SvNumFormatType::DATE) && !(nNumFmtType & SvNumFormatType::TIME))
- {
- // The format is of date type. Strip off the time
- // element.
- nCellVal = ::rtl::math::approxFloor(nCellVal);
- }
- }
- }
-
- switch (rEntry.eOp)
- {
- case SC_EQUAL :
- bOk = ::rtl::math::approxEqual(nCellVal, rItem.mfVal);
- break;
- case SC_LESS :
- bOk = (nCellVal < rItem.mfVal) && !::rtl::math::approxEqual(nCellVal, rItem.mfVal);
- break;
- case SC_GREATER :
- bOk = (nCellVal > rItem.mfVal) && !::rtl::math::approxEqual(nCellVal, rItem.mfVal);
- break;
- case SC_LESS_EQUAL :
- bOk = (nCellVal < rItem.mfVal) || ::rtl::math::approxEqual(nCellVal, rItem.mfVal);
- if ( bOk && mpTestEqualCondition )
- bTestEqual = ::rtl::math::approxEqual(nCellVal, rItem.mfVal);
- break;
- case SC_GREATER_EQUAL :
- bOk = (nCellVal > rItem.mfVal) || ::rtl::math::approxEqual( nCellVal, rItem.mfVal);
- if ( bOk && mpTestEqualCondition )
- bTestEqual = ::rtl::math::approxEqual(nCellVal, rItem.mfVal);
- break;
- case SC_NOT_EQUAL :
- bOk = !::rtl::math::approxEqual(nCellVal, rItem.mfVal);
- break;
- default:
- {
- // added to avoid warnings
- }
- }
-
- return std::pair<bool,bool>(bOk, bTestEqual);
- }
-
- std::pair<bool,bool> compareByString(
- const ScRefCellValue& rCell, SCROW nRow, const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem,
- const ScInterpreterContext* pContext)
- {
- if (!rCell.isEmpty())
- {
- if (rCell.meType == CELLTYPE_FORMULA && rCell.mpFormula->GetErrCode() != FormulaError::NONE)
- {
- // Error cell is evaluated as string (for now).
- const svl::SharedString aCellStr = mrStrPool.intern(ScGlobal::GetErrorString(rCell.mpFormula->GetErrCode()));
- return compareByStringComparator(rEntry, rItem, &aCellStr, nullptr);
- }
- else if (rCell.meType == CELLTYPE_STRING)
- {
- return compareByStringComparator(rEntry, rItem, rCell.mpString, nullptr);
- }
- else
- {
- sal_uInt32 nFormat = pContext ? mrTab.GetNumberFormat( *pContext, ScAddress(static_cast<SCCOL>(rEntry.nField), nRow, mrTab.GetTab()) ) :
- mrTab.GetNumberFormat( static_cast<SCCOL>(rEntry.nField), nRow );
- OUString aStr;
- SvNumberFormatter* pFormatter = pContext ? pContext->GetFormatTable() : mrDoc.GetFormatTable();
- ScCellFormat::GetInputString(rCell, nFormat, aStr, *pFormatter, mrDoc, rEntry.bDoQuery);
- return compareByStringComparator(rEntry, rItem, nullptr, &aStr);
- }
- }
- else
- {
- OUString aStr;
- mrTab.GetInputString(static_cast<SCCOL>(rEntry.nField), nRow, aStr);
- return compareByStringComparator(rEntry, rItem, nullptr, &aStr);
- }
- }
-
- // Called from compareByString() method, where different sources of strings are checked.
- // The value is placed inside one parameter: [pValueSource1] or [pValueSource2] but never in both.
- std::pair<bool,bool> compareByStringComparator(const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem,
- const svl::SharedString* pValueSource1, const OUString * pValueSource2)
- {
- bool bOk = false;
- bool bTestEqual = false;
- bool bMatchWholeCell = mbMatchWholeCell;
- if (isPartialTextMatchOp(rEntry))
- // may have to do partial textural comparison.
- bMatchWholeCell = false;
-
- const bool bRealWildOrRegExp = isRealWildOrRegExp(rEntry);
- const bool bTestWildOrRegExp = isTestWildOrRegExp(rEntry);
-
- // [pValueSource1] or [pValueSource2] but never both of them or none of them
- assert((pValueSource1 != nullptr) != (pValueSource2 != nullptr));
-
- if ( bRealWildOrRegExp || bTestWildOrRegExp )
- {
- const OUString & rValue = pValueSource1 ? pValueSource1->getString() : *pValueSource2;
-
- sal_Int32 nStart = 0;
- sal_Int32 nEnd = rValue.getLength();
-
- // from 614 on, nEnd is behind the found text
- bool bMatch = false;
- if ( rEntry.eOp == SC_ENDS_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH )
- {
- nEnd = 0;
- nStart = rValue.getLength();
- bMatch = rEntry.GetSearchTextPtr( mrParam.eSearchType, mrParam.bCaseSens, bMatchWholeCell )
- ->SearchBackward(rValue, &nStart, &nEnd);
- }
- else
- {
- bMatch = rEntry.GetSearchTextPtr( mrParam.eSearchType, mrParam.bCaseSens, bMatchWholeCell )
- ->SearchForward(rValue, &nStart, &nEnd);
- }
- if ( bMatch && bMatchWholeCell
- && (nStart != 0 || nEnd != rValue.getLength()) )
- bMatch = false; // RegExp must match entire cell string
- if ( bRealWildOrRegExp )
- {
- switch (rEntry.eOp)
- {
- case SC_EQUAL:
- case SC_CONTAINS:
- bOk = bMatch;
- break;
- case SC_NOT_EQUAL:
- case SC_DOES_NOT_CONTAIN:
- bOk = !bMatch;
- break;
- case SC_BEGINS_WITH:
- bOk = ( bMatch && (nStart == 0) );
- break;
- case SC_DOES_NOT_BEGIN_WITH:
- bOk = !( bMatch && (nStart == 0) );
- break;
- case SC_ENDS_WITH:
- bOk = ( bMatch && (nEnd == rValue.getLength()) );
- break;
- case SC_DOES_NOT_END_WITH:
- bOk = !( bMatch && (nEnd == rValue.getLength()) );
- break;
- default:
- {
- // added to avoid warnings
- }
- }
- }
- else
- bTestEqual = bMatch;
- }
- if ( !bRealWildOrRegExp )
- {
- // Simple string matching i.e. no regexp match.
- if (isTextMatchOp(rEntry))
- {
- if (rItem.meType != ScQueryEntry::ByString && rItem.maString.isEmpty())
- {
- // #i18374# When used from functions (match, countif, sumif, vlookup, hlookup, lookup),
- // the query value is assigned directly, and the string is empty. In that case,
- // don't find any string (isEqual would find empty string results in formula cells).
- bOk = false;
- if ( rEntry.eOp == SC_NOT_EQUAL )
- bOk = !bOk;
- }
- else if ( bMatchWholeCell )
- {
- if (pValueSource1)
- {
- // Fast string equality check by comparing string identifiers.
- if (mrParam.bCaseSens)
- {
- bOk = pValueSource1->getData() == rItem.maString.getData();
- }
- else
- {
- bOk = pValueSource1->getDataIgnoreCase() == rItem.maString.getDataIgnoreCase();
- }
- }
- else // if (pValueSource2)
- {
- if (mrParam.bCaseSens)
- {
- bOk = (*pValueSource2 == rItem.maString.getString());
- }
- else
- {
- // fallback
- const svl::SharedString rSource2(mrStrPool.intern(*pValueSource2));
- // Fast string equality check by comparing string identifiers.
- bOk = rSource2.getDataIgnoreCase() == rItem.maString.getDataIgnoreCase();
- }
- }
-
- if ( rEntry.eOp == SC_NOT_EQUAL )
- bOk = !bOk;
- }
- else
- {
- // Where do we find a match (if at all)
- sal_Int32 nStrPos;
-
- if (!mbCaseSensitive)
- { // Common case for vlookup etc.
- const svl::SharedString rSource(pValueSource1? *pValueSource1 : mrStrPool.intern(*pValueSource2));
-
- const rtl_uString *pQuer = rItem.maString.getDataIgnoreCase();
- const rtl_uString *pCellStr = rSource.getDataIgnoreCase();
-
- assert(pQuer != nullptr);
- assert(pCellStr != nullptr);
-
- const sal_Int32 nIndex = (rEntry.eOp == SC_ENDS_WITH ||
- rEntry.eOp == SC_DOES_NOT_END_WITH) ?
- (pCellStr->length - pQuer->length) : 0;
-
- if (nIndex < 0)
- nStrPos = -1;
- else if (rEntry.eOp == SC_EQUAL ||
- rEntry.eOp == SC_NOT_EQUAL)
- {
- nStrPos = pCellStr == pQuer ? 0 : -1;
- }
- else
- { // OUString::indexOf
- nStrPos = rtl_ustr_indexOfStr_WithLength(
- pCellStr->buffer + nIndex, pCellStr->length - nIndex,
- pQuer->buffer, pQuer->length );
-
- if (nStrPos >= 0)
- nStrPos += nIndex;
- }
- }
- else
- {
- const OUString & rValue = pValueSource1 ? pValueSource1->getString() : *pValueSource2;
- const OUString aQueryStr = rItem.maString.getString();
- const LanguageType nLang = ScGlobal::xSysLocale->GetLanguageTag().getLanguageType();
- setupTransliteratorIfNeeded();
- const OUString aCell( mpTransliteration->transliterate(
- rValue, nLang, 0, rValue.getLength(),
- nullptr ) );
-
- const OUString aQuer( mpTransliteration->transliterate(
- aQueryStr, nLang, 0, aQueryStr.getLength(),
- nullptr ) );
-
- const sal_Int32 nIndex = (rEntry.eOp == SC_ENDS_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH) ?
- (aCell.getLength() - aQuer.getLength()) : 0;
- nStrPos = ((nIndex < 0) ? -1 : aCell.indexOf( aQuer, nIndex ));
- }
- switch (rEntry.eOp)
- {
- case SC_EQUAL:
- bOk = ( nStrPos == 0 );
- break;
- case SC_CONTAINS:
- bOk = ( nStrPos != -1 );
- break;
- case SC_NOT_EQUAL:
- bOk = ( nStrPos != 0 );
- break;
- case SC_DOES_NOT_CONTAIN:
- bOk = ( nStrPos == -1 );
- break;
- case SC_BEGINS_WITH:
- bOk = ( nStrPos == 0 );
- break;
- case SC_DOES_NOT_BEGIN_WITH:
- bOk = ( nStrPos != 0 );
- break;
- case SC_ENDS_WITH:
- bOk = ( nStrPos >= 0 );
- break;
- case SC_DOES_NOT_END_WITH:
- bOk = ( nStrPos < 0 );
- break;
- default:
- {
- // added to avoid warnings
- }
- }
- }
- }
- else
- { // use collator here because data was probably sorted
- const OUString & rValue = pValueSource1 ? pValueSource1->getString() : *pValueSource2;
- setupCollatorIfNeeded();
- sal_Int32 nCompare = mpCollator->compareString(
- rValue, rItem.maString.getString());
- switch (rEntry.eOp)
- {
- case SC_LESS :
- bOk = (nCompare < 0);
- break;
- case SC_GREATER :
- bOk = (nCompare > 0);
- break;
- case SC_LESS_EQUAL :
- bOk = (nCompare <= 0);
- if ( bOk && mpTestEqualCondition && !bTestEqual )
- bTestEqual = (nCompare == 0);
- break;
- case SC_GREATER_EQUAL :
- bOk = (nCompare >= 0);
- if ( bOk && mpTestEqualCondition && !bTestEqual )
- bTestEqual = (nCompare == 0);
- break;
- default:
- {
- // added to avoid warnings
- }
- }
- }
- }
-
- return std::pair<bool,bool>(bOk, bTestEqual);
- }
-
- std::pair<bool, bool> compareByTextColor(SCCOL nCol, SCROW nRow, SCTAB nTab,
- const ScQueryEntry::Item& rItem)
- {
- ScAddress aPos(nCol, nRow, nTab);
- const SvxColorItem* pColor = mrDoc.GetAttr(aPos, ATTR_FONT_COLOR);
- Color color = pColor->GetValue();
- bool bMatch = rItem.maColor == color;
- return std::pair<bool, bool>(bMatch, false);
- }
-
- std::pair<bool, bool> compareByBackgroundColor(SCCOL nCol, SCROW nRow, SCTAB nTab,
- const ScQueryEntry::Item& rItem)
- {
- ScAddress aPos(nCol, nRow, nTab);
- const SvxBrushItem* pBrush = mrDoc.GetAttr(aPos, ATTR_BACKGROUND);
- Color color = pBrush->GetColor();
- bool bMatch = rItem.maColor == color;
- return std::pair<bool, bool>(bMatch, false);
- }
-
- // To be called only if both isQueryByValue() and isQueryByString()
- // returned false and range lookup is wanted! In range lookup comparison
- // numbers are less than strings. Nothing else is compared.
- std::pair<bool,bool> compareByRangeLookup(
- const ScRefCellValue& rCell, SCCOL nCol, SCROW nRow,
- const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem)
- {
- bool bTestEqual = false;
-
- if (rItem.meType == ScQueryEntry::ByString && rEntry.eOp != SC_LESS && rEntry.eOp != SC_LESS_EQUAL)
- return std::pair<bool,bool>(false, bTestEqual);
-
- if (rItem.meType != ScQueryEntry::ByString && rEntry.eOp != SC_GREATER && rEntry.eOp != SC_GREATER_EQUAL)
- return std::pair<bool,bool>(false, bTestEqual);
-
- if (!rCell.isEmpty())
- {
- if (rItem.meType == ScQueryEntry::ByString)
- {
- if (rCell.meType == CELLTYPE_FORMULA && rCell.mpFormula->GetErrCode() != FormulaError::NONE)
- // Error values are compared as string.
- return std::pair<bool,bool>(false, bTestEqual);
-
- return std::pair<bool,bool>(rCell.hasNumeric(), bTestEqual);
- }
-
- return std::pair<bool,bool>(!rCell.hasNumeric(), bTestEqual);
- }
-
- if (rItem.meType == ScQueryEntry::ByString)
- return std::pair<bool,bool>(mrTab.HasValueData(nCol, nRow), bTestEqual);
-
- return std::pair<bool,bool>(!mrTab.HasValueData(nCol, nRow), bTestEqual);
- }
-};
-
-}
-
-bool ScTable::ValidQuery(
- SCROW nRow, const ScQueryParam& rParam, const ScRefCellValue* pCell, bool* pbTestEqualCondition,
- const ScInterpreterContext* pContext, sc::TableColumnBlockPositionSet* pBlockPos)
-{
- if (!rParam.GetEntry(0).bDoQuery)
- return true;
-
- //---------------------------------------------------------------
-
- const SCSIZE nFixedBools = 32;
- bool aBool[nFixedBools];
- bool aTest[nFixedBools];
- SCSIZE nEntryCount = rParam.GetEntryCount();
- bool* pPasst = ( nEntryCount <= nFixedBools ? &aBool[0] : new bool[nEntryCount] );
- bool* pTest = ( nEntryCount <= nFixedBools ? &aTest[0] : new bool[nEntryCount] );
-
- tools::Long nPos = -1;
- QueryEvaluator aEval(rDocument, *this, rParam, pbTestEqualCondition != nullptr);
- ScQueryParam::const_iterator it, itBeg = rParam.begin(), itEnd = rParam.end();
- for (it = itBeg; it != itEnd && (*it)->bDoQuery; ++it)
- {
- const ScQueryEntry& rEntry = **it;
- SCCOL nCol = static_cast<SCCOL>(rEntry.nField);
-
- // We can only handle one single direct query passed as a known pCell,
- // subsequent queries have to obtain the cell.
- ScRefCellValue aCell;
- if(pCell && it == itBeg)
- aCell = *pCell;
- else if( pBlockPos )
- { // hinted mdds access
- ScColumn* column = FetchColumn(nCol);
- aCell = column->GetCellValue(*pBlockPos->getBlockPosition( nCol ), nRow);
- }
- else
- aCell = GetCellValue(nCol, nRow);
-
- std::pair<bool,bool> aRes(false, false);
-
- const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
- if (rItems.size() == 1 && rItems.front().meType == ScQueryEntry::ByEmpty)
- {
- bool hasData;
- if( pBlockPos )
- {
- ScColumn* column = FetchColumn(rEntry.nField);
- hasData = column->HasDataAt(*pBlockPos->getBlockPosition(rEntry.nField), nRow);
- }
- else
- hasData = aCol[rEntry.nField].HasDataAt(nRow);
- if (rEntry.IsQueryByEmpty())
- aRes.first = !hasData;
- else
- {
- assert(rEntry.IsQueryByNonEmpty());
- aRes.first = hasData;
- }
- }
- else
- {
- for (const auto& rItem : rItems)
- {
- if (rItem.meType == ScQueryEntry::ByTextColor)
- {
- std::pair<bool, bool> aThisRes
- = aEval.compareByTextColor(nCol, nRow, nTab, rItem);
- aRes.first |= aThisRes.first;
- aRes.second |= aThisRes.second;
- }
- else if (rItem.meType == ScQueryEntry::ByBackgroundColor)
- {
- std::pair<bool,bool> aThisRes =
- aEval.compareByBackgroundColor(nCol, nRow, nTab, rItem);
- aRes.first |= aThisRes.first;
- aRes.second |= aThisRes.second;
- }
- else if (aEval.isQueryByValue(rItem, nCol, nRow, aCell))
- {
- std::pair<bool,bool> aThisRes =
- aEval.compareByValue(aCell, nCol, nRow, rEntry, rItem, pContext);
- aRes.first |= aThisRes.first;
- aRes.second |= aThisRes.second;
- }
- else if (aEval.isQueryByString(rEntry, rItem, nCol, nRow, aCell))
- {
- std::pair<bool,bool> aThisRes =
- aEval.compareByString(aCell, nRow, rEntry, rItem, pContext);
- aRes.first |= aThisRes.first;
- aRes.second |= aThisRes.second;
- }
- else if (rParam.mbRangeLookup)
- {
- std::pair<bool,bool> aThisRes =
- aEval.compareByRangeLookup(aCell, nCol, nRow, rEntry, rItem);
- aRes.first |= aThisRes.first;
- aRes.second |= aThisRes.second;
- }
-
- if (aRes.first && aRes.second)
- break;
- }
- }
-
- if (nPos == -1)
- {
- nPos++;
- pPasst[nPos] = aRes.first;
- pTest[nPos] = aRes.second;
- }
- else
- {
- if (rEntry.eConnect == SC_AND)
- {
- pPasst[nPos] = pPasst[nPos] && aRes.first;
- pTest[nPos] = pTest[nPos] && aRes.second;
- }
- else
- {
- nPos++;
- pPasst[nPos] = aRes.first;
- pTest[nPos] = aRes.second;
- }
- }
- }
-
- for ( tools::Long j=1; j <= nPos; j++ )
- {
- pPasst[0] = pPasst[0] || pPasst[j];
- pTest[0] = pTest[0] || pTest[j];
- }
-
- bool bRet = pPasst[0];
- if ( pPasst != &aBool[0] )
- delete [] pPasst;
- if ( pbTestEqualCondition )
- *pbTestEqualCondition = pTest[0];
- if ( pTest != &aTest[0] )
- delete [] pTest;
-
- return bRet;
-}
-
void ScTable::TopTenQuery( ScQueryParam& rParam )
{
bool bSortCollatorInitialized = false;
@@ -3018,7 +2314,7 @@ void ScTable::TopTenQuery( ScQueryParam& rParam )
namespace {
-bool CanOptimizeQueryStringToNumber( SvNumberFormatter* pFormatter, sal_uInt32 nFormatIndex, bool& bDateFormat )
+bool CanOptimizeQueryStringToNumber( const SvNumberFormatter* pFormatter, sal_uInt32 nFormatIndex, bool& bDateFormat )
{
// tdf#105629: ScQueryEntry::ByValue queries are faster than ScQueryEntry::ByString.
// The problem with this optimization is that the autofilter dialog apparently converts
@@ -3048,15 +2344,16 @@ bool CanOptimizeQueryStringToNumber( SvNumberFormatter* pFormatter, sal_uInt32 n
class PrepareQueryItem
{
const ScDocument& mrDoc;
+ const bool mbRoundForFilter;
public:
- explicit PrepareQueryItem(const ScDocument& rDoc) : mrDoc(rDoc) {}
+ explicit PrepareQueryItem(const ScDocument& rDoc, bool bRoundForFilter) :
+ mrDoc(rDoc), mbRoundForFilter(bRoundForFilter) {}
void operator() (ScQueryEntry::Item& rItem)
{
- if (rItem.meType != ScQueryEntry::ByString && rItem.meType != ScQueryEntry::ByDate)
- return;
+ rItem.mbRoundForFilter = mbRoundForFilter;
- if (rItem.mbFormattedValue)
+ if (rItem.meType != ScQueryEntry::ByString && rItem.meType != ScQueryEntry::ByDate)
return;
sal_uInt32 nIndex = 0;
@@ -3097,7 +2394,7 @@ public:
}
};
-void lcl_PrepareQuery( const ScDocument* pDoc, ScTable* pTab, ScQueryParam& rParam )
+void lcl_PrepareQuery( const ScDocument* pDoc, ScTable* pTab, ScQueryParam& rParam, bool bRoundForFilter )
{
bool bTopTen = false;
SCSIZE nEntryCount = rParam.GetEntryCount();
@@ -3109,7 +2406,7 @@ void lcl_PrepareQuery( const ScDocument* pDoc, ScTable* pTab, ScQueryParam& rPar
continue;
ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
- std::for_each(rItems.begin(), rItems.end(), PrepareQueryItem(*pDoc));
+ std::for_each(rItems.begin(), rItems.end(), PrepareQueryItem(*pDoc, bRoundForFilter));
if ( !bTopTen )
{
@@ -3140,7 +2437,7 @@ void lcl_PrepareQuery( const ScDocument* pDoc, ScTable* pTab, ScQueryParam& rPar
void ScTable::PrepareQuery( ScQueryParam& rQueryParam )
{
- lcl_PrepareQuery(&rDocument, this, rQueryParam);
+ lcl_PrepareQuery(&rDocument, this, rQueryParam, false);
}
SCSIZE ScTable::Query(const ScQueryParam& rParamOrg, bool bKeepSub)
@@ -3158,7 +2455,7 @@ SCSIZE ScTable::Query(const ScQueryParam& rParamOrg, bool bKeepSub)
SCROW nOutRow = 0;
SCROW nHeader = aParam.bHasHeader ? 1 : 0;
- lcl_PrepareQuery(&rDocument, this, aParam);
+ lcl_PrepareQuery(&rDocument, this, aParam, true);
if (!aParam.bInplace)
{
@@ -3169,24 +2466,25 @@ SCSIZE ScTable::Query(const ScQueryParam& rParamOrg, bool bKeepSub)
}
sc::TableColumnBlockPositionSet blockPos( GetDoc(), nTab ); // cache mdds access
+ ScQueryEvaluator queryEvaluator(GetDoc(), *this, aParam);
SCROW nRealRow2 = aParam.nRow2;
for (SCROW j = aParam.nRow1 + nHeader; j <= nRealRow2; ++j)
{
bool bResult; // Filter result
- bool bValid = ValidQuery(j, aParam, nullptr, nullptr, nullptr, &blockPos);
+ bool bValid = queryEvaluator.ValidQuery(j, nullptr, &blockPos);
if (!bValid && bKeepSub) // Keep subtotals
{
for (SCCOL nCol=aParam.nCol1; nCol<=aParam.nCol2 && !bValid; nCol++)
{
ScRefCellValue aCell = GetCellValue(nCol, j);
- if (aCell.meType != CELLTYPE_FORMULA)
+ if (aCell.getType() != CELLTYPE_FORMULA)
continue;
- if (!aCell.mpFormula->IsSubTotal())
+ if (!aCell.getFormula()->IsSubTotal())
continue;
- if (RefVisible(aCell.mpFormula))
+ if (RefVisible(aCell.getFormula()))
bValid = true;
}
}
@@ -3199,8 +2497,7 @@ SCSIZE ScTable::Query(const ScQueryParam& rParamOrg, bool bKeepSub)
OUStringBuffer aStr;
for (SCCOL k=aParam.nCol1; k <= aParam.nCol2; k++)
{
- OUString aCellStr;
- GetString(k, j, aCellStr);
+ OUString aCellStr = GetString(k, j);
aStr.append(aCellStr + u"\x0001");
}
@@ -3259,16 +2556,15 @@ bool ScTable::CreateExcelQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow
// First row must be column headers
while (bValid && (nCol <= nCol2))
{
- OUString aQueryStr;
- GetUpperCellString(nCol, nRow1, aQueryStr);
+ OUString aQueryStr = GetUpperCellString(nCol, nRow1);
bool bFound = false;
SCCOL i = rQueryParam.nCol1;
while (!bFound && (i <= nDBCol2))
{
if ( nTab == nDBTab )
- GetUpperCellString(i, nDBRow1, aCellStr);
+ aCellStr = GetUpperCellString(i, nDBRow1);
else
- rDocument.GetUpperCellString(i, nDBRow1, nDBTab, aCellStr);
+ aCellStr = rDocument.GetUpperCellString(i, nDBRow1, nDBTab);
bFound = (aCellStr == aQueryStr);
if (!bFound) i++;
}
@@ -3280,8 +2576,8 @@ bool ScTable::CreateExcelQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow
}
if (bValid)
{
- sal_uLong nVisible = 0;
- for ( nCol=nCol1; nCol<=nCol2; nCol++ )
+ SCSIZE nVisible = 0;
+ for ( nCol=nCol1; nCol<=ClampToAllocatedColumns(nCol2); nCol++ )
nVisible += aCol[nCol].VisibleCount( nRow1+1, nRow2 );
if ( nVisible > SCSIZE_MAX / sizeof(void*) )
@@ -3301,7 +2597,7 @@ bool ScTable::CreateExcelQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow
nCol = nCol1;
while (nCol <= nCol2)
{
- GetInputString( nCol, nRow, aCellStr );
+ aCellStr = GetInputString( nCol, nRow );
if (!aCellStr.isEmpty())
{
if (nIndex < nNewEntries)
@@ -3359,7 +2655,7 @@ bool ScTable::CreateStarQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2
// First column AND/OR
if (nIndex > 0)
{
- GetUpperCellString(nCol1, nRow, aCellStr);
+ aCellStr = GetUpperCellString(nCol1, nRow);
if ( aCellStr == ScResId(STR_TABLE_AND) )
{
rEntry.eConnect = SC_AND;
@@ -3375,14 +2671,14 @@ bool ScTable::CreateStarQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2
if ((nIndex < 1) || bValid)
{
bool bFound = false;
- GetUpperCellString(nCol1 + 1, nRow, aCellStr);
+ aCellStr = GetUpperCellString(nCol1 + 1, nRow);
for (SCCOL i=rQueryParam.nCol1; (i <= nDBCol2) && (!bFound); i++)
{
OUString aFieldStr;
if ( nTab == nDBTab )
- GetUpperCellString(i, nDBRow1, aFieldStr);
+ aFieldStr = GetUpperCellString(i, nDBRow1);
else
- rDocument.GetUpperCellString(i, nDBRow1, nDBTab, aFieldStr);
+ aFieldStr = rDocument.GetUpperCellString(i, nDBRow1, nDBTab);
bFound = (aCellStr == aFieldStr);
if (bFound)
{
@@ -3396,7 +2692,7 @@ bool ScTable::CreateStarQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2
// Third column operator =<>...
if (bValid)
{
- GetUpperCellString(nCol1 + 2, nRow, aCellStr);
+ aCellStr = GetUpperCellString(nCol1 + 2, nRow);
if (aCellStr.startsWith("<"))
{
if (aCellStr[1] == '>')
@@ -3420,8 +2716,7 @@ bool ScTable::CreateStarQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2
// Fourth column values
if (bValid)
{
- OUString aStr;
- GetString(nCol1 + 3, nRow, aStr);
+ OUString aStr = GetString(nCol1 + 3, nRow);
rEntry.GetQueryItem().maString = rPool.intern(aStr);
rEntry.bDoQuery = true;
}
@@ -3480,14 +2775,6 @@ bool ScTable::HasColHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCR
* evaluate it has header row, but that doesn't make much sense. */
return false;
- if (nStartCol == nEndCol)
- {
- CellType eFirstCellType = GetCellType(nStartCol, nStartRow);
- CellType eSecondCellType = GetCellType(nStartCol, nStartRow+1);
- return ((eFirstCellType == CELLTYPE_STRING || eFirstCellType == CELLTYPE_EDIT) &&
- (eSecondCellType != CELLTYPE_STRING && eSecondCellType != CELLTYPE_EDIT));
- }
-
for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
{
CellType eType = GetCellType( nCol, nStartRow );
@@ -3517,14 +2804,6 @@ bool ScTable::HasRowHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCR
* evaluate it has header column, but that doesn't make much sense. */
return false;
- if (nStartRow == nEndRow)
- {
- CellType eFirstCellType = GetCellType(nStartCol, nStartRow);
- CellType eSecondCellType = GetCellType(nStartCol+1, nStartRow);
- return ((eFirstCellType == CELLTYPE_STRING || eFirstCellType == CELLTYPE_EDIT) &&
- (eSecondCellType != CELLTYPE_STRING && eSecondCellType != CELLTYPE_EDIT));
- }
-
for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++)
{
CellType eType = GetCellType( nStartCol, nRow );
@@ -3553,7 +2832,13 @@ void ScTable::GetFilterEntries( SCCOL nCol, SCROW nRow1, SCROW nRow2, ScFilterEn
sc::ColumnBlockConstPosition aBlockPos;
aCol[nCol].InitBlockPosition(aBlockPos);
- aCol[nCol].GetFilterEntries(aBlockPos, nRow1, nRow2, rFilterEntries, bFiltering);
+ aCol[nCol].GetFilterEntries(aBlockPos, nRow1, nRow2, rFilterEntries, bFiltering, false /*bFilteredRow*/);
+
+ SCROW nLastRow = aBlockPos.miCellPos->position;
+ if (nLastRow < nRow2)
+ {
+ aCol[nCol].GetBackColorFilterEntries(nLastRow, nRow2, rFilterEntries);
+ }
}
void ScTable::GetFilteredFilterEntries(
@@ -3569,24 +2854,31 @@ void ScTable::GetFilteredFilterEntries(
ScQueryParam aParam( rParam );
aParam.RemoveEntryByField(nCol);
- lcl_PrepareQuery(&rDocument, this, aParam);
+ lcl_PrepareQuery(&rDocument, this, aParam, true);
+ ScQueryEvaluator queryEvaluator(GetDoc(), *this, aParam);
for ( SCROW j = nRow1; j <= nRow2; ++j )
{
- if (ValidQuery(j, aParam))
+ if (queryEvaluator.ValidQuery(j))
{
- aCol[nCol].GetFilterEntries(aBlockPos, j, j, rFilterEntries, bFiltering);
+ aCol[nCol].GetFilterEntries(aBlockPos, j, j, rFilterEntries, bFiltering, false/*bFilteredRow*/);
+ }
+ else
+ {
+ aCol[nCol].GetFilterEntries(aBlockPos, j, j, rFilterEntries, bFiltering, true/*bFilteredRow*/);
}
}
}
bool ScTable::GetDataEntries(SCCOL nCol, SCROW nRow, std::set<ScTypedStrData>& rStrings)
{
+ if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
+ return false;
return aCol[nCol].GetDataEntries( nRow, rStrings);
}
-sal_uLong ScTable::GetCellCount() const
+sal_uInt64 ScTable::GetCellCount() const
{
- sal_uLong nCellCount = 0;
+ sal_uInt64 nCellCount = 0;
for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ )
nCellCount += aCol[nCol].GetCellCount();
@@ -3594,9 +2886,9 @@ sal_uLong ScTable::GetCellCount() const
return nCellCount;
}
-sal_uLong ScTable::GetWeightedCount() const
+sal_uInt64 ScTable::GetWeightedCount() const
{
- sal_uLong nCellCount = 0;
+ sal_uInt64 nCellCount = 0;
for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ )
nCellCount += aCol[nCol].GetWeightedCount();
@@ -3604,9 +2896,9 @@ sal_uLong ScTable::GetWeightedCount() const
return nCellCount;
}
-sal_uLong ScTable::GetWeightedCount(SCROW nStartRow, SCROW nEndRow) const
+sal_uInt64 ScTable::GetWeightedCount(SCROW nStartRow, SCROW nEndRow) const
{
- sal_uLong nCellCount = 0;
+ sal_uInt64 nCellCount = 0;
for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ )
nCellCount += aCol[nCol].GetWeightedCount(nStartRow, nEndRow);
@@ -3614,9 +2906,9 @@ sal_uLong ScTable::GetWeightedCount(SCROW nStartRow, SCROW nEndRow) const
return nCellCount;
}
-sal_uLong ScTable::GetCodeCount() const
+sal_uInt64 ScTable::GetCodeCount() const
{
- sal_uLong nCodeCount = 0;
+ sal_uInt64 nCodeCount = 0;
for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ )
if ( aCol[nCol].GetCellCount() )
@@ -3648,9 +2940,9 @@ void ScTable::UpdateSelectionFunction( ScFunctionData& rData, const ScMarkData&
ScRangeList aRanges = rMark.GetMarkedRangesForTab( nTab );
ScRange aMarkArea( ScAddress::UNINITIALIZED );
if (rMark.IsMultiMarked())
- rMark.GetMultiMarkArea( aMarkArea );
+ aMarkArea = rMark.GetMultiMarkArea();
else if (rMark.IsMarked())
- rMark.GetMarkArea( aMarkArea );
+ aMarkArea = rMark.GetMarkArea();
else
{
assert(!"ScTable::UpdateSelectionFunction - called without anything marked");
diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx
index 0f1f7193fe59..438608dc8492 100644
--- a/sc/source/core/data/table4.cxx
+++ b/sc/source/core/data/table4.cxx
@@ -23,10 +23,13 @@
#include <editeng/editeng.hxx>
#include <editeng/eeitem.hxx>
#include <editeng/escapementitem.hxx>
+#include <editeng/brushitem.hxx>
+#include <svl/numformat.hxx>
#include <svl/zforlist.hxx>
#include <vcl/keycodes.hxx>
#include <rtl/math.hxx>
#include <unotools/charclass.hxx>
+#include <tools/duration.hxx>
#include <osl/diagnose.h>
#include <attrib.hxx>
@@ -46,6 +49,7 @@
#include <editutil.hxx>
#include <listenercontext.hxx>
#include <scopetools.hxx>
+#include <o3tl/string_view.hxx>
#include <math.h>
#include <memory>
@@ -68,7 +72,7 @@ short lcl_DecompValueString( OUString& rValue, sal_Int32& nVal, sal_uInt16* pMin
sal_Int32 nNum = 0;
if ( p[nNum] == '-' || p[nNum] == '+' )
nNum = nSign = 1;
- while ( p[nNum] && CharClass::isAsciiNumeric( OUString(p[nNum]) ) )
+ while ( p[nNum] && CharClass::isAsciiNumeric( std::u16string_view(&p[nNum], 1) ) )
nNum++;
sal_Unicode cNext = p[nNum]; // 0 if at the end
@@ -77,9 +81,9 @@ short lcl_DecompValueString( OUString& rValue, sal_Int32& nVal, sal_uInt16* pMin
// #i5550# If there are numbers at the beginning and the end,
// prefer the one at the beginning only if it's followed by a space.
// Otherwise, use the number at the end, to enable things like IP addresses.
- if ( nNum > nSign && ( cNext == 0 || cNext == ' ' || !CharClass::isAsciiNumeric(OUString(cLast)) ) )
+ if ( nNum > nSign && ( cNext == 0 || cNext == ' ' || !CharClass::isAsciiNumeric(std::u16string_view(&cLast, 1)) ) )
{ // number at the beginning
- nVal = rValue.copy( 0, nNum ).toInt32();
+ nVal = o3tl::toInt32(rValue.subView( 0, nNum ));
// any number with a leading zero sets the minimum number of digits
if ( p[nSign] == '0' && pMinDigits && ( nNum - nSign > *pMinDigits ) )
*pMinDigits = nNum - nSign;
@@ -90,7 +94,7 @@ short lcl_DecompValueString( OUString& rValue, sal_Int32& nVal, sal_uInt16* pMin
{
nSign = 0;
sal_Int32 nEnd = nNum = rValue.getLength() - 1;
- while ( nNum && CharClass::isAsciiNumeric( OUString(p[nNum]) ) )
+ while ( nNum && CharClass::isAsciiNumeric( std::u16string_view(&p[nNum], 1) ) )
nNum--;
if ( p[nNum] == '-' || p[nNum] == '+' )
{
@@ -99,7 +103,7 @@ short lcl_DecompValueString( OUString& rValue, sal_Int32& nVal, sal_uInt16* pMin
}
if ( nNum < nEnd - nSign )
{ // number at the end
- nVal = rValue.copy( nNum + 1 ).toInt32();
+ nVal = o3tl::toInt32(rValue.subView( nNum + 1 ));
// any number with a leading zero sets the minimum number of digits
if ( p[nNum+1+nSign] == '0' && pMinDigits && ( nEnd - nNum - nSign > *pMinDigits ) )
*pMinDigits = nEnd - nNum - nSign;
@@ -123,9 +127,9 @@ OUString lcl_ValueString( sal_Int32 nValue, sal_uInt16 nMinDigits )
OUString aStr = OUString::number( std::abs( nValue ) );
if ( aStr.getLength() < nMinDigits )
{
- OUStringBuffer aZero;
+ OUStringBuffer aZero(nMinDigits);
comphelper::string::padToLength(aZero, nMinDigits - aStr.getLength(), '0');
- aStr = aZero.makeStringAndClear() + aStr;
+ aStr = aZero.append(aStr).makeStringAndClear();
}
// nMinDigits doesn't include the '-' sign -> add after inserting zeros
if ( nValue < 0 )
@@ -212,11 +216,21 @@ double approxDiff( double a, double b )
const int nExpArg = static_cast<int>(floor(log10(std::max(aa, ab)))) - 15;
return rtl::math::round(c, -std::max(nExp, nExpArg));
}
+
+double approxTypedDiff( double a, double b, bool bTime, tools::Duration& rDuration )
+{
+ if (bTime)
+ {
+ rDuration = tools::Duration(a - b);
+ return rDuration.GetInDays();
+ }
+ return approxDiff( a, b);
+}
}
void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
FillCmd& rCmd, FillDateCmd& rDateCmd,
- double& rInc, sal_uInt16& rMinDigits,
+ double& rInc, tools::Duration& rDuration, sal_uInt16& rMinDigits,
ScUserListData*& rListData, sal_uInt16& rListIndex,
bool bHasFiltered, bool& rSkipOverlappedCells,
std::vector<sal_Int32>& rNonOverlappedCellIdx)
@@ -224,6 +238,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
OSL_ENSURE( nCol1==nCol2 || nRow1==nRow2, "FillAnalyse: invalid range" );
rInc = 0.0;
+ rDuration = tools::Duration();
rMinDigits = 0;
rListData = nullptr;
rCmd = FILL_SIMPLE;
@@ -271,7 +286,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
if (bOverlapped)
bHasOverlappedCells = true;
- if (!bOverlapped || GetCellValue(nColCurr, nRowCurr).meType != CELLTYPE_NONE)
+ if (!bOverlapped || GetCellValue(nColCurr, nRowCurr).getType() != CELLTYPE_NONE)
{
rNonOverlappedCellIdx[nValueCount++] = i;
// if there is at least 1 non empty overlapped cell, then no cell should be skipped
@@ -298,7 +313,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
nRowCurr = nRow1 + rNonOverlappedCellIdx[0] * nAddY;
ScRefCellValue aPrevCell, aCurrCell;
aCurrCell = GetCellValue(nColCurr, nRowCurr);
- CellType eCellType = aCurrCell.meType;
+ CellType eCellType = aCurrCell.getType();
if (eCellType == CELLTYPE_VALUE)
{
bool bVal = true;
@@ -314,7 +329,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
tools::Long nDDiff = 0, nMDiff = 0, nYDiff = 0; // to avoid warnings
Date aNullDate = rDocument.GetFormatTable()->GetNullDate();
Date aCurrDate = aNullDate, aPrevDate = aNullDate;
- aCurrDate.AddDays(aCurrCell.mfValue);
+ aCurrDate.AddDays(aCurrCell.getDouble());
for (SCSIZE i = 1; i < nValueCount && bVal; i++)
{
aPrevCell = aCurrCell;
@@ -322,9 +337,9 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
nColCurr = nCol1 + rNonOverlappedCellIdx[i] * nAddX;
nRowCurr = nRow1 + rNonOverlappedCellIdx[i] * nAddY;
aCurrCell = GetCellValue(nColCurr, nRowCurr);
- if (aCurrCell.meType == CELLTYPE_VALUE)
+ if (aCurrCell.getType() == CELLTYPE_VALUE)
{
- aCurrDate = aNullDate + static_cast<sal_Int32>(aCurrCell.mfValue);
+ aCurrDate = aNullDate + static_cast<sal_Int32>(aCurrCell.getDouble());
if (eType != FILL_DAY) {
nDDiff = aCurrDate.GetDay()
- static_cast<tools::Long>(aPrevDate.GetDay());
@@ -384,25 +399,33 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
}
}
else if (nCurrCellFormatType == SvNumFormatType::LOGICAL
- && ((fVal = aCurrCell.mfValue) == 0.0 || fVal == 1.0))
+ && ((fVal = aCurrCell.getDouble()) == 0.0 || fVal == 1.0))
{
}
else if (nValueCount >= 2)
{
+ tools::Duration aDuration;
for (SCSIZE i = 1; i < nValueCount && bVal; i++)
{
aPrevCell = aCurrCell;
nColCurr = nCol1 + rNonOverlappedCellIdx[i] * nAddX;
nRowCurr = nRow1 + rNonOverlappedCellIdx[i] * nAddY;
aCurrCell = GetCellValue(nColCurr, nRowCurr);
- if (aCurrCell.meType == CELLTYPE_VALUE)
+ if (aCurrCell.getType() == CELLTYPE_VALUE)
{
- double nDiff = approxDiff(aCurrCell.mfValue, aPrevCell.mfValue);
+ const bool bTime = (nCurrCellFormatType == SvNumFormatType::TIME ||
+ nCurrCellFormatType == SvNumFormatType::DATETIME);
+ double nDiff = approxTypedDiff(aCurrCell.getDouble(), aPrevCell.getDouble(),
+ bTime, aDuration);
if (i == 1)
+ {
rInc = nDiff;
+ if (bTime)
+ rDuration = aDuration;
+ }
if (!::rtl::math::approxEqual(nDiff, rInc, 13))
bVal = false;
- else if ((aCurrCell.mfValue == 0.0 || aCurrCell.mfValue == 1.0)
+ else if ((aCurrCell.getDouble() == 0.0 || aCurrCell.getDouble() == 1.0)
&& (rDocument.GetFormatTable()->GetType(
GetNumberFormat(nColCurr, nRowCurr))
== SvNumFormatType::LOGICAL))
@@ -421,8 +444,8 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
}
else if (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT)
{
- OUString aStr,aStr2;
- GetString(nColCurr, nRowCurr, aStr);
+ OUString aStr = GetString(nColCurr, nRowCurr );
+ OUString aStr2;
rListData = const_cast<ScUserListData*>(ScGlobal::GetUserList()->GetData(aStr));
if (rListData)
@@ -435,7 +458,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
{
nColCurr = nCol1 + rNonOverlappedCellIdx[i] * nAddX;
nRowCurr = nRow1 + rNonOverlappedCellIdx[i] * nAddY;
- GetString(nColCurr, nRowCurr, aStr2);
+ aStr2 = GetString(nColCurr, nRowCurr);
nPrevListIndex = rListIndex;
if (!rListData->GetSubIndex(aStr2, rListIndex, bMatchCase))
@@ -469,7 +492,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
nColCurr = nCol1 + rNonOverlappedCellIdx[i] * nAddX;
nRowCurr = nRow1 + rNonOverlappedCellIdx[i] * nAddY;
ScRefCellValue aCell = GetCellValue(nColCurr, nRowCurr);
- CellType eType = aCell.meType;
+ CellType eType = aCell.getType();
if (eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT)
{
aStr2 = aCell.getString(&rDocument);
@@ -507,15 +530,16 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
SCROW nRow = nRow1;
ScRefCellValue aFirstCell = GetCellValue(nCol, nRow);
- CellType eCellType = aFirstCell.meType;
+ CellType eCellType = aFirstCell.getType();
if (eCellType == CELLTYPE_VALUE)
{
double fVal;
sal_uInt32 nFormat = GetAttr(nCol,nRow,ATTR_VALUE_FORMAT)->GetValue();
const SvNumFormatType nFormatType = rDocument.GetFormatTable()->GetType(nFormat);
- bool bDate = (nFormatType == SvNumFormatType::DATE );
- bool bBooleanCell = (!bDate && nFormatType == SvNumFormatType::LOGICAL);
+ bool bDate = (nFormatType == SvNumFormatType::DATE); // date without time
+ bool bTime = (nFormatType == SvNumFormatType::TIME || nFormatType == SvNumFormatType::DATETIME);
+ bool bBooleanCell = (nFormatType == SvNumFormatType::LOGICAL);
if (bDate)
{
if (nCount > 1)
@@ -523,7 +547,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
double nVal;
Date aNullDate = rDocument.GetFormatTable()->GetNullDate();
Date aDate1 = aNullDate;
- nVal = aFirstCell.mfValue;
+ nVal = aFirstCell.getDouble();
aDate1.AddDays(nVal);
Date aDate2 = aNullDate;
nVal = GetValue(nCol+nAddX, nRow+nAddY);
@@ -557,9 +581,9 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
for (SCSIZE i=1; i<nCount && bVal; i++)
{
ScRefCellValue aCell = GetCellValue(nCol,nRow);
- if (aCell.meType == CELLTYPE_VALUE)
+ if (aCell.getType() == CELLTYPE_VALUE)
{
- nVal = aCell.mfValue;
+ nVal = aCell.getDouble();
aDate2 = aNullDate + static_cast<sal_Int32>(nVal);
if ( eType == FILL_DAY )
{
@@ -610,7 +634,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
rInc = 1.0;
}
}
- else if (bBooleanCell && ((fVal = aFirstCell.mfValue) == 0.0 || fVal == 1.0))
+ else if (bBooleanCell && ((fVal = aFirstCell.getDouble()) == 0.0 || fVal == 1.0))
{
// Nothing, rInc stays 0.0, no specific fill mode.
}
@@ -618,19 +642,20 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
{
if (nCount > 1)
{
- double nVal1 = aFirstCell.mfValue;
+ tools::Duration aDuration;
+ double nVal1 = aFirstCell.getDouble();
double nVal2 = GetValue(nCol+nAddX, nRow+nAddY);
- rInc = approxDiff( nVal2, nVal1);
+ rInc = approxTypedDiff( nVal2, nVal1, bTime, aDuration);
nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
bool bVal = true;
for (SCSIZE i=1; i<nCount && bVal; i++)
{
ScRefCellValue aCell = GetCellValue(nCol,nRow);
- if (aCell.meType == CELLTYPE_VALUE)
+ if (aCell.getType() == CELLTYPE_VALUE)
{
- nVal2 = aCell.mfValue;
- double nDiff = approxDiff( nVal2, nVal1);
+ nVal2 = aCell.getDouble();
+ double nDiff = approxTypedDiff( nVal2, nVal1, bTime, aDuration);
if ( !::rtl::math::approxEqual( nDiff, rInc, 13 ) )
bVal = false;
else if ((nVal2 == 0.0 || nVal2 == 1.0) &&
@@ -643,6 +668,8 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
bVal = false;
nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
+ if (bVal && bTime)
+ rDuration = aDuration;
}
if (bVal)
rCmd = FILL_LINEAR;
@@ -655,8 +682,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
}
else if (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT)
{
- OUString aStr;
- GetString(nCol, nRow, aStr);
+ OUString aStr = GetString(nCol, nRow);
rListData = const_cast<ScUserListData*>(ScGlobal::GetUserList()->GetData(aStr));
if (rListData)
@@ -670,7 +696,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
for (SCSIZE i=1; i<nCount && rListData; i++)
{
nPrevListIndex = rListIndex;
- GetString(nCol, nRow, aStr);
+ aStr = GetString(nCol, nRow);
if (!rListData->GetSubIndex(aStr, rListIndex, bMatchCase))
rListData = nullptr;
else
@@ -699,7 +725,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
if ( nFlag1 )
{
sal_Int32 nVal2;
- GetString( nCol+nAddX, nRow+nAddY, aStr );
+ aStr = GetString( nCol+nAddX, nRow+nAddY );
short nFlag2 = lcl_DecompValueString( aStr, nVal2, &rMinDigits );
if ( nFlag1 == nFlag2 )
{
@@ -710,7 +736,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
for (SCSIZE i=1; i<nCount && bVal; i++)
{
ScRefCellValue aCell = GetCellValue(nCol, nRow);
- CellType eType = aCell.meType;
+ CellType eType = aCell.getType();
if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT )
{
aStr = aCell.getString(&rDocument);
@@ -787,7 +813,7 @@ void ScTable::FillFormula(
}
void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
- sal_uLong nFillCount, FillDir eFillDir, ScProgress* pProgress )
+ sal_uInt64 nFillCount, FillDir eFillDir, ScProgress* pProgress )
{
if ( (nFillCount == 0) || !ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2) )
return;
@@ -851,8 +877,8 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
aFillRange = ScRange(nCol1 - 1, nRow1, 0, nCol1 - nFillCount, nRow2, 0);
}
}
- sal_uLong nIMin = nIStart;
- sal_uLong nIMax = nIEnd;
+ sal_uInt64 nIMin = nIStart;
+ sal_uInt64 nIMax = nIEnd;
PutInOrder(nIMin,nIMax);
bool bHasFiltered = IsDataFiltered(aFillRange);
@@ -864,7 +890,7 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
DeleteArea(static_cast<SCCOL>(nIMin), nRow1, static_cast<SCCOL>(nIMax), nRow2, InsertDeleteFlags::AUTOFILL);
}
- sal_uLong nProgress = 0;
+ sal_uInt64 nProgress = 0;
if (pProgress)
nProgress = pProgress->GetState();
@@ -889,10 +915,10 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
// execute
- sal_uLong nActFormCnt = 0;
+ sal_uInt64 nActFormCnt = 0;
for (rOuter = nOStart; rOuter <= nOEnd; rOuter++)
{
- sal_uLong nMaxFormCnt = 0; // for formulas
+ sal_uInt64 nMaxFormCnt = 0; // for formulas
// transfer attributes
@@ -909,9 +935,9 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
if ( bGetPattern )
{
if (bVertical) // rInner&:=nRow, rOuter&:=nCol
- pSrcPattern = aCol[nCol].GetPattern(static_cast<SCROW>(nAtSrc));
+ pSrcPattern = GetColumnData(nCol).GetPattern(static_cast<SCROW>(nAtSrc));
else // rInner&:=nCol, rOuter&:=nRow
- pSrcPattern = aCol[nAtSrc].GetPattern(static_cast<SCROW>(nRow));
+ pSrcPattern = GetColumnData(nAtSrc).GetPattern(static_cast<SCROW>(nRow));
bGetPattern = false;
pStyleSheet = pSrcPattern->GetStyleSheet();
// do transfer ATTR_MERGE / ATTR_MERGE_FLAG
@@ -980,7 +1006,7 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
if ( bVertical && nISrcStart == nISrcEnd && !bHasFiltered )
{
// set all attributes at once (en bloc)
- if (pNewPattern || pSrcPattern != rDocument.GetDefPattern())
+ if (pNewPattern || !pSrcPattern->isDefault())
{
// Default is already present (DeleteArea)
SCROW nY1 = static_cast<SCROW>(std::min( nIStart, nIEnd ));
@@ -1011,7 +1037,7 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
DeleteArea(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow),
static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), InsertDeleteFlags::AUTOFILL);
- if ( pSrcPattern != aCol[nCol].GetPattern( static_cast<SCROW>(nRow) ) )
+ if ( !ScPatternAttr::areSame(pSrcPattern, aCol[nCol].GetPattern( static_cast<SCROW>(nRow) ) ) )
{
// Transfer template too
//TODO: Merge ApplyPattern to AttrArray ??
@@ -1066,6 +1092,7 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
FillCmd eFillCmd;
FillDateCmd eDateCmd = {};
double nInc;
+ tools::Duration aDurationInc;
sal_uInt16 nMinDigits;
ScUserListData* pListData = nullptr;
sal_uInt16 nListIndex;
@@ -1074,12 +1101,12 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
if (bVertical)
FillAnalyse(static_cast<SCCOL>(nCol),nRow1,
static_cast<SCCOL>(nCol),nRow2, eFillCmd,eDateCmd,
- nInc, nMinDigits, pListData, nListIndex,
+ nInc, aDurationInc, nMinDigits, pListData, nListIndex,
bHasFiltered, bSkipOverlappedCells, aNonOverlappedCellIdx);
else
FillAnalyse(nCol1,static_cast<SCROW>(nRow),
nCol2,static_cast<SCROW>(nRow), eFillCmd,eDateCmd,
- nInc, nMinDigits, pListData, nListIndex,
+ nInc, aDurationInc, nMinDigits, pListData, nListIndex,
bHasFiltered, bSkipOverlappedCells, aNonOverlappedCellIdx);
if (pListData)
@@ -1105,9 +1132,9 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
OUString aStr;
if (bVertical)
- GetString(rOuter, nLastValueIdx, aStr);
+ aStr = GetString(rOuter, nLastValueIdx);
else
- GetString(nLastValueIdx, rOuter, aStr);
+ aStr = GetString(nLastValueIdx, rOuter);
bool bMatchCase = false;
(void)pListData->GetSubIndex(aStr, nListIndex, bMatchCase);
@@ -1188,26 +1215,118 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
else
{
if (!bPositive)
+ {
nInc = -nInc;
+ aDurationInc = -aDurationInc;
+ }
double nEndVal = (nInc>=0.0) ? MAXDOUBLE : -MAXDOUBLE;
if (bVertical)
FillSeries( static_cast<SCCOL>(nCol), nRow1,
static_cast<SCCOL>(nCol), nRow2, nFillCount, eFillDir,
- eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, false,
+ eFillCmd, eDateCmd, nInc, aDurationInc, nEndVal, nMinDigits, false,
pProgress, bSkipOverlappedCells, &aNonOverlappedCellIdx);
else
FillSeries( nCol1, static_cast<SCROW>(nRow), nCol2,
static_cast<SCROW>(nRow), nFillCount, eFillDir,
- eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, false,
+ eFillCmd, eDateCmd, nInc, aDurationInc, nEndVal, nMinDigits, false,
pProgress, bSkipOverlappedCells, &aNonOverlappedCellIdx);
if (pProgress)
nProgress = pProgress->GetState();
}
+ if (bVertical)
+ FillSparkline(bVertical, nCol, nRow1, nRow2, nIStart, nIEnd);
+ else
+ FillSparkline(bVertical, nRow, nCol1, nCol2, nIStart, nIEnd);
+
nActFormCnt += nMaxFormCnt;
}
}
+void ScTable::FillSparkline(bool bVertical, SCCOLROW nFixed,
+ SCCOLROW nStart, SCCOLROW nEnd,
+ SCCOLROW nFillStart, SCCOLROW nFillEnd)
+{
+ bool bHasSparklines = false;
+ std::vector<std::shared_ptr<sc::Sparkline>> aSparklineSeries;
+
+ for (SCROW nCurrent = nStart; nCurrent <= nEnd; nCurrent++)
+ {
+ auto pSparkline = bVertical ? GetSparkline(nFixed, nCurrent) : GetSparkline(nCurrent, nFixed);
+ bHasSparklines = bHasSparklines || pSparkline;
+ aSparklineSeries.push_back(pSparkline);
+ }
+
+ if (bHasSparklines)
+ {
+ for (SCCOLROW nCurrent = nFillStart; nCurrent <= nFillEnd; nCurrent++)
+ {
+ size_t nIndex = size_t(nFillStart - nCurrent) % aSparklineSeries.size();
+ if (auto& rpSparkline = aSparklineSeries[nIndex])
+ {
+ auto pGroup = rpSparkline->getSparklineGroup();
+
+ auto* pNewSparkline = bVertical ? CreateSparkline(nFixed, nCurrent, pGroup)
+ : CreateSparkline(nCurrent, nFixed, pGroup);
+ if (pNewSparkline)
+ {
+ SCCOLROW nPosition = bVertical ? rpSparkline->getRow()
+ : rpSparkline->getColumn();
+ SCCOLROW nDelta = nCurrent - nPosition;
+ ScRangeList aRangeList(rpSparkline->getInputRange());
+ for (ScRange& rRange : aRangeList)
+ {
+ if (bVertical)
+ {
+ rRange.aStart.IncRow(nDelta);
+ rRange.aEnd.IncRow(nDelta);
+ }
+ else
+ {
+ rRange.aStart.IncCol(nDelta);
+ rRange.aEnd.IncCol(nDelta);
+ }
+ }
+ pNewSparkline->setInputRange(aRangeList);
+ }
+ }
+ }
+ }
+}
+
+void ScTable::GetBackColorArea(SCCOL& rStartCol, SCROW& /*rStartRow*/,
+ SCCOL& rEndCol, SCROW& rEndRow ) const
+{
+ bool bExtend;
+ const SvxBrushItem* pDefBackground = &rDocument.GetPool()->GetUserOrPoolDefaultItem(ATTR_BACKGROUND);
+
+ rStartCol = std::min<SCCOL>(rStartCol, aCol.size() - 1);
+ rEndCol = std::min<SCCOL>(rEndCol, aCol.size() - 1);
+
+ do
+ {
+ bExtend = false;
+
+ if (rEndRow < rDocument.MaxRow())
+ {
+ for (SCCOL nCol = rStartCol; nCol <= rEndCol; ++nCol)
+ {
+ const ScPatternAttr* pPattern = GetColumnData(nCol).GetPattern(rEndRow + 1);
+ const SvxBrushItem* pBackground = &pPattern->GetItem(ATTR_BACKGROUND);
+ if (!pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData().empty() ||
+ (pBackground->GetColor() != COL_TRANSPARENT && pBackground != pDefBackground))
+ {
+ bExtend = true;
+ break;
+ }
+ }
+
+ if (bExtend)
+ ++rEndRow;
+ }
+ } while (bExtend);
+}
+
OUString ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW nEndY )
{
OUString aValue;
@@ -1218,7 +1337,7 @@ OUString ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW
SCROW nRow2 = rSource.aEnd.Row();
bool bOk = true;
tools::Long nIndex = 0;
- sal_uLong nSrcCount = 0;
+ sal_uInt64 nSrcCount = 0;
FillDir eFillDir = FILL_TO_BOTTOM;
if ( nEndX == nCol2 && nEndY == nRow2 ) // empty
bOk = false;
@@ -1247,9 +1366,53 @@ OUString ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW
if ( bOk )
{
+ tools::Long nBegin = 0;
+ tools::Long nEnd = 0;
+ tools::Long nHidden = 0;
+ if (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP)
+ {
+ if (nEndY > nRow1)
+ {
+ nBegin = nRow2+1;
+ nEnd = nEndY;
+ }
+ else
+ {
+ nBegin = nEndY;
+ nEnd = nRow1 -1;
+ }
+
+ tools::Long nVisible = CountVisibleRows(nBegin, nEnd);
+ nHidden = nEnd + 1 - nBegin - nVisible;
+ }
+ else
+ {
+ if (nEndX > nCol1)
+ {
+ nBegin = nCol2+1;
+ nEnd = nEndX;
+ }
+ else
+ {
+ nBegin = nEndX;
+ nEnd = nCol1 -1;
+ }
+
+ tools::Long nVisible = CountVisibleCols(nBegin, nEnd);
+ nHidden = nEnd + 1 - nBegin - nVisible;
+ }
+ if (nHidden)
+ {
+ if (nIndex > 0)
+ nIndex = nIndex - nHidden;
+ else
+ nIndex = nIndex + nHidden;
+ }
+
FillCmd eFillCmd;
FillDateCmd eDateCmd;
double nInc;
+ tools::Duration aDurationInc;
sal_uInt16 nMinDigits;
ScUserListData* pListData = nullptr;
sal_uInt16 nListIndex;
@@ -1260,7 +1423,7 @@ OUString ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW
// after FillAnalyse / FillSeries fully handle them.
// Now FillAnalyse called as if there are filtered rows, so it will work in the old way.
FillAnalyse(nCol1, nRow1, nCol2, nRow2, eFillCmd, eDateCmd,
- nInc, nMinDigits, pListData, nListIndex,
+ nInc, aDurationInc, nMinDigits, pListData, nListIndex,
true, bSkipOverlappedCells, aNonOverlappedCellIdx);
if ( pListData ) // user defined list
@@ -1268,43 +1431,19 @@ OUString ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW
sal_uInt16 nListCount = pListData->GetSubCount();
if ( nListCount )
{
- sal_uLong nSub = nSrcCount - 1; // nListIndex is from last source entry
+ sal_uInt64 nSub = nSrcCount - 1; // nListIndex is from last source entry
while ( nIndex < sal::static_int_cast<tools::Long>(nSub) )
nIndex += nListCount;
- sal_uLong nPos = ( nListIndex + nIndex - nSub ) % nListCount;
+ sal_uInt64 nPos = ( nListIndex + nIndex - nSub ) % nListCount;
aValue = pListData->GetSubStr(sal::static_int_cast<sal_uInt16>(nPos));
}
}
else if ( eFillCmd == FILL_SIMPLE ) // fill with pattern/sample
{
- if ((eFillDir == FILL_TO_BOTTOM)||(eFillDir == FILL_TO_TOP))
- {
- tools::Long nBegin = 0;
- tools::Long nEnd = 0;
- if (nEndY > nRow1)
- {
- nBegin = nRow2+1;
- nEnd = nEndY;
- }
- else
- {
- nBegin = nEndY;
- nEnd = nRow1 -1;
- }
-
- tools::Long nNonFiltered = CountNonFilteredRows(nBegin, nEnd);
- tools::Long nFiltered = nEnd + 1 - nBegin - nNonFiltered;
-
- if (nIndex > 0)
- nIndex = nIndex - nFiltered;
- else
- nIndex = nIndex + nFiltered;
- }
-
tools::Long nPosIndex = nIndex;
while ( nPosIndex < 0 )
nPosIndex += nSrcCount;
- sal_uLong nPos = nPosIndex % nSrcCount;
+ sal_uInt64 nPos = nPosIndex % nSrcCount;
SCCOL nSrcX = nCol1;
SCROW nSrcY = nRow1;
if ( eFillDir == FILL_TO_TOP || eFillDir == FILL_TO_BOTTOM )
@@ -1321,7 +1460,7 @@ OUString ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW
else
nDelta = ( nIndex - nSrcCount + 1 ) / nSrcCount; // -1 -> -1
- CellType eType = aCell.meType;
+ CellType eType = aCell.getType();
switch ( eType )
{
case CELLTYPE_STRING:
@@ -1358,7 +1497,7 @@ OUString ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW
{
sal_uInt32 nNumFmt = GetNumberFormat( nSrcX, nSrcY );
// overflow is possible...
- double nVal = aCell.mfValue;
+ double nVal = aCell.getDouble();
if ( !(nScFillModeMouseModifier & KEY_MOD1) )
{
const SvNumFormatType nFormatType = rDocument.GetFormatTable()->GetType(nNumFmt);
@@ -1401,7 +1540,7 @@ OUString ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW
ScRefCellValue aCell = GetCellValue(nCol1, nRow1);
if (!aCell.isEmpty())
{
- CellType eType = aCell.meType;
+ CellType eType = aCell.getType();
switch ( eType )
{
case CELLTYPE_STRING:
@@ -1416,10 +1555,10 @@ OUString ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW
}
break;
case CELLTYPE_VALUE:
- nStart = aCell.mfValue;
+ nStart = aCell.getDouble();
break;
case CELLTYPE_FORMULA:
- nStart = aCell.mpFormula->GetValue();
+ nStart = aCell.getFormula()->GetValue();
break;
default:
nStart = 0.0;
@@ -1429,9 +1568,18 @@ OUString ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW
nStart = 0.0;
if ( eFillCmd == FILL_LINEAR )
{
- double nAdd = nInc;
- bValueOk = ( SubTotal::SafeMult( nAdd, static_cast<double>(nIndex) ) &&
- SubTotal::SafePlus( nStart, nAdd ) );
+ if (aDurationInc)
+ {
+ bool bOverflow;
+ tools::Duration aDuration( aDurationInc.Mult( nIndex, bOverflow));
+ bValueOk = SubTotal::SafePlus( nStart, aDuration.GetInDays()) && !bOverflow;
+ }
+ else
+ {
+ double nAdd = nInc;
+ bValueOk = ( SubTotal::SafeMult( nAdd, static_cast<double>(nIndex) ) &&
+ SubTotal::SafePlus( nStart, nAdd ) );
+ }
}
else // date
{
@@ -1614,7 +1762,7 @@ bool HiddenRowColumn(const ScTable* pTable, SCCOLROW nRowColumn, bool bVertical,
void ScTable::FillFormulaVertical(
const ScFormulaCell& rSrcCell,
SCCOLROW& rInner, SCCOL nCol, SCROW nRow1, SCROW nRow2,
- ScProgress* pProgress, sal_uLong& rProgress )
+ ScProgress* pProgress, sal_uInt64& rProgress )
{
// rInner is the row position when filling vertically. Also, when filling
// across hidden regions, it may create multiple dis-jointed spans of
@@ -1678,19 +1826,19 @@ void ScTable::FillFormulaVertical(
void ScTable::FillSeriesSimple(
const ScCellValue& rSrcCell, SCCOLROW& rInner, SCCOLROW nIMin, SCCOLROW nIMax,
- const SCCOLROW& rCol, const SCCOLROW& rRow, bool bVertical, ScProgress* pProgress, sal_uLong& rProgress )
+ const SCCOLROW& rCol, const SCCOLROW& rRow, bool bVertical, ScProgress* pProgress, sal_uInt64& rProgress )
{
bool bHidden = false;
SCCOLROW nHiddenLast = -1;
if (bVertical)
{
- switch (rSrcCell.meType)
+ switch (rSrcCell.getType())
{
case CELLTYPE_FORMULA:
{
FillFormulaVertical(
- *rSrcCell.mpFormula, rInner, rCol, nIMin, nIMax, pProgress, rProgress);
+ *rSrcCell.getFormula(), rInner, rCol, nIMin, nIMax, pProgress, rProgress);
}
break;
default:
@@ -1717,7 +1865,7 @@ void ScTable::FillSeriesSimple(
}
else
{
- switch (rSrcCell.meType)
+ switch (rSrcCell.getType())
{
case CELLTYPE_FORMULA:
{
@@ -1729,7 +1877,7 @@ void ScTable::FillSeriesSimple(
if (bHidden)
continue;
- FillFormula(rSrcCell.mpFormula, rCol, rRow, (rInner == nIMax));
+ FillFormula(rSrcCell.getFormula(), rCol, rRow, (rInner == nIMax));
if (pProgress)
pProgress->SetStateOnPercent(++rProgress);
}
@@ -1758,9 +1906,9 @@ void ScTable::FillSeriesSimple(
void ScTable::FillAutoSimple(
SCCOLROW nISrcStart, SCCOLROW nISrcEnd, SCCOLROW nIStart, SCCOLROW nIEnd,
- SCCOLROW& rInner, const SCCOLROW& rCol, const SCCOLROW& rRow, sal_uLong nActFormCnt,
- sal_uLong nMaxFormCnt, bool bHasFiltered, bool bVertical, bool bPositive,
- ScProgress* pProgress, sal_uLong& rProgress )
+ SCCOLROW& rInner, const SCCOLROW& rCol, const SCCOLROW& rRow, sal_uInt64 nActFormCnt,
+ sal_uInt64 nMaxFormCnt, bool bHasFiltered, bool bVertical, bool bPositive,
+ ScProgress* pProgress, sal_uInt64& rProgress )
{
SCCOLROW nSource = nISrcStart;
double nDelta;
@@ -1770,7 +1918,7 @@ void ScTable::FillAutoSimple(
nDelta = 1.0;
else
nDelta = -1.0;
- sal_uLong nFormulaCounter = nActFormCnt;
+ sal_uInt64 nFormulaCounter = nActFormCnt;
bool bGetCell = true;
bool bBooleanCell = false;
bool bPercentCell = false;
@@ -1782,16 +1930,28 @@ void ScTable::FillAutoSimple(
bool bIsOrdinalSuffix = false;
bool bColHidden = false, bRowHidden = false;
+ SCCOL nColHiddenFirst = rDocument.MaxCol();
SCCOL nColHiddenLast = -1;
+ SCROW nRowHiddenFirst = rDocument.MaxRow();
SCROW nRowHiddenLast = -1;
rInner = nIStart;
while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
{
- if (rCol > nColHiddenLast)
- bColHidden = ColHidden(rCol, nullptr, &nColHiddenLast);
- if (rRow > nRowHiddenLast)
- bRowHidden = RowHidden(rRow, nullptr, &nRowHiddenLast);
+ if (bPositive)
+ {
+ if (rCol > nColHiddenLast)
+ bColHidden = ColHidden(rCol, nullptr, &nColHiddenLast);
+ if (rRow > nRowHiddenLast)
+ bRowHidden = RowHidden(rRow, nullptr, &nRowHiddenLast);
+ }
+ else
+ {
+ if (rCol < nColHiddenFirst)
+ bColHidden = ColHidden(rCol, &nColHiddenFirst);
+ if (rRow < nRowHiddenFirst)
+ bRowHidden = RowHidden(rRow, &nRowHiddenFirst);
+ }
if (!bColHidden && !bRowHidden)
{
@@ -1799,23 +1959,23 @@ void ScTable::FillAutoSimple(
{
if (bVertical) // rInner&:=nRow, rOuter&:=nCol
{
- aSrcCell = aCol[rCol].GetCellValue(nSource);
- if (nISrcStart == nISrcEnd && aSrcCell.meType == CELLTYPE_FORMULA)
+ aSrcCell = GetCellValue(rCol, nSource);
+ if (nISrcStart == nISrcEnd && aSrcCell.getType() == CELLTYPE_FORMULA)
{
- FillFormulaVertical(*aSrcCell.mpFormula, rInner, rCol, nIStart, nIEnd, pProgress, rProgress);
+ FillFormulaVertical(*aSrcCell.getFormula(), rInner, rCol, nIStart, nIEnd, pProgress, rProgress);
return;
}
const SvNumFormatType nFormatType = rDocument.GetFormatTable()->GetType(
- aCol[rCol].GetNumberFormat( rDocument.GetNonThreadedContext(), nSource));
+ GetColumnData(rCol).GetNumberFormat( rDocument.GetNonThreadedContext(), nSource));
bBooleanCell = (nFormatType == SvNumFormatType::LOGICAL);
bPercentCell = (nFormatType == SvNumFormatType::PERCENT);
}
else // rInner&:=nCol, rOuter&:=nRow
{
- aSrcCell = aCol[nSource].GetCellValue(rRow);
+ aSrcCell = GetCellValue(nSource, rRow);
const SvNumFormatType nFormatType = rDocument.GetFormatTable()->GetType(
- aCol[nSource].GetNumberFormat( rDocument.GetNonThreadedContext(), rRow));
+ GetColumnData(nSource).GetNumberFormat( rDocument.GetNonThreadedContext(), rRow));
bBooleanCell = (nFormatType == SvNumFormatType::LOGICAL);
bPercentCell = (nFormatType == SvNumFormatType::PERCENT);
}
@@ -1823,14 +1983,14 @@ void ScTable::FillAutoSimple(
bGetCell = false;
if (!aSrcCell.isEmpty())
{
- switch (aSrcCell.meType)
+ switch (aSrcCell.getType())
{
case CELLTYPE_STRING:
case CELLTYPE_EDIT:
- if (aSrcCell.meType == CELLTYPE_STRING)
- aValue = aSrcCell.mpString->getString();
+ if (aSrcCell.getType() == CELLTYPE_STRING)
+ aValue = aSrcCell.getSharedString()->getString();
else
- aValue = ScEditUtil::GetString(*aSrcCell.mpEditText, &rDocument);
+ aValue = ScEditUtil::GetString(*aSrcCell.getEditText(), &rDocument);
if ( !(nScFillModeMouseModifier & KEY_MOD1) && !bHasFiltered )
{
nCellDigits = 0; // look at each source cell individually
@@ -1849,17 +2009,17 @@ void ScTable::FillAutoSimple(
}
}
- switch (aSrcCell.meType)
+ switch (aSrcCell.getType())
{
case CELLTYPE_VALUE:
{
double fVal;
- if (bBooleanCell && ((fVal = aSrcCell.mfValue) == 0.0 || fVal == 1.0))
- aCol[rCol].SetValue(rRow, aSrcCell.mfValue);
+ if (bBooleanCell && ((fVal = aSrcCell.getDouble()) == 0.0 || fVal == 1.0))
+ aCol[rCol].SetValue(rRow, aSrcCell.getDouble());
else if(bPercentCell)
- aCol[rCol].SetValue(rRow, aSrcCell.mfValue + nDelta * 0.01); // tdf#89998 increment by 1% at a time
+ aCol[rCol].SetValue(rRow, aSrcCell.getDouble() + nDelta * 0.01); // tdf#89998 increment by 1% at a time
else
- aCol[rCol].SetValue(rRow, aSrcCell.mfValue + nDelta);
+ aCol[rCol].SetValue(rRow, aSrcCell.getDouble() + nDelta);
}
break;
case CELLTYPE_STRING:
@@ -1877,7 +2037,7 @@ void ScTable::FillAutoSimple(
setSuffixCell(
aCol[rCol], rRow,
nNextValue, nCellDigits, aValue,
- aSrcCell.meType, bIsOrdinalSuffix);
+ aSrcCell.getType(), bIsOrdinalSuffix);
}
else
{
@@ -1896,7 +2056,7 @@ void ScTable::FillAutoSimple(
break;
case CELLTYPE_FORMULA :
FillFormula(
- aSrcCell.mpFormula, rCol, rRow, (rInner == nIEnd));
+ aSrcCell.getFormula(), rCol, rRow, (rInner == nIEnd));
if (nFormulaCounter - nActFormCnt > nMaxFormCnt)
nMaxFormCnt = nFormulaCounter - nActFormCnt;
break;
@@ -1945,7 +2105,7 @@ void ScTable::FillAutoSimple(
// and even then not individually for each one
++rProgress;
- if ( pProgress && (aSrcCell.meType == CELLTYPE_FORMULA || aSrcCell.meType == CELLTYPE_EDIT) )
+ if ( pProgress && (aSrcCell.getType() == CELLTYPE_FORMULA || aSrcCell.getType() == CELLTYPE_EDIT) )
pProgress->SetStateOnPercent( rProgress );
}
@@ -1967,7 +2127,6 @@ inline bool isOverflow( const double& rVal, const double& rMax, const double& rS
return rVal > rMax;
else
return rVal < rMax;
- break;
case FILL_GROWTH:
if (rStep > 0.0)
{
@@ -2040,8 +2199,9 @@ inline bool isOverflow( const double& rVal, const double& rMax, const double& rS
}
void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
- sal_uLong nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
- double nStepValue, double nMaxValue, sal_uInt16 nArgMinDigits,
+ sal_uInt64 nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
+ double nStepValue, const tools::Duration& rDurationStep,
+ double nMaxValue, sal_uInt16 nArgMinDigits,
bool bAttribs, ScProgress* pProgress,
bool bSkipOverlappedCells, std::vector<sal_Int32>* pNonOverlappedCellIdx )
{
@@ -2068,7 +2228,7 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
SCCOLROW nIEnd;
SCCOLROW nISource;
ScRange aFillRange;
- sal_uLong nFillerCount;
+ sal_uInt64 nFillerCount;
std::vector<bool> aIsNonEmptyCell;
if (bVertical)
@@ -2139,17 +2299,17 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
// it is still a good upper estimation.
ScCellValue aSrcCell;
if (bVertical)
- aSrcCell = aCol[static_cast<SCCOL>(nOStart)].GetCellValue(static_cast<SCROW>(nISource));
+ aSrcCell = GetCellValue(static_cast<SCCOL>(nOStart), static_cast<SCROW>(nISource));
else
- aSrcCell = aCol[static_cast<SCCOL>(nISource)].GetCellValue(static_cast<SCROW>(nOStart));
+ aSrcCell = GetCellValue(static_cast<SCCOL>(nISource), static_cast<SCROW>(nOStart));
// Same logic as for the actual series.
- if (!aSrcCell.isEmpty() && (aSrcCell.meType == CELLTYPE_VALUE || aSrcCell.meType == CELLTYPE_FORMULA))
+ if (!aSrcCell.isEmpty() && (aSrcCell.getType() == CELLTYPE_VALUE || aSrcCell.getType() == CELLTYPE_FORMULA))
{
double nStartVal;
- if (aSrcCell.meType == CELLTYPE_VALUE)
- nStartVal = aSrcCell.mfValue;
+ if (aSrcCell.getType() == CELLTYPE_VALUE)
+ nStartVal = aSrcCell.getDouble();
else
- nStartVal = aSrcCell.mpFormula->GetValue();
+ nStartVal = aSrcCell.getFormula()->GetValue();
if (eFillCmd == FILL_LINEAR)
{
if (nStepValue == 0.0)
@@ -2180,14 +2340,13 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
DeleteArea(static_cast<SCCOL>(nIMin), nRow1, static_cast<SCCOL>(nIMax), nRow2, nDel);
}
- sal_uLong nProgress = 0;
+ sal_uInt64 nProgress = 0;
if (pProgress)
nProgress = pProgress->GetState();
// Perform the fill once per each 'outer' position i.e. one per column
// when filling vertically.
- sal_uLong nActFormCnt = 0;
for (rOuter = nOStart; rOuter <= nOEnd; rOuter++)
{
rInner = nISource;
@@ -2195,7 +2354,7 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
CreateColumnIfNotExists(nCol);
// Source cell value. We need to clone the value since it may be inserted repeatedly.
- ScCellValue aSrcCell = aCol[nCol].GetCellValue(static_cast<SCROW>(nRow));
+ ScCellValue aSrcCell = GetCellValue(nCol, static_cast<SCROW>(nRow));
// Maybe another source cell need to be searched, if the fill is going through merged cells,
// where overlapped parts does not contain any information, so they can be skipped.
@@ -2220,9 +2379,9 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
//Set the real source cell
if (bVertical)
- aSrcCell = aCol[nOStart].GetCellValue(static_cast<SCROW>(nFirstValueIdx));
+ aSrcCell = GetCellValue(nOStart, static_cast<SCROW>(nFirstValueIdx));
else
- aSrcCell = aCol[nFirstValueIdx].GetCellValue(static_cast<SCROW>(nOStart));
+ aSrcCell = GetCellValue(nFirstValueIdx, static_cast<SCROW>(nOStart));
}
const ScPatternAttr* pSrcPattern = aCol[nCol].GetPattern(static_cast<SCROW>(nRow));
@@ -2268,7 +2427,7 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
if (!aSrcCell.isEmpty())
{
- CellType eCellType = aSrcCell.meType;
+ CellType eCellType = aSrcCell.getType();
if (eFillCmd == FILL_SIMPLE) // copy
{
@@ -2276,8 +2435,8 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
}
else if (eCellType == CELLTYPE_VALUE || eCellType == CELLTYPE_FORMULA)
{
- const double nStartVal = (eCellType == CELLTYPE_VALUE ? aSrcCell.mfValue :
- aSrcCell.mpFormula->GetValue());
+ const double nStartVal = (eCellType == CELLTYPE_VALUE ? aSrcCell.getDouble() :
+ aSrcCell.getFormula()->GetValue());
double nVal = nStartVal;
tools::Long nIndex = 0;
@@ -2309,10 +2468,18 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
// use multiplication instead of repeated addition
// to avoid accumulating rounding errors
nVal = nStartVal;
- double nAdd = nStepValue;
- if ( !SubTotal::SafeMult( nAdd, static_cast<double>(++nIndex) ) ||
- !SubTotal::SafePlus( nVal, nAdd ) )
- bError = true;
+ if (rDurationStep)
+ {
+ tools::Duration aDuration( rDurationStep.Mult( ++nIndex, bError));
+ bError |= !SubTotal::SafePlus( nVal, aDuration.GetInDays());
+ }
+ else
+ {
+ double nAdd = nStepValue;
+ if ( !SubTotal::SafeMult( nAdd, static_cast<double>(++nIndex) ) ||
+ !SubTotal::SafePlus( nVal, nAdd ) )
+ bError = true;
+ }
}
break;
case FILL_GROWTH:
@@ -2335,6 +2502,7 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
bOverflow = isOverflow( nVal, nMaxValue, nStepValue, nStartVal, eFillCmd);
}
+ CreateColumnIfNotExists(nCol);
if (bError)
aCol[nCol].SetError(static_cast<SCROW>(nRow), FormulaError::NoValue);
else if (!bOverflow && bNonEmpty)
@@ -2373,9 +2541,9 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
}
OUString aValue;
if (eCellType == CELLTYPE_STRING)
- aValue = aSrcCell.mpString->getString();
+ aValue = aSrcCell.getSharedString()->getString();
else
- aValue = ScEditUtil::GetString(*aSrcCell.mpEditText, &rDocument);
+ aValue = ScEditUtil::GetString(*aSrcCell.getEditText(), &rDocument);
sal_Int32 nStringValue;
sal_uInt16 nMinDigits = nArgMinDigits;
short nHeadNoneTail = lcl_DecompValueString( aValue, nStringValue, &nMinDigits );
@@ -2413,10 +2581,18 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
// use multiplication instead of repeated addition
// to avoid accumulating rounding errors
nVal = nStartVal;
- double nAdd = nStepValue;
- if ( !SubTotal::SafeMult( nAdd, static_cast<double>(++nIndex) ) ||
- !SubTotal::SafePlus( nVal, nAdd ) )
- bError = true;
+ if (rDurationStep)
+ {
+ tools::Duration aDuration( rDurationStep.Mult( ++nIndex, bError));
+ bError |= !SubTotal::SafePlus( nVal, aDuration.GetInDays());
+ }
+ else
+ {
+ double nAdd = nStepValue;
+ if ( !SubTotal::SafeMult( nAdd, static_cast<double>(++nIndex) ) ||
+ !SubTotal::SafePlus( nVal, nAdd ) )
+ bError = true;
+ }
}
break;
case FILL_GROWTH:
@@ -2481,19 +2657,19 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
nProgress += nIMax - nIMin + 1;
pProgress->SetStateOnPercent( nProgress );
}
- ++nActFormCnt;
}
}
void ScTable::Fill( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
- sal_uLong nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
- double nStepValue, double nMaxValue, ScProgress* pProgress)
+ sal_uInt64 nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
+ double nStepValue, const tools::Duration& rDurationStep,
+ double nMaxValue, ScProgress* pProgress)
{
if (eFillCmd == FILL_AUTO)
FillAuto(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir, pProgress);
else
FillSeries(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir,
- eFillCmd, eFillDateCmd, nStepValue, nMaxValue, 0, true, pProgress);
+ eFillCmd, eFillDateCmd, nStepValue, rDurationStep, nMaxValue, 0, true, pProgress);
}
void ScTable::AutoFormatArea(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
@@ -2521,7 +2697,7 @@ void ScTable::AutoFormat( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW
std::unique_ptr<ScPatternAttr> pPatternAttrs[16];
for (sal_uInt8 i = 0; i < 16; ++i)
{
- pPatternAttrs[i].reset(new ScPatternAttr(rDocument.GetPool()));
+ pPatternAttrs[i].reset(new ScPatternAttr(rDocument.getCellAttributeHelper()));
pData->FillToItemSet(i, pPatternAttrs[i]->GetItemSet(), rDocument);
}
@@ -2531,7 +2707,7 @@ void ScTable::AutoFormat( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW
// Left top corner
AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
// Left column
- if (pData->IsEqualData(4, 8))
+ if (pData->HasSameData(4, 8))
AutoFormatArea(nStartCol, nStartRow + 1, nStartCol, nEndRow - 1, *pPatternAttrs[4], nFormatNo);
else
{
@@ -2555,7 +2731,7 @@ void ScTable::AutoFormat( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW
nIndex = 3;
AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
// Right column
- if (pData->IsEqualData(7, 11))
+ if (pData->HasSameData(7, 11))
AutoFormatArea(nEndCol, nStartRow + 1, nEndCol, nEndRow - 1, *pPatternAttrs[7], nFormatNo);
else
{
@@ -2595,11 +2771,11 @@ void ScTable::AutoFormat( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW
nIndex = 13;
}
// Body
- if ((pData->IsEqualData(5, 6)) && (pData->IsEqualData(9, 10)) && (pData->IsEqualData(5, 9)))
+ if ((pData->HasSameData(5, 6)) && (pData->HasSameData(9, 10)) && (pData->HasSameData(5, 9)))
AutoFormatArea(nStartCol + 1, nStartRow + 1, nEndCol-1, nEndRow - 1, *pPatternAttrs[5], nFormatNo);
else
{
- if ((pData->IsEqualData(5, 9)) && (pData->IsEqualData(6, 10)))
+ if ((pData->HasSameData(5, 9)) && (pData->HasSameData(6, 10)))
{
nIndex = 5;
for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
diff --git a/sc/source/core/data/table5.cxx b/sc/source/core/data/table5.cxx
index 7af84bcd58dc..62f02ca66b1b 100644
--- a/sc/source/core/data/table5.cxx
+++ b/sc/source/core/data/table5.cxx
@@ -37,10 +37,16 @@
#include <bcaslot.hxx>
#include <compressedarray.hxx>
#include <userdat.hxx>
+#include <conditio.hxx>
+#include <colorscale.hxx>
+#include <cellform.hxx>
#include <com/sun/star/sheet/TablePageBreakData.hpp>
+#include <editeng/brushitem.hxx>
+#include <editeng/colritem.hxx>
#include <osl/diagnose.h>
+#include <svl/numformat.hxx>
#include <algorithm>
#include <limits>
@@ -75,7 +81,6 @@ void ScTable::UpdatePageBreaks(const ScRange* pUserArea)
return;
}
SfxItemSet* pStyleSet = &pStyle->GetItemSet();
- const SfxPoolItem* pItem;
SCCOL nStartCol = 0;
SCROW nStartRow = 0;
@@ -124,18 +129,15 @@ void ScTable::UpdatePageBreaks(const ScRange* pUserArea)
if (!mbForceBreaks)
{
- if (pStyleSet->GetItemState(ATTR_PAGE_SCALETOPAGES, false, &pItem) == SfxItemState::SET)
+ if (const SfxUInt16Item* pItem = pStyleSet->GetItemIfSet(ATTR_PAGE_SCALETOPAGES, false))
{
- OSL_ENSURE(dynamic_cast<const SfxUInt16Item*>(pItem) != nullptr, "invalid Item");
- bSkipColBreaks = bSkipRowBreaks
- = static_cast<const SfxUInt16Item*>(pItem)->GetValue() > 0;
+ bSkipColBreaks = bSkipRowBreaks = pItem->GetValue() > 0;
}
- if (!bSkipColBreaks
- && pStyleSet->GetItemState(ATTR_PAGE_SCALETO, false, &pItem) == SfxItemState::SET)
+ const ScPageScaleToItem* pScaleToItem;
+ if (!bSkipColBreaks && (pScaleToItem = pStyleSet->GetItemIfSet(ATTR_PAGE_SCALETO, false)))
{
// #i54993# when fitting to width or height, ignore only manual breaks in that direction
- const ScPageScaleToItem* pScaleToItem = static_cast<const ScPageScaleToItem*>(pItem);
if (pScaleToItem->GetWidth() > 0)
bSkipColBreaks = true;
if (pScaleToItem->GetHeight() > 0)
@@ -241,9 +243,9 @@ void ScTable::UpdatePageBreaks(const ScRange* pUserArea)
if (bStartOfPage && bRepeatRow && nY > nRepeatStartY && !bRowFound)
{
// subtract size of repeat rows from page size
- tools::ULong nHeights = GetTotalRowHeight(nRepeatStartY, nRepeatEndY);
+ tools::Long nHeights = GetTotalRowHeight(nRepeatStartY, nRepeatEndY);
#if OSL_DEBUG_LEVEL > 0
- if (nHeights == ::std::numeric_limits<tools::ULong>::max())
+ if (nHeights == ::std::numeric_limits<tools::Long>::max())
OSL_FAIL("ScTable::UpdatePageBreaks: row heights overflow");
#endif
nPageSizeY -= nHeights;
@@ -319,16 +321,16 @@ bool ScTable::HasManualBreaks() const
return !maRowManualBreaks.empty() || !maColManualBreaks.empty();
}
-void ScTable::SetRowManualBreaks(const ::std::set<SCROW>& rBreaks)
+void ScTable::SetRowManualBreaks(::std::set<SCROW>&& rBreaks)
{
- maRowManualBreaks = rBreaks;
+ maRowManualBreaks = std::move(rBreaks);
InvalidatePageBreaks();
SetStreamValid(false);
}
-void ScTable::SetColManualBreaks(const ::std::set<SCCOL>& rBreaks)
+void ScTable::SetColManualBreaks(::std::set<SCCOL>&& rBreaks)
{
- maColManualBreaks = rBreaks;
+ maColManualBreaks = std::move(rBreaks);
InvalidatePageBreaks();
SetStreamValid(false);
}
@@ -340,7 +342,6 @@ void ScTable::GetAllRowBreaks(set<SCROW>& rBreaks, bool bPage, bool bManual) con
if (bManual)
{
- using namespace std;
copy(maRowManualBreaks.begin(), maRowManualBreaks.end(),
inserter(rBreaks, rBreaks.begin()));
}
@@ -353,7 +354,6 @@ void ScTable::GetAllColBreaks(set<SCCOL>& rBreaks, bool bPage, bool bManual) con
if (bManual)
{
- using namespace std;
copy(maColManualBreaks.begin(), maColManualBreaks.end(),
inserter(rBreaks, rBreaks.begin()));
}
@@ -399,8 +399,6 @@ SCROW ScTable::GetNextManualBreak(SCROW nRow) const
void ScTable::RemoveRowPageBreaks(SCROW nStartRow, SCROW nEndRow)
{
- using namespace std;
-
if (!ValidRow(nStartRow) || !ValidRow(nEndRow))
return;
@@ -471,24 +469,16 @@ void ScTable::SetColBreak(SCCOL nCol, bool bPage, bool bManual)
Sequence<TablePageBreakData> ScTable::GetRowBreakData() const
{
- using ::std::copy;
using ::std::inserter;
set<SCROW> aRowBreaks = maRowPageBreaks;
copy(maRowManualBreaks.begin(), maRowManualBreaks.end(),
inserter(aRowBreaks, aRowBreaks.begin()));
- sal_Int32 i = 0;
Sequence<TablePageBreakData> aSeq(aRowBreaks.size());
-
- for (const SCROW nRow : aRowBreaks)
- {
- TablePageBreakData aData;
- aData.Position = nRow;
- aData.ManualBreak = HasRowManualBreak(nRow);
- aSeq[i] = aData;
- ++i;
- }
+ std::transform(aRowBreaks.begin(), aRowBreaks.end(), aSeq.getArray(), [this](const SCROW nRow) {
+ return TablePageBreakData(nRow, HasRowManualBreak(nRow));
+ });
return aSeq;
}
@@ -785,9 +775,9 @@ SCROW ScTable::CountVisibleRows(SCROW nStartRow, SCROW nEndRow) const
return nCount;
}
-sal_uInt32 ScTable::GetTotalRowHeight(SCROW nStartRow, SCROW nEndRow, bool bHiddenAsZero) const
+tools::Long ScTable::GetTotalRowHeight(SCROW nStartRow, SCROW nEndRow, bool bHiddenAsZero) const
{
- sal_uInt32 nHeight = 0;
+ tools::Long nHeight = 0;
SCROW nRow = nStartRow;
ScFlatBoolRowSegments::RangeData aData;
while (nRow <= nEndRow)
@@ -808,6 +798,28 @@ sal_uInt32 ScTable::GetTotalRowHeight(SCROW nStartRow, SCROW nEndRow, bool bHidd
return nHeight;
}
+SCCOL ScTable::CountVisibleCols(SCCOL nStartCol, SCCOL nEndCol) const
+{
+ assert(nStartCol <= nEndCol);
+ SCCOL nCount = 0;
+ SCCOL nCol = nStartCol;
+ ScFlatBoolColSegments::RangeData aData;
+ while (nCol <= nEndCol)
+ {
+ if (!mpHiddenCols->getRangeData(nCol, aData))
+ break;
+
+ if (aData.mnCol2 > nEndCol)
+ aData.mnCol2 = nEndCol;
+
+ if (!aData.mbValue)
+ nCount += aData.mnCol2 - nCol + 1;
+
+ nCol = aData.mnCol2 + 1;
+ }
+ return nCount;
+}
+
SCCOLROW ScTable::LastHiddenColRow(SCCOLROW nPos, bool bCol) const
{
if (bCol)
@@ -995,6 +1007,76 @@ SCROW ScTable::CountNonFilteredRows(SCROW nStartRow, SCROW nEndRow) const
return nCount;
}
+Color ScTable::GetCellBackgroundColor(ScAddress aPos) const
+{
+ Color backgroundColor;
+ bool bHasConditionalBackgroundColor = false;
+ // Check background color from cond. formatting
+ const ScPatternAttr* pPattern = GetDoc().GetPattern(aPos.Col(), aPos.Row(), aPos.Tab());
+ if (pPattern)
+ {
+ if (!pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData().empty())
+ {
+ const SfxItemSet* pCondSet = GetDoc().GetCondResult(aPos.Col(), aPos.Row(), aPos.Tab());
+ const SvxBrushItem* pBackgroundColor = &pPattern->GetItem(ATTR_BACKGROUND, pCondSet);
+ backgroundColor = pBackgroundColor->GetColor();
+ bHasConditionalBackgroundColor = true;
+ }
+ }
+
+ // Color scale needs a different handling
+ ScConditionalFormat* pCondFormat = GetDoc().GetCondFormat(aPos.Col(), aPos.Row(), aPos.Tab());
+ if (pCondFormat)
+ {
+ for (size_t i = 0; i < pCondFormat->size(); i++)
+ {
+ auto aEntry = pCondFormat->GetEntry(i);
+ if (aEntry->GetType() == ScFormatEntry::Type::Colorscale)
+ {
+ const ScColorScaleFormat* pColFormat
+ = static_cast<const ScColorScaleFormat*>(aEntry);
+ std::optional<Color> oColor = pColFormat->GetColor(aPos);
+ if (oColor)
+ {
+ backgroundColor = oColor.value();
+ bHasConditionalBackgroundColor = true;
+ }
+ }
+ }
+ }
+ return bHasConditionalBackgroundColor ? backgroundColor
+ : GetDoc().GetAttr(aPos, ATTR_BACKGROUND)->GetColor();
+}
+
+Color ScTable::GetCellTextColor(ScAddress aPos) const
+{
+ // Check text & background color from cond. formatting
+ const ScPatternAttr* pPattern = GetDoc().GetPattern(aPos.Col(), aPos.Row(), aPos.Tab());
+ if (pPattern)
+ {
+ if (!pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData().empty())
+ {
+ const SfxItemSet* pCondSet = GetDoc().GetCondResult(aPos.Col(), aPos.Row(), aPos.Tab());
+ const SvxColorItem* pColor = &pPattern->GetItem(ATTR_FONT_COLOR, pCondSet);
+ return pColor->GetValue();
+ }
+
+ if (pPattern->GetItem(ATTR_VALUE_FORMAT).GetValue())
+ {
+ const SfxUInt32Item pItem = pPattern->GetItem(ATTR_VALUE_FORMAT);
+ auto& rDoc = const_cast<ScDocument&>(GetDoc());
+ const Color* pColor;
+ ScRefCellValue aCell(rDoc, aPos);
+ ScCellFormat::GetString(rDoc, aPos, pItem.GetValue(), &pColor, nullptr, false, false);
+ if (pColor)
+ return *pColor;
+ }
+ }
+
+ const SvxColorItem* pColor = GetDoc().GetAttr(aPos, ATTR_FONT_COLOR);
+ return pColor->GetValue();
+}
+
bool ScTable::IsManualRowHeight(SCROW nRow) const
{
return bool(pRowFlags->GetValue(nRow) & CRFlags::ManualSize);
@@ -1007,8 +1089,6 @@ void lcl_syncFlags(const ScDocument* pDocument, ScFlatBoolColSegments& rColSegme
ScBitMaskCompressedArray<SCCOL, CRFlags>* pColFlags,
ScBitMaskCompressedArray<SCROW, CRFlags>* pRowFlags, const CRFlags nFlagMask)
{
- using ::sal::static_int_cast;
-
CRFlags nFlagMaskComplement = ~nFlagMask;
pRowFlags->AndValue(0, pDocument->MaxRow(), nFlagMaskComplement);
@@ -1152,7 +1232,8 @@ void ScTable::EndListening(sc::EndListeningContext& rCxt, const ScAddress& rAddr
if (!ValidCol(rAddress.Col()))
return;
- aCol[rAddress.Col()].EndListening(rCxt, rAddress, rListener);
+ if (rAddress.Col() < aCol.size())
+ aCol[rAddress.Col()].EndListening(rCxt, rAddress, rListener);
}
void ScTable::SetPageStyle(const OUString& rName)
@@ -1225,13 +1306,13 @@ void ScTable::InvalidateTextWidth(const ScAddress* pAdrFrom, const ScAddress* pA
if (bBroadcast)
{ // Only with CalcAsShown
- switch (aCell.meType)
+ switch (aCell.getType())
{
case CELLTYPE_VALUE:
rCol.Broadcast(nRow);
break;
case CELLTYPE_FORMULA:
- aCell.mpFormula->SetDirty();
+ aCell.getFormula()->SetDirty();
break;
default:
{
@@ -1267,13 +1348,13 @@ void ScTable::InvalidateTextWidth(const ScAddress* pAdrFrom, const ScAddress* pA
if (bBroadcast)
{ // Only with CalcAsShown
- switch (aCell.meType)
+ switch (aCell.getType())
{
case CELLTYPE_VALUE:
aCol[nCol].Broadcast(nRow);
break;
case CELLTYPE_FORMULA:
- aCell.mpFormula->SetDirty();
+ aCell.getFormula()->SetDirty();
break;
default:
{
diff --git a/sc/source/core/data/table6.cxx b/sc/source/core/data/table6.cxx
index b52247f35e14..243783c55d2e 100644
--- a/sc/source/core/data/table6.cxx
+++ b/sc/source/core/data/table6.cxx
@@ -35,14 +35,11 @@
namespace {
-bool lcl_GetTextWithBreaks( const EditTextObject& rData, ScDocument* pDoc, OUString& rVal )
+void lcl_GetTextWithBreaks( const EditTextObject& rData, ScDocument* pDoc, OUString& rVal )
{
- // true = more than 1 paragraph
-
EditEngine& rEngine = pDoc->GetEditEngine();
rEngine.SetText(rData);
rVal = rEngine.GetText();
- return ( rEngine.GetParagraphCount() > 1 );
}
}
@@ -81,43 +78,39 @@ bool ScTable::SearchCell(const SvxSearchItem& rSearchItem, SCCOL nCol, sc::Colum
pNote = nullptr;
}
- bool bMultiLine = false;
- CellType eCellType = aCell.meType;
+ CellType eCellType = aCell.getType();
switch (rSearchItem.GetCellType())
{
case SvxSearchCellType::FORMULA:
{
if ( eCellType == CELLTYPE_FORMULA )
- aCell.mpFormula->GetFormula(aString, rDocument.GetGrammar());
+ aString = aCell.getFormula()->GetFormula(rDocument.GetGrammar());
else if ( eCellType == CELLTYPE_EDIT )
- bMultiLine = lcl_GetTextWithBreaks(*aCell.mpEditText, &rDocument, aString);
+ lcl_GetTextWithBreaks(*aCell.getEditText(), &rDocument, aString);
else
{
if( !bSearchFormatted )
- aCol[nCol].GetInputString( rBlockPos, nRow, aString );
+ aString = aCol[nCol].GetInputString( rBlockPos, nRow );
else
- aCol[nCol].GetString( rBlockPos, nRow, aString );
+ aString = aCol[nCol].GetString( rBlockPos, nRow );
}
break;
}
case SvxSearchCellType::VALUE:
if ( eCellType == CELLTYPE_EDIT )
- bMultiLine = lcl_GetTextWithBreaks(*aCell.mpEditText, &rDocument, aString);
+ lcl_GetTextWithBreaks(*aCell.getEditText(), &rDocument, aString);
else
{
if( !bSearchFormatted )
- aCol[nCol].GetInputString( rBlockPos, nRow, aString );
+ aString = aCol[nCol].GetInputString( rBlockPos, nRow );
else
- aCol[nCol].GetString( rBlockPos, nRow, aString );
+ aString = aCol[nCol].GetString( rBlockPos, nRow );
}
break;
case SvxSearchCellType::NOTE:
{
if (pNote)
- {
aString = pNote->GetText();
- bMultiLine = pNote->HasMultiLineText();
- }
break;
}
default:
@@ -165,7 +158,7 @@ bool ScTable::SearchCell(const SvxSearchItem& rSearchItem, SCCOL nCol, sc::Colum
// Don't split the matrix, only replace Matrix formulas
if (eCellType == CELLTYPE_FORMULA)
{
- cMatrixFlag = aCell.mpFormula->GetMatrixFlag();
+ cMatrixFlag = aCell.getFormula()->GetMatrixFlag();
if(cMatrixFlag == ScMatrixMode::Reference)
return bFound;
}
@@ -192,7 +185,7 @@ bool ScTable::SearchCell(const SvxSearchItem& rSearchItem, SCCOL nCol, sc::Colum
OUString sReplStr = rSearchItem.GetReplaceString();
if (rSearchItem.GetRegExp())
{
- pSearchText->ReplaceBackReferences( sReplStr, aString, aSearchResult );
+ utl::TextSearch::ReplaceBackReferences( sReplStr, aString, aSearchResult );
OUStringBuffer aStrBuffer(aString);
aStrBuffer.remove(nStart, nEnd-nStart+1);
aStrBuffer.insert(nStart, sReplStr);
@@ -260,11 +253,11 @@ bool ScTable::SearchCell(const SvxSearchItem& rSearchItem, SCCOL nCol, sc::Colum
aString, rDocument.GetGrammar(), cMatrixFlag );
SCCOL nMatCols;
SCROW nMatRows;
- aCell.mpFormula->GetMatColsRows(nMatCols, nMatRows);
+ aCell.getFormula()->GetMatColsRows(nMatCols, nMatRows);
pFCell->SetMatColsRows( nMatCols, nMatRows );
aCol[nCol].SetFormulaCell(nRow, pFCell);
}
- else if ( bMultiLine && aString.indexOf('\n') != -1 )
+ else if (eCellType != CELLTYPE_FORMULA && aString.indexOf('\n') != -1)
{
ScFieldEditEngine& rEngine = rDocument.GetEditEngine();
rEngine.SetTextCurrentDefaults(aString);
@@ -323,12 +316,14 @@ bool ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
GetCellArea( nLastCol, nLastRow);
else
GetLastDataPos(nLastCol, nLastRow);
- return Search(rSearchItem, rCol, rRow, nLastCol, nLastRow, rMark, rUndoStr, pUndoDoc);
+ std::vector< sc::ColumnBlockConstPosition > blockPos;
+ return Search(rSearchItem, rCol, rRow, nLastCol, nLastRow, rMark, rUndoStr, pUndoDoc, blockPos);
}
bool ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
SCCOL nLastCol, SCROW nLastRow,
- const ScMarkData& rMark, OUString& rUndoStr, ScDocument* pUndoDoc)
+ const ScMarkData& rMark, OUString& rUndoStr, ScDocument* pUndoDoc,
+ std::vector< sc::ColumnBlockConstPosition >& blockPos)
{
bool bFound = false;
bool bAll = (rSearchItem.GetCommand() == SvxSearchCmd::FIND_ALL)
@@ -339,9 +334,12 @@ bool ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
bool bSkipFiltered = !rSearchItem.IsSearchFiltered();
bool bSearchNotes = (rSearchItem.GetCellType() == SvxSearchCellType::NOTE);
// We need to cache sc::ColumnBlockConstPosition per each column.
- std::vector< sc::ColumnBlockConstPosition > blockPos( nLastCol + 1 );
- for( SCCOL i = 0; i <= nLastCol; ++i )
- aCol[ i ].InitBlockPosition( blockPos[ i ] );
+ 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;
@@ -477,6 +475,11 @@ bool ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
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)
@@ -529,9 +532,10 @@ bool ScTable::SearchAll(const SvxSearchItem& rSearchItem, const ScMarkData& rMar
else
GetLastDataPos(nLastCol, nLastRow);
+ std::vector< sc::ColumnBlockConstPosition > blockPos;
do
{
- bFound = Search(rSearchItem, nCol, nRow, nLastCol, nLastRow, rMark, rUndoStr, pUndoDoc);
+ bFound = Search(rSearchItem, nCol, nRow, nLastCol, nLastRow, rMark, rUndoStr, pUndoDoc, blockPos);
if (bFound)
{
bEverFound = true;
@@ -579,7 +583,7 @@ bool ScTable::Replace(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow
bool ScTable::ReplaceAll(
const SvxSearchItem& rSearchItem, const ScMarkData& rMark, ScRangeList& rMatchedRanges,
- OUString& rUndoStr, ScDocument* pUndoDoc)
+ OUString& rUndoStr, ScDocument* pUndoDoc, bool& bMatchedRangesWereClamped)
{
SCCOL nCol = 0;
SCROW nRow = -1;
@@ -595,15 +599,21 @@ bool ScTable::ReplaceAll(
SvxSearchItem aCopyItem(rSearchItem);
aCopyItem.SetRowDirection(false);
+ std::vector< sc::ColumnBlockConstPosition > blockPos;
bool bEverFound = false;
while (true)
{
- bool bFound = Search(aCopyItem, nCol, nRow, nLastCol, nLastRow, rMark, rUndoStr, pUndoDoc);
+ bool bFound = Search(aCopyItem, nCol, nRow, nLastCol, nLastRow, rMark, rUndoStr, pUndoDoc, blockPos);
if (bFound)
{
bEverFound = true;
- rMatchedRanges.Join(ScRange(nCol, nRow, nTab));
+ // 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;
@@ -749,11 +759,7 @@ bool ScTable::SearchAllStyle(
if (bFound)
{
if (nEndRow<nRow)
- {
- SCROW nTemp = nRow;
- nRow = nEndRow;
- nEndRow = nTemp;
- }
+ std::swap( nRow, nEndRow );
rMatchedRanges.Join(ScRange(i, nRow, nTab, i, nEndRow, nTab));
nRow = nEndRow + 1;
bEverFound = true;
@@ -793,14 +799,14 @@ bool ScTable::ReplaceAllStyle(
bool ScTable::SearchAndReplace(
const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow, const ScMarkData& rMark,
- ScRangeList& rMatchedRanges, OUString& rUndoStr, ScDocument* pUndoDoc)
+ ScRangeList& rMatchedRanges, OUString& rUndoStr, ScDocument* pUndoDoc, bool& bMatchedRangesWereClamped)
{
SvxSearchCmd nCommand = rSearchItem.GetCommand();
bool bFound = false;
if ( ValidColRow(rCol, rRow) ||
((nCommand == SvxSearchCmd::FIND || nCommand == SvxSearchCmd::REPLACE) &&
- (((rCol == MAXCOLCOUNT || rCol == -1) && ValidRow(rRow)) ||
- ((rRow == GetDoc().GetSheetLimits().GetMaxRowCount() || rRow == -1) && ValidCol(rCol))
+ (((rCol == GetDoc().GetMaxColCount() || rCol == -1) && ValidRow(rRow)) ||
+ ((rRow == GetDoc().GetMaxRowCount() || rRow == -1) && ValidCol(rCol))
)
)
)
@@ -817,17 +823,16 @@ bool ScTable::SearchAndReplace(
else if (nCommand == SvxSearchCmd::REPLACE_ALL)
bFound = ReplaceAllStyle(rSearchItem, rMark, rMatchedRanges, pUndoDoc);
}
+ else if (ScDocument::IsEmptyCellSearch( rSearchItem))
+ {
+ // Search for empty cells.
+ bFound = SearchAndReplaceEmptyCells(rSearchItem, rCol, rRow, rMark, rMatchedRanges, rUndoStr, pUndoDoc);
+ }
else
{
// SearchParam no longer needed - SearchOptions contains all settings
i18nutil::SearchOptions2 aSearchOptions = rSearchItem.GetSearchOptions();
- aSearchOptions.Locale = *ScGlobal::GetLocale();
-
- if (aSearchOptions.searchString.isEmpty() || ( rSearchItem.GetRegExp() && aSearchOptions.searchString == "^$" ) )
- {
- // Search for empty cells.
- return SearchAndReplaceEmptyCells(rSearchItem, rCol, rRow, rMark, rMatchedRanges, rUndoStr, pUndoDoc);
- }
+ aSearchOptions.Locale = ScGlobal::GetLocale();
// reflect UseAsianOptions flag in SearchOptions
// (use only ignore case and width if asian options are disabled).
@@ -846,7 +851,7 @@ bool ScTable::SearchAndReplace(
else if (nCommand == SvxSearchCmd::REPLACE)
bFound = Replace(rSearchItem, rCol, rRow, rMark, rUndoStr, pUndoDoc);
else if (nCommand == SvxSearchCmd::REPLACE_ALL)
- bFound = ReplaceAll(rSearchItem, rMark, rMatchedRanges, rUndoStr, pUndoDoc);
+ bFound = ReplaceAll(rSearchItem, rMark, rMatchedRanges, rUndoStr, pUndoDoc, bMatchedRangesWereClamped);
pSearchText.reset();
}
@@ -1081,10 +1086,14 @@ bool ScTable::SearchRangeForAllEmptyCells(
if (aCol[nCol].IsEmptyData())
{
// The entire column is empty.
- for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
+ const SCROW nEndRow = rRange.aEnd.Row();
+ for (SCROW nRow = rRange.aStart.Row(); nRow <= nEndRow; ++nRow)
{
SCROW nLastRow;
- if (!RowFiltered(nRow, nullptr, &nLastRow))
+ const bool bFiltered = RowFiltered(nRow, nullptr, &nLastRow);
+ if (nLastRow > nEndRow)
+ nLastRow = nEndRow;
+ if (!bFiltered)
{
rMatchedRanges.Join(ScRange(nCol, nRow, nTab, nCol, nLastRow, nTab));
if (bReplace)
@@ -1098,7 +1107,7 @@ bool ScTable::SearchRangeForAllEmptyCells(
// 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), EMPTY_OUSTRING);
+ pUndoDoc->SetString(ScAddress(nCol, i, nTab), OUString());
}
}
rUndoStr.clear();
@@ -1133,7 +1142,7 @@ bool ScTable::SearchRangeForAllEmptyCells(
// 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), EMPTY_OUSTRING);
+ pUndoDoc->SetString(ScAddress(nCol, nRow, nTab), OUString());
}
}
}
diff --git a/sc/source/core/data/table7.cxx b/sc/source/core/data/table7.cxx
index 6ec79a90fd98..f9e7a878c8e5 100644
--- a/sc/source/core/data/table7.cxx
+++ b/sc/source/core/data/table7.cxx
@@ -109,12 +109,13 @@ void ScTable::DeleteBeforeCopyFromClip(
ScRange aClipRange = rCxt.getClipDoc()->GetClipParam().getWholeRange();
SCCOL nClipCol = aClipRange.aStart.Col();
{
- for (SCCOL nCol = aRange.mnCol1; nCol <= aRange.mnCol2; ++nCol, ++nClipCol)
+ const SCCOL nMaxCol2 = std::min<SCCOL>( aRange.mnCol2, aCol.size() - 1 );
+ for (SCCOL nCol = aRange.mnCol1; nCol <= nMaxCol2; ++nCol, ++nClipCol)
{
if (nClipCol > aClipRange.aEnd.Col())
nClipCol = aClipRange.aStart.Col(); // loop through columns.
- const ScColumn& rClipCol = rClipTab.aCol[nClipCol];
+ const ScColumn& rClipCol = const_cast<ScTable&>(rClipTab).CreateColumnIfNotExists(nClipCol);
aCol[nCol].DeleteBeforeCopyFromClip(rCxt, rClipCol, rBroadcastSpans);
}
}
@@ -168,12 +169,10 @@ void ScTable::CopyOneCellFromClip(
const ScAddress aSrcStartPos
= rCxt.getClipDoc()->GetClipParam().getWholeRange().aStart;
const ScAddress aSrcEndPos = rCxt.getClipDoc()->GetClipParam().getWholeRange().aEnd;
- tools::Rectangle aSourceRect = rCxt.getClipDoc()->GetMMRect(
- aSrcStartPos.Col(), aSrcStartPos.Row(), aSrcEndPos.Col(), aSrcEndPos.Row(),
- aSrcStartPos.Tab());
- tools::Rectangle aDestRect = GetDoc().GetMMRect(nCol1, nRow1, nCol2, nRow2, nTab);
+ ScRange aSourceRange(aSrcStartPos, aSrcEndPos);
+ ScRange aDestRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
pDrawLayer->CopyFromClip(rCxt.getClipDoc()->mpDrawLayer.get(), aSrcStartPos.Tab(),
- aSourceRect, ScAddress(nCol1, nRow1, nTab), aDestRect);
+ aSourceRange, ScAddress(nCol1, nRow1, nTab), aDestRange);
}
}
@@ -320,7 +319,7 @@ void ScTable::EndListeningIntersectedGroups(
if (nCol2 < nCol1 || !IsColValid(nCol1) || !ValidCol(nCol2))
return;
- for (SCCOL nCol : GetColumnsRange(nCol1, nCol2))
+ for (SCCOL nCol : GetAllocatedColumnsRange(nCol1, nCol2))
aCol[nCol].EndListeningIntersectedGroups(rCxt, nRow1, nRow2, pGroupPos);
}
@@ -421,12 +420,12 @@ bool ScTable::IsEditActionAllowed(
return false;
}
-std::unique_ptr<sc::ColumnIterator> ScTable::GetColumnIterator( SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const
+std::optional<sc::ColumnIterator> ScTable::GetColumnIterator( SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const
{
if (!ValidCol(nCol))
- return std::unique_ptr<sc::ColumnIterator>();
+ return {};
- return CreateColumnIfNotExists(nCol).GetColumnIterator(nRow1, nRow2);
+ return const_cast<ScTable*>(this)->CreateColumnIfNotExists(nCol).GetColumnIterator(nRow1, nRow2);
}
bool ScTable::EnsureFormulaCellResults( const SCCOL nCol1, SCROW nRow1, const SCCOL nCol2, SCROW nRow2, bool bSkipRunning )
@@ -511,7 +510,7 @@ OString ScTable::dumpSheetGeomData(bool bColumns, SheetGeomType eGeomType)
;
}
- return "";
+ return ""_ostr;
}
OString ScTable::dumpColumnRowSizes(bool bColumns)
@@ -519,19 +518,19 @@ OString ScTable::dumpColumnRowSizes(bool bColumns)
// If the data-structures are not available, just report that all
// rows/cols have the default sizes.
static const OString aDefaultForCols
- = OString::number(STD_COL_WIDTH) + ":" + OString::number(MAXCOL) + " ";
+ = OString::number(STD_COL_WIDTH) + ":" + OString::number(GetDoc().MaxCol()) + " ";
static const OString aDefaultForRows
- = OString::number(ScGlobal::nStdRowHeight) + ":" + OString::number(MAXROW) + " ";
+ = OString::number(GetOptimalMinRowHeight()) + ":" + OString::number(GetDoc().MaxRow()) + " ";
// ScCompressedArray is a template class and we don't want to impose
// the restriction that its value type should be string serializable,
// instead just operate on the specialized object.
typedef ScCompressedArray<SCCOL, sal_uInt16> ColWidthsType;
- auto dumpColWidths = [](const ColWidthsType& rWidths) -> OString {
+ auto dumpColWidths = [this](const ColWidthsType& rWidths) -> OString {
OString aOutput;
OString aSegment;
SCCOL nStartCol = 0;
- const SCCOL nMaxCol = std::min(rWidths.GetLastPos(), MAXCOL);
+ const SCCOL nMaxCol = std::min(rWidths.GetLastPos(), GetDoc().MaxCol());
size_t nDummy = 0;
while (nStartCol <= nMaxCol)
{
@@ -557,8 +556,8 @@ OString ScTable::dumpColumnRowSizes(bool bColumns)
OString ScTable::dumpHiddenFiltered(bool bColumns, bool bHidden)
{
// defaults to no hidden/filtered row/cols.
- static const OString aDefaultForCols = "0:" + OString::number(MAXCOL) + " ";
- static const OString aDefaultForRows = "0:" + OString::number(MAXROW) + " ";
+ static const OString aDefaultForCols = "0:" + OString::number(GetDoc().MaxCol()) + " ";
+ static const OString aDefaultForRows = "0:" + OString::number(GetDoc().MaxRow()) + " ";
if (bHidden)
{
@@ -577,7 +576,7 @@ OString ScTable::dumpHiddenFiltered(bool bColumns, bool bHidden)
OString ScTable::dumpColumnRowGroups(bool bColumns) const
{
if (!pOutlineTable)
- return "";
+ return ""_ostr;
if (bColumns)
return pOutlineTable->GetColArray().dumpAsString();
@@ -629,4 +628,37 @@ bool ScTable::SetLOKFreezeRow(SCROW nFreezeRow)
return false;
}
+std::set<SCCOL> ScTable::QueryColumnsWithFormulaCells() const
+{
+ std::set<SCCOL> aColIndices;
+
+ for (const auto& pCol : aCol)
+ {
+ if (pCol->HasFormulaCell())
+ aColIndices.insert(pCol->GetCol());
+ }
+
+ return aColIndices;
+}
+
+void ScTable::CheckIntegrity() const
+{
+ for (const auto& pCol : aCol)
+ pCol->CheckIntegrity();
+}
+
+void ScTable::CollectBroadcasterState(sc::BroadcasterState& rState) const
+{
+ for (const auto& pCol : aCol)
+ pCol->CollectBroadcasterState(rState);
+}
+
+std::shared_ptr<sc::SolverSettings> ScTable::GetSolverSettings()
+{
+ if (!m_pSolverSettings)
+ m_pSolverSettings = std::make_shared<sc::SolverSettings>(*this);
+
+ return m_pSolverSettings;
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/tabprotection.cxx b/sc/source/core/data/tabprotection.cxx
index c0cc81852190..266c5c380790 100644
--- a/sc/source/core/data/tabprotection.cxx
+++ b/sc/source/core/data/tabprotection.cxx
@@ -29,10 +29,10 @@
#define DEBUG_TAB_PROTECTION 0
-#define URI_SHA1 u"http://www.w3.org/2000/09/xmldsig#sha1"
-#define URI_SHA256_ODF12 u"http://www.w3.org/2000/09/xmldsig#sha256"
-#define URI_SHA256_W3C u"http://www.w3.org/2001/04/xmlenc#sha256"
-#define URI_XLS_LEGACY u"http://docs.oasis-open.org/office/ns/table/legacy-hash-excel"
+constexpr OUString URI_SHA1 = u"http://www.w3.org/2000/09/xmldsig#sha1"_ustr;
+constexpr OUString URI_SHA256_ODF12 = u"http://www.w3.org/2000/09/xmldsig#sha256"_ustr;
+constexpr OUStringLiteral URI_SHA256_W3C = u"http://www.w3.org/2001/04/xmlenc#sha256";
+constexpr OUString URI_XLS_LEGACY = u"http://docs.oasis-open.org/office/ns/table/legacy-hash-excel"_ustr;
using namespace ::com::sun::star;
using ::com::sun::star::uno::Sequence;
@@ -111,7 +111,7 @@ ScPassHashProtectable::~ScPassHashProtectable()
class ScTableProtectionImpl
{
public:
- static Sequence<sal_Int8> hashPassword(const OUString& aPassText, ScPasswordHash eHash);
+ static Sequence<sal_Int8> hashPassword(std::u16string_view aPassText, ScPasswordHash eHash);
static Sequence<sal_Int8> hashPassword(const Sequence<sal_Int8>& rPassHash, ScPasswordHash eHash);
explicit ScTableProtectionImpl(SCSIZE nOptSize);
@@ -137,7 +137,7 @@ public:
bool isOptionEnabled(SCSIZE nOptId) const;
void setOption(SCSIZE nOptId, bool bEnabled);
- void setEnhancedProtection( const ::std::vector< ScEnhancedProtection > & rProt );
+ void setEnhancedProtection( ::std::vector< ScEnhancedProtection > && rProt );
const ::std::vector< ScEnhancedProtection > & getEnhancedProtection() const { return maEnhancedProtection;}
bool updateReference( UpdateRefMode, const ScDocument&, const ScRange& rWhere, SCCOL nDx, SCROW nDy, SCTAB nDz );
bool isBlockEditable( const ScRange& rRange ) const;
@@ -155,7 +155,7 @@ private:
::std::vector< ScEnhancedProtection > maEnhancedProtection;
};
-Sequence<sal_Int8> ScTableProtectionImpl::hashPassword(const OUString& aPassText, ScPasswordHash eHash)
+Sequence<sal_Int8> ScTableProtectionImpl::hashPassword(std::u16string_view aPassText, ScPasswordHash eHash)
{
Sequence<sal_Int8> aHash;
switch (eHash)
@@ -423,9 +423,9 @@ void ScTableProtectionImpl::setOption(SCSIZE nOptId, bool bEnabled)
maOptions[nOptId] = bEnabled;
}
-void ScTableProtectionImpl::setEnhancedProtection( const ::std::vector< ScEnhancedProtection > & rProt )
+void ScTableProtectionImpl::setEnhancedProtection( ::std::vector< ScEnhancedProtection > && rProt )
{
- maEnhancedProtection = rProt;
+ maEnhancedProtection = std::move(rProt);
}
bool ScTableProtectionImpl::updateReference( UpdateRefMode eMode, const ScDocument& rDoc,
@@ -456,13 +456,15 @@ bool ScTableProtectionImpl::isBlockEditable( const ScRange& rRange ) const
// present we assume the permission to edit is not granted. Until we
// actually can evaluate the descriptors...
- auto lIsEditable = [rRange](const ScEnhancedProtection& rEnhancedProtection) {
- return !rEnhancedProtection.hasSecurityDescriptor()
- && rEnhancedProtection.maRangeList.is() && rEnhancedProtection.maRangeList->In( rRange)
- && !rEnhancedProtection.hasPassword(); // Range is editable if no password is assigned.
- };
- if (std::any_of(maEnhancedProtection.begin(), maEnhancedProtection.end(), lIsEditable))
- return true;
+ {
+ auto lIsEditable = [rRange](const ScEnhancedProtection& rEnhancedProtection) {
+ return !rEnhancedProtection.hasSecurityDescriptor()
+ && rEnhancedProtection.maRangeList.is() && rEnhancedProtection.maRangeList->Contains( rRange)
+ && !rEnhancedProtection.hasPassword(); // Range is editable if no password is assigned.
+ };
+ if (std::any_of(maEnhancedProtection.begin(), maEnhancedProtection.end(), std::move(lIsEditable)))
+ return true;
+ }
// For a single address, a simple check with single ranges was sufficient.
if (rRange.aStart == rRange.aEnd)
@@ -695,9 +697,9 @@ void ScTableProtection::setOption(Option eOption, bool bEnabled)
mpImpl->setOption(eOption, bEnabled);
}
-void ScTableProtection::setEnhancedProtection( const ::std::vector< ScEnhancedProtection > & rProt )
+void ScTableProtection::setEnhancedProtection( ::std::vector< ScEnhancedProtection > && rProt )
{
- mpImpl->setEnhancedProtection(rProt);
+ mpImpl->setEnhancedProtection(std::move(rProt));
}
const ::std::vector< ScEnhancedProtection > & ScTableProtection::getEnhancedProtection() const
diff --git a/sc/source/core/data/validat.cxx b/sc/source/core/data/validat.cxx
index d467db7ccf0f..f627509096fe 100644
--- a/sc/source/core/data/validat.cxx
+++ b/sc/source/core/data/validat.cxx
@@ -23,7 +23,6 @@
#include <com/sun/star/sheet/TableValidationVisibility.hpp>
#include <sfx2/app.hxx>
-#include <sfx2/objsh.hxx>
#include <sfx2/viewsh.hxx>
#include <basic/sbmeth.hxx>
#include <basic/sbmod.hxx>
@@ -31,7 +30,7 @@
#include <basic/sberrors.hxx>
#include <basic/sbx.hxx>
-#include <svl/zforlist.hxx>
+#include <svl/numformat.hxx>
#include <svl/sharedstringpool.hxx>
#include <vcl/svapp.hxx>
#include <vcl/weld.hxx>
@@ -39,6 +38,7 @@
#include <osl/diagnose.h>
#include <document.hxx>
+#include <docsh.hxx>
#include <formulacell.hxx>
#include <patattr.hxx>
#include <globstr.hrc>
@@ -50,7 +50,7 @@
#include <tokenarray.hxx>
#include <scmatrix.hxx>
#include <cellvalue.hxx>
-#include <comphelper/lok.hxx>
+#include <simpleformulacalc.hxx>
#include <math.h>
#include <memory>
@@ -186,35 +186,27 @@ bool ScValidationData::DoScript( const ScAddress& rPos, const OUString& rInput,
ScFormulaCell* pCell, weld::Window* pParent ) const
{
ScDocument* pDocument = GetDocument();
- SfxObjectShell* pDocSh = pDocument->GetDocumentShell();
+ ScDocShell* pDocSh = pDocument->GetDocumentShell();
if ( !pDocSh )
return false;
bool bScriptReturnedFalse = false; // default: do not abort
- // Set up parameters
- css::uno::Sequence< css::uno::Any > aParams(2);
-
// 1) entered or calculated value
- OUString aValStr = rInput;
- double nValue;
- bool bIsValue = false;
+ css::uno::Any aParam0(rInput);
if ( pCell ) // if cell exists, call interpret
{
- bIsValue = pCell->IsValue();
- if ( bIsValue )
- nValue = pCell->GetValue();
+ if ( pCell->IsValue() )
+ aParam0 <<= pCell->GetValue();
else
- aValStr = pCell->GetString().getString();
+ aParam0 <<= pCell->GetString().getString();
}
- if ( bIsValue )
- aParams[0] <<= nValue;
- else
- aParams[0] <<= aValStr;
// 2) Position of the cell
OUString aPosStr(rPos.Format(ScRefFlags::VALID | ScRefFlags::TAB_3D, pDocument, pDocument->GetAddressConvention()));
- aParams[1] <<= aPosStr;
+
+ // Set up parameters
+ css::uno::Sequence< css::uno::Any > aParams{ aParam0, css::uno::Any(aPosStr) };
// use link-update flag to prevent closing the document
// while the macro is running
@@ -273,7 +265,7 @@ bool ScValidationData::DoMacro( const ScAddress& rPos, const OUString& rInput,
}
ScDocument* pDocument = GetDocument();
- SfxObjectShell* pDocSh = pDocument->GetDocumentShell();
+ ScDocShell* pDocSh = pDocument->GetDocumentShell();
if ( !pDocSh )
return false;
@@ -296,8 +288,8 @@ bool ScValidationData::DoMacro( const ScAddress& rPos, const OUString& rInput,
{
SbModule* pModule = pMethod->GetModule();
SbxObject* pObject = pModule->GetParent();
- OUStringBuffer aMacroStr = pObject->GetName();
- aMacroStr.append('.').append(pModule->GetName()).append('.').append(pMethod->GetName());
+ OUString aMacroStr(
+ pObject->GetName() + "." + pModule->GetName() + "." + pMethod->GetName());
OUString aBasicStr;
// the distinction between document- and app-basic has to be done
@@ -343,7 +335,7 @@ bool ScValidationData::DoMacro( const ScAddress& rPos, const OUString& rInput,
if ( pCell )
pDocument->LockTable( rPos.Tab() );
SbxVariableRef refRes = new SbxVariable;
- ErrCode eRet = pDocSh->CallBasic( aMacroStr.makeStringAndClear(), aBasicStr, refPar.get(), refRes.get() );
+ ErrCode eRet = pDocSh->CallBasic( aMacroStr, aBasicStr, refPar.get(), refRes.get() );
if ( pCell )
pDocument->UnlockTable( rPos.Tab() );
@@ -371,7 +363,12 @@ bool ScValidationData::DoMacro( const ScAddress& rPos, const OUString& rInput,
void ScValidationData::DoCalcError( ScFormulaCell* pCell ) const
{
if ( eErrorStyle == SC_VALERR_MACRO )
- DoMacro( pCell->aPos, EMPTY_OUSTRING, pCell, nullptr );
+ DoMacro( pCell->aPos, OUString(), pCell, nullptr );
+}
+
+IMPL_STATIC_LINK_NOARG(ScValidationData, InstallLOKNotifierHdl, void*, vcl::ILibreOfficeKitNotifier*)
+{
+ return SfxViewShell::Current();
}
// true -> abort
@@ -382,6 +379,9 @@ bool ScValidationData::DoError(weld::Window* pParent, const OUString& rInput,
if ( eErrorStyle == SC_VALERR_MACRO )
return DoMacro(rPos, rInput, nullptr, pParent);
+ if (!bShowError)
+ return true;
+
// Output error message
OUString aTitle = aErrorTitle;
@@ -407,12 +407,10 @@ bool ScValidationData::DoError(weld::Window* pParent, const OUString& rInput,
break;
}
- bool bIsMobile = comphelper::LibreOfficeKit::isActive() && SfxViewShell::Current()
- && SfxViewShell::Current()->isLOKMobilePhone();
-
std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent, eType,
- eStyle, aMessage, bIsMobile));
+ eStyle, aMessage, SfxViewShell::Current()));
xBox->set_title(aTitle);
+ xBox->SetInstallLOKNotifierHdl(LINK(nullptr, ScValidationData, InstallLOKNotifierHdl));
switch (eErrorStyle)
{
@@ -443,28 +441,41 @@ bool ScValidationData::IsDataValidCustom(
if (rTest.isEmpty()) // check whether empty cells are allowed
return IsIgnoreBlank();
- if (rTest[0] == '=') // formulas do not pass the validity test
- return false;
+ SvNumberFormatter* pFormatter = nullptr;
+ sal_uInt32 nFormat = 0;
+ double nVal = 0.0;
+ OUString rStrResult = "";
+ bool bIsVal = false;
- SvNumberFormatter* pFormatter = GetDocument()->GetFormatTable();
+ if (rTest[0] == '=')
+ {
+ if (!isFormulaResultsValidatable(rTest, rPos, pFormatter, rStrResult, nVal, nFormat, bIsVal))
+ return false;
- // get the value if any
- sal_uInt32 nFormat = rPattern.GetNumberFormat( pFormatter );
- double nVal;
- bool bIsVal = pFormatter->IsNumberFormat( rTest, nFormat, nVal );
+ // check whether empty cells are allowed
+ if (rStrResult.isEmpty())
+ return IsIgnoreBlank();
+ }
+ else
+ {
+ pFormatter = GetDocument()->GetFormatTable();
+
+ // get the value if any
+ nFormat = rPattern.GetNumberFormat(pFormatter);
+ bIsVal = pFormatter->IsNumberFormat(rTest, nFormat, nVal);
+ rStrResult = rTest;
+ }
ScRefCellValue aTmpCell;
svl::SharedString aSS;
if (bIsVal)
{
- aTmpCell.meType = CELLTYPE_VALUE;
- aTmpCell.mfValue = nVal;
+ aTmpCell = ScRefCellValue(nVal);
}
else
{
- aTmpCell.meType = CELLTYPE_STRING;
- aSS = mpDoc->GetSharedStringPool().intern(rTest);
- aTmpCell.mpString = &aSS;
+ aSS = mpDoc->GetSharedStringPool().intern(rStrResult);
+ aTmpCell = ScRefCellValue(&aSS);
}
ScCellValue aOriginalCellValue(ScRefCellValue(*GetDocument(), rPos));
@@ -500,12 +511,12 @@ struct ScValidationDataIsNumeric
}
};
-bool ScValidationData::IsDataValidTextLen( const OUString& rTest, const ScAddress& rPos,
+bool ScValidationData::IsDataValidTextLen( std::u16string_view rTest, const ScAddress& rPos,
ScValidationDataIsNumeric* pDataNumeric ) const
{
sal_Int32 nLen;
if (!pDataNumeric)
- nLen = rTest.getLength();
+ nLen = rTest.size();
else
{
if (!pDataNumeric->mpFormatter)
@@ -532,25 +543,40 @@ bool ScValidationData::IsDataValid(
if (rTest.isEmpty()) // check whether empty cells are allowed
return IsIgnoreBlank();
- if (rTest[0] == '=') // formulas do not pass the validity test
- return false;
+ SvNumberFormatter* pFormatter = nullptr;
+ sal_uInt32 nFormat = 0;
+ double nVal = 0.0;
+ OUString rStrResult = "";
+ bool bIsVal = false;
- SvNumberFormatter* pFormatter = GetDocument()->GetFormatTable();
+ if (rTest[0] == '=')
+ {
+ if (!isFormulaResultsValidatable(rTest, rPos, pFormatter, rStrResult, nVal, nFormat, bIsVal))
+ return false;
- // get the value if any
- sal_uInt32 nFormat = rPattern.GetNumberFormat( pFormatter );
- double nVal;
- bool bIsVal = pFormatter->IsNumberFormat( rTest, nFormat, nVal );
+ // check whether empty cells are allowed
+ if (rStrResult.isEmpty())
+ return IsIgnoreBlank();
+ }
+ else
+ {
+ pFormatter = GetDocument()->GetFormatTable();
+
+ // get the value if any
+ nFormat = rPattern.GetNumberFormat(pFormatter);
+ bIsVal = pFormatter->IsNumberFormat(rTest, nFormat, nVal);
+ rStrResult = rTest;
+ }
bool bRet;
if (SC_VALID_TEXTLEN == eDataMode)
{
if (!bIsVal)
- bRet = IsDataValidTextLen( rTest, rPos, nullptr);
+ bRet = IsDataValidTextLen( rStrResult, rPos, nullptr);
else
{
ScValidationDataIsNumeric aDataNumeric( nVal, pFormatter, nFormat);
- bRet = IsDataValidTextLen( rTest, rPos, &aDataNumeric);
+ bRet = IsDataValidTextLen( rStrResult, rPos, &aDataNumeric);
}
}
else
@@ -562,7 +588,7 @@ bool ScValidationData::IsDataValid(
}
else
{
- svl::SharedString aSS = mpDoc->GetSharedStringPool().intern(rTest);
+ svl::SharedString aSS = mpDoc->GetSharedStringPool().intern( rStrResult );
ScRefCellValue aTmpCell(&aSS);
bRet = IsDataValid(aTmpCell, rPos);
}
@@ -583,23 +609,23 @@ bool ScValidationData::IsDataValid( ScRefCellValue& rCell, const ScAddress& rPos
OUString aString;
bool bIsVal = true;
- switch (rCell.meType)
+ switch (rCell.getType())
{
case CELLTYPE_VALUE:
- nVal = rCell.mfValue;
+ nVal = rCell.getDouble();
break;
case CELLTYPE_STRING:
- aString = rCell.mpString->getString();
+ aString = rCell.getSharedString()->getString();
bIsVal = false;
break;
case CELLTYPE_EDIT:
- if (rCell.mpEditText)
- aString = ScEditUtil::GetString(*rCell.mpEditText, GetDocument());
+ if (rCell.getEditText())
+ aString = ScEditUtil::GetString(*rCell.getEditText(), GetDocument());
bIsVal = false;
break;
case CELLTYPE_FORMULA:
{
- ScFormulaCell* pFCell = rCell.mpFormula;
+ ScFormulaCell* pFCell = rCell.getFormula();
bIsVal = pFCell->IsValue();
if ( bIsVal )
nVal = pFCell->GetValue();
@@ -645,6 +671,70 @@ bool ScValidationData::IsDataValid( ScRefCellValue& rCell, const ScAddress& rPos
return bOk;
}
+bool ScValidationData::isFormulaResultsValidatable(const OUString& rTest, const ScAddress& rPos, SvNumberFormatter* pFormatter,
+ OUString& rStrResult, double& nVal, sal_uInt32& nFormat, bool& bIsVal) const
+{
+ std::optional<ScSimpleFormulaCalculator> pFCell(std::in_place, *mpDoc, rPos, rTest, true);
+ pFCell->SetLimitString(true);
+
+ bool bColRowName = pFCell->HasColRowName();
+ if (bColRowName)
+ {
+ // ColRowName from RPN-Code?
+ if (pFCell->GetCode()->GetCodeLen() <= 1)
+ { // ==1: area
+ // ==0: would be an area if...
+ OUString aBraced = "(" + rTest + ")";
+ pFCell.emplace(*mpDoc, rPos, aBraced, true);
+ pFCell->SetLimitString(true);
+ }
+ else
+ bColRowName = false;
+ }
+
+ FormulaError nErrCode = pFCell->GetErrCode();
+ if (nErrCode == FormulaError::NONE || pFCell->IsMatrix())
+ {
+ pFormatter = mpDoc->GetFormatTable();
+ const Color* pColor;
+ if (pFCell->IsMatrix())
+ {
+ rStrResult = pFCell->GetString().getString();
+ }
+ else if (pFCell->IsValue())
+ {
+ nVal = pFCell->GetValue();
+ nFormat = pFormatter->GetStandardFormat(nVal, 0,
+ pFCell->GetFormatType(), ScGlobal::eLnge);
+ pFormatter->GetOutputString(nVal, nFormat, rStrResult, &pColor);
+ bIsVal = true;
+ }
+ else
+ {
+ nFormat = pFormatter->GetStandardFormat(
+ pFCell->GetFormatType(), ScGlobal::eLnge);
+ pFormatter->GetOutputString(pFCell->GetString().getString(), nFormat,
+ rStrResult, &pColor);
+ // Indicate it's a string, so a number string doesn't look numeric.
+ // Escape embedded quotation marks first by doubling them, as
+ // usual. Actually the result can be copy-pasted from the result
+ // box as literal into a formula expression.
+ rStrResult = "\"" + rStrResult.replaceAll("\"", "\"\"") + "\"";
+ }
+
+ ScRange aTestRange;
+ if (bColRowName || (aTestRange.Parse(rTest, *mpDoc) & ScRefFlags::VALID))
+ rStrResult += " ...";
+ // area
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
namespace {
/** Token array helper. Iterates over all string tokens.
@@ -698,11 +788,11 @@ rtl_uString* ScStringTokenIterator::Next()
}
/** Returns the number format of the passed cell, or the standard format. */
-sal_uLong lclGetCellFormat( const ScDocument& rDoc, const ScAddress& rPos )
+sal_uInt32 lclGetCellFormat( const ScDocument& rDoc, const ScAddress& rPos )
{
const ScPatternAttr* pPattern = rDoc.GetPattern( rPos.Col(), rPos.Row(), rPos.Tab() );
if( !pPattern )
- pPattern = rDoc.GetDefPattern();
+ pPattern = &rDoc.getCellAttributeHelper().getDefaultCellAttribute();
return pPattern->GetNumberFormat( rDoc.GetFormatTable() );
}
@@ -768,6 +858,7 @@ bool ScValidationData::GetSelectionFromFormula(
rMatch = -1;
SvNumberFormatter* pFormatter = GetDocument()->GetFormatTable();
+ sal_uInt32 nDestFormat = pDocument->GetNumberFormat(rPos.Col(), rPos.Row(), rPos.Tab());
SCSIZE nCol, nRow, nCols, nRows, n = 0;
pValues->GetDimensions( nCols, nRows );
@@ -843,7 +934,7 @@ bool ScValidationData::GetSelectionFromFormula(
}
if( nullptr != pStrings )
- pEntry.reset(new ScTypedStrData( aValStr, 0.0, ScTypedStrData::Standard));
+ pEntry.reset(new ScTypedStrData(aValStr, 0.0, 0.0, ScTypedStrData::Standard));
if (!rCell.isEmpty() && rMatch < 0)
aCondTokArr.AddString(rSPool.intern(aValStr));
@@ -864,12 +955,12 @@ bool ScValidationData::GetSelectionFromFormula(
//For external reference and a formula that results in an area or array, date formats are still lost.
if ( bRef )
{
- pDocument->GetInputString(static_cast<SCCOL>(nCol+aRange.aStart.Col()),
- static_cast<SCROW>(nRow+aRange.aStart.Row()), aRange.aStart.Tab() , aValStr);
+ aValStr = pDocument->GetInputString(static_cast<SCCOL>(nCol+aRange.aStart.Col()),
+ static_cast<SCROW>(nRow+aRange.aStart.Row()), aRange.aStart.Tab());
}
else
{
- pFormatter->GetInputLineString( nMatVal.fVal, 0, aValStr );
+ pFormatter->GetInputLineString( nMatVal.fVal, nDestFormat, aValStr );
}
}
@@ -880,7 +971,7 @@ bool ScValidationData::GetSelectionFromFormula(
aCondTokArr.AddDouble( nMatVal.fVal );
}
if( nullptr != pStrings )
- pEntry.reset(new ScTypedStrData( aValStr, nMatVal.fVal, ScTypedStrData::Value));
+ pEntry.reset(new ScTypedStrData(aValStr, nMatVal.fVal, nMatVal.fVal, ScTypedStrData::Value));
}
if (rMatch < 0 && !rCell.isEmpty() && IsEqualToTokenArray(rCell, rPos, aCondTokArr))
@@ -923,7 +1014,7 @@ bool ScValidationData::FillSelectionList(std::vector<ScTypedStrData>& rStrColl,
OUString aStr(pString);
bool bIsValue = GetDocument()->GetFormatTable()->IsNumberFormat(aStr, nFormat, fValue);
rStrColl.emplace_back(
- aStr, fValue, bIsValue ? ScTypedStrData::Value : ScTypedStrData::Standard);
+ aStr, fValue, fValue, bIsValue ? ScTypedStrData::Value : ScTypedStrData::Standard);
}
bOk = aIt.Ok();