diff options
author | Henry Castro <hcastro@collabora.com> | 2015-04-24 16:55:01 -0400 |
---|---|---|
committer | Andras Timar <andras.timar@collabora.com> | 2015-05-28 04:59:27 +0000 |
commit | 487880b6882ec01c1b4679eae60bec484272a86b (patch) | |
tree | 7d0c2c7c333ad7f2b86c8f8572ad89652141a790 /sc | |
parent | be01d68420086fc36ecf26b5f597ba7c6b29b369 (diff) |
Resolves tdf#67712 form controls and draw objects
anchored to cell but changes position after reopening
Also included tdf#68797 "FILEOPEN lost position of lines
anchored to cell". It was marked as duplicate but the
step to reproduce are different.
Conflicts:
sc/qa/unit/subsequent_filters-test.cxx
Conflicts:
sc/qa/unit/subsequent_export-test.cxx
Change-Id: Ia1c4010f118749256077a0ecad6ca16b867d22f7
Reviewed-on: https://gerrit.libreoffice.org/15523
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Andras Timar <andras.timar@collabora.com>
Diffstat (limited to 'sc')
-rw-r--r-- | sc/qa/unit/data/ods/move-cell-anchored-shapes.ods | bin | 0 -> 12100 bytes | |||
-rw-r--r-- | sc/qa/unit/subsequent_export-test.cxx | 166 | ||||
-rw-r--r-- | sc/qa/unit/ucalc.cxx | 100 | ||||
-rw-r--r-- | sc/qa/unit/ucalc.hxx | 2 | ||||
-rw-r--r-- | sc/source/core/data/drwlayer.cxx | 59 |
5 files changed, 327 insertions, 0 deletions
diff --git a/sc/qa/unit/data/ods/move-cell-anchored-shapes.ods b/sc/qa/unit/data/ods/move-cell-anchored-shapes.ods Binary files differnew file mode 100644 index 000000000000..9ad1568f9e1c --- /dev/null +++ b/sc/qa/unit/data/ods/move-cell-anchored-shapes.ods diff --git a/sc/qa/unit/subsequent_export-test.cxx b/sc/qa/unit/subsequent_export-test.cxx index 3f0ea9088c8c..c194e31d53f9 100644 --- a/sc/qa/unit/subsequent_export-test.cxx +++ b/sc/qa/unit/subsequent_export-test.cxx @@ -22,6 +22,7 @@ #include "helper/xpath.hxx" #include "helper/shared_test_impl.hxx" +#include "userdat.hxx" #include "docsh.hxx" #include "patattr.hxx" #include "scitems.hxx" @@ -145,6 +146,7 @@ public: void testSheetRunParagraphProperty(); void testHiddenShape(); void testHyperlinkXLSX(); + void testMoveCellAnchoredShapes(); CPPUNIT_TEST_SUITE(ScExportTest); CPPUNIT_TEST(test); @@ -200,6 +202,7 @@ public: CPPUNIT_TEST(testSheetRunParagraphProperty); CPPUNIT_TEST(testHiddenShape); CPPUNIT_TEST(testHyperlinkXLSX); + CPPUNIT_TEST(testMoveCellAnchoredShapes); CPPUNIT_TEST_SUITE_END(); @@ -2655,6 +2658,169 @@ void ScExportTest::testHyperlinkXLSX() assertXPath(pDoc, "/r:Relationships/r:Relationship", "Target", "#Sheet2!A1"); } +void ScExportTest::testMoveCellAnchoredShapes() +{ + ScDocShellRef xDocSh = loadDoc("move-cell-anchored-shapes.", ODS); + CPPUNIT_ASSERT_MESSAGE("Failed to load move-cell-anchored-shapes.ods", xDocSh.Is()); + + // There are two cell-anchored objects on the first sheet. + ScDocument& rDoc = xDocSh->GetDocument(); + + CPPUNIT_ASSERT_MESSAGE("There should be at least one sheet.", rDoc.GetTableCount() > 0); + + ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer(); + SdrPage* pPage = pDrawLayer->GetPage(0); + CPPUNIT_ASSERT_MESSAGE("draw page for sheet 1 should exist.", pPage); + SdrObject* pObj = pPage->GetObj(0); + CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object.", pObj); + + // Check cell anchor state + ScAnchorType oldType = ScDrawLayer::GetAnchorType(*pObj); + CPPUNIT_ASSERT_MESSAGE( "Failed to get anchor type", oldType == SCA_CELL ); + + // Get anchor data + ScDrawObjData* pData = ScDrawLayer::GetObjData(pObj, false); + CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData); + CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pData->maLastRect.IsEmpty()); + + ScAddress aDataStart = pData->maStart; + ScAddress aDataEnd = pData->maEnd; + + // Get non rotated anchor data + ScDrawObjData* pNData = ScDrawLayer::GetNonRotatedObjData( pObj ); + CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData); + CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pNData->maLastRect.IsEmpty()); + + ScAddress aNDataStart = pNData->maStart; + ScAddress aNDataEnd = pNData->maEnd; + CPPUNIT_ASSERT_EQUAL(aDataStart, aNDataStart); + CPPUNIT_ASSERT_EQUAL(aDataEnd , aNDataEnd); + + // Insert 2 rows. + rDoc.InsertRow(ScRange( 0, aDataStart.Row() - 1, 0, MAXCOL, aDataStart.Row(), 0)); + + // Get anchor data + pData = ScDrawLayer::GetObjData(pObj, false); + CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData); + CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pData->maLastRect.IsEmpty()); + + // Get non rotated anchor data + pNData = ScDrawLayer::GetNonRotatedObjData( pObj ); + CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData); + CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pNData->maLastRect.IsEmpty()); + + // Check if data has moved to new rows + CPPUNIT_ASSERT_EQUAL( pData->maStart.Row(), aDataStart.Row() + 2 ); + CPPUNIT_ASSERT_EQUAL( pData->maEnd.Row(), aDataEnd.Row() + 2 ); + + CPPUNIT_ASSERT_EQUAL( pNData->maStart.Row(), aNDataStart.Row() + 2 ); + CPPUNIT_ASSERT_EQUAL( pNData->maEnd.Row(), aNDataEnd.Row() + 2 ); + + // Save the anchor data + aDataStart = pData->maStart; + aDataEnd = pData->maEnd; + aNDataStart = pNData->maStart; + aNDataEnd = pNData->maEnd; + + // Save the document and load again to check anchor persist + ScDocShellRef xDocSh1 = saveAndReload(&(*xDocSh), ODS); + + // There are two cell-anchored objects on the first sheet. + ScDocument& rDoc1 = xDocSh1->GetDocument(); + + CPPUNIT_ASSERT_MESSAGE("There should be at least one sheet.", rDoc1.GetTableCount() > 0); + + pDrawLayer = rDoc1.GetDrawLayer(); + pPage = pDrawLayer->GetPage(0); + CPPUNIT_ASSERT_MESSAGE("draw page for sheet 1 should exist.", pPage); + pObj = pPage->GetObj(0); + CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object.", pObj); + + // Check cell anchor state + oldType = ScDrawLayer::GetAnchorType(*pObj); + CPPUNIT_ASSERT_MESSAGE( "Failed to get anchor type", oldType == SCA_CELL ); + + // Get anchor data + pData = ScDrawLayer::GetObjData(pObj, false); + CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData); + CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pData->maLastRect.IsEmpty()); + + // Get non rotated anchor data + pNData = ScDrawLayer::GetNonRotatedObjData( pObj ); + CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData); + CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pNData->maLastRect.IsEmpty()); + + // Check if data after save it + CPPUNIT_ASSERT_EQUAL(pData->maStart, aDataStart); + CPPUNIT_ASSERT_EQUAL(pData->maEnd , aDataEnd); + + CPPUNIT_ASSERT_EQUAL(pNData->maStart, aNDataStart); + CPPUNIT_ASSERT_EQUAL(pNData->maEnd , aNDataEnd); + + // Insert a column. + rDoc1.InsertCol(ScRange( aDataStart.Col(), 0 , 0 , aDataStart.Col(), MAXROW, 0 )); + + // Get anchor data + pData = ScDrawLayer::GetObjData(pObj, false); + CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData); + CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pData->maLastRect.IsEmpty()); + + // Get non rotated anchor data + pNData = ScDrawLayer::GetNonRotatedObjData( pObj ); + CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData); + CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pNData->maLastRect.IsEmpty()); + + // Check if data has moved to new rows + CPPUNIT_ASSERT_EQUAL(pData->maStart.Col(), SCCOL(aDataStart.Col() + 1)); + CPPUNIT_ASSERT_EQUAL(pData->maEnd.Col() , SCCOL(aDataEnd.Col() + 1)); + + CPPUNIT_ASSERT_EQUAL(pNData->maStart.Col(), SCCOL(aNDataStart.Col() + 1)); + CPPUNIT_ASSERT_EQUAL(pNData->maEnd.Col() , SCCOL(aNDataEnd.Col() + 1)); + + // Save the anchor data + aDataStart = pData->maStart; + aDataEnd = pData->maEnd; + aNDataStart = pNData->maStart; + aNDataEnd = pNData->maEnd; + + // Save the document and load again to check anchor persist + ScDocShellRef xDocSh2 = saveAndReload(&(*xDocSh1), ODS); + + // There are two cell-anchored objects on the first sheet. + ScDocument& rDoc2 = xDocSh2->GetDocument(); + + CPPUNIT_ASSERT_MESSAGE("There should be at least one sheet.", rDoc2.GetTableCount() > 0); + + pDrawLayer = rDoc2.GetDrawLayer(); + pPage = pDrawLayer->GetPage(0); + CPPUNIT_ASSERT_MESSAGE("draw page for sheet 1 should exist.", pPage); + pObj = pPage->GetObj(0); + CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object.", pObj); + + // Check cell anchor state + oldType = ScDrawLayer::GetAnchorType(*pObj); + CPPUNIT_ASSERT_MESSAGE( "Failed to get anchor type", oldType == SCA_CELL ); + + // Get anchor data + pData = ScDrawLayer::GetObjData(pObj, false); + CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData); + CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pData->maLastRect.IsEmpty()); + + // Get non rotated anchor data + pNData = ScDrawLayer::GetNonRotatedObjData( pObj ); + CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData); + CPPUNIT_ASSERT_MESSAGE("Bounding rectangle should have been calculated upon import.", !pNData->maLastRect.IsEmpty()); + + // Check if data after save it + CPPUNIT_ASSERT_EQUAL(pData->maStart, aDataStart); + CPPUNIT_ASSERT_EQUAL(pData->maEnd , aDataEnd); + + CPPUNIT_ASSERT_EQUAL(pNData->maStart, aNDataStart); + CPPUNIT_ASSERT_EQUAL(pNData->maEnd , aNDataEnd); + + xDocSh2->DoClose(); +} + CPPUNIT_TEST_SUITE_REGISTRATION(ScExportTest); CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index ad0ae3da70a3..494b5356b8da 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -6540,6 +6540,106 @@ void Test::testCopyPasteMatrixFormula() m_pDoc->DeleteTab(0); } +void Test::testUndoDataAnchor() +{ + m_pDoc->InsertTab(0, "Tab1"); + CPPUNIT_ASSERT_MESSAGE("There should be only 1 sheets to begin with", m_pDoc->GetTableCount() == 1); + + m_pDoc->InitDrawLayer(); + ScDrawLayer* pDrawLayer = m_pDoc->GetDrawLayer(); + CPPUNIT_ASSERT_MESSAGE("No drawing layer.", pDrawLayer); + SdrPage* pPage = pDrawLayer->GetPage(0); + CPPUNIT_ASSERT_MESSAGE("No page instance for the 1st sheet.", pPage); + + // Insert an object. + Rectangle aObjRect(2,1000,100,1100); + SdrObject* pObj = new SdrRectObj(aObjRect); + pPage->InsertObject(pObj); + ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *m_pDoc, 0); + + // Get anchor data + ScDrawObjData* pData = ScDrawLayer::GetObjData(pObj, false); + CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData); + + ScAddress aOldStart = pData->maStart; + ScAddress aOldEnd = pData->maEnd; + + // Get non rotated anchor data + ScDrawObjData* pNData = ScDrawLayer::GetNonRotatedObjData( pObj ); + CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData); + + ScAddress aNOldStart = pNData->maStart; + ScAddress aNOldEnd = pNData->maEnd; + CPPUNIT_ASSERT_EQUAL(aOldStart, aNOldStart); + CPPUNIT_ASSERT_EQUAL(aOldEnd, aNOldEnd); + + //pDrawLayer->BeginCalcUndo(false); + // Insert a new row at row 3. + ScDocFunc& rFunc = getDocShell().GetDocFunc(); + ScMarkData aMark; + aMark.SelectOneTable(0); + rFunc.InsertCells(ScRange( 0, aOldStart.Row() - 1, 0, MAXCOL, aOldStart.Row(), 0 ), &aMark, INS_INSROWS, true, true, false); + + pData = ScDrawLayer::GetObjData(pObj, false); + CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData); + + ScAddress aNewStart = pData->maStart; + ScAddress aNewEnd = pData->maEnd; + + // Get non rotated anchor data + pNData = ScDrawLayer::GetNonRotatedObjData( pObj ); + CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData); + + ScAddress aNNewStart = pNData->maStart; + ScAddress aNNewEnd = pNData->maEnd; + CPPUNIT_ASSERT_EQUAL(aNewStart, aNNewStart); + CPPUNIT_ASSERT_EQUAL(aNewEnd, aNNewEnd); + CPPUNIT_ASSERT_MESSAGE("Failed to compare Address.", aNewStart != aOldStart && aNewEnd != aOldEnd && + aNNewStart != aNOldStart && aNNewEnd != aNOldEnd ); + + SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager(); + CPPUNIT_ASSERT(pUndoMgr); + pUndoMgr->Undo(); + + // Check state + ScAnchorType oldType = ScDrawLayer::GetAnchorType(*pObj); + CPPUNIT_ASSERT_MESSAGE( "Failed to check state SCA_CELL.", oldType == SCA_CELL ); + + // Get anchor data + pData = ScDrawLayer::GetObjData(pObj, false); + CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData); + + // Get non rotated anchor data + pNData = ScDrawLayer::GetNonRotatedObjData( pObj ); + CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData); + + // Check if data has moved to new rows + CPPUNIT_ASSERT_EQUAL(pData->maStart, aOldStart); + CPPUNIT_ASSERT_EQUAL(pData->maEnd, aOldEnd); + + CPPUNIT_ASSERT_EQUAL(pNData->maStart, aNOldStart); + CPPUNIT_ASSERT_EQUAL(pNData->maEnd, aNOldEnd); + + pUndoMgr->Redo(); + + // Get anchor data + pData = ScDrawLayer::GetObjData(pObj, false); + CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData); + + // Get non rotated anchor data + pNData = ScDrawLayer::GetNonRotatedObjData( pObj ); + CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData); + + // Check if data has moved to new rows + CPPUNIT_ASSERT_EQUAL(pData->maStart, aNewStart); + CPPUNIT_ASSERT_EQUAL(pData->maEnd, aNewEnd); + + CPPUNIT_ASSERT_EQUAL(pNData->maStart, aNNewStart); + CPPUNIT_ASSERT_EQUAL(pNData->maEnd, aNNewEnd); + + m_pDoc->DeleteTab(0); +} + ScDocShell* Test::findLoadedDocShellByName(const OUString& rName) { TypeId aType(TYPE(ScDocShell)); diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx index a2bd05393fa3..afc4d0ae3610 100644 --- a/sc/qa/unit/ucalc.hxx +++ b/sc/qa/unit/ucalc.hxx @@ -434,6 +434,7 @@ public: // tdf#80137 void testCopyPasteMatrixFormula(); + void testUndoDataAnchor(); CPPUNIT_TEST_SUITE(Test); #if CALC_TEST_PERF @@ -643,6 +644,7 @@ public: CPPUNIT_TEST(testColumnFindEditCells); CPPUNIT_TEST(testSetStringAndNote); CPPUNIT_TEST(testCopyPasteMatrixFormula); + CPPUNIT_TEST(testUndoDataAnchor); CPPUNIT_TEST_SUITE_END(); private: diff --git a/sc/source/core/data/drwlayer.cxx b/sc/source/core/data/drwlayer.cxx index 3b4e1101eb3f..27e47c81719d 100644 --- a/sc/source/core/data/drwlayer.cxx +++ b/sc/source/core/data/drwlayer.cxx @@ -27,6 +27,7 @@ #include <com/sun/star/embed/ElementModes.hpp> #include <com/sun/star/embed/NoVisualAreaSizeException.hpp> #include <com/sun/star/datatransfer/XTransferable.hpp> +#include <basegfx/matrix/b2dhommatrixtools.hxx> #include "scitems.hxx" #include <editeng/eeitem.hxx> @@ -116,6 +117,14 @@ void ScUndoObjData::Undo() pData->maStart = aOldStt; pData->maEnd = aOldEnd; } + + // Undo also an untransformed anchor + pData = ScDrawLayer::GetNonRotatedObjData( pObj ); + if (pData) + { + pData->maStart = aOldStt; + pData->maEnd = aOldEnd; + } } void ScUndoObjData::Redo() @@ -127,6 +136,14 @@ void ScUndoObjData::Redo() pData->maStart = aNewStt; pData->maEnd = aNewEnd; } + + // Redo also an untransformed anchor + pData = ScDrawLayer::GetNonRotatedObjData( pObj ); + if (pData) + { + pData->maStart = aNewStt; + pData->maEnd = aNewEnd; + } } ScUndoAnchorData::ScUndoAnchorData( SdrObject* pObjP, ScDocument* pDoc, SCTAB nTab ) : @@ -537,6 +554,15 @@ void ScDrawLayer::MoveCells( SCTAB nTab, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SC { if ( pObj->ISA( SdrRectObj ) && pData->maStart.IsValid() && pData->maEnd.IsValid() ) pData->maStart.PutInOrder( pData->maEnd ); + + // Update also an untransformed anchor thats what we stored ( and still do ) to xml + ScDrawObjData* pNoRotatedAnchor = GetNonRotatedObjData( pObj, false ); + if ( pNoRotatedAnchor ) + { + pNoRotatedAnchor->maStart = pData->maStart; + pNoRotatedAnchor->maEnd = pData->maEnd; + } + AddCalcUndo( new ScUndoObjData( pObj, aOldStt, aOldEnd, pData->maStart, pData->maEnd ) ); RecalcPos( pObj, *pData, bNegativePage, bUpdateNoteCaptionPos ); } @@ -801,6 +827,39 @@ void ScDrawLayer::RecalcPos( SdrObject* pObj, ScDrawObjData& rData, bool bNegati ScDrawObjData& rNoRotatedAnchor = *GetNonRotatedObjData( pObj, true ); if (rData.maLastRect.IsEmpty()) { + // Every shape it is saved with an negative offset relative to cell + if (ScDrawLayer::GetAnchorType(*pObj) == SCA_CELL) + { + double fRotate(0.0); + double fShearX(0.0); + + Point aPoint; + Rectangle aRect; + + basegfx::B2DTuple aScale; + basegfx::B2DTuple aTranslate; + basegfx::B2DPolyPolygon aPolyPolygon; + basegfx::B2DHomMatrix aOriginalMatrix; + + aRect = pDoc->GetMMRect(nCol1, nRow1, nCol1 , nRow1, nTab1); + + if (bNegativePage) + aPoint.X() = aRect.Right(); + else + aPoint.X() = aRect.Left(); + aPoint.Y() = aRect.Top(); + + pObj->TRGetBaseGeometry(aOriginalMatrix, aPolyPolygon); + aOriginalMatrix.decompose(aScale, aTranslate, fRotate, fShearX); + aTranslate += ::basegfx::B2DTuple(aPoint.X(), aPoint.Y()); + aOriginalMatrix = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix( + aScale, + fShearX, + fRotate, + aTranslate); + pObj->TRSetBaseGeometry(aOriginalMatrix, aPolyPolygon); + } + // It's confusing ( but blame that we persist the anchor in terms of unrotated shape ) // that the initial anchor we get here is in terms of an unrotated shape ( if the shape is rotated ) // we need to save the old anchor ( for persisting ) and also track any resize or repositions that happen. |