sc drawstyles: Clipboard support

- Paste as Calc's own format (default in Calc, results with an
  OLE object elsewhere), should preserve style assignment. This
  can be in one of two ways: Either copy the shape itself, or a
  cell range that includes a shape.

- Similarly, copying or moving a whole sheet to another document
  should also preserve the style.

- Paste as drawing format (default in other apps, also default
  in Calc when copying shapes from other apps), should preserve
  the formatting as direct formatting. Pasting into Calc will
  also assign the default style to that shape.

Change-Id: Icb951dad1a77ba9ced706c33c928980d1ec7f8ac
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149753
Tested-by: Jenkins
Reviewed-by: Maxim Monastirsky <momonasmon@gmail.com>
diff --git a/sc/inc/stlpool.hxx b/sc/inc/stlpool.hxx
index 51694a4..131b82c 100644
--- a/sc/inc/stlpool.hxx
+++ b/sc/inc/stlpool.hxx
@@ -45,8 +45,10 @@ public:
    void                CreateStandardStyles();
    void                CopyStdStylesFrom( ScStyleSheetPool* pSrcPool );

    void                CopyStyleFrom( ScStyleSheetPool* pSrcPool,
                                       const OUString& rName, SfxStyleFamily eFamily );
    void                CopyUsedGraphicStylesFrom( SfxStyleSheetBasePool* pSrcPool );
    void                CopyStyleFrom( SfxStyleSheetBasePool* pSrcPool,
                                       const OUString& rName, SfxStyleFamily eFamily,
                                       bool bNewStyleHierarchy = false );

    bool                HasStandardStyles() const { return bHasStandardStyles; }

diff --git a/sc/source/core/data/documen9.cxx b/sc/source/core/data/documen9.cxx
index 34c25c7..f63c1ee 100644
--- a/sc/source/core/data/documen9.cxx
+++ b/sc/source/core/data/documen9.cxx
@@ -45,6 +45,7 @@
#include <rechead.hxx>
#include <poolhelp.hxx>
#include <docpool.hxx>
#include <stlpool.hxx>
#include <editutil.hxx>
#include <charthelper.hxx>
#include <conditio.hxx>
@@ -76,6 +77,12 @@ void ScDocument::TransferDrawPage(const ScDocument& rSrcDoc, SCTAB nSrcPos, SCTA
            SdrObject* pOldObject = aIter.Next();
            while (pOldObject)
            {
                // Copy style sheet
                auto pStyleSheet = pOldObject->GetStyleSheet();
                if (pStyleSheet)
                    GetStyleSheetPool()->CopyStyleFrom(rSrcDoc.GetStyleSheetPool(),
                                                       pStyleSheet->GetName(), pStyleSheet->GetFamily(), true);

                // Clone to target SdrModel
                rtl::Reference<SdrObject> pNewObject(pOldObject->CloneSdrObject(*mpDrawLayer));
                pNewObject->NbcMove(Size(0,0));
diff --git a/sc/source/core/data/drwlayer.cxx b/sc/source/core/data/drwlayer.cxx
index 263c569..a316205 100644
--- a/sc/source/core/data/drwlayer.cxx
+++ b/sc/source/core/data/drwlayer.cxx
@@ -385,8 +385,11 @@ SdrModel* ScDrawLayer::AllocModel() const
{
    //  Allocated model (for clipboard etc) must not have a pointer
    //  to the original model's document, pass NULL as document:
    auto pNewModel = std::make_unique<ScDrawLayer>(nullptr, aName);
    auto pNewPool = static_cast<ScStyleSheetPool*>(pNewModel->GetStyleSheetPool());
    pNewPool->CopyUsedGraphicStylesFrom(GetStyleSheetPool());

    return new ScDrawLayer( nullptr, aName );
    return pNewModel.release();
}

bool ScDrawLayer::ScAddPage( SCTAB nTab )
@@ -1930,6 +1933,12 @@ void ScDrawLayer::CopyFromClip( ScDrawLayer* pClipModel, SCTAB nSourceTab, const
        if (bObjectInArea && (pOldObject->GetLayer() != SC_LAYER_INTERN)
            && !IsNoteCaption(pOldObject))
        {
            // Copy style sheet
            auto pStyleSheet = pOldObject->GetStyleSheet();
            if (pStyleSheet && !bSameDoc)
                pDoc->GetStyleSheetPool()->CopyStyleFrom(pClipDoc->GetStyleSheetPool(),
                    pStyleSheet->GetName(), pStyleSheet->GetFamily(), true);

            // Clone to target SdrModel
            rtl::Reference<SdrObject> pNewObject(pOldObject->CloneSdrObject(*this));

diff --git a/sc/source/core/data/stlpool.cxx b/sc/source/core/data/stlpool.cxx
index e7f6d26..6a45048 100644
--- a/sc/source/core/data/stlpool.cxx
+++ b/sc/source/core/data/stlpool.cxx
@@ -125,8 +125,9 @@ void ScStyleSheetPool::Remove( SfxStyleSheetBase* pStyle )
    }
}

void ScStyleSheetPool::CopyStyleFrom( ScStyleSheetPool* pSrcPool,
                                      const OUString& rName, SfxStyleFamily eFamily )
void ScStyleSheetPool::CopyStyleFrom( SfxStyleSheetBasePool* pSrcPool,
                                      const OUString& rName, SfxStyleFamily eFamily,
                                      bool bNewStyleHierarchy )
{
    //  this is the Dest-Pool

@@ -136,8 +137,10 @@ void ScStyleSheetPool::CopyStyleFrom( ScStyleSheetPool* pSrcPool,

    const SfxItemSet& rSourceSet = pStyleSheet->GetItemSet();
    SfxStyleSheetBase* pDestSheet = Find( rName, eFamily );
    if (pDestSheet && bNewStyleHierarchy)
        return;
    if (!pDestSheet)
        pDestSheet = &Make( rName, eFamily );
        pDestSheet = &Make( rName, eFamily, pStyleSheet->GetMask() );
    SfxItemSet& rDestSet = pDestSheet->GetItemSet();
    rDestSet.PutExtended( rSourceSet, SfxItemState::DONTCARE, SfxItemState::DEFAULT );

@@ -176,6 +179,38 @@ void ScStyleSheetPool::CopyStyleFrom( ScStyleSheetPool* pSrcPool,
            }
        }
    }

    const OUString aParentName = pStyleSheet->GetParent();
    if (!bNewStyleHierarchy || aParentName.isEmpty())
        return;

    CopyStyleFrom(pSrcPool, aParentName, eFamily, bNewStyleHierarchy);
    pDestSheet->SetParent(aParentName);
}

void ScStyleSheetPool::CopyUsedGraphicStylesFrom(SfxStyleSheetBasePool* pSrcPool)
{
    //  this is the Dest-Pool

    std::vector<std::pair<SfxStyleSheetBase*, OUString>> aNewStyles;

    auto pSrcSheet = pSrcPool->First(SfxStyleFamily::Frame);
    while (pSrcSheet)
    {
        if (pSrcSheet->IsUsed() && !Find(pSrcSheet->GetName(), pSrcSheet->GetFamily()))
        {
            auto pDestSheet = &Make(pSrcSheet->GetName(), pSrcSheet->GetFamily(), pSrcSheet->GetMask());
            aNewStyles.emplace_back(pDestSheet, pSrcSheet->GetParent());

            SfxItemSet& rDestSet = pDestSheet->GetItemSet();
            rDestSet.Put(pSrcSheet->GetItemSet());
        }

        pSrcSheet = pSrcPool->Next();
    }

    for (const auto& style : aNewStyles)
        style.first->SetParent(style.second);
}

//                      Standard templates
@@ -185,6 +220,7 @@ void ScStyleSheetPool::CopyStdStylesFrom( ScStyleSheetPool* pSrcPool )
    //  Copy Default styles

    CopyStyleFrom( pSrcPool, ScResId(STR_STYLENAME_STANDARD),     SfxStyleFamily::Para );
    CopyStyleFrom( pSrcPool, ScResId(STR_STYLENAME_STANDARD),     SfxStyleFamily::Frame );
    CopyStyleFrom( pSrcPool, ScResId(STR_STYLENAME_STANDARD),     SfxStyleFamily::Page );
    CopyStyleFrom( pSrcPool, ScResId(STR_STYLENAME_REPORT),       SfxStyleFamily::Page );
}
diff --git a/sc/source/ui/app/drwtrans.cxx b/sc/source/ui/app/drwtrans.cxx
index 569fd6e..8dae3e5 100644
--- a/sc/source/ui/app/drwtrans.cxx
+++ b/sc/source/ui/app/drwtrans.cxx
@@ -54,6 +54,9 @@
#include <viewdata.hxx>
#include <scmod.hxx>
#include <dragdata.hxx>
#include <stlpool.hxx>
#include <scresid.hxx>
#include <globstr.hrc>

#include <editeng/eeitem.hxx>

@@ -358,7 +361,11 @@ bool ScDrawTransferObj::GetData( const css::datatransfer::DataFlavor& rFlavor, c
        }
        else if ( nFormat == SotClipboardFormatId::DRAWING )
        {
            bOK = SetObject( m_pModel.get(), SCDRAWTRANS_TYPE_DRAWMODEL, rFlavor );
            SdrView aView(*m_pModel);
            SdrPageView* pPv = aView.ShowSdrPage(aView.GetModel().GetPage(0));
            aView.MarkAllObj( pPv );
            auto pNewModel = aView.CreateMarkedObjModel();
            bOK = SetObject( pNewModel.get(), SCDRAWTRANS_TYPE_DRAWMODEL, rFlavor );
        }
        else if ( nFormat == SotClipboardFormatId::BITMAP
            || nFormat == SotClipboardFormatId::PNG
@@ -429,19 +436,20 @@ bool ScDrawTransferObj::WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* 
        case SCDRAWTRANS_TYPE_DRAWMODEL:
            {
                SdrModel* pDrawModel = static_cast<SdrModel*>(pUserObject);
                pDrawModel->BurnInStyleSheetAttributes();
                rxOStm->SetBufferSize( 0xff00 );

                // for the changed pool defaults from drawing layer pool set those
                // attributes as hard attributes to preserve them for saving
                const SfxItemPool& rItemPool = m_pModel->GetItemPool();
                const SfxItemPool& rItemPool = pDrawModel->GetItemPool();
                const SvxFontHeightItem& rDefaultFontHeight = rItemPool.GetDefaultItem(EE_CHAR_FONTHEIGHT);

                // SW should have no MasterPages
                OSL_ENSURE(0 == m_pModel->GetMasterPageCount(), "SW with MasterPages (!)");
                OSL_ENSURE(0 == pDrawModel->GetMasterPageCount(), "SW with MasterPages (!)");

                for(sal_uInt16 a(0); a < m_pModel->GetPageCount(); a++)
                for(sal_uInt16 a(0); a < pDrawModel->GetPageCount(); a++)
                {
                    const SdrPage* pPage(m_pModel->GetPage(a));
                    const SdrPage* pPage(pDrawModel->GetPage(a));
                    SdrObjListIter aIter(pPage, SdrIterMode::DeepNoGroups);

                    while(aIter.IsMore())
@@ -677,6 +685,10 @@ void ScDrawTransferObj::InitDocShell()
    ScDocument& rDestDoc = pDocSh->GetDocument();
    rDestDoc.InitDrawLayer( pDocSh );

    auto pPool = rDestDoc.GetStyleSheetPool();
    pPool->CopyStyleFrom(m_pModel->GetStyleSheetPool(), ScResId(STR_STYLENAME_STANDARD), SfxStyleFamily::Frame);
    pPool->CopyUsedGraphicStylesFrom(m_pModel->GetStyleSheetPool());

    SdrModel* pDestModel = rDestDoc.GetDrawLayer();
    // #i71538# use complete SdrViews
    // SdrExchangeView aDestView( pDestModel );
diff --git a/sc/source/ui/app/transobj.cxx b/sc/source/ui/app/transobj.cxx
index d0fbd02..138b078 100644
--- a/sc/source/ui/app/transobj.cxx
+++ b/sc/source/ui/app/transobj.cxx
@@ -677,6 +677,9 @@ void ScTransferObj::InitDocShell(bool bLimitToPageSize)
    m_pDoc->GetName( m_aBlock.aStart.Tab(), aTabName );
    rDestDoc.RenameTab( 0, aTabName );

    if (m_pDoc->GetDrawLayer() || m_pDoc->HasNotes())
        pDocSh->MakeDrawLayer();

    rDestDoc.CopyStdStylesFrom(*m_pDoc);

    SCCOL nStartX = m_aBlock.aStart.Col();
@@ -716,9 +719,6 @@ void ScTransferObj::InitDocShell(bool bLimitToPageSize)
        }
    }

    if (m_pDoc->GetDrawLayer() || m_pDoc->HasNotes())
        pDocSh->MakeDrawLayer();

    //  cell range is copied to the original position, but on the first sheet
    //  -> bCutMode must be set
    //  pDoc is always a Clipboard-document
diff --git a/sc/source/ui/view/viewfun5.cxx b/sc/source/ui/view/viewfun5.cxx
index d1a6e59..f57eca0 100644
--- a/sc/source/ui/view/viewfun5.cxx
+++ b/sc/source/ui/view/viewfun5.cxx
@@ -565,18 +565,15 @@ bool ScViewFunc::PasteDataFormat( SotClipboardFormatId nFormatId,
            MakeDrawLayer();    // before loading model, so 3D factory has been created

            ScDocShellRef aDragShellRef( new ScDocShell );
            aDragShellRef->MakeDrawLayer();
            aDragShellRef->DoInitNew();

            std::unique_ptr<FmFormModel> pModel(
                new FmFormModel(
                    nullptr,
                    aDragShellRef.get()));
            ScDrawLayer* pModel = aDragShellRef->GetDocument().GetDrawLayer();

            pModel->GetItemPool().FreezeIdRanges();
            xStm->Seek(0);

            css::uno::Reference< css::io::XInputStream > xInputStream( new utl::OInputStreamWrapper( *xStm ) );
            SvxDrawingLayerImport( pModel.get(), xInputStream );
            SvxDrawingLayerImport( pModel, xInputStream );

            // set everything to right layer:
            size_t nObjCount = 0;
@@ -598,8 +595,7 @@ bool ScViewFunc::PasteDataFormat( SotClipboardFormatId nFormatId,
                nObjCount += pPage->GetObjCount();          // count group object only once
            }

            PasteDraw(aPos, pModel.get(), (nObjCount > 1), u"A", u"B");     // grouped if more than 1 object
            pModel.reset();
            PasteDraw(aPos, pModel, (nObjCount > 1), u"A", u"B");     // grouped if more than 1 object
            aDragShellRef->DoClose();
            bRet = true;
        }
diff --git a/sc/source/ui/view/viewfun7.cxx b/sc/source/ui/view/viewfun7.cxx
index 76ede14..f704256 100644
--- a/sc/source/ui/view/viewfun7.cxx
+++ b/sc/source/ui/view/viewfun7.cxx
@@ -47,6 +47,7 @@
#include <docsh.hxx>
#include <dragdata.hxx>
#include <gridwin.hxx>
#include <stlpool.hxx>

bool bPasteIsMove = false;

@@ -213,10 +214,15 @@ void ScViewFunc::PasteDraw( const Point& rLogicPos, SdrModel* pModel,
            ScChartHelper::GetChartNames( aExcludedChartNames, pPage );
        }

        // #89247# Set flag for ScDocument::UpdateChartListeners() which is
        // called during paste.
        if ( !bSameDocClipboard )
        {
            auto pPool = static_cast<ScStyleSheetPool*>(pScDrawView->GetModel().GetStyleSheetPool());
            pPool->CopyUsedGraphicStylesFrom(pModel->GetStyleSheetPool());

            // #89247# Set flag for ScDocument::UpdateChartListeners() which is
            // called during paste.
            GetViewData().GetDocument().SetPastingDrawFromOtherDoc( true );
        }

        pScDrawView->Paste(*pModel, aPos, nullptr, nOptions);

diff --git a/svx/source/sdr/properties/attributeproperties.cxx b/svx/source/sdr/properties/attributeproperties.cxx
index 7f141b8..d4a0017 100644
--- a/svx/source/sdr/properties/attributeproperties.cxx
+++ b/svx/source/sdr/properties/attributeproperties.cxx
@@ -195,7 +195,7 @@ namespace sdr::properties
                        pTargetStyleSheet = dynamic_cast< SfxStyleSheet* >(
                            pTargetStyleSheetPool->Find(
                                rProps.GetStyleSheet()->GetName(),
                                SfxStyleFamily::All));
                                rProps.GetStyleSheet()->GetFamily()));
                    }
                }
            }