1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
10 #include <officecfg/Office/Common.hxx>
11 #include "sdmodeltestbase.hxx"
13 #include <com/sun/star/uno/Reference.hxx>
15 #include <comphelper/processfactory.hxx>
16 #include <com/sun/star/frame/Desktop.hpp>
17 #include <com/sun/star/frame/XModel2.hpp>
19 #include <com/sun/star/awt/Gradient.hpp>
20 #include <com/sun/star/awt/PosSize.hpp>
21 #include <com/sun/star/drawing/FillStyle.hpp>
22 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
23 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
24 #include <com/sun/star/drawing/XDrawPages.hpp>
25 #include <com/sun/star/drawing/XDrawPage.hpp>
26 #include <com/sun/star/drawing/XShapes.hpp>
27 #include <com/sun/star/graphic/XGraphic.hpp>
28 #include <com/sun/star/container/XIndexAccess.hpp>
29 #include <com/sun/star/frame/XLoadable.hpp>
31 #include <vcl/scheduler.hxx>
32 #include <osl/thread.hxx>
33 #include <svx/sdr/table/tablecontroller.hxx>
34 #include <sfx2/request.hxx>
35 #include <svx/svdpagv.hxx>
36 #include <svx/svxids.hrc>
37 #include <editeng/eeitem.hxx>
38 #include <editeng/adjustitem.hxx>
39 #include <editeng/outlobj.hxx>
40 #include <editeng/editobj.hxx>
41 #include <SlideSorterViewShell.hxx>
42 #include <SlideSorter.hxx>
43 #include <controller/SlideSorterController.hxx>
44 #include <controller/SlsClipboard.hxx>
45 #include <controller/SlsPageSelector.hxx>
46 #include <undo/undomanager.hxx>
47 #include <GraphicViewShell.hxx>
50 #include <comphelper/base64.hxx>
51 #include <toolkit/helper/vclunohelper.hxx>
52 #include <LayerTabBar.hxx>
53 #include <vcl/window.hxx>
54 #include <vcl/event.hxx>
55 #include <vcl/keycodes.hxx>
58 using namespace ::com::sun::star
;
60 /// Impress miscellaneous tests.
61 class SdMiscTest
: public SdModelTestBaseXML
67 void testTdf99396TextEdit();
68 void testFillGradient();
71 void testTdf101242_ODF_no_settings();
72 void testTdf101242_ODF_add_settings();
73 void testTdf101242_settings_keep();
74 void testTdf101242_settings_remove();
80 CPPUNIT_TEST_SUITE(SdMiscTest
);
81 CPPUNIT_TEST(testTdf96206
);
82 CPPUNIT_TEST(testTdf96708
);
83 CPPUNIT_TEST(testTdf99396
);
84 CPPUNIT_TEST(testTdf99396TextEdit
);
85 CPPUNIT_TEST(testFillGradient
);
86 CPPUNIT_TEST(testTdf44774
);
87 CPPUNIT_TEST(testTdf38225
);
88 CPPUNIT_TEST(testTdf101242_ODF_no_settings
);
89 CPPUNIT_TEST(testTdf101242_ODF_add_settings
);
90 CPPUNIT_TEST(testTdf101242_settings_keep
);
91 CPPUNIT_TEST(testTdf101242_settings_remove
);
92 CPPUNIT_TEST(testTdf119392
);
93 CPPUNIT_TEST(testTdf67248
);
94 CPPUNIT_TEST(testTdf119956
);
95 CPPUNIT_TEST(testTdf120527
);
96 CPPUNIT_TEST_SUITE_END();
98 virtual void registerNamespaces(xmlXPathContextPtr
& pXmlXPathCtx
) override
100 static const struct { char const * pPrefix
; char const * pURI
; } namespaces
[] =
103 { "config", "urn:oasis:names:tc:opendocument:xmlns:config:1.0"},
104 { "draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" },
105 { "fo", "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" },
106 { "loext", "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" },
107 { "office", "urn:oasis:names:tc:opendocument:xmlns:office:1.0" },
108 { "style", "urn:oasis:names:tc:opendocument:xmlns:style:1.0" },
109 { "svg", "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" },
110 { "text", "urn:oasis:names:tc:opendocument:xmlns:text:1.0" },
112 for (size_t i
= 0; i
< SAL_N_ELEMENTS(namespaces
); ++i
)
114 xmlXPathRegisterNs(pXmlXPathCtx
,
115 reinterpret_cast<xmlChar
const *>(namespaces
[i
].pPrefix
),
116 reinterpret_cast<xmlChar
const *>(namespaces
[i
].pURI
));
121 sd::DrawDocShellRef
Load(const OUString
& rURL
, sal_Int32 nFormat
);
124 sd::DrawDocShellRef
SdMiscTest::Load(const OUString
& rURL
, sal_Int32 nFormat
)
126 uno::Reference
< frame::XDesktop2
> xDesktop
= frame::Desktop::create(::comphelper::getProcessComponentContext());
127 CPPUNIT_ASSERT(xDesktop
.is());
130 uno::Reference
< frame::XFrame
> xTargetFrame
= xDesktop
->findFrame("_blank", 0);
131 CPPUNIT_ASSERT(xTargetFrame
.is());
133 // This ContainerWindow corresponds to the outermost window of a running LibreOffice.
134 // It needs a non-zero size and must be shown. Otherwise visible elements like the
135 // LayerTabBar in Draw have zero size and cannot get mouse events.
136 // The here used size is freely chosen.
137 uno::Reference
<awt::XWindow
> xContainerWindow
= xTargetFrame
->getContainerWindow();
138 CPPUNIT_ASSERT(xContainerWindow
.is());
139 xContainerWindow
->setPosSize(0, 0, 1024, 768, awt::PosSize::SIZE
);
140 VclPtr
<vcl::Window
> pContainerWindow
= VCLUnoHelper::GetWindow(xContainerWindow
);
141 CPPUNIT_ASSERT(pContainerWindow
);
142 pContainerWindow
->Show(true);
144 // 1. Open the document
145 sd::DrawDocShellRef xDocSh
= loadURL(rURL
, nFormat
);
146 CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocSh
.is());
148 uno::Reference
< frame::XModel2
> xModel2(xDocSh
->GetModel(), uno::UNO_QUERY
);
149 CPPUNIT_ASSERT(xModel2
.is());
151 uno::Reference
< frame::XController2
> xController
= xModel2
->createDefaultViewController(xTargetFrame
);
152 CPPUNIT_ASSERT(xController
.is());
154 // introduce model/view/controller to each other
155 xController
->attachModel(xModel2
.get());
156 xModel2
->connectController(xController
.get());
157 xTargetFrame
->setComponent(xController
->getComponentWindow(), xController
.get());
158 xController
->attachFrame(xTargetFrame
);
159 xModel2
->setCurrentController(xController
.get());
161 sd::ViewShell
*pViewShell
= xDocSh
->GetViewShell();
162 CPPUNIT_ASSERT(pViewShell
);
164 // Draw has no slidesorter, Impress never shows a LayerTabBar
165 if (sd::ViewShell::ST_DRAW
== pViewShell
->GetShellType())
167 sd::LayerTabBar
* pLayerTabBar
= static_cast<sd::GraphicViewShell
*>(pViewShell
)->GetLayerTabControl();
168 CPPUNIT_ASSERT(pLayerTabBar
);
169 pLayerTabBar
->StateChanged(StateChangedType::InitShow
);
173 sd::slidesorter::SlideSorterViewShell
* pSSVS
= nullptr;
174 for (int i
= 0; i
< 1000; i
++)
176 // Process all Tasks - slide sorter is created here
177 while (Scheduler::ProcessTaskScheduling());
178 if ((pSSVS
= sd::slidesorter::SlideSorterViewShell::GetSlideSorter(pViewShell
->GetViewShellBase())) != nullptr)
180 osl::Thread::wait(std::chrono::milliseconds(100));
182 CPPUNIT_ASSERT(pSSVS
);
188 void SdMiscTest::testTdf96206()
190 // Copying/pasting slide referring to a non-default master with a text duplicated the master
192 sd::DrawDocShellRef xDocSh
= Load(m_directories
.getURLFromSrc("/sd/qa/unit/data/odp/tdf96206.odp"), ODP
);
193 sd::ViewShell
*pViewShell
= xDocSh
->GetViewShell();
194 auto pSSVS
= sd::slidesorter::SlideSorterViewShell::GetSlideSorter(pViewShell
->GetViewShellBase());
195 auto& rSSController
= pSSVS
->GetSlideSorter().GetController();
197 const sal_uInt16 nMasterPageCnt1
= xDocSh
->GetDoc()->GetMasterSdPageCount(PageKind::Standard
);
198 CPPUNIT_ASSERT_EQUAL(sal_uInt16(2), nMasterPageCnt1
);
199 rSSController
.GetClipboard().DoCopy();
200 rSSController
.GetClipboard().DoPaste();
201 const sal_uInt16 nMasterPageCnt2
= xDocSh
->GetDoc()->GetMasterSdPageCount(PageKind::Standard
);
202 CPPUNIT_ASSERT_EQUAL(nMasterPageCnt1
, nMasterPageCnt2
);
207 void SdMiscTest::testTdf96708()
209 sd::DrawDocShellRef xDocSh
= Load(m_directories
.getURLFromSrc("/sd/qa/unit/data/odp/tdf96708.odp"), ODP
);
210 sd::ViewShell
*pViewShell
= xDocSh
->GetViewShell();
211 auto pSSVS
= sd::slidesorter::SlideSorterViewShell::GetSlideSorter(pViewShell
->GetViewShellBase());
212 auto& rSSController
= pSSVS
->GetSlideSorter().GetController();
213 auto& rPageSelector
= rSSController
.GetPageSelector();
215 const sal_uInt16 nMasterPageCnt1
= xDocSh
->GetDoc()->GetMasterSdPageCount(PageKind::Standard
);
216 CPPUNIT_ASSERT_EQUAL(sal_uInt16(4), nMasterPageCnt1
);
217 rPageSelector
.SelectAllPages();
218 rSSController
.GetClipboard().DoCopy();
220 // Now wait for timers to trigger creation of auto-layout
221 osl::Thread::wait(std::chrono::milliseconds(100));
222 Scheduler::ProcessTaskScheduling();
224 rSSController
.GetClipboard().DoPaste();
225 const sal_uInt16 nMasterPageCnt2
= xDocSh
->GetDoc()->GetMasterSdPageCount(PageKind::Standard
);
226 CPPUNIT_ASSERT_EQUAL(nMasterPageCnt1
, nMasterPageCnt2
);
231 void SdMiscTest::testTdf99396()
233 // Load the document and select the table.
234 sd::DrawDocShellRef xDocSh
= Load(m_directories
.getURLFromSrc("/sd/qa/unit/data/tdf99396.odp"), ODP
);
235 sd::ViewShell
*pViewShell
= xDocSh
->GetViewShell();
236 SdPage
* pPage
= pViewShell
->GetActualPage();
237 SdrObject
* pObject
= pPage
->GetObj(0);
238 SdrView
* pView
= pViewShell
->GetView();
239 pView
->MarkObj(pObject
, pView
->GetSdrPageView());
241 // Make sure that the undo stack is empty.
242 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), xDocSh
->GetDoc()->GetUndoManager()->GetUndoActionCount());
244 // Set the vertical alignment of the cells to bottom.
245 sdr::table::SvxTableController
* pTableController
= dynamic_cast<sdr::table::SvxTableController
*>(pView
->getSelectionController().get());
246 CPPUNIT_ASSERT(pTableController
);
247 SfxRequest
aRequest(pViewShell
->GetViewFrame(), SID_TABLE_VERT_BOTTOM
);
248 pTableController
->Execute(aRequest
);
249 // This was 0, it wasn't possible to undo a vertical alignment change.
250 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), xDocSh
->GetDoc()->GetUndoManager()->GetUndoActionCount());
255 void SdMiscTest::testTdf99396TextEdit()
257 // Load the document and select the table.
258 sd::DrawDocShellRef xDocSh
= Load(m_directories
.getURLFromSrc("/sd/qa/unit/data/tdf99396.odp"), ODP
);
259 sd::ViewShell
* pViewShell
= xDocSh
->GetViewShell();
260 SdPage
* pPage
= pViewShell
->GetActualPage();
261 auto pTableObject
= dynamic_cast<sdr::table::SdrTableObj
*>(pPage
->GetObj(0));
262 CPPUNIT_ASSERT(pTableObject
);
263 SdrView
* pView
= pViewShell
->GetView();
264 pView
->MarkObj(pTableObject
, pView
->GetSdrPageView());
266 // Make sure that the undo stack is empty.
267 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), xDocSh
->GetDoc()->GetUndoManager()->GetUndoActionCount());
269 // Set horizontal and vertical adjustment during text edit.
270 pView
->SdrBeginTextEdit(pTableObject
);
271 CPPUNIT_ASSERT(pView
->GetTextEditObject());
273 SfxRequest
aRequest(pViewShell
->GetViewFrame(), SID_ATTR_PARA_ADJUST_RIGHT
);
274 SfxItemSet
aEditAttr(xDocSh
->GetDoc()->GetPool());
275 pView
->GetAttributes(aEditAttr
);
276 SfxItemSet
aNewAttr(*(aEditAttr
.GetPool()), aEditAttr
.GetRanges());
277 aNewAttr
.Put(SvxAdjustItem(SvxAdjust::Right
, EE_PARA_JUST
));
278 aRequest
.Done(aNewAttr
);
279 const SfxItemSet
* pArgs
= aRequest
.GetArgs();
280 pView
->SetAttributes(*pArgs
);
283 auto pTableController
= dynamic_cast<sdr::table::SvxTableController
*>(pView
->getSelectionController().get());
284 CPPUNIT_ASSERT(pTableController
);
285 SfxRequest
aRequest(pViewShell
->GetViewFrame(), SID_TABLE_VERT_BOTTOM
);
286 pTableController
->Execute(aRequest
);
288 pView
->SdrEndTextEdit();
290 // Check that the result is what we expect.
292 uno::Reference
<table::XTable
> xTable
= pTableObject
->getTable();
293 uno::Reference
<beans::XPropertySet
> xCell(xTable
->getCellByPosition(0, 0), uno::UNO_QUERY
);
294 drawing::TextVerticalAdjust eAdjust
= xCell
->getPropertyValue("TextVerticalAdjust").get
<drawing::TextVerticalAdjust
>();
295 CPPUNIT_ASSERT_EQUAL(int(drawing::TextVerticalAdjust_BOTTOM
), static_cast<int>(eAdjust
));
298 const EditTextObject
& rEdit
= pTableObject
->getText(0)->GetOutlinerParaObject()->GetTextObject();
299 const SfxItemSet
& rParaAttribs
= rEdit
.GetParaAttribs(0);
300 auto pAdjust
= rParaAttribs
.GetItem(EE_PARA_JUST
);
301 CPPUNIT_ASSERT_EQUAL(SvxAdjust::Right
, pAdjust
->GetAdjust());
305 xDocSh
->GetUndoManager()->Undo();
307 // Check again that the result is what we expect.
309 uno::Reference
<table::XTable
> xTable
= pTableObject
->getTable();
310 uno::Reference
<beans::XPropertySet
> xCell(xTable
->getCellByPosition(0, 0), uno::UNO_QUERY
);
311 drawing::TextVerticalAdjust eAdjust
= xCell
->getPropertyValue("TextVerticalAdjust").get
<drawing::TextVerticalAdjust
>();
312 // This failed: Undo() did not change it from drawing::TextVerticalAdjust_BOTTOM.
313 CPPUNIT_ASSERT_EQUAL(int(drawing::TextVerticalAdjust_TOP
), static_cast<int>(eAdjust
));
316 const EditTextObject
& rEdit
= pTableObject
->getText(0)->GetOutlinerParaObject()->GetTextObject();
317 const SfxItemSet
& rParaAttribs
= rEdit
.GetParaAttribs(0);
318 auto pAdjust
= rParaAttribs
.GetItem(EE_PARA_JUST
);
319 CPPUNIT_ASSERT_EQUAL(SvxAdjust::Center
, pAdjust
->GetAdjust());
324 * now test tdf#103950 - Undo does not revert bundled font size changes for table cells
326 pTableObject
= dynamic_cast<sdr::table::SdrTableObj
*>(pPage
->GetObj(0));
327 pView
->MarkObj(pTableObject
, pView
->GetSdrPageView()); // select table
329 SfxRequest
aRequest(pViewShell
->GetViewFrame(), SID_GROW_FONT_SIZE
);
330 static_cast<sd::DrawViewShell
*>(pViewShell
)->ExecChar(aRequest
);
332 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), xDocSh
->GetDoc()->GetUndoManager()->GetUndoActionCount());
338 void SdMiscTest::testFillGradient()
340 ::sd::DrawDocShellRef xDocShRef
= new ::sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED
, false, DocumentType::Impress
);
341 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier
= getDoc( xDocShRef
);
342 uno::Reference
<drawing::XDrawPages
> xDrawPages
= xDrawPagesSupplier
->getDrawPages();
343 // Insert a new page.
344 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPages
->insertNewByIndex(0), uno::UNO_SET_THROW
);
345 uno::Reference
<drawing::XShapes
> xShapes(xDrawPage
,uno::UNO_QUERY_THROW
);
346 uno::Reference
<lang::XMultiServiceFactory
> const xDoc(xDocShRef
->GetDoc()->getUnoModel(), uno::UNO_QUERY
);
347 // Create a rectangle
348 uno::Reference
<drawing::XShape
> xShape1(xDoc
->createInstance("com.sun.star.drawing.RectangleShape"),uno::UNO_QUERY_THROW
);
349 uno::Reference
<beans::XPropertySet
> xPropSet(xShape1
, uno::UNO_QUERY_THROW
);
350 // Set FillStyle and FillGradient
351 awt::Gradient aGradient
;
352 aGradient
.StartColor
= sal_Int32(Color(255, 0, 0));
353 aGradient
.EndColor
= sal_Int32(Color(0, 255, 0));
354 xPropSet
->setPropertyValue("FillStyle", uno::makeAny(drawing::FillStyle_GRADIENT
));
355 xPropSet
->setPropertyValue("FillGradient", uno::makeAny(aGradient
));
356 // Add the rectangle to the page.
357 xShapes
->add(xShape1
);
359 // Retrieve the shape and check FillStyle and FillGradient
360 uno::Reference
<container::XIndexAccess
> xIndexAccess(xDrawPage
, uno::UNO_QUERY_THROW
);
361 uno::Reference
<beans::XPropertySet
> xPropSet2(xIndexAccess
->getByIndex(0), uno::UNO_QUERY_THROW
);
362 drawing::FillStyle eFillStyle
;
363 awt::Gradient aGradient2
;
364 CPPUNIT_ASSERT(xPropSet2
->getPropertyValue("FillStyle") >>= eFillStyle
);
365 CPPUNIT_ASSERT_EQUAL(int(drawing::FillStyle_GRADIENT
), static_cast<int>(eFillStyle
));
366 CPPUNIT_ASSERT(xPropSet2
->getPropertyValue("FillGradient") >>= aGradient2
);
367 CPPUNIT_ASSERT_EQUAL(sal_Int32(Color(255, 0, 0)),aGradient2
.StartColor
);
368 CPPUNIT_ASSERT_EQUAL(sal_Int32(Color(0, 255, 0)),aGradient2
.EndColor
);
370 xDocShRef
->DoClose();
373 void SdMiscTest::testTdf44774()
375 sd::DrawDocShellRef xDocShRef
= new sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED
, false,
377 const uno::Reference
<frame::XLoadable
> xLoadable(xDocShRef
->GetModel(), uno::UNO_QUERY_THROW
);
378 xLoadable
->initNew();
379 SfxStyleSheetBasePool
* pSSPool
= xDocShRef
->GetStyleSheetPool();
381 // Create a new style with an empty name, like what happens in UI when creating a new style
382 SfxStyleSheetBase
& rStyleA
= pSSPool
->Make("", SfxStyleFamily::Para
, SfxStyleSearchBits::UserDefined
);
383 // Assign a new name, which does not yet set its ApiName
384 rStyleA
.SetName("StyleA");
385 // Create another style
386 SfxStyleSheetBase
& rStyleB
= pSSPool
->Make("StyleB", SfxStyleFamily::Para
, SfxStyleSearchBits::UserDefined
);
387 // ... and set its parent to the first one
388 rStyleB
.SetParent("StyleA");
390 // Now save the file and reload
391 xDocShRef
= saveAndReload(xDocShRef
.get(), ODG
);
392 pSSPool
= xDocShRef
->GetStyleSheetPool();
394 SfxStyleSheetBase
* pStyle
= pSSPool
->Find("StyleB", SfxStyleFamily::Para
);
395 CPPUNIT_ASSERT(pStyle
);
396 // The parent set in StyleB used to reset, because parent style's msApiName was empty
397 CPPUNIT_ASSERT_EQUAL(OUString("StyleA"), pStyle
->GetParent());
399 xDocShRef
->DoClose();
402 void SdMiscTest::testTdf38225()
404 sd::DrawDocShellRef xDocShRef
= new sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED
, false,
406 const uno::Reference
<frame::XLoadable
> xLoadable(xDocShRef
->GetModel(), uno::UNO_QUERY_THROW
);
407 xLoadable
->initNew();
408 SfxStyleSheetBasePool
* pSSPool
= xDocShRef
->GetStyleSheetPool();
410 // Create a new style with a name
411 pSSPool
->Make("StyleWithName1", SfxStyleFamily::Para
, SfxStyleSearchBits::UserDefined
);
413 // Now save the file and reload
414 xDocShRef
= saveAndReload(xDocShRef
.get(), ODG
);
415 pSSPool
= xDocShRef
->GetStyleSheetPool();
417 SfxStyleSheetBase
* pStyle
= pSSPool
->Find("StyleWithName1", SfxStyleFamily::Para
);
418 CPPUNIT_ASSERT(pStyle
);
421 CPPUNIT_ASSERT(pStyle
->SetName("StyleWithName2"));
423 // Save the file and reload again
424 xDocShRef
= saveAndReload(xDocShRef
.get(), ODG
);
425 pSSPool
= xDocShRef
->GetStyleSheetPool();
427 // The problem was that the style kept the old name upon reloading
428 pStyle
= pSSPool
->Find("StyleWithName1", SfxStyleFamily::Para
);
429 CPPUNIT_ASSERT(!pStyle
);
430 pStyle
= pSSPool
->Find("StyleWithName2", SfxStyleFamily::Para
);
431 CPPUNIT_ASSERT(pStyle
);
433 xDocShRef
->DoClose();
436 void SdMiscTest::testTdf120527()
438 sd::DrawDocShellRef xDocShRef
439 = new sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED
, false, DocumentType::Draw
);
440 uno::Reference
<frame::XLoadable
> xLoadable(xDocShRef
->GetModel(), uno::UNO_QUERY
);
441 CPPUNIT_ASSERT(xLoadable
.is());
442 xLoadable
->initNew();
444 // Load a bitmap into the bitmap table.
445 uno::Reference
<lang::XMultiServiceFactory
> xFactory(xDocShRef
->GetModel(), uno::UNO_QUERY
);
446 CPPUNIT_ASSERT(xFactory
.is());
447 uno::Reference
<container::XNameContainer
> xBitmaps(
448 xFactory
->createInstance("com.sun.star.drawing.BitmapTable"), uno::UNO_QUERY
);
449 CPPUNIT_ASSERT(xBitmaps
.is());
450 OUString aGraphicURL
= m_directories
.getURLFromSrc("/sd/qa/unit/data/tdf120527.jpg");
451 xBitmaps
->insertByName("test", uno::makeAny(aGraphicURL
));
454 uno::Reference
<drawing::XShape
> xShape(
455 xFactory
->createInstance("com.sun.star.drawing.GraphicObjectShape"), uno::UNO_QUERY
);
456 CPPUNIT_ASSERT(xShape
.is());
457 uno::Reference
<beans::XPropertySet
> xShapeProperySet(xShape
, uno::UNO_QUERY
);
458 CPPUNIT_ASSERT(xShapeProperySet
.is());
459 xShapeProperySet
->setPropertyValue("GraphicURL", xBitmaps
->getByName("test"));
462 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(xDocShRef
->GetModel(),
464 CPPUNIT_ASSERT(xDrawPagesSupplier
.is());
465 uno::Reference
<drawing::XDrawPages
> xDrawPages
= xDrawPagesSupplier
->getDrawPages();
466 CPPUNIT_ASSERT(xDrawPages
.is());
467 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPages
->getByIndex(0), uno::UNO_QUERY
);
468 CPPUNIT_ASSERT(xDrawPage
.is());
469 // This failed with a lang.IllegalArgumentException.
470 xDrawPage
->add(xShape
);
472 // Verify that the graphic was actually consumed.
473 uno::Reference
<graphic::XGraphic
> xGraphic
;
474 xShapeProperySet
->getPropertyValue("Graphic") >>= xGraphic
;
475 CPPUNIT_ASSERT(xGraphic
.is());
477 xDocShRef
->DoClose();
480 /// Draw miscellaneous tests.
482 // Since LO 6.2 the visible/printable/locked information for layers is always
483 // written as ODF attributes draw:display and draw:protected. It is only read from
484 // there, if the config items VisibleLayers, PrintableLayers and LockedLayers do
485 // not exist. The user option WriteLayerStateAsConfigItem can be set to 'true' to
486 // write these config items in addition to the ODF attributes for to produce
487 // documents for older LO versions or Apache OpenOffice. With value 'false' no
488 // config items are written. The 'testTdf101242_xyz' tests combinate source
489 // files with and without config items with option values 'true' and 'false'.
491 void SdMiscTest::testTdf101242_ODF_add_settings()
493 // Loads a document, which has the visible/printable/locked information for layers
494 // only in the ODF attributes draw:display and draw:protected. The resaved document
495 // should still have the ODF attributes and in addition the config items in settings.xml.
496 // "Load" is needed for to handle layers, simple "loadURL" does not work.
497 sd::DrawDocShellRef xDocShRef
= Load(m_directories
.getURLFromSrc("/sd/qa/unit/data/tdf101242_ODF.odg"), ODG
);
498 CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocShRef
.is());
500 // Saving including items in settings.xml
501 std::shared_ptr
<comphelper::ConfigurationChanges
> pBatch( comphelper::ConfigurationChanges::create() );
502 officecfg::Office::Common::Misc::WriteLayerStateAsConfigItem::set(true, pBatch
);
504 utl::TempFile aTempFile
;
505 aTempFile
.EnableKillingFile();
506 save(xDocShRef
.get(), getFormat(ODG
), aTempFile
);
508 // Verify, that the saved document still has the ODF attributes
509 xmlDocPtr pXmlDoc
= parseExport(aTempFile
, "styles.xml");
510 CPPUNIT_ASSERT_MESSAGE("Failed to get 'styles.xml'", pXmlDoc
);
511 const OString
sPathStart("/office:document-styles/office:master-styles/draw:layer-set/draw:layer");
512 assertXPath(pXmlDoc
, sPathStart
+ "[@draw:name='backgroundobjects' and @draw:protected='true']");
513 assertXPath(pXmlDoc
, sPathStart
+ "[@draw:name='controls' and @draw:display='screen']");
514 assertXPath(pXmlDoc
, sPathStart
+ "[@draw:name='measurelines' and @draw:display='printer']");
516 // Verify, that the saved document has got the items in settings.xml
517 xmlDocPtr pXmlDoc2
= parseExport(aTempFile
, "settings.xml");
518 CPPUNIT_ASSERT_MESSAGE("Failed to get 'settings.xml'", pXmlDoc2
);
519 const OString
sPathStart2("/office:document-settings/office:settings/config:config-item-set[@config:name='ooo:view-settings']/config:config-item-map-indexed[@config:name='Views']/config:config-item-map-entry");
520 // Value is a bitfield with first Byte in order '* * * measurelines controls backgroundobjects background layout'
521 // The first three bits depend on initialization and may change. The values in file are Base64 encoded.
523 uno::Sequence
<sal_Int8
> aDecodedSeq
;
524 sBase64
= getXPathContent(pXmlDoc2
, sPathStart2
+ "/config:config-item[@config:name='VisibleLayers']");
525 CPPUNIT_ASSERT_MESSAGE( "Item VisibleLayers does not exists.", !sBase64
.isEmpty());
526 comphelper::Base64::decode(aDecodedSeq
, sBase64
);
527 CPPUNIT_ASSERT_EQUAL( 0x0F, static_cast<sal_uInt8
>(aDecodedSeq
[0]) & 0x1F );
529 sBase64
= getXPathContent(pXmlDoc2
, sPathStart2
+ "/config:config-item[@config:name='PrintableLayers']");
530 CPPUNIT_ASSERT_MESSAGE( "Item PrintableLayers does not exists.", !sBase64
.isEmpty());
531 comphelper::Base64::decode(aDecodedSeq
, sBase64
);
532 CPPUNIT_ASSERT_EQUAL( 0x17, static_cast<sal_uInt8
>(aDecodedSeq
[0]) & 0x1F);
534 sBase64
= getXPathContent(pXmlDoc2
, sPathStart2
+ "/config:config-item[@config:name='LockedLayers']");
535 CPPUNIT_ASSERT_MESSAGE( "Item LockedLayers does not exists.", !sBase64
.isEmpty());
536 comphelper::Base64::decode(aDecodedSeq
, sBase64
);
537 CPPUNIT_ASSERT_EQUAL( 0x04, static_cast<sal_uInt8
>(aDecodedSeq
[0]) & 0x1F);
539 xDocShRef
->DoClose();
542 void SdMiscTest::testTdf101242_ODF_no_settings()
544 // Loads a document, which has the visible/printable/locked information for layers
545 // only in the ODF attributes draw:display and draw:protected. The resave document
546 // should have only the ODF attributes and no config items in settings.xml.
547 sd::DrawDocShellRef xDocShRef
= Load(m_directories
.getURLFromSrc("/sd/qa/unit/data/tdf101242_ODF.odg"), ODG
);
548 CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocShRef
.is());
550 // Saving without items in settings.xml
551 std::shared_ptr
<comphelper::ConfigurationChanges
> pBatch( comphelper::ConfigurationChanges::create() );
552 officecfg::Office::Common::Misc::WriteLayerStateAsConfigItem::set(false, pBatch
);
554 utl::TempFile aTempFile
;
555 aTempFile
.EnableKillingFile();
556 save(xDocShRef
.get(), getFormat(ODG
), aTempFile
);
558 // Verify, that the saved document still has the ODF attributes
559 xmlDocPtr pXmlDoc
= parseExport(aTempFile
, "styles.xml");
560 CPPUNIT_ASSERT_MESSAGE("Failed to get 'styles.xml'", pXmlDoc
);
561 const OString
sPathStart("/office:document-styles/office:master-styles/draw:layer-set/draw:layer");
562 assertXPath(pXmlDoc
, sPathStart
+ "[@draw:name='backgroundobjects' and @draw:protected='true']");
563 assertXPath(pXmlDoc
, sPathStart
+ "[@draw:name='controls' and @draw:display='screen']");
564 assertXPath(pXmlDoc
, sPathStart
+ "[@draw:name='measurelines' and @draw:display='printer']");
566 // Verify, that the saved document has no layer items in settings.xml
567 xmlDocPtr pXmlDoc2
= parseExport(aTempFile
, "settings.xml");
568 CPPUNIT_ASSERT_MESSAGE("Failed to get 'settings.xml'", pXmlDoc2
);
569 const OString
sPathStart2("/office:document-settings/office:settings/config:config-item-set[@config:name='ooo:view-settings']/config:config-item-map-indexed[@config:name='Views']/config:config-item-map-entry");
570 xmlXPathObjectPtr pXmlObj
=getXPathNode(pXmlDoc2
, sPathStart2
+ "/config:config-item[@config:name='VisibleLayers']");
571 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlObj
->nodesetval
));
572 xmlXPathFreeObject(pXmlObj
);
573 pXmlObj
=getXPathNode(pXmlDoc2
, sPathStart2
+ "/config:config-item[@config:name='PrintableLayers']");
574 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlObj
->nodesetval
));
575 xmlXPathFreeObject(pXmlObj
);
576 pXmlObj
=getXPathNode(pXmlDoc2
, sPathStart2
+ "/config:config-item[@config:name='LockedLayers']");
577 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlObj
->nodesetval
));
578 xmlXPathFreeObject(pXmlObj
);
580 xDocShRef
->DoClose();
583 void SdMiscTest::testTdf101242_settings_keep()
585 // Loads a document, which has the visible/printable/locked information for layers
586 // only in the config items in settings.xml. That is the case for all old documents.
587 // The resaved document should have the ODF attributes draw:display and draw:protected
588 // and should still have these config items in settings.xml.
589 sd::DrawDocShellRef xDocShRef
= Load(m_directories
.getURLFromSrc("/sd/qa/unit/data/tdf101242_settings.odg"), ODG
);
590 CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocShRef
.is());
592 // Saving including items in settings.xml
593 std::shared_ptr
<comphelper::ConfigurationChanges
> pBatch( comphelper::ConfigurationChanges::create() );
594 officecfg::Office::Common::Misc::WriteLayerStateAsConfigItem::set(true, pBatch
);
596 utl::TempFile aTempFile
;
597 aTempFile
.EnableKillingFile();
598 save(xDocShRef
.get(), getFormat(ODG
), aTempFile
);
600 // Verify, that the saved document has the ODF attributes
601 xmlDocPtr pXmlDoc
= parseExport(aTempFile
, "styles.xml");
602 CPPUNIT_ASSERT_MESSAGE("Failed to get 'styles.xml'", pXmlDoc
);
603 const OString
sPathStart("/office:document-styles/office:master-styles/draw:layer-set/draw:layer");
604 assertXPath(pXmlDoc
, sPathStart
+ "[@draw:name='backgroundobjects' and @draw:protected='true']");
605 assertXPath(pXmlDoc
, sPathStart
+ "[@draw:name='controls' and @draw:display='screen']");
606 assertXPath(pXmlDoc
, sPathStart
+ "[@draw:name='measurelines' and @draw:display='printer']");
608 // Verify, that the saved document still has the items in settings.xml
609 xmlDocPtr pXmlDoc2
= parseExport(aTempFile
, "settings.xml");
610 CPPUNIT_ASSERT_MESSAGE("Failed to get 'settings.xml'", pXmlDoc2
);
611 const OString
sPathStart2("/office:document-settings/office:settings/config:config-item-set[@config:name='ooo:view-settings']/config:config-item-map-indexed[@config:name='Views']/config:config-item-map-entry");
612 // Value is a bitfield with first Byte in order '* * * measurelines controls backgroundobjects background layout'
613 // The first three bits depend on initialization and may change. The values in file are Base64 encoded.
615 uno::Sequence
<sal_Int8
> aDecodedSeq
;
616 sBase64
= getXPathContent(pXmlDoc2
, sPathStart2
+ "/config:config-item[@config:name='VisibleLayers']");
617 CPPUNIT_ASSERT_MESSAGE( "Item VisibleLayers does not exists.", !sBase64
.isEmpty());
618 comphelper::Base64::decode(aDecodedSeq
, sBase64
);
619 CPPUNIT_ASSERT_EQUAL( 0x0F, static_cast<sal_uInt8
>(aDecodedSeq
[0]) & 0x1F );
621 sBase64
= getXPathContent(pXmlDoc2
, sPathStart2
+ "/config:config-item[@config:name='PrintableLayers']");
622 CPPUNIT_ASSERT_MESSAGE( "Item PrintableLayers does not exists.", !sBase64
.isEmpty());
623 comphelper::Base64::decode(aDecodedSeq
, sBase64
);
624 CPPUNIT_ASSERT_EQUAL( 0x17, static_cast<sal_uInt8
>(aDecodedSeq
[0]) & 0x1F);
626 sBase64
= getXPathContent(pXmlDoc2
, sPathStart2
+ "/config:config-item[@config:name='LockedLayers']");
627 CPPUNIT_ASSERT_MESSAGE( "Item LockedLayers does not exists.", !sBase64
.isEmpty());
628 comphelper::Base64::decode(aDecodedSeq
, sBase64
);
629 CPPUNIT_ASSERT_EQUAL( 0x04, static_cast<sal_uInt8
>(aDecodedSeq
[0]) & 0x1F);
631 xDocShRef
->DoClose();
634 void SdMiscTest::testTdf101242_settings_remove()
636 // Loads a document, which has the visible/printable/locked information for layers
637 // only in the config items in settings.xml. That is the case for all old documents.
638 // The resaved document should have only the ODF attributes draw:display and draw:protected
639 // and should have no config items in settings.xml.
640 sd::DrawDocShellRef xDocShRef
= Load(m_directories
.getURLFromSrc("/sd/qa/unit/data/tdf101242_settings.odg"), ODG
);
641 CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocShRef
.is());
643 // Saving without config items in settings.xml
644 std::shared_ptr
<comphelper::ConfigurationChanges
> pBatch( comphelper::ConfigurationChanges::create() );
645 officecfg::Office::Common::Misc::WriteLayerStateAsConfigItem::set(false, pBatch
);
647 utl::TempFile aTempFile
;
648 aTempFile
.EnableKillingFile();
649 save(xDocShRef
.get(), getFormat(ODG
), aTempFile
);
651 // Verify, that the saved document has the ODF attributes
652 xmlDocPtr pXmlDoc
= parseExport(aTempFile
, "styles.xml");
653 CPPUNIT_ASSERT_MESSAGE("Failed to get 'styles.xml'", pXmlDoc
);
654 const OString
sPathStart("/office:document-styles/office:master-styles/draw:layer-set/draw:layer");
655 assertXPath(pXmlDoc
, sPathStart
+ "[@draw:name='backgroundobjects' and @draw:protected='true']");
656 assertXPath(pXmlDoc
, sPathStart
+ "[@draw:name='controls' and @draw:display='screen']");
657 assertXPath(pXmlDoc
, sPathStart
+ "[@draw:name='measurelines' and @draw:display='printer']");
659 // Verify, that the saved document has no layer items in settings.xml
660 xmlDocPtr pXmlDoc2
= parseExport(aTempFile
, "settings.xml");
661 CPPUNIT_ASSERT_MESSAGE("Failed to get 'settings.xml'", pXmlDoc2
);
662 const OString
sPathStart2("/office:document-settings/office:settings/config:config-item-set[@config:name='ooo:view-settings']/config:config-item-map-indexed[@config:name='Views']/config:config-item-map-entry");
663 xmlXPathObjectPtr pXmlObj
=getXPathNode(pXmlDoc2
, sPathStart2
+ "/config:config-item[@config:name='VisibleLayers']");
664 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlObj
->nodesetval
));
665 xmlXPathFreeObject(pXmlObj
);
666 pXmlObj
=getXPathNode(pXmlDoc2
, sPathStart2
+ "/config:config-item[@config:name='PrintableLayers']");
667 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlObj
->nodesetval
));
668 xmlXPathFreeObject(pXmlObj
);
669 pXmlObj
=getXPathNode(pXmlDoc2
, sPathStart2
+ "/config:config-item[@config:name='LockedLayers']");
670 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlObj
->nodesetval
));
671 xmlXPathFreeObject(pXmlObj
);
673 xDocShRef
->DoClose();
676 void SdMiscTest::testTdf119392()
678 // Loads a document which has two user layers "V--" and "V-L". Inserts a new layer "-P-" between them.
679 // Checks, that the bitfields in the saved file have the bits in the correct order, in case
680 // option WriteLayerAsConfigItem is true and the config items are written.
681 std::shared_ptr
<comphelper::ConfigurationChanges
> batch( comphelper::ConfigurationChanges::create() );
682 officecfg::Office::Common::Misc::WriteLayerStateAsConfigItem::set(true, batch
);
685 sd::DrawDocShellRef xDocShRef
= Load(m_directories
.getURLFromSrc("sd/qa/unit/data/tdf119392_InsertLayer.odg"), ODG
);
686 CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocShRef
.is());
687 // Insert layer "-P-", not visible, printable, not locked
688 SdrView
* pView
= xDocShRef
-> GetViewShell()->GetView();
689 pView
-> InsertNewLayer("-P-", 6); // 0..4 standard layer, 5 layer "V--"
690 SdrPageView
* pPageView
= pView
-> GetSdrPageView();
691 pPageView
-> SetLayerVisible("-P-", false);
692 pPageView
-> SetLayerPrintable("-P-", true);
693 pPageView
-> SetLayerLocked("-P-", false);
694 utl::TempFile aTempFile
;
695 aTempFile
.EnableKillingFile();
696 save(xDocShRef
.get(), getFormat(ODG
), aTempFile
);
698 // Verify correct bit order in bitfield in the config items in settings.xml
699 xmlDocPtr pXmlDoc
= parseExport(aTempFile
, "settings.xml");
700 CPPUNIT_ASSERT_MESSAGE("Failed to get 'settings.xml'", pXmlDoc
);
701 const OString
sPathStart("/office:document-settings/office:settings/config:config-item-set[@config:name='ooo:view-settings']/config:config-item-map-indexed[@config:name='Views']/config:config-item-map-entry");
702 // First Byte is in order 'V-L -P- V-- measurelines controls backgroundobjects background layout'
703 // Bits need to be: visible=10111111=0xbf=191 printable=01011111=0x5f=95 locked=10000000=0x80=128
704 // The values in file are Base64 encoded.
706 uno::Sequence
<sal_Int8
> aDecodedSeq
;
707 sBase64
= getXPathContent(pXmlDoc
, sPathStart
+ "/config:config-item[@config:name='VisibleLayers']");
708 CPPUNIT_ASSERT_MESSAGE( "Item VisibleLayers does not exists.", !sBase64
.isEmpty());
709 comphelper::Base64::decode(aDecodedSeq
, sBase64
);
710 CPPUNIT_ASSERT_EQUAL( 0xbF, static_cast<sal_uInt8
>(aDecodedSeq
[0]) & 0xff); // & 0xff forces unambiguous types for CPPUNIT_ASSERT_EQUAL
712 sBase64
= getXPathContent(pXmlDoc
, sPathStart
+ "/config:config-item[@config:name='PrintableLayers']");
713 CPPUNIT_ASSERT_MESSAGE( "Item PrintableLayers does not exists.", !sBase64
.isEmpty());
714 comphelper::Base64::decode(aDecodedSeq
, sBase64
);
715 CPPUNIT_ASSERT_EQUAL( 0x5f, static_cast<sal_uInt8
>(aDecodedSeq
[0]) & 0xff);
717 sBase64
= getXPathContent(pXmlDoc
, sPathStart
+ "/config:config-item[@config:name='LockedLayers']");
718 CPPUNIT_ASSERT_MESSAGE( "Item LockedLayers does not exists.", !sBase64
.isEmpty());
719 comphelper::Base64::decode(aDecodedSeq
, sBase64
);
720 CPPUNIT_ASSERT_EQUAL( 0x80, static_cast<sal_uInt8
>(aDecodedSeq
[0]) & 0xff);
722 xDocShRef
->DoClose();
725 void SdMiscTest::testTdf67248()
727 // The document tdf67248.odg has been created with a German UI. It has a user layer named "Background".
728 // On opening the user layer must still exists. The error was, that it was merged into the standard
729 // layer "background".
730 sd::DrawDocShellRef xDocShRef
= Load(m_directories
.getURLFromSrc("sd/qa/unit/data/tdf67248.odg"), ODG
);
731 CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocShRef
.is());
732 SdrLayerAdmin
& rLayerAdmin
= xDocShRef
->GetDoc()->GetLayerAdmin();
733 CPPUNIT_ASSERT_EQUAL( sal_uInt16(6), rLayerAdmin
.GetLayerCount());
735 xDocShRef
->DoClose();
738 void SdMiscTest::testTdf119956()
740 sd::DrawDocShellRef xDocShRef
= Load(m_directories
.getURLFromSrc("sd/qa/unit/data/tdf119956.odg"), ODG
);
741 CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocShRef
.is());
742 sd::GraphicViewShell
* pGraphicViewShell
= static_cast<sd::GraphicViewShell
*>(xDocShRef
-> GetViewShell());
743 CPPUNIT_ASSERT(pGraphicViewShell
);
744 sd::LayerTabBar
* pLayerTabBar
= pGraphicViewShell
->GetLayerTabControl();
745 CPPUNIT_ASSERT(pLayerTabBar
);
747 // Alt+Click sets a tab in edit mode, so that you can rename it.
748 // The error was, that Alt+Click on a tab, which was not the current tab, did not set the clicked tab
749 // as current tab. As a result, the entered text was applied to the wrong tab.
751 // The test document has the layer tabs "layout", "controls", "measurelines" and "Layer4" in this order
752 // The "pagePos" is 0, 1, 2, 3
753 // Make sure, that tab "layout" is the current tab.
754 MouseEvent aSyntheticMouseEvent
;
755 if (pLayerTabBar
->GetCurPagePos() != 0)
757 sal_uInt16
nIdOfTabPos0(pLayerTabBar
->GetPageId(0));
758 tools::Rectangle
aTabPos0Rect(pLayerTabBar
->GetPageRect(nIdOfTabPos0
));
759 aSyntheticMouseEvent
= MouseEvent(aTabPos0Rect
.Center(), 1, MouseEventModifiers::SYNTHETIC
, MOUSE_LEFT
, 0);
760 pLayerTabBar
->MouseButtonDown(aSyntheticMouseEvent
);
762 CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), pLayerTabBar
->GetCurPagePos());
764 // Alt+Click on tab "Layer4"
765 sal_uInt16
nIdOfTabPos3(pLayerTabBar
->GetPageId(3));
766 tools::Rectangle
aTabPos3Rect(pLayerTabBar
->GetPageRect(nIdOfTabPos3
));
767 aSyntheticMouseEvent
= MouseEvent(aTabPos3Rect
.Center(), 1, MouseEventModifiers::SYNTHETIC
, MOUSE_LEFT
, KEY_MOD2
);
768 pLayerTabBar
->MouseButtonDown(aSyntheticMouseEvent
);
770 // Make sure, tab 3 is current tab now.
771 CPPUNIT_ASSERT_EQUAL(sal_uInt16(3), pLayerTabBar
->GetCurPagePos());
773 xDocShRef
->DoClose();
776 CPPUNIT_TEST_SUITE_REGISTRATION(SdMiscTest
);
778 CPPUNIT_PLUGIN_IMPLEMENT();
780 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */