diff options
Diffstat (limited to 'sc/qa/unit/copy_paste_test.cxx')
-rw-r--r-- | sc/qa/unit/copy_paste_test.cxx | 450 |
1 files changed, 450 insertions, 0 deletions
diff --git a/sc/qa/unit/copy_paste_test.cxx b/sc/qa/unit/copy_paste_test.cxx new file mode 100644 index 000000000..71adbe5c8 --- /dev/null +++ b/sc/qa/unit/copy_paste_test.cxx @@ -0,0 +1,450 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <sal/config.h> +#include <test/bootstrapfixture.hxx> +#include <comphelper/processfactory.hxx> + +#include <docsh.hxx> +#include <tabvwsh.hxx> +#include <impex.hxx> + +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/frame/XModel2.hpp> + +#include "helper/qahelper.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +class ScCopyPasteTest : public ScBootstrapFixture +{ +public: + ScCopyPasteTest(); + + virtual void setUp() override; + virtual void tearDown() override; + + void testCopyPasteXLS(); + void testTdf84411(); + void testTdf124565(); + void testTdf126421(); + void testTdf107394(); + + CPPUNIT_TEST_SUITE(ScCopyPasteTest); + CPPUNIT_TEST(testCopyPasteXLS); + CPPUNIT_TEST(testTdf84411); + CPPUNIT_TEST(testTdf124565); + CPPUNIT_TEST(testTdf126421); + CPPUNIT_TEST(testTdf107394); + CPPUNIT_TEST_SUITE_END(); + +private: + + uno::Reference<uno::XInterface> m_xCalcComponent; +}; + +// tdf#83366 +void ScCopyPasteTest::testCopyPasteXLS() +{ + uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create(::comphelper::getProcessComponentContext()); + CPPUNIT_ASSERT( xDesktop.is() ); + + // create a frame + Reference< frame::XFrame > xTargetFrame = xDesktop->findFrame( "_blank", 0 ); + CPPUNIT_ASSERT( xTargetFrame.is() ); + + // 1. Open the document + ScDocShellRef xDocSh = loadDoc("chartx2.", FORMAT_XLS); + CPPUNIT_ASSERT_MESSAGE("Failed to load chartx2.xls.", xDocSh.is()); + + uno::Reference< frame::XModel2 > xModel2 ( xDocSh->GetModel(), UNO_QUERY ); + CPPUNIT_ASSERT( xModel2.is() ); + + Reference< frame::XController2 > xController = xModel2->createDefaultViewController( xTargetFrame ); + CPPUNIT_ASSERT( xController.is() ); + + // introduce model/view/controller to each other + xController->attachModel( xModel2.get() ); + xModel2->connectController( xController.get() ); + xTargetFrame->setComponent( xController->getComponentWindow(), xController.get() ); + xController->attachFrame( xTargetFrame ); + xModel2->setCurrentController( xController.get() ); + + ScDocument& rDoc = xDocSh->GetDocument(); + + // Get the document controller + ScTabViewShell* pViewShell = xDocSh->GetBestViewShell(false); + CPPUNIT_ASSERT(pViewShell != nullptr); + + // 2. Highlight B2:C5 + ScRange aSrcRange; + ScRefFlags nRes = aSrcRange.Parse("B2:C5", &rDoc, rDoc.GetAddressConvention()); + CPPUNIT_ASSERT_MESSAGE("Failed to parse.", (nRes & ScRefFlags::VALID)); + + ScMarkData aMark(MAXROW, MAXCOL); + aMark.SetMarkArea(aSrcRange); + + pViewShell->GetViewData().GetMarkData().SetMarkArea(aSrcRange); + + // 3. Copy + ScDocument aClipDoc(SCDOCMODE_CLIP); + pViewShell->GetViewData().GetView()->CopyToClip(&aClipDoc, false, false, false, false); + + // 4. Close the document (Ctrl-W) + xDocSh->DoClose(); + + // 5. Create a new Spreadsheet + Sequence < beans::PropertyValue > args(1); + args[0].Name = "Hidden"; + args[0].Value <<= true; + + uno::Reference< lang::XComponent > xComponent = xDesktop->loadComponentFromURL( + "private:factory/scalc", + "_blank", + 0, + args ); + CPPUNIT_ASSERT( xComponent.is() ); + + // Get the document model + SfxObjectShell* pFoundShell = SfxObjectShell::GetShellFromComponent(xComponent); + CPPUNIT_ASSERT_MESSAGE("Failed to access document shell", pFoundShell); + + xDocSh = dynamic_cast<ScDocShell*>(pFoundShell); + CPPUNIT_ASSERT(xDocSh.get() != nullptr); + + // Get the document controller + pViewShell = xDocSh->GetBestViewShell(false); + CPPUNIT_ASSERT(pViewShell != nullptr); + + // 6. Paste + pViewShell->GetViewData().GetView()->PasteFromClip(InsertDeleteFlags::ALL, &aClipDoc); + + xComponent->dispose(); +} + +namespace { + +ScMarkData::MarkedTabsType TabsInRange(const ScRange& r) +{ + ScMarkData::MarkedTabsType aResult; + for (SCTAB i = r.aStart.Tab(); i <= r.aEnd.Tab(); ++i) + aResult.insert(i); + return aResult; +} + +void lcl_copy( const OUString& rSrcRange, const OUString& rDstRange, ScDocument& rDoc, ScTabViewShell* pViewShell ) +{ + ScDocument aClipDoc(SCDOCMODE_CLIP); + + // 1. Copy + ScRange aSrcRange; + ScRefFlags nRes = aSrcRange.Parse(rSrcRange, &rDoc, rDoc.GetAddressConvention()); + CPPUNIT_ASSERT_MESSAGE("Failed to parse.", (nRes & ScRefFlags::VALID)); + pViewShell->GetViewData().GetMarkData().SetMarkArea(aSrcRange); + pViewShell->GetViewData().GetMarkData().SetSelectedTabs(TabsInRange(aSrcRange)); + pViewShell->GetViewData().GetView()->CopyToClip(&aClipDoc, false, false, false, false); + + // 2. Paste + ScRange aDstRange; + nRes = aDstRange.Parse(rDstRange, &rDoc, rDoc.GetAddressConvention()); + CPPUNIT_ASSERT_MESSAGE("Failed to parse.", (nRes & ScRefFlags::VALID)); + pViewShell->GetViewData().GetMarkData().SetMarkArea(aDstRange); + pViewShell->GetViewData().GetMarkData().SetSelectedTabs(TabsInRange(aDstRange)); + pViewShell->GetViewData().GetView()->PasteFromClip(InsertDeleteFlags::ALL, &aClipDoc); +} + +} // anonymous namespace + +void ScCopyPasteTest::testTdf84411() +{ + uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create(::comphelper::getProcessComponentContext()); + CPPUNIT_ASSERT( xDesktop.is() ); + + // create a frame + Reference< frame::XFrame > xTargetFrame = xDesktop->findFrame( "_blank", 0 ); + CPPUNIT_ASSERT( xTargetFrame.is() ); + + // 1. Create spreadsheet + uno::Sequence< beans::PropertyValue > aEmptyArgList; + uno::Reference< lang::XComponent > xComponent = xDesktop->loadComponentFromURL( + "private:factory/scalc", + "_blank", + 0, + aEmptyArgList ); + CPPUNIT_ASSERT( xComponent.is() ); + + // Get the document model + SfxObjectShell* pFoundShell = SfxObjectShell::GetShellFromComponent(xComponent); + CPPUNIT_ASSERT_MESSAGE("Failed to access document shell", pFoundShell); + + ScDocShellRef xDocSh = dynamic_cast<ScDocShell*>(pFoundShell); + CPPUNIT_ASSERT(xDocSh.get() != nullptr); + + uno::Reference< frame::XModel2 > xModel2 ( xDocSh->GetModel(), UNO_QUERY ); + CPPUNIT_ASSERT( xModel2.is() ); + + Reference< frame::XController2 > xController = xModel2->createDefaultViewController( xTargetFrame ); + CPPUNIT_ASSERT( xController.is() ); + + // introduce model/view/controller to each other + xController->attachModel( xModel2.get() ); + xModel2->connectController( xController.get() ); + xTargetFrame->setComponent( xController->getComponentWindow(), xController.get() ); + xController->attachFrame( xTargetFrame ); + xModel2->setCurrentController( xController.get() ); + + ScDocument& rDoc = xDocSh->GetDocument(); + + // Get the document controller + ScTabViewShell* pViewShell = xDocSh->GetBestViewShell(false); + CPPUNIT_ASSERT(pViewShell != nullptr); + + + // 2. Setup data and formulas + for (unsigned int r = 0; r <= 4991; ++r) + for (unsigned int c = 0; c <= 14; ++c) + rDoc.SetValue( ScAddress(c,r,0), (r+1)*(c+1) ); + + rDoc.SetString(ScAddress(15,10000,0), "=AVERAGE(A10001:O10001)"); + rDoc.SetString(ScAddress(16,10000,0), "=MIN(A10001:O10001)"); + rDoc.SetString(ScAddress(17,10000,0), "=MAX(A10001:O10001)"); + + lcl_copy("P10001:R10001", "P10002:R12500", rDoc, pViewShell); + + + // 3. Disable OpenCL + ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>(pFoundShell->GetModel()); + CPPUNIT_ASSERT(pModel != nullptr); + bool bOpenCLState = ScCalcConfig::isOpenCLEnabled(); + pModel->enableOpenCL(false); + CPPUNIT_ASSERT(!ScCalcConfig::isOpenCLEnabled() || ScCalcConfig::getForceCalculationType() == ForceCalculationOpenCL); + pModel->enableAutomaticCalculation(true); + + + // 4. Copy and Paste + lcl_copy("A1:O2500", "A10001:O12500", rDoc, pViewShell); + + lcl_copy("A2501:O5000", "A12501:O15000", rDoc, pViewShell); + + lcl_copy("P10001:R10001", "P12501:R15000", rDoc, pViewShell); + + + // 5. Close the document (Ctrl-W) + pModel->enableOpenCL(bOpenCLState); + xComponent->dispose(); +} + +void ScCopyPasteTest::testTdf124565() +{ + // Create new document + ScDocShell* xDocSh = new ScDocShell( + SfxModelFlags::EMBEDDED_OBJECT | + SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS | + SfxModelFlags::DISABLE_DOCUMENT_RECOVERY); + xDocSh->DoInitNew(); + + uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create(::comphelper::getProcessComponentContext()); + CPPUNIT_ASSERT( xDesktop.is() ); + + Reference< frame::XFrame > xTargetFrame = xDesktop->findFrame( "_blank", 0 ); + CPPUNIT_ASSERT( xTargetFrame.is() ); + + uno::Reference< frame::XModel2 > xModel2 ( xDocSh->GetModel(), UNO_QUERY ); + CPPUNIT_ASSERT( xModel2.is() ); + + Reference< frame::XController2 > xController = xModel2->createDefaultViewController( xTargetFrame ); + CPPUNIT_ASSERT( xController.is() ); + + // introduce model/view/controller to each other + xController->attachModel( xModel2.get() ); + xModel2->connectController( xController.get() ); + xTargetFrame->setComponent( xController->getComponentWindow(), xController.get() ); + xController->attachFrame( xTargetFrame ); + xModel2->setCurrentController( xController.get() ); + + ScDocument& rDoc = xDocSh->GetDocument(); + ScTabViewShell* pViewShell = xDocSh->GetBestViewShell(false); + CPPUNIT_ASSERT(pViewShell != nullptr); + + // Set content and height of first row + rDoc.SetString(ScAddress(0, 0, 0), "Test"); + rDoc.SetRowHeight(0, 0, 500); + rDoc.SetManualHeight(0, 0, 0, true); + + // Copy first row + ScDocument aClipDoc(SCDOCMODE_CLIP); + ScRange aCopyRange(0, 0, 0, aClipDoc.MaxCol(), 0, 0); + pViewShell->GetViewData().GetMarkData().SetMarkArea(aCopyRange); + pViewShell->GetViewData().GetView()->CopyToClip(&aClipDoc, false, false, false, false); + + // Paste to second row + SCTAB nTab = 0; + SCCOL nCol = 0; + SCROW nRow = 1; + + ScRange aPasteRange(nCol, nRow, nTab, aClipDoc.MaxCol(), nRow, nTab); + pViewShell->GetViewData().GetMarkData().SetMarkArea(aPasteRange); + pViewShell->GetViewData().GetView()->PasteFromClip(InsertDeleteFlags::ALL, &aClipDoc); + + // Copy-pasted? + CPPUNIT_ASSERT_EQUAL_MESSAGE("String was not pasted!", OUString("Test"), rDoc.GetString(nCol, nRow, nTab)); + + // And height same as in source? + CPPUNIT_ASSERT_EQUAL_MESSAGE("Row#2 height is invalid!", sal_uInt16(500), rDoc.GetRowHeight(nRow, nTab)); + + CPPUNIT_ASSERT_MESSAGE("Row#2 must be manual height!", rDoc.IsManualRowHeight(nRow, nTab)); + + xDocSh->DoClose(); +} + +void ScCopyPasteTest::testTdf126421() +{ + uno::Reference<frame::XDesktop2> xDesktop + = frame::Desktop::create(::comphelper::getProcessComponentContext()); + CPPUNIT_ASSERT(xDesktop.is()); + + // create a frame + Reference<frame::XFrame> xTargetFrame = xDesktop->findFrame("_blank", 0); + CPPUNIT_ASSERT(xTargetFrame.is()); + + // 1. Create spreadsheet + uno::Sequence<beans::PropertyValue> aEmptyArgList; + uno::Reference<lang::XComponent> xComponent + = xDesktop->loadComponentFromURL("private:factory/scalc", "_blank", 0, aEmptyArgList); + CPPUNIT_ASSERT(xComponent.is()); + + // Get the document model + SfxObjectShell* pFoundShell = SfxObjectShell::GetShellFromComponent(xComponent); + CPPUNIT_ASSERT_MESSAGE("Failed to access document shell", pFoundShell); + + ScDocShellRef xDocSh = dynamic_cast<ScDocShell*>(pFoundShell); + CPPUNIT_ASSERT(xDocSh); + + uno::Reference<frame::XModel2> xModel2(xDocSh->GetModel(), UNO_QUERY); + CPPUNIT_ASSERT(xModel2.is()); + + Reference<frame::XController2> xController = xModel2->createDefaultViewController(xTargetFrame); + CPPUNIT_ASSERT(xController.is()); + + // introduce model/view/controller to each other + xController->attachModel(xModel2.get()); + xModel2->connectController(xController.get()); + xTargetFrame->setComponent(xController->getComponentWindow(), xController.get()); + xController->attachFrame(xTargetFrame); + xModel2->setCurrentController(xController.get()); + + ScDocument& rDoc = xDocSh->GetDocument(); + + // Get the document controller + ScTabViewShell* pViewShell = xDocSh->GetBestViewShell(false); + CPPUNIT_ASSERT(pViewShell != nullptr); + + // 2. Setup data + for (int r = 0; r < 2; ++r) + for (int c = 0; c < 1024; ++c) + rDoc.SetValue(c, r, 0, (c + 1) * 100 + (r + 1)); + + const SCTAB n2ndTab = rDoc.GetMaxTableNumber() + 1; + rDoc.MakeTable(n2ndTab); + const auto aTabNames = rDoc.GetAllTableNames(); + + lcl_copy(aTabNames[0] + ".A1:AMJ2", aTabNames[n2ndTab] + ".A1:AMJ2", rDoc, pViewShell); + + // 3. Check all cells in destination table + for (int r = 0; r < 2; ++r) + for (int c = 0; c < 1024; ++c) + CPPUNIT_ASSERT_EQUAL(double((c + 1) * 100 + (r + 1)), rDoc.GetValue(c, r, n2ndTab)); + + xDocSh->DoClose(); +} + +void ScCopyPasteTest::testTdf107394() +{ + uno::Reference<frame::XDesktop2> xDesktop + = frame::Desktop::create(::comphelper::getProcessComponentContext()); + CPPUNIT_ASSERT(xDesktop.is()); + + uno::Reference<lang::XComponent> xComponent + = xDesktop->loadComponentFromURL("private:factory/scalc", "_blank", 0, {}); + CPPUNIT_ASSERT(xComponent.is()); + + auto pModelObj = dynamic_cast<ScModelObj*>(xComponent.get()); + CPPUNIT_ASSERT(pModelObj); + CPPUNIT_ASSERT(pModelObj->GetDocument()); + + ScDocument& rDoc = *pModelObj->GetDocument(); + + sal_uInt16 nFirstRowHeight = rDoc.GetRowHeight(0, 0); + sal_uInt16 nSecondRowHeight = rDoc.GetRowHeight(1, 0); + CPPUNIT_ASSERT_EQUAL(nFirstRowHeight, nSecondRowHeight); + + // Import values to A1:A2. + ScImportExport aObj(&rDoc, ScAddress(0,0,0)); + aObj.SetImportBroadcast(true); + + OString aHTML("<pre>First\nVery long sentence.</pre>"); + SvMemoryStream aStream; + aStream.WriteOString(aHTML); + aStream.Seek(0); + CPPUNIT_ASSERT(aObj.ImportStream(aStream, OUString(), SotClipboardFormatId::HTML)); + + CPPUNIT_ASSERT_EQUAL(OUString("First"), rDoc.GetString(ScAddress(0,0,0))); + CPPUNIT_ASSERT_EQUAL(OUString("Very long sentence."), rDoc.GetString(ScAddress(0,1,0))); + + nFirstRowHeight = rDoc.GetRowHeight(0, 0); + nSecondRowHeight = rDoc.GetRowHeight(1, 0); + CPPUNIT_ASSERT_GREATER(nFirstRowHeight, nSecondRowHeight); + + // Undo, and check the result. + SfxUndoManager* pUndoMgr = rDoc.GetUndoManager(); + CPPUNIT_ASSERT_MESSAGE("Failed to get the undo manager.", pUndoMgr); + pUndoMgr->Undo(); + + CPPUNIT_ASSERT(rDoc.GetString(ScAddress(0,0,0)).isEmpty()); + CPPUNIT_ASSERT(rDoc.GetString(ScAddress(0,1,0)).isEmpty()); + + nFirstRowHeight = rDoc.GetRowHeight(0, 0); + nSecondRowHeight = rDoc.GetRowHeight(1, 0); + // Without the accompanying fix in place, this test would have failed: + // - Expected: 256 + // - Actual : 477 + // i.e. the increased height of the second row remained after undo. + CPPUNIT_ASSERT_EQUAL(nFirstRowHeight, nSecondRowHeight); + + xComponent->dispose(); +} + +ScCopyPasteTest::ScCopyPasteTest() + : ScBootstrapFixture( "sc/qa/unit/data" ) +{ +} + +void ScCopyPasteTest::setUp() +{ + test::BootstrapFixture::setUp(); + + // This is a bit of a fudge, we do this to ensure that ScGlobals::ensure, + // which is a private symbol to us, gets called + m_xCalcComponent = + getMultiServiceFactory()->createInstance("com.sun.star.comp.Calc.SpreadsheetDocument"); + CPPUNIT_ASSERT_MESSAGE("no calc component!", m_xCalcComponent.is()); +} + +void ScCopyPasteTest::tearDown() +{ + uno::Reference< lang::XComponent >( m_xCalcComponent, UNO_QUERY_THROW )->dispose(); + test::BootstrapFixture::tearDown(); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(ScCopyPasteTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |