Rebased ref, commits from common ancestor:
commit 77971aa38eca3a52d559bfa5b9f7344e7e710d2b
Author: Andrzej Hunt <andr...@ahunt.org>
Date:   Mon Jun 1 18:10:29 2015 +0100

    Add tests for output unit verification.
    
    Change-Id: Ia273a64fdbb5e1fe57f41679e9d77e0df78987de

diff --git a/sc/qa/unit/units.cxx b/sc/qa/unit/units.cxx
index 4e9c2f9..e2ad7cc 100644
--- a/sc/qa/unit/units.cxx
+++ b/sc/qa/unit/units.cxx
@@ -205,6 +205,14 @@ void UnitsTest::testUnitVerification() {
     setNumberFormatUnit(address, "m");
     mpDoc->SetValue(address, 1);
 
+    // 6th column: header annotation for output verification
+    address = ScAddress(5, 0, 0);
+    mpDoc->SetString(address, "foobar [cm]");
+
+    // 7th column: another header annotation
+    address = ScAddress(6, 0, 0);
+    mpDoc->SetString(address, "foobar (cm/s)");
+
     ScFormulaCell* pCell;
     ScTokenArray* pTokens;
 
@@ -359,6 +367,52 @@ void UnitsTest::testUnitVerification() {
         pTokens = pCell->GetCode();
         CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::ERROR_INPUT_INCOMPATIBLE);
     }
+
+
+    // Test output unit verification (i.e. using header annotations)
+
+    // header in [cm], cell with cm
+    address = ScAddress(5, 1, 0);
+    mpDoc->SetFormula(address, "=A1");
+    pCell = mpDoc->GetFormulaCell(address);
+    pTokens = pCell->GetCode();
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::VERIFIED);
+
+
+    // header in [cm], cell with 100*cm
+    address.IncRow();
+    mpDoc->SetFormula(address, "=100*A1");
+    pCell = mpDoc->GetFormulaCell(address);
+    pTokens = pCell->GetCode();
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::ERROR_OUTPUT_SCALING);
+
+    // header in [cm], cell with kg
+    address.IncRow();
+    mpDoc->SetFormula(address, "=B1");
+    pCell = mpDoc->GetFormulaCell(address);
+    pTokens = pCell->GetCode();
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::ERROR_OUTPUT_INCOMPATIBLE);
+
+    // header in [cm], cell with m
+    address.IncRow();
+    mpDoc->SetFormula(address, "=E1");
+    pCell = mpDoc->GetFormulaCell(address);
+    pTokens = pCell->GetCode();
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::ERROR_OUTPUT_SCALING);
+
+    // header in [cm], cell with 100*m
+    address.IncRow();
+    mpDoc->SetFormula(address, "=100*E1");
+    pCell = mpDoc->GetFormulaCell(address);
+    pTokens = pCell->GetCode();
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::VERIFIED);
+
+    // header in (cm/s), formula resulting in cm/s
+    address = ScAddress(6, 1, 0);
+    mpDoc->SetFormula(address, "=A1/C1");
+    pCell = mpDoc->GetFormulaCell(address);
+    pTokens = pCell->GetCode();
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::VERIFIED);
 }
 
 void UnitsTest::testUnitFromFormatStringExtraction() {
commit 80c15be131e8bcb9063fd93a5aa2d32a36c8c72b
Author: Andrzej Hunt <andr...@ahunt.org>
Date:   Mon Jun 1 17:53:48 2015 +0100

    Return status for formula errors
    
    Returning a status (instead of a boolean) means we will be able to
    print better error messages for the user in future.
    
    Change-Id: I0b08913267fedb5735112acc7427156e07e32b31

diff --git a/sc/inc/units.hxx b/sc/inc/units.hxx
index b428d40..411fb84 100644
--- a/sc/inc/units.hxx
+++ b/sc/inc/units.hxx
@@ -38,11 +38,26 @@ struct RangeUnits {
     bool compatible;
 };
 
+/**
+ * The unit correctness status for a formula.
+ * UNKNOWN denotes that the units could not be verified
+ * (this can occur if e.g. an unsupported operator or formula
+ * is used).
+ */
+enum class FormulaStatus {
+    VERIFIED,
+    UNKNOWN,
+    ERROR_INPUT_SCALING,
+    ERROR_INPUT_INCOMPATIBLE,
+    ERROR_OUTPUT_SCALING,
+    ERROR_OUTPUT_INCOMPATIBLE
+};
+
 class Units {
 public:
     static ::boost::shared_ptr< Units > GetUnits();
 
-    virtual bool verifyFormula(ScTokenArray* pArray, const ScAddress& 
rFormulaAddress, ScDocument* pDoc) = 0;
+    virtual FormulaStatus verifyFormula(ScTokenArray* pArray, const ScAddress& 
rFormulaAddress, ScDocument* pDoc) = 0;
 
     /*
      * Split the input into value and unit, where rInput == rValue + rUnit.
diff --git a/sc/qa/unit/units.cxx b/sc/qa/unit/units.cxx
index b35cd40..4e9c2f9 100644
--- a/sc/qa/unit/units.cxx
+++ b/sc/qa/unit/units.cxx
@@ -213,65 +213,65 @@ void UnitsTest::testUnitVerification() {
     mpDoc->SetFormula(address, "=A1+A2");
     pCell = mpDoc->GetFormulaCell(address);
     pTokens = pCell->GetCode();
-    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::VERIFIED);
 
-    // Test that addition of different units fails
+    // Test that addition of different units fails - incompatible types
     address = ScAddress(0, 6, 0);
     mpDoc->SetFormula(address, "=A1+B1");
     pCell = mpDoc->GetFormulaCell(address);
     pTokens = pCell->GetCode();
-    CPPUNIT_ASSERT(!mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::ERROR_INPUT_INCOMPATIBLE);
 
     // Test that addition and multiplication works (i.e. kg*s+kg*s)
     address = ScAddress(0, 7, 0);
     mpDoc->SetFormula(address, "=A1*B1+A2*B2");
     pCell = mpDoc->GetFormulaCell(address);
     pTokens = pCell->GetCode();
-    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::VERIFIED);
 
     // Test another combination (i.e. cm/s+'cm/s')
     address = ScAddress(0, 8, 0);
     mpDoc->SetFormula(address, "=A1/C1+D1");
     pCell = mpDoc->GetFormulaCell(address);
     pTokens = pCell->GetCode();
-    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::VERIFIED);
 
     // Test that another combination fails (cm*kg/s+'cm/s')
     address = ScAddress(0, 9, 0);
     mpDoc->SetFormula(address, "=A1*B1/C1+D1");
     pCell = mpDoc->GetFormulaCell(address);
     pTokens = pCell->GetCode();
-    CPPUNIT_ASSERT(!mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::ERROR_INPUT_INCOMPATIBLE);
 
     // Test that addition of scaled units works (cm + 100*m)
     address = ScAddress(0, 10, 0);
     mpDoc->SetFormula(address, "=A1+100*E1");
     pCell = mpDoc->GetFormulaCell(address);
     pTokens = pCell->GetCode();
-    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::VERIFIED);
     // 10cm + 100*1m = 110cm
-    CPPUNIT_ASSERT(mpDoc->GetValue(address) == 110);
+    CPPUNIT_ASSERT_EQUAL(mpDoc->GetValue(address), 110.0);
 
     // But addition of them unscaled fails (cm + m)
     address = ScAddress(0, 11, 0);
     mpDoc->SetFormula(address, "=A1+E1");
     pCell = mpDoc->GetFormulaCell(address);
     pTokens = pCell->GetCode();
-    CPPUNIT_ASSERT(!mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::ERROR_INPUT_SCALING);
 
     // As does wrong scaling (cm+m/50)
     address = ScAddress(0, 12, 0);
     mpDoc->SetFormula(address, "=A1+E1/50");
     pCell = mpDoc->GetFormulaCell(address);
     pTokens = pCell->GetCode();
-    CPPUNIT_ASSERT(!mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::ERROR_INPUT_SCALING);
 
     // And scaling doesn't help when adding incompatible units (kg + 100*m)
     address = ScAddress(0, 13, 0);
     mpDoc->SetFormula(address, "=B1+100*E1");
     pCell = mpDoc->GetFormulaCell(address);
     pTokens = pCell->GetCode();
-    CPPUNIT_ASSERT(!mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::ERROR_INPUT_INCOMPATIBLE);
 
     // Test Ranges:
     // SUM("kg")
@@ -279,49 +279,49 @@ void UnitsTest::testUnitVerification() {
     mpDoc->SetFormula(address, "=SUM(B1:B3)");
     pCell = mpDoc->GetFormulaCell(address);
     pTokens = pCell->GetCode();
-    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::VERIFIED);
 
     // SUM("cm"&"kg")
     address.IncRow();
     mpDoc->SetFormula(address, "=SUM(A1:B3)");
     pCell = mpDoc->GetFormulaCell(address);
     pTokens = pCell->GetCode();
-    CPPUNIT_ASSERT(!mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::ERROR_INPUT_INCOMPATIBLE);
 
     // SUM("cm"&"kg") - multiple ranges
     address.IncRow();
     mpDoc->SetFormula(address, "=SUM(A1:A3,B1:B3)");
     pCell = mpDoc->GetFormulaCell(address);
     pTokens = pCell->GetCode();
-    CPPUNIT_ASSERT(!mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::ERROR_INPUT_INCOMPATIBLE);
 
     // SUM("cm")+SUM("kg")
     address.IncRow();
     mpDoc->SetFormula(address, "=SUM(A1:A3)+SUM(B1:B3)");
     pCell = mpDoc->GetFormulaCell(address);
     pTokens = pCell->GetCode();
-    CPPUNIT_ASSERT(!mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::ERROR_INPUT_INCOMPATIBLE);
 
     // SUM("cm")/SUM("s")+SUM("cm/s")
     address.IncRow();
     mpDoc->SetFormula(address, "=SUM(A1:A3)/SUM(C1:C3)+SUM(D1:D3)");
     pCell = mpDoc->GetFormulaCell(address);
     pTokens = pCell->GetCode();
-    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::VERIFIED);
 
     // PRODUCT("cm/","s")+"cm"
     address.IncRow();
     mpDoc->SetFormula(address, "=PRODUCT(C1:D1)+A1");
     pCell = mpDoc->GetFormulaCell(address);
     pTokens = pCell->GetCode();
-    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::VERIFIED);
 
     // PRODUCT("cm/","s")+"kg"
     address.IncRow();
     mpDoc->SetFormula(address, "=PRODUCT(C1:D1)+B1");
     pCell = mpDoc->GetFormulaCell(address);
     pTokens = pCell->GetCode();
-    CPPUNIT_ASSERT(!mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::ERROR_INPUT_INCOMPATIBLE);
 
     // Test that multiple arguments of mixed types work too
     // Adding multiple cells from one column is ok
@@ -329,7 +329,7 @@ void UnitsTest::testUnitVerification() {
     mpDoc->SetFormula(address, "=SUM(A1,A2:A3)");
     pCell = mpDoc->GetFormulaCell(address);
     pTokens = pCell->GetCode();
-    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::VERIFIED);
 
     // But mixing the columns fails because of mixed units
     // (This test is primarily to ensure that we can handle arbitrary numbers
@@ -338,7 +338,7 @@ void UnitsTest::testUnitVerification() {
     mpDoc->SetFormula(address, "=SUM(A1,A2:A3,B1:B3,C1,C2,C3)");
     pCell = mpDoc->GetFormulaCell(address);
     pTokens = pCell->GetCode();
-    CPPUNIT_ASSERT(!mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+    CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::ERROR_INPUT_INCOMPATIBLE);
 
     // Do a quick sanity check for all the other supported functions
     // The following all expect identically united inputs, and should
@@ -350,14 +350,14 @@ void UnitsTest::testUnitVerification() {
         mpDoc->SetFormula(address, "=" + aFunc + "(A1:A2)+A3");
         pCell = mpDoc->GetFormulaCell(address);
         pTokens = pCell->GetCode();
-        CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+        CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::VERIFIED);
 
         // FOO(cm) + kg
         address.IncRow();
         mpDoc->SetFormula(address, "=" + aFunc + "(A1:A2)+B3");
         pCell = mpDoc->GetFormulaCell(address);
         pTokens = pCell->GetCode();
-        CPPUNIT_ASSERT(!mpUnitsImpl->verifyFormula(pTokens, address, mpDoc));
+        CPPUNIT_ASSERT(mpUnitsImpl->verifyFormula(pTokens, address, mpDoc) == 
FormulaStatus::ERROR_INPUT_INCOMPATIBLE);
     }
 }
 
diff --git a/sc/source/core/units/unitsimpl.cxx 
b/sc/source/core/units/unitsimpl.cxx
index 567265b..84d5c0e 100644
--- a/sc/source/core/units/unitsimpl.cxx
+++ b/sc/source/core/units/unitsimpl.cxx
@@ -105,7 +105,7 @@ UnitsResult UnitsImpl::getOutputUnitsForOpCode(stack< 
RAUSItem >& rStack, const
         switch (aOpCode) {
         case ocNot:
             if (!pUnit.isDimensionless()) {
-                return { UnitsStatus::UNITS_INVALID, boost::none };
+                return { UnitsStatus::UNITS_INVALID_INCOMPATIBLE, boost::none 
};
             }
             // We just keep the same unit (in this case no unit) so can
             // fall through.
@@ -147,10 +147,12 @@ UnitsResult UnitsImpl::getOutputUnitsForOpCode(stack< 
RAUSItem >& rStack, const
                 // The two units are identical, hence we can return either.
                 pOut = pFirstUnit;
                 SAL_INFO("sc.units", "verified equality for unit " << 
pFirstUnit);
+            } else if (pFirstUnit.areConvertibleTo(pSecondUnit)) {
+                return { UnitsStatus::UNITS_INVALID_SCALING, boost::none };
             } else {
-                return { UnitsStatus::UNITS_INVALID, boost::none };
-                // TODO: notify/link UI.
+                return { UnitsStatus::UNITS_INVALID_INCOMPATIBLE, boost::none 
};
             }
+
             break;
         case ocMul:
             pOut = pFirstUnit * pSecondUnit;
@@ -213,8 +215,13 @@ UnitsResult UnitsImpl::getOutputUnitsForOpCode(stack< 
RAUSItem >& rStack, const
                     aFirstUnit = aUnitsStack.top();
                 } else {
                     UtUnit aCurrentUnit(aUnitsStack.top());
+
                     if (aFirstUnit.get() != aCurrentUnit) {
-                        return { UnitsStatus::UNITS_INVALID, boost::none };
+                        if (aFirstUnit.get().areConvertibleTo(aCurrentUnit)) {
+                            return { UnitsStatus::UNITS_INVALID_SCALING, 
boost::none };
+                        } else {
+                            return { UnitsStatus::UNITS_INVALID_INCOMPATIBLE, 
boost::none };
+                        }
                     }
                 }
                 aUnitsStack.pop();
@@ -226,8 +233,13 @@ UnitsResult UnitsImpl::getOutputUnitsForOpCode(stack< 
RAUSItem >& rStack, const
                         aFirstUnit = getUnitForCell(aIt.GetPos(), pDoc);
                     } else {
                         UtUnit aCurrentUnit = getUnitForCell(aIt.GetPos(), 
pDoc);
+
                         if (aFirstUnit.get() != aCurrentUnit) {
-                            return { UnitsStatus::UNITS_INVALID, boost::none };
+                            if 
(aFirstUnit.get().areConvertibleTo(aCurrentUnit)) {
+                                return { UnitsStatus::UNITS_INVALID_SCALING, 
boost::none };
+                            } else {
+                                return { 
UnitsStatus::UNITS_INVALID_INCOMPATIBLE, boost::none };
+                            }
                         }
                     }
                 } while (aIt.next());
@@ -510,8 +522,7 @@ HeaderUnitDescriptor UnitsImpl::findHeaderUnitForCell(const 
ScAddress& rCellAddr
     return { false, UtUnit(), boost::optional< ScAddress >(), "", -1 };
 }
 
-// getUnitForRef: check format -> if not in format, use more complicated 
method? (Format overrides header definition)
-bool UnitsImpl::verifyFormula(ScTokenArray* pArray, const ScAddress& 
rFormulaAddress, ScDocument* pDoc) {
+FormulaStatus UnitsImpl::verifyFormula(ScTokenArray* pArray, const ScAddress& 
rFormulaAddress, ScDocument* pDoc) {
 #if DEBUG_FORMULA_COMPILER
     pArray->Dump();
 #endif
@@ -532,7 +543,7 @@ bool UnitsImpl::verifyFormula(ScTokenArray* pArray, const 
ScAddress& rFormulaAdd
                 // unparseable formulas?
                 // (or even have a "can't be verified" state too?)
                 // see below for more.x
-                return false;
+                return FormulaStatus::UNKNOWN;
             }
 
             aStack.push( { RAUSItemType::UNITS, aUnit } );
@@ -551,11 +562,13 @@ bool UnitsImpl::verifyFormula(ScTokenArray* pArray, const 
ScAddress& rFormulaAdd
             UnitsResult aResult = getOutputUnitsForOpCode(aStack, pToken, 
pDoc);
 
             switch (aResult.status) {
-            case UnitsStatus::UNITS_INVALID:
-                return false;
+            case UnitsStatus::UNITS_INVALID_SCALING:
+                return FormulaStatus::ERROR_INPUT_SCALING;
+            case UnitsStatus::UNITS_INVALID_INCOMPATIBLE:
+                return FormulaStatus::ERROR_INPUT_INCOMPATIBLE;
             case UnitsStatus::UNITS_UNKNOWN:
                 // Unsupported hence we stop processing.
-                return true;
+                return FormulaStatus::UNKNOWN;
             case UnitsStatus::UNITS_VALID:
                 assert(aResult.units); // ensure that we have the optional unit
                 assert(aResult.units->isValid());
@@ -583,26 +596,30 @@ bool UnitsImpl::verifyFormula(ScTokenArray* pArray, const 
ScAddress& rFormulaAdd
             // was correct.
             // TODO: maybe we should have a "unverified" return state instead?
             SAL_WARN("sc.units", "Unrecognised token type " << 
pToken->GetType());
-            return true;
+            return FormulaStatus::UNKNOWN;
         }
     }
 
     if (aStack.size() != 1) {
         SAL_WARN("sc.units", "Wrong number of units on stack, should be 1, 
actual number: " << aStack.size());
-        return false;
+        return FormulaStatus::UNKNOWN;
     } else if (aStack.top().type != RAUSItemType::UNITS) {
         SAL_WARN("sc.units", "End of verification: item on stack does not 
contain units");
-        return false;
+        return FormulaStatus::UNKNOWN;
     }
 
     HeaderUnitDescriptor aHeader = findHeaderUnitForCell(rFormulaAddress, 
pDoc);
     UtUnit aResultUnit = boost::get< UtUnit>(aStack.top().item);
 
     if (aHeader.valid && aHeader.unit != aResultUnit) {
-        return false;
+        if (aHeader.unit.areConvertibleTo(aResultUnit)) {
+            return FormulaStatus::ERROR_OUTPUT_SCALING;
+        } else {
+            return FormulaStatus::ERROR_OUTPUT_INCOMPATIBLE;
+        }
     }
 
-    return true;
+    return FormulaStatus::VERIFIED;
 }
 
 bool IsDigit(sal_Unicode c) {
diff --git a/sc/source/core/units/unitsimpl.hxx 
b/sc/source/core/units/unitsimpl.hxx
index 176a34d..b0fb137 100644
--- a/sc/source/core/units/unitsimpl.hxx
+++ b/sc/source/core/units/unitsimpl.hxx
@@ -45,7 +45,8 @@ namespace test {
 enum class UnitsStatus {
     UNITS_VALID,
     UNITS_UNKNOWN,
-    UNITS_INVALID
+    UNITS_INVALID_SCALING,
+    UNITS_INVALID_INCOMPATIBLE
 };
 
 /**
@@ -91,7 +92,7 @@ public:
     UnitsImpl();
     virtual ~UnitsImpl();
 
-    virtual bool verifyFormula(ScTokenArray* pArray, const ScAddress& 
rFormulaAddress, ScDocument* pDoc) SAL_OVERRIDE;
+    virtual FormulaStatus verifyFormula(ScTokenArray* pArray, const ScAddress& 
rFormulaAddress, ScDocument* pDoc) SAL_OVERRIDE;
     virtual bool splitUnitsFromInputString(const OUString& rInput, OUString& 
rValue, OUString& rUnit) SAL_OVERRIDE;
     virtual bool isCellConversionRecommended(const ScAddress& rCellAddress,
                                              ScDocument* pDoc,
diff --git a/sc/source/ui/inc/viewfunc.hxx b/sc/source/ui/inc/viewfunc.hxx
index a6b36b8..5574fcf 100644
--- a/sc/source/ui/inc/viewfunc.hxx
+++ b/sc/source/ui/inc/viewfunc.hxx
@@ -58,6 +58,10 @@ namespace sc {
 
 struct ColRowSpan;
 
+namespace units {
+enum class FormulaStatus;
+}
+
 }
 
 namespace com { namespace sun { namespace star { namespace datatransfer { 
class XTransferable; } } } }
@@ -373,7 +377,9 @@ private:
     void            CopyAutoSpellData( FillDir eDir, SCCOL nStartCol, SCROW 
nStartRow,
                                        SCCOL nEndCol, SCROW nEndRow, sal_uLong 
nCount );
 
-    void            NotifyUnitErrorInFormula( const ScAddress& rAddress, 
ScDocument* pDoc );
+    void            NotifyUnitErrorInFormula( const ScAddress& rAddress,
+                                              ScDocument* pDoc,
+                                              const sc::units::FormulaStatus& 
rStatus);
     DECL_LINK( EditUnitErrorFormulaHandler, PushButton* );
 
     void            NotifyUnitConversionRecommended( const ScAddress& 
rCellAddress,
diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx
index b156587..b9a08c3 100644
--- a/sc/source/ui/view/viewfunc.cxx
+++ b/sc/source/ui/view/viewfunc.cxx
@@ -84,6 +84,8 @@
 #include <boost/scoped_ptr.hpp>
 #include <boost/shared_ptr.hpp>
 
+using namespace sc::units;
+
 static void lcl_PostRepaintCondFormat( const ScConditionalFormat *pCondFmt, 
ScDocShell *pDocSh )
 {
     if( pCondFmt )
@@ -467,8 +469,9 @@ void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB 
nTab,
             }
 
 #ifdef ENABLE_CALC_UNITVERIFICATION
-            boost::shared_ptr< sc::units::Units > pUnits = 
sc::units::Units::GetUnits();
-            if ( pUnits->verifyFormula( pArr, aPos, pDoc ) )
+            boost::shared_ptr< Units > pUnits = Units::GetUnits();
+            FormulaStatus aStatus = pUnits->verifyFormula( pArr, aPos, pDoc );
+            if ( aStatus == FormulaStatus::VERIFIED || aStatus == 
FormulaStatus::UNKNOWN )
             {
                 SAL_INFO( "sc.units", "verification successful" );
 
@@ -484,7 +487,7 @@ void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB 
nTab,
             else
             {
                 SAL_INFO( "sc.units", "verification failed" );
-                NotifyUnitErrorInFormula( aPos, pDoc );
+                NotifyUnitErrorInFormula( aPos, pDoc, aStatus );
             }
 #endif
         } while ( bAgain );
@@ -580,7 +583,7 @@ void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB 
nTab,
             }
 
 #ifdef ENABLE_CALC_UNITVERIFICATION
-            boost::shared_ptr< sc::units::Units > pUnits = 
sc::units::Units::GetUnits();
+            boost::shared_ptr< Units > pUnits = Units::GetUnits();
 
             OUString sHeaderUnit, sCellUnit;
             ScAddress aHeaderAddress;
@@ -2838,8 +2841,10 @@ void ScViewFunc::UpdateSelectionArea( const ScMarkData& 
rSel, ScPatternAttr* pAt
     pTabViewShell->AdjustBlockHeight(false, const_cast<ScMarkData*>(&rSel));
 }
 
-void ScViewFunc::NotifyUnitErrorInFormula( const ScAddress& rAddress, 
ScDocument* pDoc )
+void ScViewFunc::NotifyUnitErrorInFormula( const ScAddress& rAddress, 
ScDocument* pDoc, const FormulaStatus& rStatus )
 {
+    (void) rStatus;
+
     SfxViewFrame* pViewFrame = GetViewData().GetViewShell()->GetFrame();
 
     // We use the cell address as the infobar id to allow us to easily get 
back to the
@@ -2967,7 +2972,7 @@ IMPL_LINK( ScViewFunc, UnitConversionRecommendedHandler, 
UnitConversionPushButto
     // Do conversion first, and only then remove the infobar as we need data 
from the infobar
     // (specifically from the pushbutton) to do the conversion.
 #ifdef ENABLE_CALC_UNITVERIFICATION
-    boost::shared_ptr< sc::units::Units > pUnits = 
sc::units::Units::GetUnits();
+    boost::shared_ptr< Units > pUnits = Units::GetUnits();
 
     ScDocShellModificator aModificator( *pButton->mpDocSh );
 
commit 1172fbb2707c5c9d08f4ae2dc9584000c2a13246
Author: Andrzej Hunt <andr...@ahunt.org>
Date:   Mon Jun 1 17:51:48 2015 +0100

    Invalid formulas can't have unit correctness verified.
    
    Formulas that can't be processed will already be treated as invalid,
    we shouldn't additionally complain about unit verification in this case.
    
    Change-Id: I0556bf76b6e2343cdf27ec53669e6fd78da9280b

diff --git a/sc/source/core/units/unitsimpl.cxx 
b/sc/source/core/units/unitsimpl.cxx
index e764aad..567265b 100644
--- a/sc/source/core/units/unitsimpl.cxx
+++ b/sc/source/core/units/unitsimpl.cxx
@@ -95,10 +95,7 @@ UnitsResult UnitsImpl::getOutputUnitsForOpCode(stack< 
RAUSItem >& rStack, const
     if (nOpCode >= SC_OPCODE_START_UN_OP &&
         nOpCode < SC_OPCODE_STOP_UN_OP) {
 
-        if (rStack.size() == 0) {
-            SAL_WARN("sc.units", "Single item opcode failed (no stack items, 
or range used)");
-            return { UnitsStatus::UNITS_INVALID, boost::none };
-        } else if (rStack.top().type != RAUSItemType::UNITS) {
+        if ((rStack.size() == 0) || (rStack.top().type != 
RAUSItemType::UNITS)) {
             return { UnitsStatus::UNITS_UNKNOWN, boost::none };
         }
 
@@ -129,12 +126,7 @@ UnitsResult UnitsImpl::getOutputUnitsForOpCode(stack< 
RAUSItem >& rStack, const
     } else if (nOpCode >= SC_OPCODE_START_BIN_OP &&
         nOpCode < SC_OPCODE_STOP_BIN_OP) {
 
-        if (rStack.size() < 2) {
-            SAL_WARN("sc.units", "less than two items on stack when attempting 
binary operation");
-            return { UnitsStatus::UNITS_INVALID, boost::none };
-        }
-
-        if (rStack.top().type != RAUSItemType::UNITS) {
+        if ((rStack.size() < 2) || (rStack.top().type != RAUSItemType::UNITS)) 
{
             return { UnitsStatus::UNITS_UNKNOWN, boost::none };
         }
         UtUnit pSecondUnit = boost::get<UtUnit>(rStack.top().item);
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to