sc/inc/drwlayer.hxx                                   |    5 
 sc/qa/unit/data/ods/tdf139083_copy_without_resize.ods |binary
 sc/qa/unit/data/ods/tdf155093_double_names.ods        |binary
 sc/qa/unit/scshapetest.cxx                            |   47 +
 sc/source/core/data/document.cxx                      |   23 
 sc/source/core/data/drwlayer.cxx                      |  444 ++++++++++++------
 sc/source/core/data/table7.cxx                        |    8 
 7 files changed, 378 insertions(+), 149 deletions(-)

New commits:
commit dfb0d118f6b23730bc632885eb4703a37eeaec16
Author:     Regina Henschel <rb.hensc...@t-online.de>
AuthorDate: Sat Apr 8 18:38:04 2023 +0200
Commit:     Regina Henschel <rb.hensc...@t-online.de>
CommitDate: Sun May 7 10:57:04 2023 +0200

    tdf#139083 Only resize if 'resize with cell' is set
    
    The copy&paste of ranges with shapes had the following further bugs:
    * For cell anchored shapes the position was taken from the source
    rectangle instead of the anchor.
    * Resizing was calculated from source and destination rectangle, but
    should only depend on size of object range.
    * tdf#125938 Shapes were moved without adapting the anchor.
    * tdf#155091 Source with filtered rows produced doubled objects in
    paste.
    * The CopyToClip method has a useless NbcMove(size(0,0)). NbcMove
    is a move 'by', not a move 'to'.
    * tdf#155093 Pasted object has same name as source object and thus
    is not accessible via Navigator.
    * tdf#155094 Transposed pasted objects have wrong position
    * tdf#155095 Objects over collapsed group are incorrectly resized
    * tdf#141437, tdf#141436 transposed objects have wrong size
    
    Only objects, which can really resize, are now resized. In case of
    transposing no objects are resized. Transposing would need to
    transpose the object geometry, but that is missing.
    The offset inside the start anchor cell is adapted to the size of
    the destination cell to keep the anchor in this cell.
    Object resizing considers that filtered rows are removed whereas
    collapsed or hidden rows are shown in pasted area.
    Object resizing does no longer use global factors but calculate the
    desired snap rectangle and fits the object into it.
    
    Change-Id: I42924b28a2d652d8b70cb8e1a1d7ca4324b09cf6
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150161
    Tested-by: Jenkins
    Reviewed-by: Regina Henschel <rb.hensc...@t-online.de>

diff --git a/sc/inc/drwlayer.hxx b/sc/inc/drwlayer.hxx
index c127f597bab2..eea0b118b521 100644
--- a/sc/inc/drwlayer.hxx
+++ b/sc/inc/drwlayer.hxx
@@ -156,8 +156,9 @@ public:
 
     void            CopyToClip( ScDocument* pClipDoc, SCTAB nTab, const 
tools::Rectangle& rRange );
     void            CopyFromClip( ScDrawLayer* pClipModel,
-                                    SCTAB nSourceTab, const tools::Rectangle& 
rSourceRange,
-                                    const ScAddress& rDestPos, const 
tools::Rectangle& rDestRange );
+                                    SCTAB nSourceTab, const ScRange& 
rSourceRange,
+                                    const ScAddress& rDestPos, const ScRange& 
rDestRange,
+                                    bool bTransposing = false);
 
     void            SetPageSize(sal_uInt16 nPageNo, const Size& rSize, bool 
bUpdateNoteCaptionPos,
                                 const ScObjectHandling eObjectHandling = 
ScObjectHandling::RecalcPosMode);
diff --git a/sc/qa/unit/data/ods/tdf139083_copy_without_resize.ods 
b/sc/qa/unit/data/ods/tdf139083_copy_without_resize.ods
new file mode 100644
index 000000000000..ea3b8908ede2
Binary files /dev/null and 
b/sc/qa/unit/data/ods/tdf139083_copy_without_resize.ods differ
diff --git a/sc/qa/unit/data/ods/tdf155093_double_names.ods 
b/sc/qa/unit/data/ods/tdf155093_double_names.ods
new file mode 100644
index 000000000000..6dd7a69554c4
Binary files /dev/null and b/sc/qa/unit/data/ods/tdf155093_double_names.ods 
differ
diff --git a/sc/qa/unit/scshapetest.cxx b/sc/qa/unit/scshapetest.cxx
index 814384effe83..6f9a39c8eafa 100644
--- a/sc/qa/unit/scshapetest.cxx
+++ b/sc/qa/unit/scshapetest.cxx
@@ -999,6 +999,53 @@ CPPUNIT_TEST_FIXTURE(ScShapeTest, testLargeAnchorOffset)
     CPPUNIT_ASSERT_POINT_EQUAL_WITH_TOLERANCE(aOldPos, aNewPos, 1);
 }
 
+CPPUNIT_TEST_FIXTURE(ScShapeTest, testTdf139083_copy_without_resize)
+{
+    // Load a document, which has a shape anchored to cell B2, but without 
'resize with cell'.
+    // When the range B2:B3 is copied and pasted to D5, then the copied shape 
should keep its size.
+    createScDoc("ods/tdf139083_copy_without_resize.ods");
+
+    // Get document
+    ScDocument* pDoc = getScDoc();
+
+    // Copy cells B2:B3. They have row height 2cm and column width 3cm.
+    goToCell("$B$2:$B$3");
+    dispatchCommand(mxComponent, ".uno:Copy", {});
+
+    // Paste to D5. There are row height 0.5cm and column width 1cm.
+    goToCell("$D$5");
+    dispatchCommand(mxComponent, ".uno:Paste", {});
+
+    // Make sure original and pasted shape have the same size.
+    // Size of original shape is 2001x3002, without fix size of pasted shape 
was 668x750.
+    SdrObject* pObjOrig = lcl_getSdrObjectWithAssert(*pDoc, 0); // original 
shape
+    SdrObject* pObjPasted = lcl_getSdrObjectWithAssert(*pDoc, 1); // pasted 
shape
+    CPPUNIT_ASSERT_DOUBLES_EQUAL(2001, pObjOrig->GetSnapRect().GetWidth(), 1);
+    CPPUNIT_ASSERT_DOUBLES_EQUAL(3002, pObjOrig->GetSnapRect().GetHeight(), 1);
+    CPPUNIT_ASSERT_DOUBLES_EQUAL(2001, pObjPasted->GetSnapRect().GetWidth(), 
1);
+    CPPUNIT_ASSERT_DOUBLES_EQUAL(3002, pObjPasted->GetSnapRect().GetHeight(), 
1);
+}
+
+CPPUNIT_TEST_FIXTURE(ScShapeTest, testTdf155093_double_names)
+{
+    // Load a document, which has a shape in range B6:C14 with name "myArrow". 
When the range was
+    // copied and pasted, then the copied shape got the same name and thus was 
not accessible with
+    // Navigator.
+    createScDoc("ods/tdf155093_double_names.ods");
+    ScDocument* pDoc = getScDoc();
+
+    // Copy and paste
+    goToCell("$B$6:$C$14");
+    dispatchCommand(mxComponent, ".uno:Copy", {});
+    goToCell("$D$16");
+    dispatchCommand(mxComponent, ".uno:Paste", {});
+
+    // Make sure original and pasted shape have different names.
+    SdrObject* pObjOrig = lcl_getSdrObjectWithAssert(*pDoc, 0); // original 
shape
+    SdrObject* pObjPasted = lcl_getSdrObjectWithAssert(*pDoc, 1); // pasted 
shape
+    CPPUNIT_ASSERT(pObjOrig->GetName() != pObjPasted->GetName());
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index fdf300a6e229..b39dcc8756cb 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -2409,13 +2409,14 @@ void ScDocument::TransposeClip(ScDocument* pTransClip, 
InsertDeleteFlags nFlags,
                     //  (mpDrawLayer in the original clipboard document is set 
only if there
                     //  are drawing objects to copy)
 
+                    // ToDo: Loop over blocks of non-filtered rows in case of 
filtered rows exist.
                     pTransClip->InitDrawLayer();
-                    tools::Rectangle aSourceRect = GetMMRect( 
aClipRange.aStart.Col(), aClipRange.aStart.Row(),
-                                                        aClipRange.aEnd.Col(), 
aClipRange.aEnd.Row(), i );
-                    tools::Rectangle aDestRect = pTransClip->GetMMRect( 0, 0,
-                            static_cast<SCCOL>(aClipRange.aEnd.Row() - 
aClipRange.aStart.Row()),
-                            static_cast<SCROW>(aClipRange.aEnd.Col() - 
aClipRange.aStart.Col()), i );
-                    pTransClip->mpDrawLayer->CopyFromClip( mpDrawLayer.get(), 
i, aSourceRect, ScAddress(0,0,i), aDestRect );
+                    ScAddress aTransposedEnd(
+                        static_cast<SCCOL>(aClipRange.aEnd.Row() - 
aClipRange.aStart.Row() + aClipRange.aStart.Col()),
+                        static_cast<SCROW>(aClipRange.aEnd.Col() - 
aClipRange.aStart.Col() + aClipRange.aStart.Row()), i);
+                    ScRange aDestRange(aClipRange.aStart, aTransposedEnd);
+                    ScAddress aDestStart = aClipRange.aStart;
+                    pTransClip->mpDrawLayer->CopyFromClip(mpDrawLayer.get(), 
i, aClipRange, aDestStart, aDestRange, true);
                 }
             }
         }
@@ -2690,12 +2691,10 @@ void ScDocument::CopyBlockFromClip(
                     //  For GetMMRect, the row heights in the target document 
must already be valid
                     //  (copied in an extra step before pasting, or updated 
after pasting cells, but
                     //  before pasting objects).
-
-                    tools::Rectangle aSourceRect = 
rCxt.getClipDoc()->GetMMRect(
-                                    nCol1-nDx, nRow1-nDy, nCol2-nDx, 
nRow2-nDy, nClipTab );
-                    tools::Rectangle aDestRect = GetMMRect( nCol1, nRow1, 
nCol2, nRow2, i );
-                    
mpDrawLayer->CopyFromClip(rCxt.getClipDoc()->mpDrawLayer.get(), nClipTab, 
aSourceRect,
-                                                ScAddress( nCol1, nRow1, i ), 
aDestRect );
+                    ScRange aSourceRange(nCol1 - nDx, nRow1 - nDy, nClipTab, 
nCol2 - nDx, nRow2 - nDy, nClipTab);
+                    ScRange aDestRange(nCol1, nRow1, i, nCol2, nRow2, i);
+                    
mpDrawLayer->CopyFromClip(rCxt.getClipDoc()->mpDrawLayer.get(), nClipTab, 
aSourceRange,
+                                                ScAddress( nCol1, nRow1, i ), 
aDestRange);
                 }
             }
 
diff --git a/sc/source/core/data/drwlayer.cxx b/sc/source/core/data/drwlayer.cxx
index 8191dfcede66..134c7258ed4a 100644
--- a/sc/source/core/data/drwlayer.cxx
+++ b/sc/source/core/data/drwlayer.cxx
@@ -87,6 +87,7 @@
 #include <docpool.hxx>
 #include <detfunc.hxx>
 #include <basegfx/matrix/b2dhommatrix.hxx>
+#include <clipparam.hxx>
 
 #include <memory>
 #include <algorithm>
@@ -1785,19 +1786,18 @@ void ScDrawLayer::CopyToClip( ScDocument* pClipDoc, 
SCTAB nTab, const tools::Rec
     ScDrawLayer* pDestModel = nullptr;
     SdrPage* pDestPage = nullptr;
 
+    ScRange aClipRange = lcl_getClipRangeFromClipDoc(pClipDoc, nTab);
+
     SdrObjListIter aIter( pSrcPage, SdrIterMode::Flat );
     SdrObject* pOldObject = aIter.Next();
     while (pOldObject)
     {
-        tools::Rectangle aObjRect = pOldObject->GetCurrentBoundRect();
-
-        bool bObjectInArea = rRange.Contains(aObjRect);
+        // Catch objects where the object itself is inside the rectangle to be 
copied.
+        bool bObjectInArea = 
rRange.Contains(pOldObject->GetCurrentBoundRect());
+        // Catch objects whose anchor is inside the rectangle to be copied.
         const ScDrawObjData* pObjData = ScDrawLayer::GetObjData(pOldObject);
         if (pObjData)
-        {
-            ScRange aClipRange = lcl_getClipRangeFromClipDoc(pClipDoc, nTab);
             bObjectInArea = bObjectInArea || 
aClipRange.Contains(pObjData->maStart);
-        }
 
         // do not copy internal objects (detective) and note captions
         if (bObjectInArea && pOldObject->GetLayer() != SC_LAYER_INTERN
@@ -1822,10 +1822,35 @@ void ScDrawLayer::CopyToClip( ScDocument* pClipDoc, 
SCTAB nTab, const tools::Rec
             {
                 // Clone to target SdrModel
                 rtl::Reference<SdrObject> 
pNewObject(pOldObject->CloneSdrObject(*pDestModel));
-
                 uno::Reference< chart2::XChartDocument > xOldChart( 
ScChartHelper::GetChartFromSdrObject( pOldObject ) );
                 if(!xOldChart.is())//#i110034# do not move charts as they lose 
all their data references otherwise
-                    pNewObject->NbcMove(Size(0,0));
+                {
+                    if (pObjData)
+                    {
+                        // The object is anchored to cell. The position is 
determined by the start
+                        // address. Copying into the clipboard does not change 
the anchor.
+                        // ToDo: Adapt Offset relative to anchor cell size for 
cell anchored.
+                        // ToDo: Adapt Offset and size for cell-anchored with 
resize objects.
+                        // ToDo: Exclude object from resize if disallowed at 
object.
+                    }
+                    else
+                    {
+                        // The object is anchored to page. We make its 
position so, that the
+                        // cell behind the object will have the same address 
in clipboard document as
+                        // in source document. So we will be able to 
reconstruct the original cell
+                        // address from position when pasting the object.
+                        tools::Rectangle aObjRect = pOldObject->GetSnapRect();
+                        ScRange aPseudoAnchor
+                            = pDoc->GetRange(nTab, aObjRect, true 
/*bHiddenAsZero*/);
+                        tools::Rectangle aSourceCellRect
+                            = GetCellRect(*pDoc, aPseudoAnchor.aStart, false 
/*bMergedCell*/);
+                        tools::Rectangle aDestCellRect
+                            = GetCellRect(*pClipDoc, aPseudoAnchor.aStart, 
false);
+                        Point aMove = aDestCellRect.TopLeft() - 
aSourceCellRect.TopLeft();
+                        pNewObject->NbcMove(Size(aMove.getX(), aMove.getY()));
+                    }
+                }
+
                 pDestPage->InsertObject( pNewObject.get() );
 
                 //  no undo needed in clipboard document
@@ -1884,8 +1909,9 @@ static bool lcl_MoveRanges( ::std::vector< ScRangeList >& 
rRangesVector, const S
     return bChanged;
 }
 
-void ScDrawLayer::CopyFromClip( ScDrawLayer* pClipModel, SCTAB nSourceTab, 
const tools::Rectangle& rSourceRange,
-                                    const ScAddress& rDestPos, const 
tools::Rectangle& rDestRange )
+void ScDrawLayer::CopyFromClip(ScDrawLayer* pClipModel, SCTAB nSourceTab,
+                               const ScRange& rSourceRange, const ScAddress& 
rDestPos,
+                               const ScRange& rDestRange, bool bTransposing)
 {
     OSL_ENSURE( pDoc, "ScDrawLayer::CopyFromClip without document" );
     if ( !pDoc )
@@ -1900,14 +1926,6 @@ void ScDrawLayer::CopyFromClip( ScDrawLayer* pClipModel, 
SCTAB nSourceTab, const
         return;
     }
 
-    bool bMirrorObj = ( rSourceRange.Left() < 0 && rSourceRange.Right() < 0 &&
-                        rDestRange.Left()   > 0 && rDestRange.Right()   > 0 ) 
||
-                      ( rSourceRange.Left() > 0 && rSourceRange.Right() > 0 &&
-                        rDestRange.Left()   < 0 && rDestRange.Right()   < 0 );
-    tools::Rectangle aMirroredSource = rSourceRange;
-    if ( bMirrorObj )
-        MirrorRectRTL( aMirroredSource );
-
     SCTAB nDestTab = rDestPos.Tab();
 
     SdrPage* pSrcPage = 
pClipModel->GetPage(static_cast<sal_uInt16>(nSourceTab));
@@ -1916,168 +1934,334 @@ void ScDrawLayer::CopyFromClip( ScDrawLayer* 
pClipModel, SCTAB nSourceTab, const
     if ( !pSrcPage || !pDestPage )
         return;
 
+    ScDocument* pClipDoc = pClipModel->GetDocument();
+    if (!pClipDoc)
+        return; // Can this happen? And if yes, what to do?
+
     SdrObjListIter aIter( pSrcPage, SdrIterMode::Flat );
     SdrObject* pOldObject = aIter.Next();
+    if (!pOldObject)
+        return; // no objects at all. Nothing to do.
 
-    ScDocument* pClipDoc = pClipModel->GetDocument();
     //  a clipboard document and its source share the same document item pool,
     //  so the pointers can be compared to see if this is copy&paste within
     //  the same document
-    bool bSameDoc = pDoc && pClipDoc && pDoc->GetPool() == pClipDoc->GetPool();
-    bool bDestClip = pDoc && pDoc->IsClipboard();
+    bool bSameDoc = pDoc->GetPool() == pClipDoc->GetPool();
+    bool bDestClip = pDoc->IsClipboard(); // Happens while transposing. ToDo: 
Other cases?
 
     //#i110034# charts need correct sheet names for xml range conversion 
during load
     //so the target sheet name is temporarily renamed (if we have any 
SdrObjects)
     OUString aDestTabName;
     bool bRestoreDestTabName = false;
-    if( pOldObject && !bSameDoc && !bDestClip )
+    if (!bSameDoc && !bDestClip)
     {
-        if( pDoc && pClipDoc )
+        OUString aSourceTabName;
+        if (pClipDoc->GetName(nSourceTab, aSourceTabName) && 
pDoc->GetName(nDestTab, aDestTabName)
+            && aSourceTabName != aDestTabName && 
pDoc->ValidNewTabName(aSourceTabName))
         {
-            OUString aSourceTabName;
-            if( pClipDoc->GetName( nSourceTab, aSourceTabName )
-                && pDoc->GetName( nDestTab, aDestTabName ) )
-            {
-                if( aSourceTabName != aDestTabName &&
-                    pDoc->ValidNewTabName(aSourceTabName) )
-                {
-                    bRestoreDestTabName = pDoc->RenameTab( nDestTab, 
aSourceTabName );
-                }
-            }
+            bRestoreDestTabName = pDoc->RenameTab( nDestTab, aSourceTabName );
         }
     }
 
-    // first mirror, then move
-    Size aMove( rDestRange.Left() - aMirroredSource.Left(), rDestRange.Top() - 
aMirroredSource.Top() );
-
-    tools::Long nDestWidth = rDestRange.GetWidth();
-    tools::Long nDestHeight = rDestRange.GetHeight();
-    tools::Long nSourceWidth = rSourceRange.GetWidth();
-    tools::Long nSourceHeight = rSourceRange.GetHeight();
-
-    tools::Long nWidthDiff = nDestWidth - nSourceWidth;
-    tools::Long nHeightDiff = nDestHeight - nSourceHeight;
+    SCTAB nClipTab = bRestoreDestTabName ? nDestTab : nSourceTab;
+    ScRange aClipRange = lcl_getClipRangeFromClipDoc(pClipDoc, nClipTab);
 
-    Fraction aHorFract(1,1);
-    Fraction aVerFract(1,1);
-    bool bResize = false;
-    // sizes can differ by 1 from twips->1/100mm conversion for equal cell 
sizes,
-    // don't resize to empty size when pasting into hidden columns or rows
-    if ( std::abs(nWidthDiff) > 1 && nDestWidth > 1 && nSourceWidth > 1 )
-    {
-        aHorFract = Fraction( nDestWidth, nSourceWidth );
-        bResize = true;
-    }
-    if ( std::abs(nHeightDiff) > 1 && nDestHeight > 1 && nSourceHeight > 1 )
-    {
-        aVerFract = Fraction( nDestHeight, nSourceHeight );
-        bResize = true;
-    }
-    Point aRefPos = rDestRange.TopLeft();       // for resizing (after moving)
+    // We are going to make all rectangle calculations on LTR, so determine 
whether doc is RTL.
+    bool bSourceRTL = pClipDoc->IsLayoutRTL(nSourceTab);
+    bool bDestRTL = pDoc->IsLayoutRTL(nDestTab);
 
     while (pOldObject)
     {
-        tools::Rectangle aObjRect = pOldObject->GetCurrentBoundRect();
+        // ToDO: Can this happen? Such objects should not be in the clipboard 
document.
         // do not copy internal objects (detective) and note captions
+        if ((pOldObject->GetLayer() == SC_LAYER_INTERN) || 
IsNoteCaption(pOldObject))
+        {
+            pOldObject = aIter.Next();
+            continue;
+        }
 
-        SCTAB nClipTab = bRestoreDestTabName ? nDestTab : nSourceTab;
-        ScRange aClipRange = lcl_getClipRangeFromClipDoc(pClipDoc, nClipTab);
-
-        bool bObjectInArea = rSourceRange.Contains(aObjRect);
+        // 'aIter' considers all objects on pSrcPage. But 
ScDocument::CopyBlockFromClip, which is used
+        // for filtered data, acts not on the total range but only on parts of 
it. So we need to look,
+        // whether an object is really contained in the current rSourceRange.
+        // For cell anchored objects we use the start address of the anchor, 
for page anchored objects
+        // we use the cell range behind the bounding box of the shape.
+        ScAddress aSrcObjStart;
         const ScDrawObjData* pObjData = ScDrawLayer::GetObjData(pOldObject);
-        if (pObjData) // Consider images anchored to the copied cell
-            bObjectInArea = bObjectInArea || 
aClipRange.Contains(pObjData->maStart);
-        if (bObjectInArea && (pOldObject->GetLayer() != SC_LAYER_INTERN)
-            && !IsNoteCaption(pOldObject))
+        if (pObjData) // Object is anchored to cell.
+        {
+            aSrcObjStart = (*pObjData).maStart;
+        }
+        else // Object is anchored to page.
+        {
+            aSrcObjStart = pClipDoc->GetRange(nClipTab, 
pOldObject->GetCurrentBoundRect()).aStart;
+        }
+        if (!rSourceRange.Contains(aSrcObjStart))
+        {
+            pOldObject = aIter.Next();
+            continue;
+        }
+        // If object is anchored to a filtered cell, we will not copy it, 
because filtered rows are
+        // eliminated in paste. Copying would produce hidden objects which can 
only be accessed per
+        // macro.
+        if (pObjData && pClipDoc->RowFiltered((*pObjData).maStart.Row(), 
nSourceTab))
         {
-            // Copy style sheet
-            auto pStyleSheet = pOldObject->GetStyleSheet();
-            if (pStyleSheet && !bSameDoc)
-                
pDoc->GetStyleSheetPool()->CopyStyleFrom(pClipModel->GetStyleSheetPool(),
-                    pStyleSheet->GetName(), pStyleSheet->GetFamily(), true);
+            pOldObject = aIter.Next();
+            continue;
+        }
 
-            // Clone to target SdrModel
-            rtl::Reference<SdrObject> 
pNewObject(pOldObject->CloneSdrObject(*this));
+        // Copy style sheet
+        auto pStyleSheet = pOldObject->GetStyleSheet();
+        if (pStyleSheet && !bSameDoc)
+            
pDoc->GetStyleSheetPool()->CopyStyleFrom(pClipModel->GetStyleSheetPool(),
+                                                     pStyleSheet->GetName(),
+                                                     pStyleSheet->GetFamily(), 
true);
 
-            if ( bMirrorObj )
-                MirrorRTL( pNewObject.get() );        // first mirror, then 
move
+        rtl::Reference<SdrObject> 
pNewObject(pOldObject->CloneSdrObject(*this));
+        tools::Rectangle aObjRect = pOldObject->GetSnapRect();
+        if (bSourceRTL)
+        {
+            MirrorRTL(pNewObject.get()); // We make the calculations in LTR.
+            MirrorRectRTL(aObjRect);
+        }
 
-            pNewObject->NbcMove( aMove );
-            if ( bResize )
-                pNewObject->NbcResize( aRefPos, aHorFract, aVerFract );
+        bool bCanResize = IsResizeWithCell(*pOldObject) && 
!pOldObject->IsResizeProtect();
+        // We do not resize charts or other OLE objects and do not resize when 
transposing.
+        bCanResize &= pOldObject->GetObjIdentifier() != SdrObjKind::OLE2;
+        bCanResize &= !bTransposing && 
!pClipDoc->GetClipParam().isTransposed();
+        if (bCanResize)
+        {
+            // Filtered rows are eliminated on paste. Filtered cols do not 
exist as of May 2023.
+            // Collapsed or hidden rows/cols are shown on paste.
+            // Idea: First calculate top left cell and bottom right cell of 
pasted object. Then
+            // calculate the object corners inside these cell and from that 
build new snap rectangle.
+            // We assume that pObjData is valid and pObjData and aObjRect 
correspond to each other
+            // in the source document.
+
+            // Start cell of object in source and destination. The case of a 
filtered start cell is
+            // already excluded above. aSrcObjStart = (*pObjData).maStart is 
already done above.
+            // If filtered rows exist in the total range, the range was 
divided into blocks which
+            // do not contain filtered rows. So the rows between start of 
aSourceRange and object
+            // start row do not contain filtered rows.
+            SCROW nStartRowDiff = aSrcObjStart.Row() - 
rSourceRange.aStart.Row();
+            SCCOL nStartColDiff = aSrcObjStart.Col() - 
rSourceRange.aStart.Col();
+            ScAddress aDestObjStart = rDestRange.aStart;
+            aDestObjStart.IncCol(nStartColDiff);
+            aDestObjStart.IncRow(nStartRowDiff);
+
+            // End cell of object in source and destination. We look at the 
amount of rows/cols to be
+            // added to get object end cell from object start cell.
+            ScAddress aSrcObjEnd = (*pObjData).maEnd;
+            SCCOL nColsToAdd = aSrcObjEnd.Col() - aSrcObjStart.Col();
+            SCROW nRowsToAdd
+                = pClipDoc->CountNonFilteredRows(aSrcObjStart.Row(), 
aSrcObjEnd.Row(), nSourceTab)
+                  - 1;
+            ScAddress aDestObjEnd = aDestObjStart;
+            aDestObjEnd.IncCol(nColsToAdd);
+            aDestObjEnd.IncRow(nRowsToAdd);
+
+            // Position of object inside start and end cell in source. We 
describe the distance from
+            // cell corner to object corner as ratio of offset to cell 
width/height.
+            // We cannot use GetCellRect method, because that uses 
bHiddenAsZero=true.
+            Point aSrcObjTopLeftOffset = (*pObjData).maStartOffset;
+            tools::Rectangle aSrcStartRect
+                = pClipDoc->GetMMRect(aSrcObjStart.Col(), aSrcObjStart.Row(), 
aSrcObjStart.Col(),
+                                      aSrcObjStart.Row(), nSourceTab, false 
/*bHiddenAsZero*/);
+            if (bSourceRTL)
+                MirrorRectRTL(aSrcStartRect);
+            double fStartXRatio
+                = aSrcStartRect.getOpenWidth() == 0
+                      ? 1.0
+                      : double(aSrcObjTopLeftOffset.X()) / 
double(aSrcStartRect.getOpenWidth());
+            double fStartYRatio
+                = aSrcStartRect.getOpenHeight() == 0
+                      ? 1.0
+                      : double(aSrcObjTopLeftOffset.Y()) / 
double(aSrcStartRect.getOpenHeight());
+
+            Point aSrcObjBottomRightOffset = (*pObjData).maEndOffset;
+            tools::Rectangle aSrcEndRect
+                = pClipDoc->GetMMRect(aSrcObjEnd.Col(), aSrcObjEnd.Row(), 
aSrcObjEnd.Col(),
+                                      aSrcObjEnd.Row(), nSourceTab, false 
/*bHiddenAsZero*/);
+            if (bSourceRTL)
+                MirrorRectRTL(aSrcEndRect);
+            double fEndXRatio
+                = aSrcEndRect.getOpenWidth() == 0
+                      ? 1.0
+                      : double(aSrcObjBottomRightOffset.X()) / 
double(aSrcEndRect.getOpenWidth());
+            double fEndYRatio
+                = aSrcEndRect.getOpenHeight() == 0
+                      ? 1.0
+                      : double(aSrcObjBottomRightOffset.Y()) / 
double(aSrcEndRect.getOpenHeight());
+            // The end cell given in pObjData might be filtered. In that case 
the object is cut at
+            // the lower cell edge. The offset is as large as the cell.
+            if (pClipDoc->RowFiltered(aSrcObjEnd.Row(), nSourceTab))
+                fEndYRatio = 1.0;
+
+            // Position of object inside start and end cell in destination
+            tools::Rectangle aDestStartRect
+                = GetCellRect(*pDoc, aDestObjStart, false /*bMergedCell*/);
+            if (bDestRTL)
+                MirrorRectRTL(aDestStartRect);
+            Point aDestObjTopLeftOffset(fStartXRatio * 
aDestStartRect.getOpenWidth(),
+                                        fStartYRatio * 
aDestStartRect.getOpenHeight());
+            Point aDestObjTopLeft = aDestStartRect.TopLeft() + 
aDestObjTopLeftOffset;
+
+            tools::Rectangle aDestEndRect = GetCellRect(*pDoc, aDestObjEnd, 
false /*bMergedCell*/);
+            if (bDestRTL)
+                MirrorRectRTL(aDestEndRect);
+            Point aDestObjBottomRightOffset(fEndXRatio * 
aDestEndRect.getOpenWidth(),
+                                            fEndYRatio * 
aDestEndRect.getOpenHeight());
+            Point aDestObjBottomRight = aDestEndRect.TopLeft() + 
aDestObjBottomRightOffset;
+
+            // Fit new object into destination rectangle
+            tools::Rectangle aNewObjRect(aDestObjTopLeft, aDestObjBottomRight);
+            aNewObjRect = lcl_makeSafeRectangle(aNewObjRect);
+            if (pNewObject->GetObjIdentifier() == SdrObjKind::CustomShape)
+                pNewObject->AdjustToMaxRect(aNewObjRect);
+            else
+                pNewObject->SetSnapRect(aNewObjRect);
+        }
+        else
+        {
+            // We determine the MM-distance of the new object from its start 
cell in destination from
+            // the ratio of offset to cell width/height. Thus the object still 
starts in this cell
+            // even if the destination cell has different size. Otherwise we 
might lose objects when
+            // transposing.
+
+            // Start Cell address in source and destination
+            SCCOLROW nStartRowDiff = 
pClipDoc->CountNonFilteredRows(rSourceRange.aStart.Row(),
+                                                                    
aSrcObjStart.Row(), nSourceTab)
+                                     - 1;
+            SCCOLROW nStartColDiff = aSrcObjStart.Col() - 
rSourceRange.aStart.Col();
+            if (bTransposing)
+                std::swap(nStartRowDiff, nStartColDiff);
+            ScAddress aDestObjStart = rDestRange.aStart;
+            aDestObjStart.IncCol(nStartColDiff);
+            aDestObjStart.IncRow(nStartRowDiff);
+
+            // Position of object inside start cell in source.
+            tools::Rectangle aSrcStartRect
+                = pClipDoc->GetMMRect(aSrcObjStart.Col(), aSrcObjStart.Row(), 
aSrcObjStart.Col(),
+                                      aSrcObjStart.Row(), nSourceTab, false 
/*bHiddenAsZero*/);
+            if (bSourceRTL)
+                MirrorRectRTL(aSrcStartRect);
+            Point aSrcObjTopLeftOffset = pObjData ? (*pObjData).maStartOffset
+                                                  : aObjRect.TopLeft() - 
aSrcStartRect.TopLeft();
+
+            double fStartXRatio
+                = aSrcStartRect.getOpenWidth() == 0
+                      ? 1.0
+                      : double(aSrcObjTopLeftOffset.X()) / 
double(aSrcStartRect.getOpenWidth());
+            double fStartYRatio
+                = aSrcStartRect.getOpenHeight() == 0
+                      ? 1.0
+                      : double(aSrcObjTopLeftOffset.Y()) / 
double(aSrcStartRect.getOpenHeight());
+
+            // Position of object inside start cell in destination
+            tools::Rectangle aDestStartRect
+                = GetCellRect(*pDoc, aDestObjStart, false /*bMergedCell*/);
+            if (bDestRTL)
+                MirrorRectRTL(aDestStartRect);
+            Point aDestObjTopLeftOffset(fStartXRatio * 
aDestStartRect.getOpenWidth(),
+                                        fStartYRatio * 
aDestStartRect.getOpenHeight());
+            Point aDestObjTopLeft = aDestStartRect.TopLeft() + 
aDestObjTopLeftOffset;
+
+            // Move new object to new position
+            Point aMoveBy = aDestObjTopLeft - aObjRect.TopLeft();
+            pNewObject->NbcMove(Size(aMoveBy.getX(), aMoveBy.getY()));
+        }
+
+        if (bDestRTL)
+            MirrorRTL(pNewObject.get());
 
-            pDestPage->InsertObject( pNewObject.get() );
+        // Changing object position or size does not automatically change its 
anchor.
+        if (IsCellAnchored(*pOldObject))
+            SetCellAnchoredFromPosition(*pNewObject, *pDoc, nDestTab,
+                                        IsResizeWithCell(*pOldObject));
+
+        // InsertObject includes broadcasts
+        // MakeNameUnique makes the pasted objects accessible via Navigator.
+        if (bDestClip)
+            pDestPage->InsertObject(pNewObject.get());
+        else
+        {
             if (bRecording)
-                AddCalcUndo( std::make_unique<SdrUndoInsertObj>( *pNewObject ) 
);
+                pDoc->EnableUndo(false);
+            pDestPage->InsertObjectThenMakeNameUnique(pNewObject.get());
+            if (bRecording)
+                pDoc->EnableUndo(true);
+        }
 
-            //#i110034# handle chart data references (after InsertObject)
+        if (bRecording)
+            AddCalcUndo(std::make_unique<SdrUndoInsertObj>(*pNewObject));
 
-            if ( pNewObject->GetObjIdentifier() == SdrObjKind::OLE2 )
+        //#i110034# handle chart data references (after InsertObject)
+        if (pNewObject->GetObjIdentifier() == SdrObjKind::OLE2)
+        {
+            uno::Reference<embed::XEmbeddedObject> xIPObj
+                = static_cast<SdrOle2Obj*>(pNewObject.get())->GetObjRef();
+            uno::Reference<embed::XClassifiedObject> xClassified = xIPObj;
+            SvGlobalName aObjectClassName;
+            if (xClassified.is())
             {
-                uno::Reference< embed::XEmbeddedObject > xIPObj = 
static_cast<SdrOle2Obj*>(pNewObject.get())->GetObjRef();
-                uno::Reference< embed::XClassifiedObject > xClassified = 
xIPObj;
-                SvGlobalName aObjectClassName;
-                if ( xClassified.is() )
+                try
                 {
-                    try {
-                        aObjectClassName = SvGlobalName( 
xClassified->getClassID() );
-                    } catch( uno::Exception& )
-                    {
-                        // TODO: handle error?
-                    }
+                    aObjectClassName = SvGlobalName(xClassified->getClassID());
                 }
+                catch (uno::Exception&)
+                {
+                    // TODO: handle error?
+                }
+            }
 
-                if ( xIPObj.is() && SotExchange::IsChart( aObjectClassName ) )
+            if (xIPObj.is() && SotExchange::IsChart(aObjectClassName))
+            {
+                uno::Reference<chart2::XChartDocument> xNewChart(
+                    ScChartHelper::GetChartFromSdrObject(pNewObject.get()));
+                if (xNewChart.is() && !xNewChart->hasInternalDataProvider())
                 {
-                    uno::Reference< chart2::XChartDocument > xNewChart( 
ScChartHelper::GetChartFromSdrObject( pNewObject.get() ) );
-                    if( xNewChart.is() && 
!xNewChart->hasInternalDataProvider() )
+                    OUString aChartName
+                        = 
static_cast<SdrOle2Obj*>(pNewObject.get())->GetPersistName();
+                    ::std::vector<ScRangeList> aRangesVector;
+                    pDoc->GetChartRanges(aChartName, aRangesVector, *pDoc);
+                    if (!aRangesVector.empty())
                     {
-                        OUString aChartName = 
static_cast<SdrOle2Obj*>(pNewObject.get())->GetPersistName();
-                        ::std::vector< ScRangeList > aRangesVector;
-                        pDoc->GetChartRanges( aChartName, aRangesVector, *pDoc 
);
-                        if( !aRangesVector.empty() )
-                        {
-                            bool bInSourceRange = false;
-                            if ( pClipDoc )
-                            {
-                                bInSourceRange = lcl_IsAllInRange( 
aRangesVector, aClipRange );
-                            }
+                        bool bInSourceRange = false;
+                        bInSourceRange = lcl_IsAllInRange(aRangesVector, 
aClipRange);
 
-                            // always lose references when pasting into a 
clipboard document (transpose)
-                            if ( ( bInSourceRange || bSameDoc ) && !bDestClip )
+                        // always lose references when pasting into a 
clipboard document (transpose)
+                        if ((bInSourceRange || bSameDoc) && !bDestClip)
+                        {
+                            if (bInSourceRange)
                             {
-                                if ( bInSourceRange )
-                                {
-                                    if ( rDestPos != aClipRange.aStart )
-                                    {
-                                        //  update the data ranges to the new 
(copied) position
-                                        if ( lcl_MoveRanges( aRangesVector, 
aClipRange, rDestPos, *pDoc ) )
-                                            pDoc->SetChartRanges( aChartName, 
aRangesVector );
-                                    }
-                                }
-                                else
+                                if (rDestPos != aClipRange.aStart)
                                 {
-                                    //  leave the ranges unchanged
+                                    //  update the data ranges to the new 
(copied) position
+                                    if (lcl_MoveRanges(aRangesVector, 
aClipRange, rDestPos, *pDoc))
+                                        pDoc->SetChartRanges(aChartName, 
aRangesVector);
                                 }
                             }
                             else
                             {
-                                //  pasting into a new document without the 
complete source data
-                                //  -> break connection to source data and 
switch to own data
-
-                                uno::Reference< chart::XChartDocument > 
xOldChartDoc( ScChartHelper::GetChartFromSdrObject( pOldObject ), 
uno::UNO_QUERY );
-                                uno::Reference< chart::XChartDocument > 
xNewChartDoc( xNewChart, uno::UNO_QUERY );
-                                if( xOldChartDoc.is() && xNewChartDoc.is() )
-                                    xNewChartDoc->attachData( 
xOldChartDoc->getData() );
-
-                                //  (see 
ScDocument::UpdateChartListenerCollection, PastingDrawFromOtherDoc)
+                                //  leave the ranges unchanged
                             }
                         }
+                        else
+                        {
+                            //  pasting into a new document without the 
complete source data
+                            //  -> break connection to source data and switch 
to own data
+                            uno::Reference<chart::XChartDocument> xOldChartDoc(
+                                
ScChartHelper::GetChartFromSdrObject(pOldObject), uno::UNO_QUERY);
+                            uno::Reference<chart::XChartDocument> 
xNewChartDoc(xNewChart,
+                                                                               
uno::UNO_QUERY);
+                            if (xOldChartDoc.is() && xNewChartDoc.is())
+                                
xNewChartDoc->attachData(xOldChartDoc->getData());
+
+                            //  (see 
ScDocument::UpdateChartListenerCollection, PastingDrawFromOtherDoc)
+                        }
                     }
                 }
             }
         }
-
         pOldObject = aIter.Next();
     }
 
diff --git a/sc/source/core/data/table7.cxx b/sc/source/core/data/table7.cxx
index 230833e8b7a6..49929f99da94 100644
--- a/sc/source/core/data/table7.cxx
+++ b/sc/source/core/data/table7.cxx
@@ -169,12 +169,10 @@ void ScTable::CopyOneCellFromClip(
         const ScAddress aSrcStartPos
             = rCxt.getClipDoc()->GetClipParam().getWholeRange().aStart;
         const ScAddress aSrcEndPos = 
rCxt.getClipDoc()->GetClipParam().getWholeRange().aEnd;
-        tools::Rectangle aSourceRect = rCxt.getClipDoc()->GetMMRect(
-            aSrcStartPos.Col(), aSrcStartPos.Row(), aSrcEndPos.Col(), 
aSrcEndPos.Row(),
-            aSrcStartPos.Tab());
-        tools::Rectangle aDestRect = GetDoc().GetMMRect(nCol1, nRow1, nCol2, 
nRow2, nTab);
+        ScRange aSourceRange(aSrcStartPos, aSrcEndPos);
+        ScRange aDestRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
         pDrawLayer->CopyFromClip(rCxt.getClipDoc()->mpDrawLayer.get(), 
aSrcStartPos.Tab(),
-                                 aSourceRect, ScAddress(nCol1, nRow1, nTab), 
aDestRect);
+                                 aSourceRange, ScAddress(nCol1, nRow1, nTab), 
aDestRange);
     }
 }
 

Reply via email to