tdf#101242 Support draw:display and draw:protect attributes of ODF

LibreOffice writes the properties visible, printable and locked of
layers into items in the subfile settings.xml and handles them as
properties of the view. ODF handles them as property of the layer.
To become more ODF conform as a first step these properties are now
read and written. They are used to initialize the view in case they
are missing in settings.xml, which is the case for foreign documents.
The ODF properties are written in addition to the items in
settings.xml, so that older versions will notice no difference with
such documents. SdModelTestBase is changed to handle odg as Draw
document.

Change-Id: I190ecc51fc6ee91ec4b96d06bb216ce517bdfcfe
Reviewed-on: https://gerrit.libreoffice.org/59269
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
diff --git a/include/svx/svdlayer.hxx b/include/svx/svdlayer.hxx
index 36fa08a..60e7027 100644
--- a/include/svx/svdlayer.hxx
+++ b/include/svx/svdlayer.hxx
@@ -62,6 +62,9 @@ class SVX_DLLPUBLIC SdrLayer
    OUString maName;
    OUString maTitle;
    OUString maDescription;
    bool mbVisibleODF; // corresponds to ODF draw:display
    bool mbPrintableODF; // corresponds to ODF draw:display
    bool mbLockedODF; // corresponds to ODF draw:protected
    SdrModel*  pModel; // For broadcasting
    sal_uInt16 nType;  // 0= userdefined, 1= default layer
    SdrLayerID nID;
@@ -80,6 +83,15 @@ public:
    void SetDescription(const OUString& rDesc) { maDescription = rDesc; }
    const OUString& GetDescription() const { return maDescription; }

    void SetVisibleODF(const bool& rVisibleODF) { mbVisibleODF = rVisibleODF; }
    bool IsVisibleODF() const { return mbVisibleODF; }

    void SetPrintableODF(const bool& rPrintableODF) { mbPrintableODF = rPrintableODF; }
    bool IsPrintableODF() const { return mbPrintableODF; }

    void SetLockedODF(const bool& rLockedODF) { mbLockedODF = rLockedODF; }
    bool IsLockedODF() const { return mbLockedODF; }

    SdrLayerID    GetID() const                               { return nID; }
    void          SetModel(SdrModel* pNewModel)               { pModel=pNewModel; }
    // A SdrLayer should be considered the standard Layer. It shall then set the
@@ -114,16 +126,11 @@ public:
    SdrLayerAdmin(const SdrLayerAdmin& rSrcLayerAdmin);
    ~SdrLayerAdmin();
    SdrLayerAdmin& operator=(const SdrLayerAdmin& rSrcLayerAdmin);
    SdrLayerAdmin*    GetParent() const { return pParent; }

    void               SetModel(SdrModel* pNewModel);
    void               InsertLayer(SdrLayer* pLayer, sal_uInt16 nPos)
    {
        if(nPos==0xFFFF)
            aLayer.push_back(pLayer);
        else
            aLayer.insert(aLayer.begin() + nPos, pLayer);
        pLayer->SetModel(pModel);
        Broadcast();
    }

    void               InsertLayer(SdrLayer* pLayer, sal_uInt16 nPos);
    SdrLayer*          RemoveLayer(sal_uInt16 nPos);

    // Delete the entire layer
@@ -151,6 +158,12 @@ public:

    void               SetControlLayerName(const OUString& rNewName);
    const OUString&    GetControlLayerName() const { return maControlLayerName; }

    // Removes all elements in rOutSet and then adds all IDs of layers from member aLayer
    // that fullfill the criterion visible, printable, or locked respectively.
    void               getVisibleLayersODF( SdrLayerIDSet& rOutSet) const;
    void               getPrintableLayersODF( SdrLayerIDSet& rOutSet) const;
    void               getLockedLayersODF( SdrLayerIDSet& rOutSet) const;
};

#endif // INCLUDED_SVX_SVDLAYER_HXX
diff --git a/sd/qa/unit/data/tdf101242_ODF.odg b/sd/qa/unit/data/tdf101242_ODF.odg
new file mode 100644
index 0000000..98934c7
--- /dev/null
+++ b/sd/qa/unit/data/tdf101242_ODF.odg
Binary files differ
diff --git a/sd/qa/unit/data/tdf101242_settings.odg b/sd/qa/unit/data/tdf101242_settings.odg
new file mode 100644
index 0000000..5bea0d0
--- /dev/null
+++ b/sd/qa/unit/data/tdf101242_settings.odg
Binary files differ
diff --git a/sd/qa/unit/misc-tests.cxx b/sd/qa/unit/misc-tests.cxx
index a1b83e8..4382825 100644
--- a/sd/qa/unit/misc-tests.cxx
+++ b/sd/qa/unit/misc-tests.cxx
@@ -49,11 +49,12 @@
#include <DrawViewShell.hxx>
#include <chrono>
#include <sdpage.hxx>
#include <comphelper/base64.hxx>

using namespace ::com::sun::star;

/// Impress miscellaneous tests.
class SdMiscTest : public SdModelTestBase
class SdMiscTest : public SdModelTestBaseXML
{
public:
    void testTdf96206();
@@ -63,6 +64,8 @@ public:
    void testFillGradient();
    void testTdf44774();
    void testTdf38225();
    void testTdf101242_ODF();
    void testTdf101242_settings();

    CPPUNIT_TEST_SUITE(SdMiscTest);
    CPPUNIT_TEST(testTdf96206);
@@ -72,8 +75,32 @@ public:
    CPPUNIT_TEST(testFillGradient);
    CPPUNIT_TEST(testTdf44774);
    CPPUNIT_TEST(testTdf38225);
    CPPUNIT_TEST(testTdf101242_ODF);
    CPPUNIT_TEST(testTdf101242_settings);
    CPPUNIT_TEST_SUITE_END();

virtual void registerNamespaces(xmlXPathContextPtr& pXmlXPathCtx) override
    {
        struct { char const * pPrefix; char const * pURI; } namespaces[] =
        {
            // ODF
            { "config", "urn:oasis:names:tc:opendocument:xmlns:config:1.0"},
            { "draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" },
            { "fo", "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" },
            { "loext", "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" },
            { "office", "urn:oasis:names:tc:opendocument:xmlns:office:1.0" },
            { "style", "urn:oasis:names:tc:opendocument:xmlns:style:1.0" },
            { "svg", "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" },
            { "text", "urn:oasis:names:tc:opendocument:xmlns:text:1.0" },
        };
        for (size_t i = 0; i < SAL_N_ELEMENTS(namespaces); ++i)
        {
            xmlXPathRegisterNs(pXmlXPathCtx,
                reinterpret_cast<xmlChar const *>(namespaces[i].pPrefix),
                reinterpret_cast<xmlChar const *>(namespaces[i].pURI));
        }
    }

private:
    sd::DrawDocShellRef Load(const OUString& rURL, sal_Int32 nFormat);
};
@@ -362,6 +389,105 @@ void SdMiscTest::testTdf38225()
    CPPUNIT_ASSERT(pStyle);
}

/// Draw miscellaneous tests.

void SdMiscTest::testTdf101242_ODF()
{
    // Loads a document, which has the visible/printable/locked information for layers
    // only in the ODF attributes draw:display and draw:protected.
    // The resaved document should still have the ODF attributes and in addition (at least in a
    // transition period) the Visible, Printable and Locked items in settings.xml.

    // loading and saving document
    // "Load" is needed for to handle layers, simple "loadURL" does not work.
    sd::DrawDocShellRef xDocShRef = Load(m_directories.getURLFromSrc("/sd/qa/unit/data/tdf101242_ODF.odg"), ODG);
    CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocShRef.is());
    utl::TempFile aTempFile;
    aTempFile.EnableKillingFile();
    save(xDocShRef.get(), getFormat(ODG), aTempFile );

    // Verify, that the saved document still has the ODF attributes
    xmlDocPtr pXmlDoc = parseExport(aTempFile, "styles.xml");
    CPPUNIT_ASSERT_MESSAGE("Failed to get 'styles.xml'", pXmlDoc);
    const OString sPathStart("/office:document-styles/office:master-styles/draw:layer-set/draw:layer");
    assertXPath(pXmlDoc, sPathStart + "[@draw:name='backgroundobjects' and @draw:protected='true']");
    assertXPath(pXmlDoc, sPathStart + "[@draw:name='controls' and @draw:display='screen']");
    assertXPath(pXmlDoc, sPathStart + "[@draw:name='measurelines' and @draw:display='printer']");

    // Verify, that the saved document has got the items in settings.xml
    xmlDocPtr pXmlDoc2 = parseExport(aTempFile, "settings.xml");
    CPPUNIT_ASSERT_MESSAGE("Failed to get 'settings.xml'", pXmlDoc2);
    const OString sPathStart2("/office:document-settings/office:settings/config:config-item-set[@config:name='ooo:view-settings']/config:config-item-map-indexed[@config:name='Views']/config:config-item-map-entry");
    // Value is a bitfield with first Byte in order '* * * measurelines controls backgroundobjects background layout'
    // The first three bits depend on initialization and may change. The values in file are Base64 encoded.
    OUString sBase64;
    uno::Sequence<sal_Int8> aDecodedSeq;
    sBase64 = getXPathContent(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='VisibleLayers']");
    CPPUNIT_ASSERT_MESSAGE( "Item VisibleLayers does not exists.", !sBase64.isEmpty());
    comphelper::Base64::decode(aDecodedSeq, sBase64);
    CPPUNIT_ASSERT_EQUAL( 0x0F, static_cast<sal_uInt8>(aDecodedSeq[0]) & 0x1F );

    sBase64 = getXPathContent(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='PrintableLayers']");
    CPPUNIT_ASSERT_MESSAGE( "Item PrintableLayers does not exists.", !sBase64.isEmpty());
    comphelper::Base64::decode(aDecodedSeq, sBase64);
    CPPUNIT_ASSERT_EQUAL( 0x17, static_cast<sal_uInt8>(aDecodedSeq[0]) & 0x1F);

    sBase64 = getXPathContent(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='LockedLayers']");
    CPPUNIT_ASSERT_MESSAGE( "Item LockedLayers does not exists.", !sBase64.isEmpty());
    comphelper::Base64::decode(aDecodedSeq, sBase64);
    CPPUNIT_ASSERT_EQUAL( 0x04, static_cast<sal_uInt8>(aDecodedSeq[0]) & 0x1F);

    xDocShRef->DoClose();
}

void SdMiscTest::testTdf101242_settings()
{
    // Loads a document, which has the visible/printable/locked information for layers
    // only in the items in settings.xml That is the case for all old documents.
    // The resaved document should still have these items in settings.xml (at least in a
    // transition period) and in addition the ODF attributes draw:display and draw:protected.

    // loading and saving document
    sd::DrawDocShellRef xDocShRef = Load(m_directories.getURLFromSrc("/sd/qa/unit/data/tdf101242_settings.odg"), ODG);
    CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocShRef.is());
    utl::TempFile aTempFile;
    aTempFile.EnableKillingFile();
    save(xDocShRef.get(), getFormat(ODG), aTempFile );

    // Verify, that the saved document has the ODF attributes
    xmlDocPtr pXmlDoc = parseExport(aTempFile, "styles.xml");
    CPPUNIT_ASSERT_MESSAGE("Failed to get 'styles.xml'", pXmlDoc);
    const OString sPathStart("/office:document-styles/office:master-styles/draw:layer-set/draw:layer");
    assertXPath(pXmlDoc, sPathStart + "[@draw:name='backgroundobjects' and @draw:protected='true']");
    assertXPath(pXmlDoc, sPathStart + "[@draw:name='controls' and @draw:display='screen']");
    assertXPath(pXmlDoc, sPathStart + "[@draw:name='measurelines' and @draw:display='printer']");

    // Verify, that the saved document still has the items in settings.xml
    xmlDocPtr pXmlDoc2 = parseExport(aTempFile, "settings.xml");
    CPPUNIT_ASSERT_MESSAGE("Failed to get 'settings.xml'", pXmlDoc2);
    const OString sPathStart2("/office:document-settings/office:settings/config:config-item-set[@config:name='ooo:view-settings']/config:config-item-map-indexed[@config:name='Views']/config:config-item-map-entry");
    // Value is a bitfield with first Byte in order '* * * measurelines controls backgroundobjects background layout'
    // The first three bits depend on initialization and may change. The values in file are Base64 encoded.
    OUString sBase64;
    uno::Sequence<sal_Int8> aDecodedSeq;
    sBase64 = getXPathContent(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='VisibleLayers']");
    CPPUNIT_ASSERT_MESSAGE( "Item VisibleLayers does not exists.", !sBase64.isEmpty());
    comphelper::Base64::decode(aDecodedSeq, sBase64);
    CPPUNIT_ASSERT_EQUAL( 0x0F, static_cast<sal_uInt8>(aDecodedSeq[0]) & 0x1F );

    sBase64 = getXPathContent(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='PrintableLayers']");
    CPPUNIT_ASSERT_MESSAGE( "Item PrintableLayers does not exists.", !sBase64.isEmpty());
    comphelper::Base64::decode(aDecodedSeq, sBase64);
    CPPUNIT_ASSERT_EQUAL( 0x17, static_cast<sal_uInt8>(aDecodedSeq[0]) & 0x1F);

    sBase64 = getXPathContent(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='LockedLayers']");
    CPPUNIT_ASSERT_MESSAGE( "Item LockedLayers does not exists.", !sBase64.isEmpty());
    comphelper::Base64::decode(aDecodedSeq, sBase64);
    CPPUNIT_ASSERT_EQUAL( 0x04, static_cast<sal_uInt8>(aDecodedSeq[0]) & 0x1F);

    xDocShRef->DoClose();
}

CPPUNIT_TEST_SUITE_REGISTRATION(SdMiscTest);

CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sd/qa/unit/sdmodeltestbase.hxx b/sd/qa/unit/sdmodeltestbase.hxx
index 16af585..089e36c 100644
--- a/sd/qa/unit/sdmodeltestbase.hxx
+++ b/sd/qa/unit/sdmodeltestbase.hxx
@@ -59,6 +59,7 @@ struct FileFormat
#define FODG_FORMAT_TYPE  (SfxFilterFlags::STARONEFILTER | SfxFilterFlags::OWN | SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT)
#define FODP_FORMAT_TYPE  (SfxFilterFlags::STARONEFILTER | SfxFilterFlags::OWN | SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT)
#define SXI_FORMAT_TYPE  (SfxFilterFlags::IMPORT | SfxFilterFlags::TEMPLATE | SfxFilterFlags::OWN | SfxFilterFlags::ALIEN | SfxFilterFlags::PREFERED | SfxFilterFlags::ENCRYPTION)
#define ODG_FORMAT_TYPE  ( SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT | SfxFilterFlags::TEMPLATE | SfxFilterFlags::OWN | SfxFilterFlags::DEFAULT | SfxFilterFlags::ENCRYPTION | SfxFilterFlags::PREFERED )
#define PPTM_FORMAT_TYPE ( SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT | SfxFilterFlags::ALIEN | SfxFilterFlags::STARONEFILTER | SfxFilterFlags::PREFERED )

/** List of file formats we support in Impress unit tests.
@@ -79,7 +80,7 @@ FileFormat aFileFormats[] =
    { "fodg", "OpenDocument Drawing Flat XML", "draw_ODG_FlatXML", "", FODG_FORMAT_TYPE },
    { "fodp", "OpenDocument Presentation Flat XML", "impress_ODP_FlatXML", "", FODP_FORMAT_TYPE },
    { "sxi",  "StarOffice XML (Impress)", "impress_StarOffice_XML_Impress", "", SXI_FORMAT_TYPE },
    { "odg",  "draw8", "draw8", "", ODP_FORMAT_TYPE },
    { "odg",  "draw8", "draw8", "", ODG_FORMAT_TYPE },
    { "pptm", "Impress MS PowerPoint 2007 XML VBA", "MS PowerPoint 2007 XML VBA", "", PPTM_FORMAT_TYPE },
    { nullptr, nullptr, nullptr, nullptr, SfxFilterFlags::NONE }
};
@@ -100,6 +101,7 @@ class SdModelTestBase : public test::BootstrapFixture, public unotest::MacrosTes
{
private:
    uno::Reference<uno::XInterface> mxDrawComponent;
    uno::Reference<uno::XInterface> mxImpressComponent;

public:
    SdModelTestBase()
@@ -111,12 +113,15 @@ public:

        // This is a bit of a fudge, we do this to ensure that ScGlobals::ensure,
        // which is a private symbol to us, gets called
        mxDrawComponent = getMultiServiceFactory()->createInstance("com.sun.star.comp.Draw.PresentationDocument");
        CPPUNIT_ASSERT_MESSAGE("no impress component!", mxDrawComponent.is());
        mxImpressComponent = getMultiServiceFactory()->createInstance("com.sun.star.comp.Draw.PresentationDocument");
        CPPUNIT_ASSERT_MESSAGE("no impress component!", mxImpressComponent.is());
        mxDrawComponent = getMultiServiceFactory()->createInstance("com.sun.star.comp.Draw.DrawingDocument");
        CPPUNIT_ASSERT_MESSAGE("no draw component!", mxDrawComponent.is());
    }

    virtual void tearDown() override
    {
        uno::Reference<lang::XComponent>(mxImpressComponent, uno::UNO_QUERY_THROW)->dispose();
        uno::Reference<lang::XComponent>(mxDrawComponent, uno::UNO_QUERY_THROW)->dispose();
        test::BootstrapFixture::tearDown();
    }
@@ -127,31 +132,58 @@ protected:
    {
        FileFormat *pFmt = getFormat(nFormat);
        CPPUNIT_ASSERT_MESSAGE( "missing filter info", pFmt->pName != nullptr );
        if ( std::strcmp(pFmt->pName, "odg") == 0)
        { // Draw
            SotClipboardFormatId nOptions = SotClipboardFormatId::NONE;
            if (pFmt->nFormatType != SfxFilterFlags::NONE)
                nOptions = SotClipboardFormatId::STARDRAW_8;
            SfxFilter* pFilter = new SfxFilter(
                OUString::createFromAscii( pFmt->pFilterName ),
                OUString(), pFmt->nFormatType, nOptions,
                OUString::createFromAscii( pFmt->pTypeName ),
                OUString(),
                OUString::createFromAscii( pFmt->pUserData ),
                "private:factory/sdraw*" );
            pFilter->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
            std::shared_ptr<const SfxFilter> pFilt(pFilter);

        SotClipboardFormatId nOptions = SotClipboardFormatId::NONE;
        if (pFmt->nFormatType != SfxFilterFlags::NONE)
            nOptions = SotClipboardFormatId::STARCALC_8;
        SfxFilter* pFilter = new SfxFilter(
            OUString::createFromAscii( pFmt->pFilterName ),
            OUString(), pFmt->nFormatType, nOptions,
            OUString::createFromAscii( pFmt->pTypeName ),
            OUString(),
            OUString::createFromAscii( pFmt->pUserData ),
            "private:factory/simpress*" );
        pFilter->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
        std::shared_ptr<const SfxFilter> pFilt(pFilter);

        ::sd::DrawDocShellRef xDocShRef = new ::sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED, false, DocumentType::Impress);
        SfxMedium* pSrcMed = new SfxMedium(rURL, StreamMode::STD_READ, pFilt, std::move(pParams));
        if ( !xDocShRef->DoLoad(pSrcMed) || !xDocShRef.is() )
        {
            if (xDocShRef.is())
                xDocShRef->DoClose();
            CPPUNIT_ASSERT_MESSAGE( OUStringToOString( "failed to load " + rURL, RTL_TEXTENCODING_UTF8 ).getStr(), false );
            ::sd::DrawDocShellRef xDocShRef = new ::sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED, false, DocumentType::Draw);
            SfxMedium* pSrcMed = new SfxMedium(rURL, StreamMode::STD_READ, pFilt, std::move(pParams));
            if ( !xDocShRef->DoLoad(pSrcMed) || !xDocShRef.is() )
            {
                if (xDocShRef.is())
                    xDocShRef->DoClose();
                CPPUNIT_ASSERT_MESSAGE( OUStringToOString( "failed to load Draw doc" + rURL, RTL_TEXTENCODING_UTF8 ).getStr(), false );
            }
            CPPUNIT_ASSERT_MESSAGE( "not in destruction", !xDocShRef->IsInDestruction() );
            return xDocShRef;
        }
        CPPUNIT_ASSERT_MESSAGE( "not in destruction", !xDocShRef->IsInDestruction() );
        else // Impress
        {
            SotClipboardFormatId nOptions = SotClipboardFormatId::NONE;
            if (pFmt->nFormatType != SfxFilterFlags::NONE)
                nOptions = SotClipboardFormatId::STARIMPRESS_8;
            SfxFilter* pFilter = new SfxFilter(
                OUString::createFromAscii( pFmt->pFilterName ),
                OUString(), pFmt->nFormatType, nOptions,
                OUString::createFromAscii( pFmt->pTypeName ),
                OUString(),
                OUString::createFromAscii( pFmt->pUserData ),
                "private:factory/simpress*" );
            pFilter->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
            std::shared_ptr<const SfxFilter> pFilt(pFilter);

        return xDocShRef;
            ::sd::DrawDocShellRef xDocShRef = new ::sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED, false, DocumentType::Impress);
            SfxMedium* pSrcMed = new SfxMedium(rURL, StreamMode::STD_READ, pFilt, std::move(pParams));
            if ( !xDocShRef->DoLoad(pSrcMed) || !xDocShRef.is() )
            {
                if (xDocShRef.is())
                    xDocShRef->DoClose();
                CPPUNIT_ASSERT_MESSAGE( OUStringToOString( "failed to load " + rURL, RTL_TEXTENCODING_UTF8 ).getStr(), false );
            }
            CPPUNIT_ASSERT_MESSAGE( "not in destruction", !xDocShRef->IsInDestruction() );
            return xDocShRef;
        }
    }

    FileFormat* getFormat(sal_Int32 nExportType)
@@ -165,37 +197,76 @@ protected:
    void exportTo(sd::DrawDocShell* pShell, FileFormat const * pFormat, utl::TempFile const & rTempFile)
    {
        SfxMedium aStoreMedium(rTempFile.GetURL(), StreamMode::STD_WRITE);
        SotClipboardFormatId nExportFormat = SotClipboardFormatId::NONE;
        if (pFormat->nFormatType == ODP_FORMAT_TYPE)
            nExportFormat = SotClipboardFormatId::STARCALC_8;
        std::shared_ptr<const SfxFilter> pExportFilter(new SfxFilter(
                                        OUString::createFromAscii(pFormat->pFilterName),
                                        OUString(), pFormat->nFormatType, nExportFormat,
                                        OUString::createFromAscii(pFormat->pTypeName),
                                        OUString(),
                                        OUString::createFromAscii(pFormat->pUserData),
                                        "private:factory/simpress*" ));
        const_cast<SfxFilter*>(pExportFilter.get())->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
        aStoreMedium.SetFilter(pExportFilter);
        if ( std::strcmp(pFormat->pName, "odg") == 0)
        { // Draw
            SotClipboardFormatId nExportFormat = SotClipboardFormatId::NONE;
            if (pFormat->nFormatType == ODG_FORMAT_TYPE)
                nExportFormat = SotClipboardFormatId::STARDRAW_8;
            std::shared_ptr<const SfxFilter> pExportFilter(new SfxFilter(
                                            OUString::createFromAscii(pFormat->pFilterName),
                                            OUString(), pFormat->nFormatType, nExportFormat,
                                            OUString::createFromAscii(pFormat->pTypeName),
                                            OUString(),
                                            OUString::createFromAscii(pFormat->pUserData),
                                            "private:factory/sdraw*" ));

            const_cast<SfxFilter*>(pExportFilter.get())->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
            aStoreMedium.SetFilter(pExportFilter);
        }
        else // Impress
        {
            SotClipboardFormatId nExportFormat = SotClipboardFormatId::NONE;
            if (pFormat->nFormatType == ODP_FORMAT_TYPE)
                nExportFormat = SotClipboardFormatId::STARIMPRESS_8;
            std::shared_ptr<const SfxFilter> pExportFilter(new SfxFilter(
                                            OUString::createFromAscii(pFormat->pFilterName),
                                            OUString(), pFormat->nFormatType, nExportFormat,
                                            OUString::createFromAscii(pFormat->pTypeName),
                                            OUString(),
                                            OUString::createFromAscii(pFormat->pUserData),
                                            "private:factory/simpress*" ));

            const_cast<SfxFilter*>(pExportFilter.get())->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
            aStoreMedium.SetFilter(pExportFilter);
        }
        pShell->ConvertTo(aStoreMedium);
        pShell->DoClose();

    }

    void save(sd::DrawDocShell* pShell, FileFormat const * pFormat, utl::TempFile const & rTempFile)
    {
        SfxMedium aStoreMedium(rTempFile.GetURL(), StreamMode::STD_WRITE);
        SotClipboardFormatId nExportFormat = SotClipboardFormatId::NONE;
        if (pFormat->nFormatType == ODP_FORMAT_TYPE)
            nExportFormat = SotClipboardFormatId::STARCHART_8;
        std::shared_ptr<const SfxFilter> pExportFilter(new SfxFilter(
                                        OUString::createFromAscii(pFormat->pFilterName),
                                        OUString(), pFormat->nFormatType, nExportFormat,
                                        OUString::createFromAscii(pFormat->pTypeName),
                                        OUString(),
                                        OUString::createFromAscii(pFormat->pUserData),
                                        "private:factory/simpress*" ));
        const_cast<SfxFilter*>(pExportFilter.get())->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
        aStoreMedium.SetFilter(pExportFilter);
        if ( std::strcmp(pFormat->pName, "odg") == 0 )
        { // Draw
            SotClipboardFormatId nExportFormat = SotClipboardFormatId::NONE;
            if (pFormat->nFormatType == ODG_FORMAT_TYPE)
                nExportFormat = SotClipboardFormatId::STARDRAW_8;
            std::shared_ptr<const SfxFilter> pExportFilter(new SfxFilter(
                                            OUString::createFromAscii(pFormat->pFilterName),
                                            OUString(), pFormat->nFormatType, nExportFormat,
                                            OUString::createFromAscii(pFormat->pTypeName),
                                            OUString(),
                                            OUString::createFromAscii(pFormat->pUserData),
                                            "private:factory/sdraw*" ));
            const_cast<SfxFilter*>(pExportFilter.get())->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
            aStoreMedium.SetFilter(pExportFilter);
        }
        else // Impress
        {
            SotClipboardFormatId nExportFormat = SotClipboardFormatId::NONE;
            if (pFormat->nFormatType == ODP_FORMAT_TYPE)
                nExportFormat = SotClipboardFormatId::STARCHART_8;
            std::shared_ptr<const SfxFilter> pExportFilter(new SfxFilter(
                                            OUString::createFromAscii(pFormat->pFilterName),
                                            OUString(), pFormat->nFormatType, nExportFormat,
                                            OUString::createFromAscii(pFormat->pTypeName),
                                            OUString(),
                                            OUString::createFromAscii(pFormat->pUserData),
                                            "private:factory/simpress*" ));
            const_cast<SfxFilter*>(pExportFilter.get())->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
            aStoreMedium.SetFilter(pExportFilter);
        }
        pShell->DoSaveAs(aStoreMedium);
        pShell->DoClose();
    }
diff --git a/sd/source/ui/unoidl/unolayer.cxx b/sd/source/ui/unoidl/unolayer.cxx
index a55f913..a3ae65f 100644
--- a/sd/source/ui/unoidl/unolayer.cxx
+++ b/sd/source/ui/unoidl/unolayer.cxx
@@ -136,6 +136,9 @@ SdLayer::SdLayer(SdLayerManager* pLayerManager_, SdrLayer* pSdrLayer_)
, pLayer(pSdrLayer_)
, pPropSet(ImplGetSdLayerPropertySet())
{
    // no defaults possible yet, a "set" would overwrite existing information
    // in view, which is currently needed for saving, because pLayer is not updated
    // from view.
}

SdLayer::~SdLayer() throw()
@@ -183,17 +186,20 @@ void SAL_CALL SdLayer::setPropertyValue( const OUString& aPropertyName, const un
    {
    case WID_LAYER_LOCKED:
    {
        set(LOCKED, cppu::any2bool(aValue));
        pLayer->SetLockedODF( cppu::any2bool(aValue) );
        set(LOCKED, cppu::any2bool(aValue)); // changes the View, if any exists
        break;
    }
    case WID_LAYER_PRINTABLE:
    {
        set(PRINTABLE, cppu::any2bool(aValue));
        pLayer->SetPrintableODF( cppu::any2bool(aValue) );
        set(PRINTABLE, cppu::any2bool(aValue)); // changes the View, if any exists
        break;
    }
    case WID_LAYER_VISIBLE:
    {
        set(VISIBLE, cppu::any2bool(aValue));
        pLayer->SetVisibleODF( cppu::any2bool(aValue) );
        set(VISIBLE, cppu::any2bool(aValue)); // changes the View, if any exists
        break;
    }
    case WID_LAYER_NAME:
diff --git a/sd/source/ui/view/drviews5.cxx b/sd/source/ui/view/drviews5.cxx
index 6859857..bd9e9f8 100644
--- a/sd/source/ui/view/drviews5.cxx
+++ b/sd/source/ui/view/drviews5.cxx
@@ -474,6 +474,36 @@ void DrawViewShell::ReadUserDataSequence ( const css::uno::Sequence < css::beans
        else GetDocSh()->GetDoc()->ReadUserDataSequenceValue(pValue);
    }

    // The parameter rSequence contains the config-items from
    // <config:config-item-set config:name="ooo:view-settings">. Determine, whether
    // they contain "VisibleLayers", "PrintableLayers" and "LockedLayers". If not, it
    // is a foreign document or a new document after transition period and the corresponding
    // information were read from <draw:layer-set>. In that case we need to bring
    // the information from model to view.
    bool bHasVisiPrnLockSettings(false);
    for ( auto & rPropertyValue : rSequence )
    {
        if ( rPropertyValue.Name == sUNO_View_VisibleLayers
          || rPropertyValue.Name == sUNO_View_PrintableLayers
          || rPropertyValue.Name == sUNO_View_LockedLayers )
        {
            bHasVisiPrnLockSettings = true;
            break;
        }
    }
    if ( !bHasVisiPrnLockSettings )
    {
        const SdrLayerAdmin& rLayerAdmin = GetDocSh()->GetDoc()->GetLayerAdmin();
        SdrLayerIDSet aSdrLayerIDSet;
        rLayerAdmin.getVisibleLayersODF( aSdrLayerIDSet );
        mpFrameView -> SetVisibleLayers( aSdrLayerIDSet );
        rLayerAdmin.getPrintableLayersODF( aSdrLayerIDSet );
        mpFrameView -> SetPrintableLayers( aSdrLayerIDSet );
        rLayerAdmin.getLockedLayersODF( aSdrLayerIDSet );
        mpFrameView -> SetLockedLayers( aSdrLayerIDSet );
    }


    if( mpFrameView->GetPageKind() != mePageKind )
    {
        mePageKind = mpFrameView->GetPageKind();
diff --git a/sd/source/ui/view/frmview.cxx b/sd/source/ui/view/frmview.cxx
index 450ee2f..1232d9f 100644
--- a/sd/source/ui/view/frmview.cxx
+++ b/sd/source/ui/view/frmview.cxx
@@ -196,8 +196,15 @@ FrameView::FrameView(SdDrawDocument* pDrawDoc, FrameView* pFrameView /* = NULL *
    else
    {
        // initialize FrameView with the application data
        maVisibleLayers.SetAll();
        maPrintableLayers.SetAll();

        // Layers need to be set, otherwise they are not visible and not printable in
        // Impress documents. The document contains already the actual layers and their
        // settings for visible, printable and locked. In case not read from <draw:layer-set>,
        // ODF defaults are used.
        SdrLayerAdmin rLayerAdmin = pDrawDoc -> GetLayerAdmin();
        rLayerAdmin.getVisibleLayersODF(maVisibleLayers);
        rLayerAdmin.getPrintableLayersODF(maPrintableLayers);
        rLayerAdmin.getLockedLayersODF(maLockedLayers);
        SetGridCoarse( Size( 1000, 1000 ) );
        SetSnapGridWidth(Fraction(1000, 1), Fraction(1000, 1));
        SetActiveLayer( SdResId(STR_LAYER_LAYOUT) );
diff --git a/svx/source/svdraw/svdlayer.cxx b/svx/source/svdraw/svdlayer.cxx
index ff497d3..d17b61d 100644
--- a/svx/source/svdraw/svdlayer.cxx
+++ b/svx/source/svdraw/svdlayer.cxx
@@ -92,9 +92,14 @@ void SdrLayerIDSet::QueryValue( css::uno::Any & rAny ) const
    rAny <<= aSeq;
}


SdrLayer::SdrLayer(SdrLayerID nNewID, const OUString& rNewName) :
    maName(rNewName), pModel(nullptr), nType(0), nID(nNewID)
{
    // ODF default values
    mbVisibleODF = true;
    mbPrintableODF = true;
    mbLockedODF = false;
}

void SdrLayer::SetStandardLayer()
@@ -193,6 +198,16 @@ void SdrLayerAdmin::Broadcast() const
    }
}

void SdrLayerAdmin::InsertLayer(SdrLayer* pLayer, sal_uInt16 nPos)
{
        if(nPos==0xFFFF)
            aLayer.push_back(pLayer);
        else
            aLayer.insert(aLayer.begin() + nPos, pLayer);
        pLayer->SetModel(pModel);
        Broadcast();
}

SdrLayer* SdrLayerAdmin::RemoveLayer(sal_uInt16 nPos)
{
    SdrLayer* pRetLayer=aLayer[nPos];
@@ -321,4 +336,35 @@ void SdrLayerAdmin::SetControlLayerName(const OUString& rNewName)
    maControlLayerName = rNewName;
}

void  SdrLayerAdmin::getVisibleLayersODF( SdrLayerIDSet& rOutSet) const
{
    rOutSet.ClearAll();
    for( SdrLayer* pCurrentLayer : aLayer )
    {
        if ( pCurrentLayer->IsVisibleODF() )
            rOutSet.Set( pCurrentLayer->GetID() );
    }
}

void SdrLayerAdmin::getPrintableLayersODF( SdrLayerIDSet& rOutSet) const
{
    rOutSet.ClearAll();
    for( SdrLayer* pCurrentLayer : aLayer )
    {
        if ( pCurrentLayer->IsPrintableODF() )
            rOutSet.Set( pCurrentLayer->GetID() );
    }
}

void SdrLayerAdmin::getLockedLayersODF( SdrLayerIDSet& rOutSet) const
{
    rOutSet.ClearAll();
    for( SdrLayer* pCurrentLayer : aLayer )
    {
        if ( pCurrentLayer->IsLockedODF() )
            rOutSet.Set( pCurrentLayer->GetID() );
    }
}


/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdpagv.cxx b/svx/source/svdraw/svdpagv.cxx
index 1f9a53a..bbb0d8e 100644
--- a/svx/source/svdraw/svdpagv.cxx
+++ b/svx/source/svdraw/svdpagv.cxx
@@ -143,11 +143,48 @@ SdrPageView::SdrPageView(SdrPage* pPage1, SdrView& rNewView)
    {
        aPgOrg.setX(mpPage->GetLeftBorder() );
        aPgOrg.setY(mpPage->GetUpperBorder() );

        // Get layersets from document, master page or page to be ODF conform.
        // Currently only partly implemented, the comments show, what is missing.
        const SdrLayerAdmin& rPageLayerAdmin( mpPage->GetLayerAdmin() );
        if ( rPageLayerAdmin.GetLayerCount() == 0 )
        {
            // if (master page has layers)
            //      Get LayerIDSet from master page.
            // else
            //      Get default LayerIDSet from document
            //      Currently the parent LayerAdmin is the LayerAdmin of the document
                    SdrLayerAdmin* pParentLayerAdmin = rPageLayerAdmin.GetParent();
                    if ( pParentLayerAdmin )
                    {
                        pParentLayerAdmin->getVisibleLayersODF( aLayerVisi );
                        pParentLayerAdmin->getPrintableLayersODF( aLayerPrn );
                        pParentLayerAdmin->getLockedLayersODF( aLayerLock );
                    }
                     else
                    {
                        // This should not happen. ToDo: assertion for debug mode
                        aLayerVisi.SetAll();
                        aLayerPrn.SetAll();
                    }
        }
        else
        {
            // page has own Layers. Get LayerIDSet from page, maybe from master page in addition.
            rPageLayerAdmin.getVisibleLayersODF( aLayerVisi );
            rPageLayerAdmin.getPrintableLayersODF( aLayerPrn );
            rPageLayerAdmin.getLockedLayersODF( aLayerLock );
            // if (master page has layers)
            //        Add the layer IDs for master page layers to the set from the page.
        }
    }
    else
    {   // SdrPageView without page?
        // ToDo: assertion for debug mode
        aLayerVisi.SetAll();
        aLayerPrn.SetAll();
    }
    mbHasMarked = false;
    aLayerVisi.SetAll();
    aLayerPrn.SetAll();

    mbVisible = false;
    pCurrentList = nullptr;
    pCurrentGroup = nullptr;
diff --git a/xmloff/source/draw/layerexp.cxx b/xmloff/source/draw/layerexp.cxx
index e1a3727..72f6b1d 100644
--- a/xmloff/source/draw/layerexp.cxx
+++ b/xmloff/source/draw/layerexp.cxx
@@ -56,9 +56,13 @@ void SdXMLayerExporter::exportLayer( SvXMLExport& rExport )
    const OUString strName( "Name" );
    const OUString strTitle( "Title" );
    const OUString strDescription( "Description" );
    const OUString strIsVisible( "IsVisible");
    const OUString strIsPrintable( "IsPrintable");
    const OUString strIsLocked( "IsLocked" );

    OUString sTmp;


    SvXMLElementExport aElem( rExport, XML_NAMESPACE_DRAW, XML_LAYER_SET, true, true );

    for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
@@ -70,6 +74,32 @@ void SdXMLayerExporter::exportLayer( SvXMLExport& rExport )
            if(!sTmp.isEmpty())
                rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, sTmp );

            bool bTmpVisible( true );
            bool bTmpPrintable( true );
            xLayer->getPropertyValue( strIsVisible) >>= bTmpVisible;
            xLayer->getPropertyValue( strIsPrintable) >>= bTmpPrintable;
            // only write non-default values, default is "always"
            if ( bTmpVisible )
            {
                if ( !bTmpPrintable )
                    rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY, OUString("screen") );
            }
            else
            {
                if ( bTmpPrintable)
                    rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY, OUString("printer") );
                else
                    rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY, OUString("none") );
            }

            bool bTmpLocked( false );
            xLayer->getPropertyValue( strIsLocked ) >>= bTmpLocked;
            // only write non-default value, default is "false"
            if ( bTmpLocked )
            {
                rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_PROTECTED, OUString("true") );
            }

            SvXMLElementExport aEle( rExport, XML_NAMESPACE_DRAW, XML_LAYER, true, true );

            // title property (as <svg:title> element)
diff --git a/xmloff/source/draw/layerimp.cxx b/xmloff/source/draw/layerimp.cxx
index 3ffde05..13071e6 100644
--- a/xmloff/source/draw/layerimp.cxx
+++ b/xmloff/source/draw/layerimp.cxx
@@ -60,6 +60,8 @@ private:
    OUString msName;
    OUStringBuffer sDescriptionBuffer;
    OUStringBuffer sTitleBuffer;
    OUString msDisplay;
    OUString msProtected;
};

SdXMLLayerContext::SdXMLLayerContext( SvXMLImport& rImport, sal_uInt16 nPrefix, const OUString& rLocalName, const Reference< XAttributeList >& xAttrList, const Reference< XNameAccess >& xLayerManager )
@@ -77,7 +79,14 @@ SdXMLLayerContext::SdXMLLayerContext( SvXMLImport& rImport, sal_uInt16 nPrefix, 
            if( IsXMLToken( aLocalName, XML_NAME ) )
            {
                msName = sValue;
                break; // no more attributes needed
            }
            else if ( IsXMLToken( aLocalName, XML_DISPLAY))
            {
                msDisplay = sValue;
            }
            else if ( IsXMLToken( aLocalName, XML_PROTECTED))
            {
                msProtected = sValue;
            }
        }
    }
@@ -127,6 +136,19 @@ void SdXMLLayerContext::EndElement()
        {
            xLayer->setPropertyValue("Title", Any( sTitleBuffer.makeStringAndClear() ) );
            xLayer->setPropertyValue("Description", Any( sDescriptionBuffer.makeStringAndClear() ) );
            bool bIsVisible( true );
            bool bIsPrintable( true );
            if ( !msDisplay.isEmpty() )
            {
                bIsVisible = (msDisplay == "always") || (msDisplay == "screen");
                bIsPrintable = (msDisplay == "always") || (msDisplay == "printer");
            }
            xLayer->setPropertyValue("IsVisible", Any( bIsVisible ) );
            xLayer->setPropertyValue("IsPrintable", Any( bIsPrintable ) );
            bool bIsLocked( false );
            if ( !msProtected.isEmpty() )
                bIsLocked = (msProtected == "true");
            xLayer->setPropertyValue("IsLocked", Any( bIsLocked ) );
        }
    }
    catch( Exception& )