Avoid potential negative array index access to cached text.
[LibreOffice.git] / sc / qa / unit / anchor.cxx
blob18daecd23aa102e7279030c9d343449f654fb9c5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <sfx2/dispatch.hxx>
11 #include <svx/svdograf.hxx>
12 #include <svx/svdpage.hxx>
13 #include <test/unoapi_test.hxx>
15 #include <com/sun/star/sheet/XSpreadsheet.hpp>
16 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
17 #include <com/sun/star/text/XText.hpp>
19 #include <attrib.hxx>
20 #include <docsh.hxx>
21 #include <drwlayer.hxx>
22 #include <svx/svdocirc.hxx>
23 #include <vcl/scheduler.hxx>
24 #include <tabvwsh.hxx>
25 #include <undomanager.hxx>
27 #include <sc.hrc>
29 using namespace css;
31 namespace sc_apitest
33 class ScAnchorTest : public UnoApiTest
35 public:
36 ScAnchorTest();
38 void testUndoAnchor();
39 void testTdf76183();
40 void testODFAnchorTypes();
41 void testCopyColumnWithImages();
42 void testCutWithImages();
43 void testTdf121963();
44 void testTdf129552();
45 void testTdf130556();
46 void testTdf134161();
48 CPPUNIT_TEST_SUITE(ScAnchorTest);
49 CPPUNIT_TEST(testUndoAnchor);
50 CPPUNIT_TEST(testTdf76183);
51 CPPUNIT_TEST(testODFAnchorTypes);
52 CPPUNIT_TEST(testCopyColumnWithImages);
53 CPPUNIT_TEST(testCutWithImages);
54 CPPUNIT_TEST(testTdf121963);
55 CPPUNIT_TEST(testTdf129552);
56 CPPUNIT_TEST(testTdf130556);
57 CPPUNIT_TEST(testTdf134161);
58 CPPUNIT_TEST_SUITE_END();
61 ScAnchorTest::ScAnchorTest()
62 : UnoApiTest("sc/qa/unit/data/ods")
66 void ScAnchorTest::testUndoAnchor()
68 loadFromFile(u"document_with_linked_graphic.ods");
70 // Get the document model
71 SfxObjectShell* pFoundShell = SfxObjectShell::GetShellFromComponent(mxComponent);
72 CPPUNIT_ASSERT_MESSAGE("Failed to access document shell", pFoundShell);
74 ScDocShell* pDocSh = dynamic_cast<ScDocShell*>(pFoundShell);
75 CPPUNIT_ASSERT(pDocSh);
77 // Check whether graphic imported well
78 ScDocument& rDoc = pDocSh->GetDocument();
79 ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
80 CPPUNIT_ASSERT(pDrawLayer);
82 const SdrPage* pPage = pDrawLayer->GetPage(0);
83 CPPUNIT_ASSERT(pPage);
85 SdrGrafObj* pObject = dynamic_cast<SdrGrafObj*>(pPage->GetObj(0));
86 CPPUNIT_ASSERT(pObject);
87 CPPUNIT_ASSERT(pObject->IsLinkedGraphic());
89 const GraphicObject& rGraphicObj = pObject->GetGraphicObject(true);
90 CPPUNIT_ASSERT_EQUAL(int(GraphicType::Bitmap), int(rGraphicObj.GetGraphic().GetType()));
91 CPPUNIT_ASSERT_EQUAL(sal_uLong(864900), rGraphicObj.GetGraphic().GetSizeBytes());
93 // Get the document controller
94 ScTabViewShell* pViewShell = pDocSh->GetBestViewShell(false);
95 CPPUNIT_ASSERT(pViewShell);
97 // Get the draw view of the document
98 ScDrawView* pDrawView = pViewShell->GetViewData().GetScDrawView();
99 CPPUNIT_ASSERT(pDrawView);
101 // Select graphic object
102 pDrawView->MarkNextObj();
103 CPPUNIT_ASSERT(pDrawView->AreObjectsMarked());
105 // Set Cell Anchor
106 ScDrawLayer::SetCellAnchoredFromPosition(*pObject, rDoc, 0, false);
107 // Check state
108 ScAnchorType oldType = ScDrawLayer::GetAnchorType(*pObject);
109 CPPUNIT_ASSERT_EQUAL(SCA_CELL, oldType);
111 // Change all selected objects to page anchor
112 pViewShell->GetViewData().GetDispatcher().Execute(SID_ANCHOR_PAGE);
113 // Check state
114 ScAnchorType newType = ScDrawLayer::GetAnchorType(*pObject);
115 CPPUNIT_ASSERT_EQUAL(SCA_PAGE, newType);
117 // Undo and check its result.
118 SfxUndoManager* pUndoMgr = rDoc.GetUndoManager();
119 CPPUNIT_ASSERT(pUndoMgr);
120 pUndoMgr->Undo();
122 // Check anchor type
123 CPPUNIT_ASSERT_EQUAL(oldType, ScDrawLayer::GetAnchorType(*pObject));
124 CPPUNIT_ASSERT_EQUAL(int(GraphicType::Bitmap), int(rGraphicObj.GetGraphic().GetType()));
125 CPPUNIT_ASSERT_EQUAL(sal_uLong(864900), rGraphicObj.GetGraphic().GetSizeBytes());
127 pUndoMgr->Redo();
129 // Check anchor type
130 CPPUNIT_ASSERT_EQUAL(newType, ScDrawLayer::GetAnchorType(*pObject));
131 CPPUNIT_ASSERT_EQUAL(int(GraphicType::Bitmap), int(rGraphicObj.GetGraphic().GetType()));
132 CPPUNIT_ASSERT_EQUAL(sal_uLong(864900), rGraphicObj.GetGraphic().GetSizeBytes());
134 ScDrawLayer::SetPageAnchored(*pObject);
135 // Check state
136 oldType = ScDrawLayer::GetAnchorType(*pObject);
137 CPPUNIT_ASSERT_EQUAL(SCA_PAGE, oldType);
139 // Change all selected objects to cell anchor
140 pViewShell->GetViewData().GetDispatcher().Execute(SID_ANCHOR_CELL);
141 // Check state
142 newType = ScDrawLayer::GetAnchorType(*pObject);
143 CPPUNIT_ASSERT_EQUAL(SCA_CELL, newType);
145 pUndoMgr->Undo();
147 // Check anchor type
148 CPPUNIT_ASSERT_EQUAL(oldType, ScDrawLayer::GetAnchorType(*pObject));
149 CPPUNIT_ASSERT_EQUAL(int(GraphicType::Bitmap), int(rGraphicObj.GetGraphic().GetType()));
150 CPPUNIT_ASSERT_EQUAL(sal_uLong(864900), rGraphicObj.GetGraphic().GetSizeBytes());
152 pUndoMgr->Redo();
154 // Check anchor type
155 CPPUNIT_ASSERT_EQUAL(newType, ScDrawLayer::GetAnchorType(*pObject));
156 CPPUNIT_ASSERT_EQUAL(int(GraphicType::Bitmap), int(rGraphicObj.GetGraphic().GetType()));
157 CPPUNIT_ASSERT_EQUAL(sal_uLong(864900), rGraphicObj.GetGraphic().GetSizeBytes());
160 void ScAnchorTest::testTdf76183()
162 mxComponent = loadFromDesktop("private:factory/scalc");
163 SfxObjectShell* pFoundShell = SfxObjectShell::GetShellFromComponent(mxComponent);
164 ScDocShell* pDocSh = dynamic_cast<ScDocShell*>(pFoundShell);
165 ScDocument& rDoc = pDocSh->GetDocument();
166 ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
167 SdrPage* pPage = pDrawLayer->GetPage(0);
169 // Add a circle somewhere below first row.
170 const tools::Rectangle aOrigRect(1000, 1000, 1200, 1200);
171 rtl::Reference<SdrCircObj> pObj = new SdrCircObj(*pDrawLayer, SdrCircKind::Full, aOrigRect);
172 pPage->InsertObject(pObj.get());
173 // Anchor to cell
174 ScDrawLayer::SetCellAnchoredFromPosition(*pObj, rDoc, 0, false);
175 const tools::Rectangle& rNewRect = pObj->GetLogicRect();
177 // Set word wrap to true
178 rDoc.ApplyAttr(0, 0, 0, ScLineBreakCell(true));
179 // Add multi-line text to cell to initiate optimal height change
180 uno::Reference<sheet::XSpreadsheetDocument> xDoc(mxComponent, uno::UNO_QUERY_THROW);
181 uno::Reference<container::XIndexAccess> xIA(xDoc->getSheets(), uno::UNO_QUERY_THROW);
182 uno::Reference<sheet::XSpreadsheet> xSheet(xIA->getByIndex(0), uno::UNO_QUERY_THROW);
183 uno::Reference<text::XText> xText(xSheet->getCellByPosition(0, 0), uno::UNO_QUERY_THROW);
184 xText->setString("first\nsecond\nthird");
186 // The resize of first row must have moved the object down after its anchor cell
187 CPPUNIT_ASSERT(aOrigRect.Top() < rNewRect.Top());
189 pObj.clear();
192 void ScAnchorTest::testODFAnchorTypes()
194 loadFromFile(u"3AnchorTypes.ods");
196 // Get the document model
197 SfxObjectShell* pFoundShell = SfxObjectShell::GetShellFromComponent(mxComponent);
198 CPPUNIT_ASSERT_MESSAGE("Failed to access document shell", pFoundShell);
200 ScDocShell* pDocSh = dynamic_cast<ScDocShell*>(pFoundShell);
201 CPPUNIT_ASSERT(pDocSh);
203 // Check whether graphic imported well
204 ScDocument& rDoc = pDocSh->GetDocument();
205 ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
206 CPPUNIT_ASSERT(pDrawLayer);
208 const SdrPage* pPage = pDrawLayer->GetPage(0);
209 CPPUNIT_ASSERT(pPage);
211 // Check 1st object: Page anchored
212 SdrGrafObj* pObject = dynamic_cast<SdrGrafObj*>(pPage->GetObj(0));
213 CPPUNIT_ASSERT(pObject);
214 ScAnchorType anchorType = ScDrawLayer::GetAnchorType(*pObject);
215 CPPUNIT_ASSERT_EQUAL(SCA_PAGE, anchorType);
217 // Check 2nd object: Cell anchored, resize with cell
218 pObject = dynamic_cast<SdrGrafObj*>(pPage->GetObj(1));
219 CPPUNIT_ASSERT(pObject);
220 anchorType = ScDrawLayer::GetAnchorType(*pObject);
221 CPPUNIT_ASSERT_EQUAL(SCA_CELL_RESIZE, anchorType);
223 // Check 3rd object: Cell anchored
224 pObject = dynamic_cast<SdrGrafObj*>(pPage->GetObj(2));
225 CPPUNIT_ASSERT(pObject);
226 anchorType = ScDrawLayer::GetAnchorType(*pObject);
227 CPPUNIT_ASSERT_EQUAL(SCA_CELL, anchorType);
230 /// Test that copying a column with an image anchored to it also copies the image
231 void ScAnchorTest::testCopyColumnWithImages()
233 loadFromFile(u"3AnchorTypes.ods");
235 // Get the document model
236 SfxObjectShell* pFoundShell = SfxObjectShell::GetShellFromComponent(mxComponent);
237 CPPUNIT_ASSERT_MESSAGE("Failed to access document shell", pFoundShell);
239 ScDocShell* pDocSh = dynamic_cast<ScDocShell*>(pFoundShell);
240 CPPUNIT_ASSERT(pDocSh);
242 ScDocument* pDoc = &(pDocSh->GetDocument());
243 ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
244 CPPUNIT_ASSERT(pDrawLayer);
246 // Get the document controller
247 ScTabViewShell* pViewShell = pDocSh->GetBestViewShell(false);
248 CPPUNIT_ASSERT(pViewShell != nullptr);
250 ScDocument aClipDoc(SCDOCMODE_CLIP);
252 // Copy whole column
254 // 1. Copy source range
255 ScRange aSrcRange;
256 aSrcRange.Parse("A1:A11", *pDoc, pDoc->GetAddressConvention());
257 pViewShell->GetViewData().GetMarkData().SetMarkArea(aSrcRange);
258 pViewShell->GetViewData().GetView()->CopyToClip(&aClipDoc, false, false, true, false);
260 // 2. Paste to target range
261 ScRange aDstRange;
262 aDstRange.Parse("D1:D11", *pDoc, pDoc->GetAddressConvention());
263 pViewShell->GetViewData().GetMarkData().SetMarkArea(aDstRange);
264 pViewShell->GetViewData().GetView()->PasteFromClip(InsertDeleteFlags::ALL, &aClipDoc);
266 // 3. Make sure the images have been copied too
267 std::map<SCROW, std::vector<SdrObject*>> aRowObjects
268 = pDrawLayer->GetObjectsAnchoredToRange(0, 3, 0, 11);
269 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be an image anchored to D3", 1,
270 static_cast<int>(aRowObjects[2].size()));
271 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be an image anchored to D11", 1,
272 static_cast<int>(aRowObjects[10].size()));
275 // Copy individual cells
277 // 1. Copy source cells
278 ScRange aSrcRange;
279 aSrcRange.Parse("A3:B3", *pDoc, pDoc->GetAddressConvention());
280 pViewShell->GetViewData().GetMarkData().SetMarkArea(aSrcRange);
281 pViewShell->GetViewData().GetView()->CopyToClip(&aClipDoc, false, false, true, false);
283 // 2. Paste to target cells
284 ScRange aDstRange;
285 aDstRange.Parse("G3:H3", *pDoc, pDoc->GetAddressConvention());
286 pViewShell->GetViewData().GetMarkData().SetMarkArea(aDstRange);
287 pViewShell->GetViewData().GetView()->PasteFromClip(InsertDeleteFlags::ALL, &aClipDoc);
289 // 3. Make sure the image has been copied too
290 std::map<SCROW, std::vector<SdrObject*>> aRowObjects
291 = pDrawLayer->GetObjectsAnchoredToRange(0, 6, 2, 2);
292 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be an image anchored to G3", 1,
293 static_cast<int>(aRowObjects[2].size()));
297 void ScAnchorTest::testCutWithImages()
299 loadFromFile(u"3AnchorTypes.ods");
300 // open the document with graphic included
302 // Get the document model
303 SfxObjectShell* pFoundShell = SfxObjectShell::GetShellFromComponent(mxComponent);
304 CPPUNIT_ASSERT_MESSAGE("Failed to access document shell", pFoundShell);
306 ScDocShell* pDocSh = dynamic_cast<ScDocShell*>(pFoundShell);
307 CPPUNIT_ASSERT(pDocSh);
309 ScDocument* pDoc = &(pDocSh->GetDocument());
310 ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
311 CPPUNIT_ASSERT(pDrawLayer);
313 // Get the document controller
314 ScTabViewShell* pViewShell = pDocSh->GetBestViewShell(false);
315 CPPUNIT_ASSERT(pViewShell != nullptr);
317 // Cut whole column
319 // Cut source range
320 ScRange aSrcRange;
321 aSrcRange.Parse("A1:A11", *pDoc, pDoc->GetAddressConvention());
322 pViewShell->GetViewData().GetMarkData().SetMarkArea(aSrcRange);
323 pViewShell->GetViewData().GetView()->CutToClip();
325 std::map<SCROW, std::vector<SdrObject*>> aRowObjects
326 = pDrawLayer->GetObjectsAnchoredToRange(0, 0, 0, 11);
328 // Images should have been removed from the cells
329 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no image anchored to A3", 0,
330 static_cast<int>(aRowObjects[2].size()));
331 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no image anchored to A11", 0,
332 static_cast<int>(aRowObjects[10].size()));
335 // Cut individual cells
337 // Cut source cells
338 ScRange aSrcRange;
339 aSrcRange.Parse("A3:B3", *pDoc, pDoc->GetAddressConvention());
340 pViewShell->GetViewData().GetMarkData().SetMarkArea(aSrcRange);
341 pViewShell->GetViewData().GetView()->CutToClip();
343 // Image should have been removed from the cell
344 std::map<SCROW, std::vector<SdrObject*>> aRowObjects
345 = pDrawLayer->GetObjectsAnchoredToRange(0, 0, 2, 2);
346 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no image anchored to A3", 0,
347 static_cast<int>(aRowObjects[2].size()));
351 void ScAnchorTest::testTdf121963()
353 loadFromFile(u"tdf121963.ods");
355 // Without the accompanying fix in place, this test would have never returned due to an infinite
356 // invalidation loop, where ScGridWindow::Paint() invalidated itself.
357 Scheduler::ProcessEventsToIdle();
360 void ScAnchorTest::testTdf129552()
362 loadFromFile(u"tdf129552.fods");
364 // Without the accompanying fix in place, this test would have never returned due to an infinite
365 // invalidation loop, where ScGridWindow::Paint() invalidated itself.
366 Scheduler::ProcessEventsToIdle();
369 void ScAnchorTest::testTdf130556()
371 loadFromFile(u"tdf130556.ods");
373 // Without the accompanying fix in place, this test would have never returned due to an infinite
374 // invalidation loop, where ScGridWindow::Paint() invalidated itself.
375 Scheduler::ProcessEventsToIdle();
378 void ScAnchorTest::testTdf134161()
380 loadFromFile(u"tdf134161.ods");
382 // Without the accompanying fix in place, this test would have never returned due to an infinite
383 // invalidation loop
384 Scheduler::ProcessEventsToIdle();
387 CPPUNIT_TEST_SUITE_REGISTRATION(ScAnchorTest);
390 CPPUNIT_PLUGIN_IMPLEMENT();
392 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */