diff options
-rw-r--r-- | sw/inc/docufld.hxx | 11 | ||||
-rwxr-xr-x | sw/qa/extras/odfexport/data/tdf43569_conditionalfield.doc | bin | 0 -> 22016 bytes | |||
-rw-r--r-- | sw/qa/extras/odfexport/odfexport.cxx | 108 | ||||
-rw-r--r-- | sw/source/core/fields/docufld.cxx | 100 | ||||
-rw-r--r-- | sw/source/filter/ww8/ww8par5.cxx | 24 |
5 files changed, 242 insertions, 1 deletions
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 Binary files differnew file mode 100755 index 000000000000..456a6ed833cf --- /dev/null +++ b/sw/qa/extras/odfexport/data/tdf43569_conditionalfield.doc 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() ) |