tdf#125191 Give object copies unique names

This patch makes a unique name for a copy of an object having
a user given name.

Change-Id: I14a7f45cc02962fc34a1532dd5db1cb9657b41d3
Reviewed-on: https://gerrit.libreoffice.org/77500
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/include/svx/svdmodel.hxx b/include/svx/svdmodel.hxx
index d5c14c0..8153e4f 100644
--- a/include/svx/svdmodel.hxx
+++ b/include/svx/svdmodel.hxx
@@ -260,6 +260,9 @@ private:
    // this is a weak reference to a possible living api wrapper for this model
    css::uno::Reference< css::uno::XInterface > mxUnoModel;

    // used to disable unique name checking during page move
    bool mbMakePageObjectsNamesUnique = true;

public:
    SVX_DLLPRIVATE virtual bool IsCreatingDataObj() const { return false; }
    bool     IsTransportContainer() const { return bTransportContainer; }
@@ -597,6 +600,10 @@ public:
        also during the runtime of the Undo() and Redo() methods. */
    bool IsUndoEnabled() const;

    // used to prevent object name change during page move
    bool DoesMakePageObjectsNamesUnique() const { return mbMakePageObjectsNamesUnique; }
    void DoMakePageObjectsNamesUnique(bool bDo) { mbMakePageObjectsNamesUnique = bDo; }

    virtual void dumpAsXml(xmlTextWriterPtr pWriter) const;
};

diff --git a/include/svx/svdobj.hxx b/include/svx/svdobj.hxx
index 97f0825..3d0699b 100644
--- a/include/svx/svdobj.hxx
+++ b/include/svx/svdobj.hxx
@@ -38,6 +38,8 @@
#include <osl/diagnose.h>
#include <typeinfo>

#include <unordered_set>

class SfxBroadcaster;
class AutoTimer;
class OutlinerParaObject;
@@ -425,6 +427,7 @@ public:
    // It may also have a Title and a Description for accessibility purposes.
    void SetName(const OUString& rStr);
    OUString GetName() const;
    void MakeNameUnique(std::unordered_set<OUString>& rNameSet);
    void SetTitle(const OUString& rStr);
    OUString GetTitle() const;
    void SetDescription(const OUString& rStr);
diff --git a/include/svx/svdpage.hxx b/include/svx/svdpage.hxx
index 60cf0bb..cdeb74d 100644
--- a/include/svx/svdpage.hxx
+++ b/include/svx/svdpage.hxx
@@ -110,6 +110,9 @@ public:
    virtual void   InsertObject(SdrObject* pObj, size_t nPos=SAL_MAX_SIZE);
    virtual void sort( std::vector<sal_Int32>& sortOrder );

    void InsertObjectThenMakeNameUnique(SdrObject* pObj);
    void InsertObjectThenMakeNameUnique(SdrObject* pObj, std::unordered_set<rtl::OUString>& rNameSet, size_t nPos=SAL_MAX_SIZE);

    /// remove from list without delete
    virtual SdrObject* NbcRemoveObject(size_t nObjNum);
    virtual SdrObject* RemoveObject(size_t nObjNum);
@@ -487,6 +490,8 @@ public:
    void TRG_SetMasterPageVisibleLayers(const SdrLayerIDSet& rNew);
    sdr::contact::ViewContact& TRG_GetMasterPageDescriptorViewContact() const;

    void MakePageObjectsNamesUnique();

protected:
    void TRG_ImpMasterPageRemoved(const SdrPage& rRemovedPage);
public:
diff --git a/sd/source/ui/slidesorter/controller/SlsClipboard.cxx b/sd/source/ui/slidesorter/controller/SlsClipboard.cxx
index 95a38e0..38fcbd9 100644
--- a/sd/source/ui/slidesorter/controller/SlsClipboard.cxx
+++ b/sd/source/ui/slidesorter/controller/SlsClipboard.cxx
@@ -730,7 +730,17 @@ sal_Int8 Clipboard::ExecuteDrop (
                    mrSlideSorter.GetViewShell()->GetViewShellBase().GetMainViewShell()));
                mxSelectionObserverContext.reset(new SelectionObserver::Context(mrSlideSorter));

                HandlePageDrop(*pDragTransferable);
                if (rEvent.mnAction == DND_ACTION_MOVE)
                {
                    SdDrawDocument* pDoc = mrSlideSorter.GetModel().GetDocument();
                    const bool bDoesMakePageObjectsNamesUnique = pDoc->DoesMakePageObjectsNamesUnique();
                    pDoc->DoMakePageObjectsNamesUnique(false);
                    HandlePageDrop(*pDragTransferable);
                    pDoc->DoMakePageObjectsNamesUnique(bDoesMakePageObjectsNamesUnique);
                }
                else
                    HandlePageDrop(*pDragTransferable);

                nResult = rEvent.mnAction;

                // We leave the undo context alive for when moving or
diff --git a/sd/source/ui/view/sdview3.cxx b/sd/source/ui/view/sdview3.cxx
index e45441d1..6b750c9 100644
--- a/sd/source/ui/view/sdview3.cxx
+++ b/sd/source/ui/view/sdview3.cxx
@@ -463,6 +463,7 @@ bool View::InsertData( const TransferableDataHelper& rDataHelper,

                                const Size aVector( maDropPos.X() - aCurPos.X(), maDropPos.Y() - aCurPos.Y() );

                                std::unordered_set<rtl::OUString> aNameSet;
                                for(size_t a = 0; a < pMarkList->GetMarkCount(); ++a)
                                {
                                    SdrMark* pM = pMarkList->GetMark(a);
@@ -476,7 +477,11 @@ bool View::InsertData( const TransferableDataHelper& rDataHelper,
                                            pObj->NbcMove(aVector);
                                        }

                                        pPage->InsertObject(pObj);
                                        SdrObject* pMarkParent = pM->GetMarkedSdrObj()->getParentSdrObjectFromSdrObject();
                                        if (bCopy || (pMarkParent && pMarkParent->IsGroupObject()))
                                            pPage->InsertObjectThenMakeNameUnique(pObj, aNameSet);
                                        else
                                            pPage->InsertObject(pObj);

                                        if( IsUndoEnabled() )
                                        {
diff --git a/svx/source/svdraw/svdedtv.cxx b/svx/source/svdraw/svdedtv.cxx
index d83910a..6dfb249 100644
--- a/svx/source/svdraw/svdedtv.cxx
+++ b/svx/source/svdraw/svdedtv.cxx
@@ -903,13 +903,14 @@ void SdrEditView::CopyMarkedObj()

    GetMarkedObjectListWriteAccess().Clear();
    size_t nCloneErrCnt=0;
    std::unordered_set<rtl::OUString> aNameSet;
    const size_t nMarkCount=aSourceObjectsForCopy.GetMarkCount();
    for (size_t nm=0; nm<nMarkCount; ++nm) {
        SdrMark* pM=aSourceObjectsForCopy.GetMark(nm);
        SdrObject* pSource(pM->GetMarkedSdrObj());
        SdrObject* pO(pSource->CloneSdrObject(pSource->getSdrModelFromSdrObject()));
        if (pO!=nullptr) {
            pM->GetPageView()->GetObjList()->InsertObject(pO, SAL_MAX_SIZE);
            pM->GetPageView()->GetObjList()->InsertObjectThenMakeNameUnique(pO, aNameSet);

            if( bUndo )
                AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoCopyObject(*pO));
diff --git a/svx/source/svdraw/svdmodel.cxx b/svx/source/svdraw/svdmodel.cxx
index eec87abc..e49833f 100644
--- a/svx/source/svdraw/svdmodel.cxx
+++ b/svx/source/svdraw/svdmodel.cxx
@@ -1309,6 +1309,9 @@ void SdrModel::InsertPage(SdrPage* pPage, sal_uInt16 nPos)
    pPage->SetInserted();
    pPage->SetPageNum(nPos);

    if (mbMakePageObjectsNamesUnique)
        pPage->MakePageObjectsNamesUnique();

    if (nPos<nCount) bPagNumsDirty=true;
    SetChanged();
    SdrHint aHint(SdrHintKind::PageOrderChange, pPage);
diff --git a/svx/source/svdraw/svdobj.cxx b/svx/source/svdraw/svdobj.cxx
index 7b3d0ba..eaa5abf 100644
--- a/svx/source/svdraw/svdobj.cxx
+++ b/svx/source/svdraw/svdobj.cxx
@@ -136,6 +136,8 @@
#include <svdobjplusdata.hxx>
#include <svdobjuserdatalist.hxx>

#include <unordered_set>

#include <boost/optional.hpp>
#include <libxml/xmlwriter.h>
#include <memory>
@@ -3016,6 +3018,44 @@ bool SdrObject::IsTextBox() const
    return false;
}

void SdrObject::MakeNameUnique(std::unordered_set<OUString>& rNameSet)
{
    if (GetName().isEmpty())
        return;

    if (rNameSet.empty())
    {
        SdrPage* pPage;
        SdrObject* pObj;
        for (sal_uInt16 nPage(0); nPage < mrSdrModelFromSdrObject.GetPageCount(); ++nPage)
        {
            pPage = mrSdrModelFromSdrObject.GetPage(nPage);
            SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups);
            while (aIter.IsMore())
            {
                pObj = aIter.Next();
                if (pObj != this)
                    rNameSet.insert(pObj->GetName());
            }
        }
    }

    OUString sName(GetName());
    OUString sRootName(GetName());
    sal_Int32 index = sName.lastIndexOf("_");
    if ( index > 0)
        sRootName = sRootName.copy(0, index);

    sal_uInt32 n = 0;
    while (rNameSet.find(sName) != rNameSet.end())
    {
        sName = sRootName + "_" + OUString::number(n++);
    }
    rNameSet.insert(sName);

    SetName(sName);
}

SdrObject* SdrObjFactory::CreateObjectFromFactory(SdrModel& rSdrModel, SdrInventor nInventor, sal_uInt16 nObjIdentifier)
{
    SdrObjCreatorParams aParams { nInventor, nObjIdentifier, rSdrModel };
diff --git a/svx/source/svdraw/svdpage.cxx b/svx/source/svdraw/svdpage.cxx
index 8794c23..a6cef06 100644
--- a/svx/source/svdraw/svdpage.cxx
+++ b/svx/source/svdraw/svdpage.cxx
@@ -19,6 +19,7 @@

#include <memory>
#include <cassert>
#include <unordered_set>

#include <svx/svdpage.hxx>

@@ -328,6 +329,32 @@ void SdrObjList::NbcInsertObject(SdrObject* pObj, size_t nPos)
    pObj->InsertedStateChange(); // calls the UserCall (among others)
}

void SdrObjList::InsertObjectThenMakeNameUnique(SdrObject* pObj)
{
    std::unordered_set<rtl::OUString> aNameSet;
    InsertObjectThenMakeNameUnique(pObj, aNameSet);
}

void SdrObjList::InsertObjectThenMakeNameUnique(SdrObject* pObj, std::unordered_set<OUString>& rNameSet, size_t nPos)
{
    InsertObject(pObj, nPos);
    if (!pObj->GetName().isEmpty())
    {
        pObj->MakeNameUnique(rNameSet);
        SdrObjList* pSdrObjList = pObj->GetSubList(); // group
        if (pSdrObjList)
        {
            SdrObject* pListObj;
            SdrObjListIter aIter(pSdrObjList, SdrIterMode::DeepWithGroups);
            while (aIter.IsMore())
            {
                pListObj = aIter.Next();
                pListObj->MakeNameUnique(rNameSet);
            }
        }
    }
}

void SdrObjList::InsertObject(SdrObject* pObj, size_t nPos)
{
    DBG_ASSERT(pObj!=nullptr,"SdrObjList::InsertObject(NULL)");
@@ -1573,6 +1600,33 @@ void SdrPage::TRG_ImpMasterPageRemoved(const SdrPage& rRemovedPage)
    }
}

void SdrPage::MakePageObjectsNamesUnique()
{
    std::unordered_set<OUString> aNameSet;
    for (size_t no(0); no < GetObjCount(); ++no)
    {
        SdrObject* pObj(GetObj(no));
        if(nullptr != pObj)
        {
            if (!pObj->GetName().isEmpty())
            {
                pObj->MakeNameUnique(aNameSet);
                SdrObjList* pSdrObjList = pObj->GetSubList(); // group
                if (pSdrObjList)
                {
                    SdrObject* pListObj;
                    SdrObjListIter aIter(pSdrObjList, SdrIterMode::DeepWithGroups);
                    while (aIter.IsMore())
                    {
                        pListObj = aIter.Next();
                        pListObj->MakeNameUnique(aNameSet);
                    }
                }
            }
        }
    }
}

const SdrPageGridFrameList* SdrPage::GetGridFrameList(const SdrPageView* /*pPV*/, const tools::Rectangle* /*pRect*/) const
{
    return nullptr;
diff --git a/svx/source/svdraw/svdxcgv.cxx b/svx/source/svdraw/svdxcgv.cxx
index a65d38c..f18d536 100644
--- a/svx/source/svdraw/svdxcgv.cxx
+++ b/svx/source/svdraw/svdxcgv.cxx
@@ -18,6 +18,7 @@
 */

#include <vector>
#include <unordered_set>
#include <editeng/editdata.hxx>
#include <editeng/editeng.hxx>
#include <rtl/strbuf.hxx>
@@ -301,7 +302,7 @@ bool SdrExchangeView::Paste(
        // #i13033#
        // New mechanism to re-create the connections of cloned connectors
        CloneList aCloneList;

        std::unordered_set<rtl::OUString> aNameSet;
        for (size_t nOb=0; nOb<nObjCount; ++nOb)
        {
            const SdrObject* pSrcOb=pSrcPg->GetObj(nOb);
@@ -346,7 +347,7 @@ bool SdrExchangeView::Paste(
                    pNewObj->SetLayer(nLayer);
                }

                pDstLst->InsertObject(pNewObj, SAL_MAX_SIZE);
                pDstLst->InsertObjectThenMakeNameUnique(pNewObj, aNameSet);

                if( bUndo )
                    AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pNewObj));
diff --git a/sw/source/core/doc/doclay.cxx b/sw/source/core/doc/doclay.cxx
index 5f6e9c6..2ab4759 100644
--- a/sw/source/core/doc/doclay.cxx
+++ b/sw/source/core/doc/doclay.cxx
@@ -142,12 +142,12 @@ SdrObject* SwDoc::CloneSdrObj( const SdrObject& rObj, bool bMoveWithinDoc,
        if( xSet.is() )
            aVal = xSet->getPropertyValue( sName );
        if( bInsInPage )
            pPg->InsertObject( pObj );
            pPg->InsertObjectThenMakeNameUnique( pObj );
        if( xSet.is() )
            xSet->setPropertyValue( sName, aVal );
    }
    else if( bInsInPage )
        pPg->InsertObject( pObj );
        pPg->InsertObjectThenMakeNameUnique( pObj );

    // For drawing objects: set layer of cloned object to invisible layer
    SdrLayerID nLayerIdForClone = rObj.GetLayer();