[Libreoffice-commits] core.git: 5 commits - include/sfx2 sfx2/source sw/qa sw/source writerfilter/source
Miklos Vajna
vmiklos at collabora.co.uk
Wed Mar 9 13:19:17 UTC 2016
include/sfx2/classificationhelper.hxx | 10 +++
sfx2/source/view/classificationhelper.cxx | 29 +++++++++
sw/qa/extras/rtfimport/data/custom-doc-props.rtf | 10 +++
sw/qa/extras/rtfimport/rtfimport.cxx | 10 +++
sw/qa/extras/uiwriter/uiwriter.cxx | 27 +++++++++
sw/source/uibase/dochdl/swdtflvr.cxx | 29 +++------
writerfilter/source/rtftok/rtfcontrolwords.hxx | 3 +
writerfilter/source/rtftok/rtfdocumentimpl.cxx | 68 +++++++++++++++++++++++
writerfilter/source/rtftok/rtfdocumentimpl.hxx | 5 +
9 files changed, 173 insertions(+), 18 deletions(-)
New commits:
commit 8ff32dc66e3adb00209c82bddebfbeb47a275066
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date: Wed Mar 9 12:21:36 2016 +0100
RTF import: handle \staticval
With this, user-defined document properties are imported from RTF.
Change-Id: I8dfb8e802bd26906827620550d6f5d88f047d364
diff --git a/sw/qa/extras/rtfimport/data/custom-doc-props.rtf b/sw/qa/extras/rtfimport/data/custom-doc-props.rtf
new file mode 100644
index 0000000..b36d864
--- /dev/null
+++ b/sw/qa/extras/rtfimport/data/custom-doc-props.rtf
@@ -0,0 +1,10 @@
+{\rtf1
+{\*\userprops
+{\propname urn:bails:IntellectualProperty:Authorization:StartValidity}
+\proptype30
+{\staticval 2016-03-08T10:55:18,531376147}
+{\propname urn:bails:IntellectualProperty:Authorization:StopValidity}
+\proptype30
+{\staticval None}
+}
+}
diff --git a/sw/qa/extras/rtfimport/rtfimport.cxx b/sw/qa/extras/rtfimport/rtfimport.cxx
index d98b9b9..6ee8729 100644
--- a/sw/qa/extras/rtfimport/rtfimport.cxx
+++ b/sw/qa/extras/rtfimport/rtfimport.cxx
@@ -2525,6 +2525,16 @@ DECLARE_RTFIMPORT_TEST(testTdf87034, "tdf87034.rtf")
CPPUNIT_ASSERT_EQUAL(OUString("A1B3C4D"), getParagraph(1)->getString());
}
+DECLARE_RTFIMPORT_TEST(testCustomDocProps, "custom-doc-props.rtf")
+{
+ // Custom document properties were not improved, this resulted in a beans::UnknownPropertyException.
+ uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<document::XDocumentProperties> xDocumentProperties = xDocumentPropertiesSupplier->getDocumentProperties();
+ uno::Reference<beans::XPropertyContainer> xUserDefinedProperties = xDocumentProperties->getUserDefinedProperties();
+ CPPUNIT_ASSERT_EQUAL(OUString("2016-03-08T10:55:18,531376147"), getProperty<OUString>(xUserDefinedProperties, "urn:bails:IntellectualProperty:Authorization:StartValidity"));
+ CPPUNIT_ASSERT_EQUAL(OUString("None"), getProperty<OUString>(xUserDefinedProperties, "urn:bails:IntellectualProperty:Authorization:StopValidity"));
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfcontrolwords.hxx b/writerfilter/source/rtftok/rtfcontrolwords.hxx
index dab8196..80a2d1e 100644
--- a/writerfilter/source/rtftok/rtfcontrolwords.hxx
+++ b/writerfilter/source/rtftok/rtfcontrolwords.hxx
@@ -158,6 +158,7 @@ enum class Destination
TOCENTRY,
USERPROPS,
PROPNAME,
+ STATICVAL,
};
enum RTFKeyword
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
index 1fa5cbc..6dd561b 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
@@ -1291,6 +1291,7 @@ void RTFDocumentImpl::text(OUString& rString)
case Destination::INDEXENTRY:
case Destination::TOCENTRY:
case Destination::PROPNAME:
+ case Destination::STATICVAL:
m_aStates.top().pDestinationText->append(rString);
break;
default:
@@ -2059,6 +2060,9 @@ RTFError RTFDocumentImpl::dispatchDestination(RTFKeyword nKeyword)
case RTF_PROPNAME:
m_aStates.top().eDestination = Destination::PROPNAME;
break;
+ case RTF_STATICVAL:
+ m_aStates.top().eDestination = Destination::STATICVAL;
+ break;
default:
{
// Check if it's a math token.
@@ -5108,6 +5112,14 @@ void RTFDocumentImpl::resetAttributes()
m_aStates.top().aParagraphAttributes.clear();
}
+bool lcl_containsProperty(const uno::Sequence<beans::Property>& rProperties, const OUString& rName)
+{
+ return std::find_if(rProperties.begin(), rProperties.end(), [&](const beans::Property& rProperty)
+ {
+ return rProperty.Name == rName;
+ }) != rProperties.end();
+}
+
RTFError RTFDocumentImpl::popState()
{
//SAL_INFO("writerfilter", OSL_THIS_FUNC << " before pop: m_pTokenizer->getGroup() " << m_pTokenizer->getGroup() <<
@@ -5897,6 +5909,35 @@ RTFError RTFDocumentImpl::popState()
break; // not for nested group
aState.aPropName = m_aStates.top().pDestinationText->makeStringAndClear();
break;
+ case Destination::STATICVAL:
+ if (&m_aStates.top().aDestinationText != m_aStates.top().pDestinationText)
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ {
+ // Find out what is the key, value type and value we want to set.
+ uno::Reference<beans::XPropertyContainer> xPropertyContainer = m_xDocumentProperties->getUserDefinedProperties();
+ uno::Reference<beans::XPropertySet> xPropertySet(xPropertyContainer, uno::UNO_QUERY);
+ uno::Sequence<beans::Property> aProperties = xPropertySet->getPropertySetInfo()->getProperties();
+ const OUString& rKey = m_aStates.top().aPropName;
+ OUString aStaticVal = m_aStates.top().pDestinationText->makeStringAndClear();
+ uno::Any aAny;
+ if (m_aStates.top().aPropType == cppu::UnoType<OUString>::get())
+ aAny = uno::makeAny(aStaticVal);
+
+ // Set it.
+ try
+ {
+ if (lcl_containsProperty(aProperties, rKey))
+ xPropertySet->setPropertyValue(rKey, aAny);
+ else
+ xPropertyContainer->addProperty(rKey, beans::PropertyAttribute::REMOVABLE, aAny);
+ }
+ catch (const uno::Exception& rException)
+ {
+ SAL_WARN("writerfilter", "failed to set property " << rKey << ": " << rException.Message);
+ }
+ }
+ break;
default:
break;
}
commit d11b43fe02a6daf2384d50de14f98fbfd55c180e
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date: Wed Mar 9 12:05:17 2016 +0100
RTF import: handle \proptype
Change-Id: I398785ff0ac47a678e3171982119a85b107404b4
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
index 7d7ee39..1fa5cbc 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
@@ -4808,6 +4808,16 @@ RTFError RTFDocumentImpl::dispatchValue(RTFKeyword nKeyword, int nParam)
lcl_putNestedSprm(m_aStates.top().aTableRowSprms, NS_ooxml::LN_CT_TblPrBase_tblCellMar, NS_ooxml::LN_CT_TblCellMar_right, std::make_shared<RTFValue>(aAttributes));
}
break;
+ case RTF_PROPTYPE:
+ {
+ switch (nParam)
+ {
+ case 30:
+ m_aStates.top().aPropType = cppu::UnoType<OUString>::get();
+ break;
+ }
+ }
+ break;
default:
{
SAL_INFO("writerfilter", "TODO handle value '" << lcl_RtfToString(nKeyword) << "'");
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.hxx b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
index 9445ac9..fe239a4 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.hxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
@@ -300,6 +300,8 @@ public:
/// User-defined property: key name.
OUString aPropName;
+ /// User-defined property: value type.
+ css::uno::Type aPropType;
};
/// An RTF stack is similar to std::stack, except that it has an operator[].
commit cf773edad7033b23c53b5e9a60ecc0b56d7f83f9
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date: Wed Mar 9 11:59:14 2016 +0100
RTF import: handle \userprops and \propname
Change-Id: I3fa0be5186603006e671779933625efff5d31867
diff --git a/writerfilter/source/rtftok/rtfcontrolwords.hxx b/writerfilter/source/rtftok/rtfcontrolwords.hxx
index dfbbabf..dab8196 100644
--- a/writerfilter/source/rtftok/rtfcontrolwords.hxx
+++ b/writerfilter/source/rtftok/rtfcontrolwords.hxx
@@ -156,6 +156,8 @@ enum class Destination
FOOTNOTESEPARATOR,
INDEXENTRY,
TOCENTRY,
+ USERPROPS,
+ PROPNAME,
};
enum RTFKeyword
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
index 187eb5a..7d7ee39 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
@@ -1290,6 +1290,7 @@ void RTFDocumentImpl::text(OUString& rString)
case Destination::MGROW:
case Destination::INDEXENTRY:
case Destination::TOCENTRY:
+ case Destination::PROPNAME:
m_aStates.top().pDestinationText->append(rString);
break;
default:
@@ -2051,6 +2052,13 @@ RTFError RTFDocumentImpl::dispatchDestination(RTFKeyword nKeyword)
m_aStates.top().eDestination = Destination::FOOTNOTESEPARATOR;
m_aStates.top().aCharacterAttributes.set(NS_ooxml::LN_CT_FtnEdn_type, std::make_shared<RTFValue>(NS_ooxml::LN_Value_doc_ST_FtnEdn_separator));
break;
+ case RTF_USERPROPS:
+ // Container of all user-defined properties.
+ m_aStates.top().eDestination = Destination::USERPROPS;
+ break;
+ case RTF_PROPNAME:
+ m_aStates.top().eDestination = Destination::PROPNAME;
+ break;
default:
{
// Check if it's a math token.
@@ -5874,6 +5882,11 @@ RTFError RTFDocumentImpl::popState()
if (aState.bCreatedShapeGroup)
m_pSdrImport->popParent();
break;
+ case Destination::PROPNAME:
+ if (&m_aStates.top().aDestinationText != m_aStates.top().pDestinationText)
+ break; // not for nested group
+ aState.aPropName = m_aStates.top().pDestinationText->makeStringAndClear();
+ break;
default:
break;
}
@@ -6143,6 +6156,10 @@ RTFError RTFDocumentImpl::popState()
m_aStates.top().aDrawingObject.nBottom = aState.aDrawingObject.nBottom;
}
break;
+ case Destination::PROPNAME:
+ if (m_aStates.top().eDestination == Destination::USERPROPS)
+ m_aStates.top().aPropName = aState.aPropName;
+ break;
default:
{
if (!m_aStates.empty() && m_aStates.top().eDestination == Destination::PICT)
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.hxx b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
index 37727d8..9445ac9 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.hxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
@@ -297,6 +297,9 @@ public:
bool bInShape; ///< If we're inside a \shp group.
bool bCreatedShapeGroup; ///< A GroupShape was created and pushed to the parent stack.
bool bStartedTrackchange; ///< Track change is started, need to end it before popping.
+
+ /// User-defined property: key name.
+ OUString aPropName;
};
/// An RTF stack is similar to std::stack, except that it has an operator[].
commit 38dd218425b3e4a56d71af7082eea1dda24b48da
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date: Wed Mar 9 11:32:12 2016 +0100
CppunitTest_sw_uiwriter: add classification copy/paste testcase
Change-Id: Ic3ac02fe28bee0ea3189fb2c9d3548f5ca13fe5c
diff --git a/sw/qa/extras/uiwriter/uiwriter.cxx b/sw/qa/extras/uiwriter/uiwriter.cxx
index 96e8cd5..fced549 100644
--- a/sw/qa/extras/uiwriter/uiwriter.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter.cxx
@@ -89,6 +89,7 @@
#include <txtfrm.hxx>
#include <editeng/svxenum.hxx>
#include <comphelper/propertysequence.hxx>
+#include <sfx2/classificationhelper.hxx>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
static const char* DATA_DIRECTORY = "/sw/qa/extras/uiwriter/data/";
@@ -187,6 +188,7 @@ public:
void testTdf96536();
void testTdf96479();
void testTdf96961();
+ void testClassificationPaste();
CPPUNIT_TEST_SUITE(SwUiWriterTest);
CPPUNIT_TEST(testReplaceForward);
@@ -277,6 +279,7 @@ public:
CPPUNIT_TEST(testTdf96536);
CPPUNIT_TEST(testTdf96479);
CPPUNIT_TEST(testTdf96961);
+ CPPUNIT_TEST(testClassificationPaste);
CPPUNIT_TEST_SUITE_END();
private:
@@ -3246,6 +3249,30 @@ void SwUiWriterTest::testTdf96961()
CPPUNIT_ASSERT(nLast > nOther);
}
+void SwUiWriterTest::testClassificationPaste()
+{
+ SwDocShell* pSourceShell = createDoc()->GetDocShell();
+ uno::Reference<lang::XComponent> xSourceComponent = mxComponent;
+ mxComponent.clear();
+
+ SwDocShell* pDestinationShell = createDoc()->GetDocShell();
+
+ // Not classified source, not classified destination.
+ CPPUNIT_ASSERT_EQUAL(int(SfxClassificationCheckPasteResult::None), int(SfxClassificationHelper::CheckPaste(*pSourceShell, *pDestinationShell)));
+
+ // Classified source, not classified destination.
+ uno::Sequence<beans::PropertyValue> aInternalOnly = comphelper::InitPropertySequence({{"Name", uno::makeAny(OUString("Internal Only"))}});
+ lcl_dispatchCommand(xSourceComponent, ".uno:ClassificationApply", aInternalOnly);
+ CPPUNIT_ASSERT_EQUAL(int(SfxClassificationCheckPasteResult::TargetDocNotClassified), int(SfxClassificationHelper::CheckPaste(*pSourceShell, *pDestinationShell)));
+
+ // Classified source and classified destination -- internal only has a higher level than confidential.
+ uno::Sequence<beans::PropertyValue> aConfidential = comphelper::InitPropertySequence({{"Name", uno::makeAny(OUString("Confidential"))}});
+ lcl_dispatchCommand(mxComponent, ".uno:ClassificationApply", aConfidential);
+ CPPUNIT_ASSERT_EQUAL(int(SfxClassificationCheckPasteResult::DocClassificationTooLow), int(SfxClassificationHelper::CheckPaste(*pSourceShell, *pDestinationShell)));
+
+ xSourceComponent->dispose();
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(SwUiWriterTest);
CPPUNIT_PLUGIN_IMPLEMENT();
commit 76e2cede5a415df8d3e7a874f56be7a0b5953e12
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date: Wed Mar 9 10:58:25 2016 +0100
Move copy/paste classification check from sw to sfx2
So that it's easy to unit test it and other apps can use it as well in
the future.
Change-Id: I38d601924b7fbb17615ff6e9c031a71b40777c4c
diff --git a/include/sfx2/classificationhelper.hxx b/include/sfx2/classificationhelper.hxx
index 5c49db7..5a58fcc 100644
--- a/include/sfx2/classificationhelper.hxx
+++ b/include/sfx2/classificationhelper.hxx
@@ -23,6 +23,14 @@ namespace basegfx
class BColor;
}
+/// Return code of SfxClassificationHelper::CheckPaste().
+enum class SfxClassificationCheckPasteResult
+{
+ None = 1,
+ TargetDocNotClassified = 2,
+ DocClassificationTooLow = 3
+};
+
/// Shared code to handle Business Authorization Identification and Labeling Scheme (BAILS) properties.
class SFX2_DLLPUBLIC SfxClassificationHelper
{
@@ -32,6 +40,8 @@ class SFX2_DLLPUBLIC SfxClassificationHelper
public:
/// Does the document have any BAILS properties?
static bool IsClassified(SfxObjectShell& rObjectShell);
+ /// Checks if pasting from rSource to rDestination would leak information.
+ static SfxClassificationCheckPasteResult CheckPaste(SfxObjectShell& rSource, SfxObjectShell& rDestination);
SfxClassificationHelper(SfxObjectShell& rObjectShell);
~SfxClassificationHelper();
diff --git a/sfx2/source/view/classificationhelper.cxx b/sfx2/source/view/classificationhelper.cxx
index ab913b5..6950048 100644
--- a/sfx2/source/view/classificationhelper.cxx
+++ b/sfx2/source/view/classificationhelper.cxx
@@ -426,6 +426,35 @@ bool SfxClassificationHelper::IsClassified(SfxObjectShell& rObjectShell)
return false;
}
+SfxClassificationCheckPasteResult SfxClassificationHelper::CheckPaste(SfxObjectShell& rSource, SfxObjectShell& rDestination)
+{
+ bool bSourceClassified = SfxClassificationHelper::IsClassified(rSource);
+ if (!bSourceClassified)
+ // No classification on the source side. Return early, regardless the
+ // state of the destination side.
+ return SfxClassificationCheckPasteResult::None;
+
+ bool bDestinationClassified = SfxClassificationHelper::IsClassified(rDestination);
+ if (bSourceClassified && !bDestinationClassified)
+ {
+ // Paste from a classified document to a non-classified one -> deny.
+ return SfxClassificationCheckPasteResult::TargetDocNotClassified;
+ }
+
+ // Remaining case: paste between two classified documents.
+ SfxClassificationHelper aSource(rSource);
+ SfxClassificationHelper aDestination(rDestination);
+ if (aSource.GetImpactScale() != aDestination.GetImpactScale())
+ // It's possible to compare them if they have the same scale.
+ return SfxClassificationCheckPasteResult::None;
+
+ if (aSource.GetImpactLevel() > aDestination.GetImpactLevel())
+ // Paste from a doc that has higher classification -> deny.
+ return SfxClassificationCheckPasteResult::DocClassificationTooLow;
+
+ return SfxClassificationCheckPasteResult::None;
+}
+
SfxClassificationHelper::SfxClassificationHelper(SfxObjectShell& rObjectShell)
: m_pImpl(o3tl::make_unique<Impl>(rObjectShell))
{
diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx b/sw/source/uibase/dochdl/swdtflvr.cxx
index 04c3ae1..fb46de91 100644
--- a/sw/source/uibase/dochdl/swdtflvr.cxx
+++ b/sw/source/uibase/dochdl/swdtflvr.cxx
@@ -3222,33 +3222,26 @@ bool lcl_checkClassification(SwDoc* pSourceDoc, SwDoc* pDestinationDoc)
if (!pSourceShell || !pDestinationShell)
return true;
- bool bSourceClassified = SfxClassificationHelper::IsClassified(*pSourceShell);
- if (!bSourceClassified)
- // No classification on the source side. Return early, regardless the
- // state of the destination side.
+ switch (SfxClassificationHelper::CheckPaste(*pSourceShell, *pDestinationShell))
+ {
+ case SfxClassificationCheckPasteResult::None:
+ {
return true;
-
- bool bDestinationClassified = SfxClassificationHelper::IsClassified(*pDestinationShell);
- if (bSourceClassified && !bDestinationClassified)
+ }
+ break;
+ case SfxClassificationCheckPasteResult::TargetDocNotClassified:
{
- // Paste from a classified document to a non-classified one -> deny.
ScopedVclPtrInstance<MessageDialog>::Create(nullptr, SW_RES(STR_TARGET_DOC_NOT_CLASSIFIED), VCL_MESSAGE_INFO)->Execute();
return false;
}
-
- // Remaining case: paste between two classified documents.
- SfxClassificationHelper aSource(*pSourceShell);
- SfxClassificationHelper aDestination(*pDestinationShell);
- if (aSource.GetImpactScale() != aDestination.GetImpactScale())
- // It's possible to compare them if they have the same scale.
- return true;
-
- if (aSource.GetImpactLevel() > aDestination.GetImpactLevel())
+ break;
+ case SfxClassificationCheckPasteResult::DocClassificationTooLow:
{
- // Paste from a doc that has higher classification -> deny.
ScopedVclPtrInstance<MessageDialog>::Create(nullptr, SW_RES(STR_DOC_CLASSIFICATION_TOO_LOW), VCL_MESSAGE_INFO)->Execute();
return false;
}
+ break;
+ }
return true;
}
More information about the Libreoffice-commits
mailing list