[Libreoffice-commits] core.git: sw/inc sw/qa sw/source

Serge Krot Serge.Krot at cib.de
Thu Dec 14 12:28:08 UTC 2017


 sw/inc/docufld.hxx                                        |   11 +
 sw/qa/extras/odfexport/data/tdf43569_conditionalfield.doc |binary
 sw/qa/extras/odfexport/odfexport.cxx                      |  108 ++++++++++++++
 sw/source/core/fields/docufld.cxx                         |  100 ++++++++++++
 sw/source/filter/ww8/ww8par5.cxx                          |   24 +++
 5 files changed, 242 insertions(+), 1 deletion(-)

New commits:
commit 29378bd510226adb23659525203beec18f8708a3
Author: Serge Krot <Serge.Krot at cib.de>
Date:   Wed Dec 13 17:13:35 2017 +0100

    tdf#43569 DOC input: insert ConditionalText field instead of field marks
    
    In case of IF field input inside DOC document the ConditionalText field
    should be created instead of the two field marks that leads to handling
    of unsupported field routine.
    
    Added unit tests.
    
    Change-Id: I31875d8e6be7f536766ef640a366b843f7e0532c
    Reviewed-on: https://gerrit.libreoffice.org/46022
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>

diff --git a/sw/inc/docufld.hxx b/sw/inc/docufld.hxx
index 7d986154753e..8e0bf46e9ba6 100644
--- a/sw/inc/docufld.hxx
+++ b/sw/inc/docufld.hxx
@@ -287,7 +287,7 @@ public:
     bool             GetHiddenFlag() const { return bHidden; }
 };
 
-class SwHiddenTextField : public SwField
+class SW_DLLPUBLIC SwHiddenTextField : public SwField
 {
     OUString aTRUEText;         ///< Text if condition true.
     OUString aFALSEText;        ///< If condition false.
@@ -317,6 +317,10 @@ public:
                       const OUString& rFalse,
                       sal_uInt16 nSubType = TYP_HIDDENTXTFLD);
 
+    // nSubType = TYP_CONDTXTFLD
+    SwHiddenTextField(SwHiddenTextFieldType*,
+                      const OUString& rCondTrueFalse); // value sample: " IF A == B \"TrueText\" \"FalseText\""
+
     virtual OUString    GetFieldName() const override;
 
     void                Evaluate(SwDoc*);
@@ -337,6 +341,11 @@ public:
 
     virtual bool        QueryValue( css::uno::Any& rVal, sal_uInt16 nWhich ) const override;
     virtual bool        PutValue( const css::uno::Any& rVal, sal_uInt16 nWhich ) override;
+
+    static void         ParseIfFieldDefinition(const OUString& aFieldDefinition,
+                                               OUString& rCondition,
+                                               OUString& rTrue,
+                                               OUString& rFalse);
 };
 
 // Field that expands to an empty line (without height).
diff --git a/sw/qa/extras/odfexport/data/tdf43569_conditionalfield.doc b/sw/qa/extras/odfexport/data/tdf43569_conditionalfield.doc
new file mode 100755
index 000000000000..456a6ed833cf
Binary files /dev/null and b/sw/qa/extras/odfexport/data/tdf43569_conditionalfield.doc differ
diff --git a/sw/qa/extras/odfexport/odfexport.cxx b/sw/qa/extras/odfexport/odfexport.cxx
index eea19faccea8..f571b66cfbe8 100644
--- a/sw/qa/extras/odfexport/odfexport.cxx
+++ b/sw/qa/extras/odfexport/odfexport.cxx
@@ -36,6 +36,7 @@
 #include <comphelper/fileformat.h>
 #include <comphelper/propertysequence.hxx>
 #include <unotools/streamwrap.hxx>
+#include <docufld.hxx> // for SwHiddenTextField::ParseIfFieldDefinition() method call
 
 class Test : public SwModelTestBase
 {
@@ -114,6 +115,113 @@ DECLARE_ODFEXPORT_TEST(testMathObjectFlatExport, "2_MathType3.docx")
     CPPUNIT_ASSERT_EQUAL(OUString(" size 12{2+2=4} {}"), formula2);
 }
 
+void testTdf43569_CheckIfFieldParse()
+{
+    {
+        const OUString fieldDefinition("IF A B C");
+
+        OUString paramCondition;
+        OUString paramTrue;
+        OUString paramFalse;
+
+        SwHiddenTextField::ParseIfFieldDefinition(fieldDefinition, paramCondition, paramTrue, paramFalse);
+
+        CPPUNIT_ASSERT_EQUAL(OUString("A"), paramCondition);
+        CPPUNIT_ASSERT_EQUAL(OUString("B"), paramTrue);
+        CPPUNIT_ASSERT_EQUAL(OUString("C"), paramFalse);
+    }
+
+    {
+        const OUString fieldDefinition("  IF AAA BBB CCC  ");
+
+        OUString paramCondition;
+        OUString paramTrue;
+        OUString paramFalse;
+
+        SwHiddenTextField::ParseIfFieldDefinition(fieldDefinition, paramCondition, paramTrue, paramFalse);
+
+        CPPUNIT_ASSERT_EQUAL(OUString("AAA"), paramCondition);
+        CPPUNIT_ASSERT_EQUAL(OUString("BBB"), paramTrue);
+        CPPUNIT_ASSERT_EQUAL(OUString("CCC"), paramFalse);
+    }
+
+    {
+        const OUString fieldDefinition("  IF AAA \"BBB\" \"CCC\"  ");
+
+        OUString paramCondition;
+        OUString paramTrue;
+        OUString paramFalse;
+
+        SwHiddenTextField::ParseIfFieldDefinition(fieldDefinition, paramCondition, paramTrue, paramFalse);
+
+        CPPUNIT_ASSERT_EQUAL(OUString("AAA"), paramCondition);
+        CPPUNIT_ASSERT_EQUAL(OUString("BBB"), paramTrue);
+        CPPUNIT_ASSERT_EQUAL(OUString("CCC"), paramFalse);
+    }
+
+    // true-case and false-case have spaces inside
+    {
+        const OUString fieldDefinition("  IF A A A \"B B B\" \"C C C\"  ");
+
+        OUString paramCondition;
+        OUString paramTrue;
+        OUString paramFalse;
+
+        SwHiddenTextField::ParseIfFieldDefinition(fieldDefinition, paramCondition, paramTrue, paramFalse);
+
+        CPPUNIT_ASSERT_EQUAL(OUString("A A A"), paramCondition);
+        CPPUNIT_ASSERT_EQUAL(OUString("B B B"), paramTrue);
+        CPPUNIT_ASSERT_EQUAL(OUString("C C C"), paramFalse);
+    }
+
+    // true-case and false-case have leading/trailing space
+    {
+        const OUString fieldDefinition("IF A1 A2 A3 \"B1 B2 \" \" C1 C2\"  ");
+
+        OUString paramCondition;
+        OUString paramTrue;
+        OUString paramFalse;
+
+        SwHiddenTextField::ParseIfFieldDefinition(fieldDefinition, paramCondition, paramTrue, paramFalse);
+
+        CPPUNIT_ASSERT_EQUAL(OUString("A1 A2 A3"), paramCondition);
+        CPPUNIT_ASSERT_EQUAL(OUString("B1 B2 "), paramTrue);
+        CPPUNIT_ASSERT_EQUAL(OUString(" C1 C2"), paramFalse);
+    }
+
+    // true-case and false-case are empty
+    {
+        const OUString fieldDefinition("IF condition \"\" \"\"  ");
+
+        OUString paramCondition;
+        OUString paramTrue;
+        OUString paramFalse;
+
+        SwHiddenTextField::ParseIfFieldDefinition(fieldDefinition, paramCondition, paramTrue, paramFalse);
+
+        CPPUNIT_ASSERT_EQUAL(OUString("condition"), paramCondition);
+        CPPUNIT_ASSERT_EQUAL(OUString(""), paramTrue);
+        CPPUNIT_ASSERT_EQUAL(OUString(""), paramFalse);
+    }
+}
+
+// Input document contains only one IF-field,
+// and it should be imported as com.sun.star.text.TextField.ConditionalText in any case,
+// instead of insertion of the the pair of two field-marks: <field:fieldmark-start> + <field:fieldmark-end>.
+DECLARE_ODFEXPORT_TEST(testTdf43569, "tdf43569_conditionalfield.doc")
+{
+    // check if our parser is valid
+    testTdf43569_CheckIfFieldParse();
+
+    // now check field creation during import
+    uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
+    uno::Reference<container::XEnumerationAccess> xFieldsAccess(xTextFieldsSupplier->getTextFields());
+    uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
+
+    // at least one field should be detected
+    CPPUNIT_ASSERT(xFields->hasMoreElements());
+}
+
 DECLARE_ODFEXPORT_TEST(testTdf103567, "tdf103567.odt")
 {
     uno::Reference<drawing::XShape> const xShape(getShape(1));
diff --git a/sw/source/core/fields/docufld.cxx b/sw/source/core/fields/docufld.cxx
index a53c16882c34..8e360155f1b8 100644
--- a/sw/source/core/fields/docufld.cxx
+++ b/sw/source/core/fields/docufld.cxx
@@ -1541,6 +1541,106 @@ OUString SwHiddenTextField::GetDBName(const OUString& rName, SwDoc *pDoc)
     return aData.sDataSource + OUStringLiteral1(DB_DELIM) + aData.sCommand;
 }
 
+// [aFieldDefinition] value sample : " IF A == B \"TrueText\" \"FalseText\""
+void SwHiddenTextField::ParseIfFieldDefinition(const OUString& aFieldDefinition,
+                                               OUString& rCondition,
+                                               OUString& rTrue,
+                                               OUString& rFalse)
+{
+    // get all positions inside the input string where words are started
+    //
+    // In: " IF A == B \"TrueText\" \"FalseText\""
+    //      0         1           2          3
+    //      01234567890 123456789 01 2345678901 2
+    //
+    // result:
+    //      [1, 4, 6, 9, 11, 22]
+    std::vector<sal_Int32> wordPosition;
+    {
+        bool quoted = false;
+        bool insideWord = false;
+        for (sal_Int32 i = 0; i < aFieldDefinition.getLength(); i++)
+        {
+            if (quoted)
+            {
+                if (aFieldDefinition[i] == '\"')
+                {
+                    quoted = false;
+                    insideWord = false;
+                }
+            }
+            else
+            {
+                if (aFieldDefinition[i] == ' ')
+                {
+                    // word delimiter
+                    insideWord = false;
+                }
+                else
+                {
+                    if (insideWord)
+                    {
+                        quoted = (aFieldDefinition[i] == '\"');
+                    }
+                    else
+                    {
+                        insideWord = true;
+                        wordPosition.push_back(i);
+                        quoted = (aFieldDefinition[i] == '\"');
+                    }
+                }
+            }
+        }
+    }
+
+    // first word is always "IF"
+    // last two words are: true-case and false-case,
+    // everything before is treated as condition expression
+    // => we need at least 4 words to be inside the input string
+    if (wordPosition.size() < 4)
+    {
+        return;
+    }
+
+
+    const sal_Int32 conditionBegin = wordPosition[1];
+    const sal_Int32 trueBegin      = wordPosition[wordPosition.size() - 2];
+    const sal_Int32 falseBegin     = wordPosition[wordPosition.size() - 1];
+
+    const sal_Int32 conditionLength = trueBegin - conditionBegin;
+    const sal_Int32 trueLength      = falseBegin - trueBegin;
+
+    // Syntax
+    // OUString::copy( sal_Int32 beginIndex, sal_Int32 count )
+    rCondition = aFieldDefinition.copy(conditionBegin, conditionLength);
+    rTrue = aFieldDefinition.copy(trueBegin, trueLength);
+    rFalse = aFieldDefinition.copy(falseBegin);
+
+    // trim
+    rCondition = rCondition.trim();
+    rTrue = rTrue.trim();
+    rFalse = rFalse.trim();
+
+    // remove quotes
+    if (rCondition.getLength() >= 2)
+    {
+        if (rCondition[0] == '\"' && rCondition[rCondition.getLength() - 1] == '\"')
+            rCondition = rCondition.copy(1, rCondition.getLength() - 2);
+    }
+    if (rTrue.getLength() >= 2)
+    {
+        if (rTrue[0] == '\"' && rTrue[rTrue.getLength() - 1] == '\"')
+            rTrue = rTrue.copy(1, rTrue.getLength() - 2);
+    }
+    if (rFalse.getLength() >= 2)
+    {
+        if (rFalse[0] == '\"' && rFalse[rFalse.getLength() - 1] == '\"')
+            rFalse = rFalse.copy(1, rFalse.getLength() - 2);
+    }
+
+    // Note: do not make trim once again, while this is a user defined data
+}
+
 // field type for line height 0
 
 SwHiddenParaFieldType::SwHiddenParaFieldType()
diff --git a/sw/source/filter/ww8/ww8par5.cxx b/sw/source/filter/ww8/ww8par5.cxx
index e6dee54d5d50..eb04cb5a50d0 100644
--- a/sw/source/filter/ww8/ww8par5.cxx
+++ b/sw/source/filter/ww8/ww8par5.cxx
@@ -589,6 +589,30 @@ sal_uInt16 SwWW8ImplReader::End_Field()
                 //Move outside the section associated with this type of field
                 *m_pPaM->GetPoint() = m_aFieldStack.back().maStartPos;
                 break;
+            case 7: // IF-field
+            {
+                // conditional field parameters
+                const OUString& fieldDefinition = m_aFieldStack.back().GetBookmarkCode();
+
+                OUString paramCondition;
+                OUString paramTrue;
+                OUString paramFalse;
+
+                SwHiddenTextField::ParseIfFieldDefinition(fieldDefinition, paramCondition, paramTrue, paramFalse);
+
+                // create new field
+                SwFieldType* pFieldType = m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::HiddenText);
+                SwHiddenTextField *const pHTField = new SwHiddenTextField(
+                    static_cast<SwHiddenTextFieldType*>(pFieldType),
+                    paramCondition,
+                    paramTrue,
+                    paramFalse,
+                    static_cast<sal_uInt16>(TYP_CONDTXTFLD));
+
+                // insert new field into document
+                m_rDoc.getIDocumentContentOperations().InsertPoolItem(*m_pPaM, SwFormatField(*pHTField));
+                break;
+            }
             default:
                 OUString aCode = m_aFieldStack.back().GetBookmarkCode();
                 if ( !aCode.isEmpty() )


More information about the Libreoffice-commits mailing list