summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrzej Hunt <andrzej@ahunt.org>2015-05-11 17:37:27 +0100
committerAndrzej Hunt <andrzej@ahunt.org>2015-10-20 18:18:32 +0200
commit426e2981448b28a9edea67e53fa0e3d1b4a3c709 (patch)
treeb8de0abbbf5497a2e1c4c5d66a0b4914aa01d4b6
parent045c51150f1c719a39089f7b7684261985fea96b (diff)
Use HeaderUnitDescriptor to pass around header specifics
Change-Id: I7c74211236b00c570941fda39cb0d69c1ce4e02c
-rw-r--r--sc/qa/unit/units.cxx75
-rw-r--r--sc/source/core/units/unitsimpl.cxx178
-rw-r--r--sc/source/core/units/unitsimpl.hxx27
3 files changed, 162 insertions, 118 deletions
diff --git a/sc/qa/unit/units.cxx b/sc/qa/unit/units.cxx
index 8e834830647c..e2be8534421f 100644
--- a/sc/qa/unit/units.cxx
+++ b/sc/qa/unit/units.cxx
@@ -409,54 +409,73 @@ void UnitsTest::testUnitValueStringSplitting() {
}
void UnitsTest::testUnitFromHeaderExtraction() {
- UtUnit aUnit;
- OUString sUnitString;
+ HeaderUnitDescriptor aHeader;
OUString sEmpty = "";
- CPPUNIT_ASSERT(!mpUnitsImpl->extractUnitFromHeaderString(sEmpty, aUnit, sUnitString));
- CPPUNIT_ASSERT(aUnit == UtUnit());
- CPPUNIT_ASSERT(sUnitString.isEmpty());
+ aHeader = mpUnitsImpl->extractUnitFromHeaderString(sEmpty);
+ CPPUNIT_ASSERT(!aHeader.valid);
+ CPPUNIT_ASSERT(aHeader.unit == UtUnit());
+ CPPUNIT_ASSERT(aHeader.unitString.isEmpty());
OUString sSimple = "bla bla [cm/s]";
- CPPUNIT_ASSERT(mpUnitsImpl->extractUnitFromHeaderString(sSimple, aUnit, sUnitString));
+ aHeader = mpUnitsImpl->extractUnitFromHeaderString(sSimple);
+ CPPUNIT_ASSERT(aHeader.valid);
// We need to test in Units (rather than testing Unit::getString()) as
// any given unit can have multiple string representations (and utunits defaults to
// representing e.g. cm as (I think) "0.01m").
UtUnit aTestUnit;
CPPUNIT_ASSERT(UtUnit::createUnit("cm/s", aTestUnit, mpUnitsImpl->mpUnitSystem));
- CPPUNIT_ASSERT(aUnit == aTestUnit);
- CPPUNIT_ASSERT(sUnitString == "cm/s");
+ CPPUNIT_ASSERT(aHeader.unit == aTestUnit);
+ CPPUNIT_ASSERT(aHeader.unitString == "cm/s");
+ CPPUNIT_ASSERT_EQUAL(aHeader.unitStringPosition, 9);
+
+ OUString sSimple2 = "bla bla [km/s] (more text)";
+ aHeader = mpUnitsImpl->extractUnitFromHeaderString(sSimple2);
+ CPPUNIT_ASSERT(aHeader.valid);
+ CPPUNIT_ASSERT(UtUnit::createUnit("km/s", aTestUnit, mpUnitsImpl->mpUnitSystem));
+ CPPUNIT_ASSERT(aHeader.unit == aTestUnit);
+ CPPUNIT_ASSERT(aHeader.unitString == "km/s");
+ CPPUNIT_ASSERT_EQUAL(aHeader.unitStringPosition, 9);
OUString sFreeStanding = "bla bla kg/h";
- CPPUNIT_ASSERT(mpUnitsImpl->extractUnitFromHeaderString(sFreeStanding, aUnit, sUnitString));
+ aHeader = mpUnitsImpl->extractUnitFromHeaderString(sFreeStanding);
+ CPPUNIT_ASSERT(aHeader.valid);
CPPUNIT_ASSERT(UtUnit::createUnit("kg/h", aTestUnit, mpUnitsImpl->mpUnitSystem));
- CPPUNIT_ASSERT(aUnit == aTestUnit);
- CPPUNIT_ASSERT(sUnitString == "kg/h");
+ CPPUNIT_ASSERT(aHeader.unit == aTestUnit);
+ CPPUNIT_ASSERT(aHeader.unitString == "kg/h");
+ CPPUNIT_ASSERT_EQUAL(aHeader.unitStringPosition, 8);
+
+ OUString sFreeStanding2 = "bla bla J/m and more text here";
+ aHeader = mpUnitsImpl->extractUnitFromHeaderString(sFreeStanding2);
+ CPPUNIT_ASSERT(aHeader.valid);
+ CPPUNIT_ASSERT(UtUnit::createUnit("J/m", aTestUnit, mpUnitsImpl->mpUnitSystem));
+ CPPUNIT_ASSERT(aHeader.unit == aTestUnit);
+ CPPUNIT_ASSERT(aHeader.unitString == "J/m");
+ CPPUNIT_ASSERT_EQUAL(aHeader.unitStringPosition, 8);
OUString sFreeStandingWithSpaces = "bla bla m / s";
- CPPUNIT_ASSERT(mpUnitsImpl->extractUnitFromHeaderString(sFreeStandingWithSpaces, aUnit, sUnitString));
+ aHeader = mpUnitsImpl->extractUnitFromHeaderString(sFreeStandingWithSpaces);
+ CPPUNIT_ASSERT(aHeader.valid);
CPPUNIT_ASSERT(UtUnit::createUnit("m/s", aTestUnit, mpUnitsImpl->mpUnitSystem));
- CPPUNIT_ASSERT(aUnit == aTestUnit);
- CPPUNIT_ASSERT(sUnitString == "m/s");
+ CPPUNIT_ASSERT(aHeader.unit == aTestUnit);
+ CPPUNIT_ASSERT(aHeader.unitString == "m / s");
+ CPPUNIT_ASSERT_EQUAL(aHeader.unitStringPosition, 8);
- OUString sOperatorSeparated = "bla bla / t/s";
- CPPUNIT_ASSERT(mpUnitsImpl->extractUnitFromHeaderString(sOperatorSeparated, aUnit, sUnitString));
+ OUString sOperatorSeparated = "foobar / t/s";
+ aHeader = mpUnitsImpl->extractUnitFromHeaderString(sOperatorSeparated);
+ CPPUNIT_ASSERT(aHeader.valid);
CPPUNIT_ASSERT(UtUnit::createUnit("t/s", aTestUnit, mpUnitsImpl->mpUnitSystem));
- CPPUNIT_ASSERT(aUnit == aTestUnit);
- CPPUNIT_ASSERT(sUnitString == "t/s");
-
+ CPPUNIT_ASSERT(aHeader.unit == aTestUnit);
+ CPPUNIT_ASSERT(aHeader.unitString == "t/s");
+ CPPUNIT_ASSERT_EQUAL(aHeader.unitStringPosition, 9);
OUString sRoundBrackets = "bla bla (t/h)";
- CPPUNIT_ASSERT(mpUnitsImpl->extractUnitFromHeaderString(sRoundBrackets, aUnit, sUnitString));
+ aHeader = mpUnitsImpl->extractUnitFromHeaderString(sRoundBrackets);
+ CPPUNIT_ASSERT(aHeader.valid);
CPPUNIT_ASSERT(UtUnit::createUnit("t/h", aTestUnit, mpUnitsImpl->mpUnitSystem));
- CPPUNIT_ASSERT(aUnit == aTestUnit);
- CPPUNIT_ASSERT(sUnitString == "(t/h)");
-
- // This becomes more of a nightmare to support, so let's not bother for now.
- // OUString sFreeStandingMixedSpaces = "bla bla m /s* kg";
- // CPPUNIT_ASSERT(mpUnitsImpl->extractUnitFromHeaderString(sFreeStanding, aUnit, sUnitString));
- // CPPUNIT_ASSERT(UtUnit::createUnit("m/s", aTestUnit, mpUnitsImpl->mpUnitSystem));
- // CPPUNIT_ASSERT(aUnit == aTestUnit);
+ CPPUNIT_ASSERT(aHeader.unit == aTestUnit);
+ CPPUNIT_ASSERT(aHeader.unitString == "(t/h)");
+ CPPUNIT_ASSERT_EQUAL(aHeader.unitStringPosition, 8);
}
void UnitsTest::testCellConversion() {
diff --git a/sc/source/core/units/unitsimpl.cxx b/sc/source/core/units/unitsimpl.cxx
index aa3fc1ea5579..cca532d4614d 100644
--- a/sc/source/core/units/unitsimpl.cxx
+++ b/sc/source/core/units/unitsimpl.cxx
@@ -313,7 +313,7 @@ OUString UnitsImpl::extractUnitStringForCell(const ScAddress& rAddress, ScDocume
return extractUnitStringFromFormat(rFormatString);
}
-bool UnitsImpl::findUnitInStandardHeader(const OUString& rsHeader, UtUnit& aUnit, OUString& sUnitString) {
+HeaderUnitDescriptor UnitsImpl::findUnitInStandardHeader(const OUString& rsHeader) {
// TODO: we should do a sanity check that there's only one such unit though (and fail if there are multiple).
// Since otherwise there's no way for us to know which unit is the intended one, hence we need to get
// the user to deconfuse us by correcting their header to only contain the intended unit.
@@ -347,21 +347,23 @@ bool UnitsImpl::findUnitInStandardHeader(const OUString& rsHeader, UtUnit& aUnit
// i.e. startOffset is the last character of the intended substring, endOffset the first character.
// We specifically grab the offsets for the first actual regex group, which are stored in [1], the indexes
// at [0] represent the whole matched string (i.e. including square brackets).
- sUnitString = rsHeader.copy(aResult.endOffset[1], aResult.startOffset[1] - aResult.endOffset[1]);
+ UtUnit aUnit;
+ sal_Int32 nBegin = aResult.endOffset[1];
+ sal_Int32 nEnd = aResult.startOffset[1] - aResult.endOffset[1];
+ OUString sUnitString = rsHeader.copy( nBegin, nEnd);
if (UtUnit::createUnit(sUnitString, aUnit, mpUnitSystem)) {
- return true;
+ return { true, aUnit, boost::optional< ScAddress >(), sUnitString, nBegin };
}
nStartPosition = aResult.endOffset[0];
}
}
- sUnitString.clear();
- return false;
-}
+ return { false, UtUnit(), boost::optional< ScAddress >(), "", -1 };
+}
-bool UnitsImpl::findFreestandingUnitInHeader(const OUString& rsHeader, UtUnit& aUnit, OUString& sUnitString) {
+HeaderUnitDescriptor UnitsImpl::findFreestandingUnitInHeader(const OUString& rsHeader) {
// We just split the string and test whether each token is either a valid unit in its own right,
// or is an operator that could glue together multiple units (i.e. multiplication/division).
// This is sufficient for when there are spaces between elements composing the unit, and none
@@ -373,50 +375,69 @@ bool UnitsImpl::findFreestandingUnitInHeader(const OUString& rsHeader, UtUnit& a
const sal_Int32 nTokenCount = comphelper::string::getTokenCount(rsHeader, ' ');
const OUString sOperators = "/*"; // valid
- sUnitString.clear();
+
+ OUStringBuffer sUnitStringBuf;
+
+ sal_Int32 nStartPos = -1;
+ sal_Int32 nTokenPos = 0;
for (sal_Int32 nToken = 0; nToken < nTokenCount; nToken++) {
- OUString sToken = rsHeader.getToken(nToken, ' ');
+ OUString sToken = rsHeader.getToken( 0,' ', nTokenPos);
UtUnit aTestUnit;
+
+ // Only test for a separator character if we have already got something in our string, as
+ // some of the operators could be used as separators from description to unit
+ // (e.g. "a description / kg").
if (UtUnit::createUnit(sToken, aTestUnit, mpUnitSystem) ||
- // Only test for a separator character if we have already got something in our string, as
- // some of the operators could be used as separators from description to unit
- // (e.g. "a description / kg").
- ((sUnitString.getLength() > 0) && (sToken.getLength() == 1) && (sOperators.indexOf(sToken[0]) != -1))) {
- // we're repeatedly testing the string hence using an OUStringBuffer isn't of much use since there's
- // no simple/efficient way of repeatedly getting a testable OUString from the buffer.
- sUnitString += sToken;
- } else if (sUnitString.getLength() > 0) {
+ ((sUnitStringBuf.getLength() > 0) && (sToken.getLength() == 1) && (sOperators.indexOf(sToken[0]) != -1))) {
+
+ if (nStartPos == -1) {
+ // getToken sets nTokenPos to the first position after
+ // the current token (or -1 if the token is at the end
+ // the string).
+ if (nTokenPos == -1) {
+ nStartPos = rsHeader.getLength() - sToken.getLength();
+ } else {
+ nStartPos = nTokenPos - sToken.getLength() - 1;
+ }
+ }
+
+ sUnitStringBuf.append(" ").append(sToken);
+ } else if (sUnitStringBuf.getLength() > 0) {
// If we have units, followed by text, followed by units, we should still flag an error since
// that's ambiguous (unless the desired units are enclose in [] in which case we've
// already extracted these desired units in step 1 above.
break;
}
}
+ // Remove the leading space, it doesn't count as part of the unit string.
+ // (We reinsert spaces above as the HeaderUnitDescriptor must have the
+ // the original string as found in the header, i.e. we can't remove the
+ // spaces.)
+ sUnitStringBuf.remove(0, 1);
// We test the length to make sure we don't return the dimensionless unit 1 if we haven't found any units
// in the header.
+ UtUnit aUnit;
+ OUString sUnitString = sUnitStringBuf.makeStringAndClear();
if (sUnitString.getLength() && UtUnit::createUnit(sUnitString, aUnit, mpUnitSystem)) {
- return true;
+ return { true, aUnit, boost::optional< ScAddress >(), sUnitString, nStartPos };
}
- sUnitString.clear();
- return false;
+
+ return { false, UtUnit(), boost::optional< ScAddress >(), "", -1 };
}
-bool UnitsImpl::extractUnitFromHeaderString(const OUString& rsHeader, UtUnit& aUnit, OUString& sUnitString) {
+HeaderUnitDescriptor UnitsImpl::extractUnitFromHeaderString(const OUString& rsHeader) {
// 1. Ideally we have units in a 'standard' format, i.e. enclose in square brackets:
- if (findUnitInStandardHeader(rsHeader, aUnit, sUnitString)) {
- return true;
+ HeaderUnitDescriptor aHeader = findUnitInStandardHeader(rsHeader);
+ if (aHeader.valid) {
+ return aHeader;
}
// 2. But if not we check for free-standing units
- if (findFreestandingUnitInHeader(rsHeader, aUnit, sUnitString)) {
- return true;
- }
-
- // 3. Give up
- aUnit = UtUnit(); // assign invalid
- sUnitString.clear();
- return false;
+ aHeader = findFreestandingUnitInHeader(rsHeader);
+ // We return the result either way (it's either a valid unit,
+ // or invalid).
+ return aHeader;
}
UtUnit UnitsImpl::getUnitForCell(const ScAddress& rCellAddress, ScDocument* pDoc) {
@@ -428,11 +449,11 @@ UtUnit UnitsImpl::getUnitForCell(const ScAddress& rCellAddress, ScDocument* pDoc
return aUnit;
}
- OUString aHeaderUnitString; // Unused -- passed by reference below
- ScAddress aHeaderAddress; // Unused too
- UtUnit aHeaderUnit = findHeaderUnitForCell(rCellAddress, pDoc, aHeaderUnitString, aHeaderAddress);
- if (aHeaderUnit.isValid())
- return aHeaderUnit;
+ HeaderUnitDescriptor aHeader = findHeaderUnitForCell(rCellAddress, pDoc);
+
+ if (aHeader.valid) {
+ return aHeader.unit;
+ }
SAL_INFO("sc.units", "no unit obtained for token at cell " << rCellAddress.GetColRowString());
@@ -457,23 +478,27 @@ UtUnit UnitsImpl::getUnitForRef(FormulaToken* pToken, const ScAddress& rFormulaA
return getUnitForCell(aCellAddress, pDoc);
}
-UtUnit UnitsImpl::findHeaderUnitForCell(const ScAddress& rCellAddress,
- ScDocument* pDoc,
- OUString& rsHeaderUnitString,
- ScAddress& rHeaderAddress) {
+HeaderUnitDescriptor UnitsImpl::findHeaderUnitForCell(const ScAddress& rCellAddress,
+ ScDocument* pDoc) {
// Scan UPwards from the current cell to find a header. This is since we could potentially
// have two different sets of data sharing a column, hence finding the closest header is necessary.
- rHeaderAddress = rCellAddress;
- while (rHeaderAddress.Row() > 0) {
- rHeaderAddress.IncRow(-1);
+ ScAddress address = rCellAddress;
+
+ while (address.Row() > 0) {
+ address.IncRow(-1);
// We specifically test for string cells as intervening data cells could have
// differently defined units of their own. (However as these intervening cells
// will have the unit stored in the number format it would be ignored when
// checking the cell's string anyway.)
UtUnit aUnit;
- if (pDoc->GetCellType(rHeaderAddress) == CELLTYPE_STRING &&
- extractUnitFromHeaderString(pDoc->GetString(rHeaderAddress), aUnit, rsHeaderUnitString)) {
+ if (pDoc->GetCellType(address) == CELLTYPE_STRING) {
+ HeaderUnitDescriptor aHeader = extractUnitFromHeaderString(pDoc->GetString(address));
+
+ if (aHeader.valid) {
+ aHeader.address = address;
+ return aHeader;
+ }
// TODO: one potential problem is that we could have a text only "united" data cell
// (where the unit wasn't automatically extracted due to being entered via
// a different spreadsheet program).
@@ -482,12 +507,10 @@ UtUnit UnitsImpl::findHeaderUnitForCell(const ScAddress& rCellAddress,
//
// TODO: and what if there are multiple units in the header (for whatever reason?)?
// We can probably just warn the user that we'll be giving them garbage in that case?
- return aUnit;
}
}
- rHeaderAddress.SetInvalid();
- rsHeaderUnitString.clear();
- return UtUnit();
+
+ return { false, UtUnit(), boost::optional< ScAddress >(), "", -1 };
}
// getUnitForRef: check format -> if not in format, use more complicated method? (Format overrides header definition)
@@ -575,13 +598,10 @@ bool UnitsImpl::verifyFormula(ScTokenArray* pArray, const ScAddress& rFormulaAdd
return false;
}
- OUString sUnitString;
- ScAddress aAddress;
-
- UtUnit aHeaderUnit = findHeaderUnitForCell(rFormulaAddress, pDoc, sUnitString, aAddress);
+ HeaderUnitDescriptor aHeader = findHeaderUnitForCell(rFormulaAddress, pDoc);
UtUnit aResultUnit = boost::get< UtUnit>(aStack.top().item);
- if (aHeaderUnit.isValid() && aHeaderUnit != aResultUnit) {
+ if (aHeader.valid && aHeader.unit != aResultUnit) {
return false;
}
@@ -635,11 +655,12 @@ bool UnitsImpl::isCellConversionRecommended(const ScAddress& rCellAddress,
rsCellUnit = extractUnitStringForCell(rCellAddress, pDoc);
if (!rsCellUnit.isEmpty() && UtUnit::createUnit(rsCellUnit, aCellUnit, mpUnitSystem)) {
- UtUnit aHeaderUnit = findHeaderUnitForCell(rCellAddress, pDoc, rsHeaderUnit, rHeaderCellAddress);
- if (rHeaderCellAddress.IsValid()) {
- if (aHeaderUnit.areConvertibleTo(aCellUnit)) {
- return true;
- }
+ HeaderUnitDescriptor aHeader = findHeaderUnitForCell(rCellAddress, pDoc);
+ if (aHeader.valid && aHeader.unit.areConvertibleTo(aCellUnit)) {
+ rsHeaderUnit = aHeader.unitString;
+ assert(aHeader.address);
+ rHeaderCellAddress = *aHeader.address;
+ return true;
}
}
@@ -659,9 +680,8 @@ bool UnitsImpl::convertCellToHeaderUnit(const ScAddress& rCellAddress,
UtUnit aOldUnit;
UtUnit::createUnit(sCellUnit, aOldUnit, mpUnitSystem);
- OUString sHeaderUnitFound;
- ScAddress aHeaderAddress; // Unused, but passed by reference
- UtUnit aNewUnit = findHeaderUnitForCell(rCellAddress, pDoc, sHeaderUnitFound, aHeaderAddress);
+ HeaderUnitDescriptor aHeader = findHeaderUnitForCell(rCellAddress, pDoc);
+ assert(aHeader.valid);
// We test that we still have all data in the same format as expected.
// This is maybe a tad defensive, but this call is most likely to be delayed
@@ -671,11 +691,11 @@ bool UnitsImpl::convertCellToHeaderUnit(const ScAddress& rCellAddress,
// called afterwards (especially for non-modal interactions, e.g.
// with an infobar which can remain open whilst the document is edited).
if ((sCellUnit == rsOldUnit) &&
- (sHeaderUnitFound == rsNewUnit) &&
+ (aHeader.unitString == rsNewUnit) &&
(pDoc->GetCellType(rCellAddress) == CELLTYPE_VALUE)) {
- assert(aOldUnit.areConvertibleTo(aNewUnit));
+ assert(aOldUnit.areConvertibleTo(aHeader.unit));
double nOldValue = pDoc->GetValue(rCellAddress);
- double nNewValue = aOldUnit.convertValueTo(nOldValue, aNewUnit);
+ double nNewValue = aOldUnit.convertValueTo(nOldValue, aHeader.unit);
pDoc->SetValue(rCellAddress, nNewValue);
pDoc->SetNumberFormat(rCellAddress, 0); // 0 == no number format?
@@ -712,37 +732,33 @@ bool UnitsImpl::convertCellUnits(const ScRange& rRange,
// Each column is independent hence we are able to handle each separately.
for (SCCOL nCol = nStartCol; nCol <= nEndCol; nCol++) {
- ScAddress aCurrentHeaderAddress(ScAddress::INITIALIZE_INVALID);
- UtUnit aCurrentHeaderUnit;
- OUString sHeaderUnitString;
+ HeaderUnitDescriptor aHeader = { false, UtUnit(), boost::optional< ScAddress >(), "", -1 };
for (SCROW nRow = nEndRow; nRow >= nStartRow; nRow--) {
ScAddress aCurrent(nCol, nRow, nStartTab);
- if (aCurrent == aCurrentHeaderAddress) {
- // TODO: rewrite this to use HeaderUnitDescriptor once implemented.
- // We can't do a dumb replace since that might overwrite other characters
- // (many units are just single characters).
+ if (aCurrent == aHeader.address) {
OUString sHeader = pDoc->GetString(aCurrent);
- sHeader = sHeader.replaceAll(sHeaderUnitString, rsOutputUnit);
+ sHeader = sHeader.replaceAt(aHeader.unitStringPosition, aHeader.unitString.getLength(), rsOutputUnit);
pDoc->SetString(aCurrent, sHeader);
- aCurrentHeaderAddress.SetInvalid();
+ aHeader.valid = false;
} else if (pDoc->GetCellType(aCurrent) != CELLTYPE_STRING) {
- if (!aCurrentHeaderUnit.isValid()) {
- aCurrentHeaderUnit = findHeaderUnitForCell(aCurrent, pDoc, sHeaderUnitString, aCurrentHeaderAddress);
+ if (!aHeader.valid) {
+ aHeader = findHeaderUnitForCell(aCurrent, pDoc);
// If there is no header we get an invalid unit returned from findHeaderUnitForCell,
// and therfore assume the dimensionless unit 1.
- if (!aCurrentHeaderUnit.isValid()) {
- UtUnit::createUnit("", aCurrentHeaderUnit, mpUnitSystem);
+ if (!aHeader.valid) {
+ UtUnit::createUnit("", aHeader.unit, mpUnitSystem);
+ aHeader.valid = true;
}
}
OUString sLocalUnit(extractUnitStringForCell(aCurrent, pDoc));
UtUnit aLocalUnit;
if (sLocalUnit.isEmpty()) {
- aLocalUnit = aCurrentHeaderUnit;
+ aLocalUnit = aHeader.unit;
} else { // override header unit with annotation unit
if (!UtUnit::createUnit(sLocalUnit, aLocalUnit, mpUnitSystem)) {
// but assume dimensionless if invalid
@@ -750,8 +766,8 @@ bool UnitsImpl::convertCellUnits(const ScRange& rRange,
}
}
- bool bLocalAnnotationRequired = (!aRange.In(aCurrentHeaderAddress)) &&
- (aOutputUnit != aCurrentHeaderUnit);
+ bool bLocalAnnotationRequired = (!aRange.In(*aHeader.address)) &&
+ (aOutputUnit != aHeader.unit);
double nValue = pDoc->GetValue(aCurrent);
if (!aLocalUnit.areConvertibleTo(aOutputUnit)) {
diff --git a/sc/source/core/units/unitsimpl.hxx b/sc/source/core/units/unitsimpl.hxx
index ff927f2a1393..7320baad1d19 100644
--- a/sc/source/core/units/unitsimpl.hxx
+++ b/sc/source/core/units/unitsimpl.hxx
@@ -58,6 +58,17 @@ struct UnitsResult {
boost::optional<UtUnit> units;
};
+struct HeaderUnitDescriptor {
+ bool valid;
+ UtUnit unit;
+ boost::optional< ScAddress > address;
+ // This must be the unit string copied verbatim from the header
+ // (i.e. including spaces)
+ OUString unitString;
+ // Position of unitString within the cell contents
+ sal_Int32 unitStringPosition;
+};
+
class UnitsImpl: public Units {
friend class test::UnitsTest;
@@ -103,9 +114,9 @@ private:
* Find and extract a Unit in the standard header notation,
* i.e. a unit enclose within square brackets (e.g. "length [cm]".
*
- * @return true if such a unit is found.
+ * @return The HeaderUnitDescriptor, with valid set to true if a unit was found.
*/
- bool findUnitInStandardHeader(const OUString& rHeader, UtUnit& aUnit, OUString& sUnitString);
+ HeaderUnitDescriptor findUnitInStandardHeader(const OUString& rHeader);
/**
* Find and extract a freestanding Unit from a header string.
* This includes strings such as "speed m/s", "speed m / s",
@@ -117,11 +128,11 @@ private:
* more permutations of the same unit, but this should at least cover the most
* obvious cases.
*
- * @ return true if a unit is found.
+ * @ return The HeaderUnitDescriptor, with valid set to true if a unit was found.
*/
- bool findFreestandingUnitInHeader(const OUString& rHeader, UtUnit& aUnit, OUString& sUnitString);
+ HeaderUnitDescriptor findFreestandingUnitInHeader(const OUString& rHeader);
- bool extractUnitFromHeaderString(const OUString& rHeader, UtUnit& aUnit, OUString& sUnitString);
+ HeaderUnitDescriptor extractUnitFromHeaderString(const OUString& rHeader);
static OUString extractUnitStringFromFormat(const OUString& rFormatString);
static OUString extractUnitStringForCell(const ScAddress& rAddress, ScDocument* pDoc);
@@ -142,10 +153,8 @@ private:
* that there is a valid unit), but we might also need the original
* String (which can't necessarily be regenerated from the UtUnit).
*/
- UtUnit findHeaderUnitForCell(const ScAddress& rCellAddress,
- ScDocument* pDoc,
- OUString& rsHeaderUnitString,
- ScAddress& rHeaderAddress);
+ HeaderUnitDescriptor findHeaderUnitForCell(const ScAddress& rCellAddress,
+ ScDocument* pDoc);
};
}} // namespace sc::units