Bug Summary

File:home/maarten/src/libreoffice/core/sd/source/ui/animations/CustomAnimationPane.cxx
Warning:line 2545, column 5
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name CustomAnimationPane.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -isystem /usr/include/dbus-1.0 -isystem /usr/lib64/dbus-1.0/include -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SD_DLLIMPLEMENTATION -D SDUI_DLL_NAME="libsduilo.so" -D SYSTEM_LIBXML -D ENABLE_SDREMOTE -D ENABLE_SDREMOTE_BLUETOOTH -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/external/bluez_bluetooth/inc -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/sd/inc -I /home/maarten/src/libreoffice/core/sd/source/ui/inc -I /home/maarten/src/libreoffice/core/sd/source/ui/slidesorter/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sd/sdi -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/oox/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sd/source/ui/animations/CustomAnimationPane.cxx

/home/maarten/src/libreoffice/core/sd/source/ui/animations/CustomAnimationPane.cxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <com/sun/star/presentation/EffectPresetClass.hpp>
21#include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
22#include <com/sun/star/animations/AnimationNodeType.hpp>
23#include <com/sun/star/animations/ParallelTimeContainer.hpp>
24#include <com/sun/star/view/XSelectionSupplier.hpp>
25#include <com/sun/star/drawing/XDrawView.hpp>
26#include <com/sun/star/drawing/XShape.hpp>
27#include <com/sun/star/beans/XPropertySet.hpp>
28#include <com/sun/star/presentation/EffectNodeType.hpp>
29#include <com/sun/star/presentation/EffectCommands.hpp>
30#include <com/sun/star/animations/AnimationTransformType.hpp>
31#include <com/sun/star/text/XTextRangeCompare.hpp>
32#include <com/sun/star/container/XEnumerationAccess.hpp>
33#include <com/sun/star/container/XIndexAccess.hpp>
34#include <com/sun/star/presentation/ParagraphTarget.hpp>
35#include <com/sun/star/text/XText.hpp>
36#include <com/sun/star/drawing/LineStyle.hpp>
37#include <com/sun/star/drawing/FillStyle.hpp>
38#include <comphelper/processfactory.hxx>
39#include <sfx2/dispatch.hxx>
40#include <sfx2/viewfrm.hxx>
41#include <tools/debug.hxx>
42#include "STLPropertySet.hxx"
43#include "CustomAnimationPane.hxx"
44#include "CustomAnimationDialog.hxx"
45#include "CustomAnimationList.hxx"
46#include "motionpathtag.hxx"
47#include <CustomAnimationPreset.hxx>
48#include <createcustomanimationpanel.hxx>
49
50#include <comphelper/lok.hxx>
51#include <comphelper/sequence.hxx>
52#include <sfx2/frame.hxx>
53#include <sfx2/sidebar/Theme.hxx>
54
55#include <svx/unoapi.hxx>
56#include <svx/svxids.hrc>
57#include <DrawDocShell.hxx>
58#include <ViewShellBase.hxx>
59#include <DrawViewShell.hxx>
60#include <DrawController.hxx>
61#include <sdresid.hxx>
62#include <drawview.hxx>
63#include <slideshow.hxx>
64#include <undoanim.hxx>
65#include <optsitem.hxx>
66#include <sdmod.hxx>
67#include <framework/FrameworkHelper.hxx>
68
69#include <EventMultiplexer.hxx>
70
71#include <strings.hrc>
72#include <sdpage.hxx>
73#include <app.hrc>
74
75#include <svx/strings.hrc>
76#include <svx/dialmgr.hxx>
77
78#include <algorithm>
79#include <memory>
80
81using namespace ::com::sun::star;
82using namespace ::com::sun::star::animations;
83using namespace ::com::sun::star::presentation;
84using namespace ::com::sun::star::text;
85
86using namespace ::com::sun::star::uno;
87using namespace ::com::sun::star::drawing;
88using ::com::sun::star::view::XSelectionSupplier;
89using ::com::sun::star::beans::XPropertySet;
90using ::com::sun::star::container::XIndexAccess;
91using ::com::sun::star::container::XEnumerationAccess;
92using ::com::sun::star::container::XEnumeration;
93using ::com::sun::star::text::XText;
94using ::sd::framework::FrameworkHelper;
95using ::com::sun::star::uno::UNO_QUERY;
96using ::com::sun::star::uno::UNO_QUERY_THROW;
97using ::com::sun::star::uno::Any;
98using ::com::sun::star::uno::Reference;
99using ::com::sun::star::uno::Exception;
100
101namespace sd {
102
103void fillRepeatComboBox(weld::ComboBox& rBox)
104{
105 OUString aNone( SdResId( STR_CUSTOMANIMATION_REPEAT_NONEreinterpret_cast<char const *>("STR_CUSTOMANIMATION_REPEAT_NONE"
"\004" u8"none")
) );
106 rBox.append_text(aNone);
107 rBox.append_text(OUString::number(2));
108 rBox.append_text(OUString::number(3));
109 rBox.append_text(OUString::number(4));
110 rBox.append_text(OUString::number(5));
111 rBox.append_text(OUString::number(10));
112
113 OUString aUntilClick( SdResId( STR_CUSTOMANIMATION_REPEAT_UNTIL_NEXT_CLICKreinterpret_cast<char const *>("STR_CUSTOMANIMATION_REPEAT_UNTIL_NEXT_CLICK"
"\004" u8"Until next click")
) );
114 rBox.append_text(aUntilClick);
115
116 OUString aEndOfSlide( SdResId( STR_CUSTOMANIMATION_REPEAT_UNTIL_END_OF_SLIDEreinterpret_cast<char const *>("STR_CUSTOMANIMATION_REPEAT_UNTIL_END_OF_SLIDE"
"\004" u8"Until end of slide")
) );
117 rBox.append_text(aEndOfSlide);
118}
119
120CustomAnimationPane::CustomAnimationPane( Window* pParent, ViewShellBase& rBase,
121 const css::uno::Reference<css::frame::XFrame>& rxFrame )
122 : PanelLayout(pParent, "CustomAnimationsPanel", "modules/simpress/ui/customanimationspanel.ui", rxFrame)
123 , mrBase(rBase)
124 // load resources
125 , mxFTAnimation(m_xBuilder->weld_label("effectlabel"))
126 , mxCustomAnimationList(new CustomAnimationList(m_xBuilder->weld_tree_view("custom_animation_list"),
127 m_xBuilder->weld_label("custom_animation_label"),
128 m_xBuilder->weld_widget("custom_animation_label_parent")))
129 , mxPBAddEffect(m_xBuilder->weld_button("add_effect"))
130 , mxPBRemoveEffect(m_xBuilder->weld_button("remove_effect"))
131 , mxPBMoveUp(m_xBuilder->weld_button("move_up"))
132 , mxPBMoveDown(m_xBuilder->weld_button("move_down"))
133 , mxFTCategory(m_xBuilder->weld_label("categorylabel"))
134 , mxLBCategory(m_xBuilder->weld_combo_box("categorylb"))
135 , mxFTEffect(m_xBuilder->weld_label("effect_label"))
136 , mxLBAnimation(m_xBuilder->weld_tree_view("effect_list"))
137 , mxFTStart(m_xBuilder->weld_label("start_effect"))
138 , mxLBStart(m_xBuilder->weld_combo_box("start_effect_list"))
139 , mxFTProperty(m_xBuilder->weld_label("effect_property"))
140 , mxPlaceholderBox(m_xBuilder->weld_container("placeholder"))
141 , mxPBPropertyMore(m_xBuilder->weld_button("more_properties"))
142 , mxFTDuration(m_xBuilder->weld_label("effect_duration"))
143 , mxCBXDuration(m_xBuilder->weld_metric_spin_button("anim_duration", FieldUnit::SECOND))
144 , mxFTStartDelay(m_xBuilder->weld_label("delay_label"))
145 , mxMFStartDelay(m_xBuilder->weld_metric_spin_button("delay_value", FieldUnit::SECOND))
146 , mxCBAutoPreview(m_xBuilder->weld_check_button("auto_preview"))
147 , mxPBPlay(m_xBuilder->weld_button("play"))
148 , maIdle("sd idle treeview select")
149 , mnLastSelectedAnimation(-1)
150 , mnPropertyType(nPropertyTypeNone)
151 , mnCurvePathPos(-1)
152 , mnPolygonPathPos(-1)
153 , mnFreeformPathPos(-1)
154 , maLateInitTimer()
155{
156 initialize();
157}
158
159void CustomAnimationPane::initialize()
160{
161 mxLBAnimation->connect_changed(LINK(this, CustomAnimationPane, AnimationSelectHdl)::tools::detail::makeLink( ::tools::detail::castTo<CustomAnimationPane
*>(this), &CustomAnimationPane::LinkStubAnimationSelectHdl
)
);
162 mxCustomAnimationList->setController( dynamic_cast<ICustomAnimationListController*> ( this ) );
163 mxCustomAnimationList->set_size_request(mxCustomAnimationList->get_approximate_digit_width() * 15,
164 mxCustomAnimationList->get_height_rows(8));
165
166 mxLBAnimation->set_size_request(mxLBAnimation->get_approximate_digit_width() * 15,
167 mxLBAnimation->get_height_rows(8));
168
169 maStrProperty = mxFTProperty->get_label();
170
171 mxPBAddEffect->connect_clicked( LINK( this, CustomAnimationPane, implClickHdl )::tools::detail::makeLink( ::tools::detail::castTo<CustomAnimationPane
*>(this), &CustomAnimationPane::LinkStubimplClickHdl)
);
172 mxPBRemoveEffect->connect_clicked( LINK( this, CustomAnimationPane, implClickHdl )::tools::detail::makeLink( ::tools::detail::castTo<CustomAnimationPane
*>(this), &CustomAnimationPane::LinkStubimplClickHdl)
);
173 mxLBStart->connect_changed( LINK( this, CustomAnimationPane, implControlListBoxHdl )::tools::detail::makeLink( ::tools::detail::castTo<CustomAnimationPane
*>(this), &CustomAnimationPane::LinkStubimplControlListBoxHdl
)
);
174 mxCBXDuration->connect_value_changed(LINK( this, CustomAnimationPane, DurationModifiedHdl)::tools::detail::makeLink( ::tools::detail::castTo<CustomAnimationPane
*>(this), &CustomAnimationPane::LinkStubDurationModifiedHdl
)
);
175 mxPBPropertyMore->connect_clicked( LINK( this, CustomAnimationPane, implClickHdl )::tools::detail::makeLink( ::tools::detail::castTo<CustomAnimationPane
*>(this), &CustomAnimationPane::LinkStubimplClickHdl)
);
176 mxPBMoveUp->connect_clicked( LINK( this, CustomAnimationPane, implClickHdl )::tools::detail::makeLink( ::tools::detail::castTo<CustomAnimationPane
*>(this), &CustomAnimationPane::LinkStubimplClickHdl)
);
177 mxPBMoveDown->connect_clicked( LINK( this, CustomAnimationPane, implClickHdl )::tools::detail::makeLink( ::tools::detail::castTo<CustomAnimationPane
*>(this), &CustomAnimationPane::LinkStubimplClickHdl)
);
178 mxPBPlay->connect_clicked( LINK( this, CustomAnimationPane, implClickHdl )::tools::detail::makeLink( ::tools::detail::castTo<CustomAnimationPane
*>(this), &CustomAnimationPane::LinkStubimplClickHdl)
);
179 mxCBAutoPreview->connect_clicked( LINK( this, CustomAnimationPane, implClickHdl )::tools::detail::makeLink( ::tools::detail::castTo<CustomAnimationPane
*>(this), &CustomAnimationPane::LinkStubimplClickHdl)
);
180 mxLBCategory->connect_changed( LINK(this, CustomAnimationPane, UpdateAnimationLB)::tools::detail::makeLink( ::tools::detail::castTo<CustomAnimationPane
*>(this), &CustomAnimationPane::LinkStubUpdateAnimationLB
)
);
181 mxMFStartDelay->connect_value_changed( LINK(this, CustomAnimationPane, DelayModifiedHdl)::tools::detail::makeLink( ::tools::detail::castTo<CustomAnimationPane
*>(this), &CustomAnimationPane::LinkStubDelayModifiedHdl
)
);
182 mxMFStartDelay->connect_focus_out(LINK( this, CustomAnimationPane, DelayLoseFocusHdl)::tools::detail::makeLink( ::tools::detail::castTo<CustomAnimationPane
*>(this), &CustomAnimationPane::LinkStubDelayLoseFocusHdl
)
);
183
184 maIdle.SetPriority(TaskPriority::DEFAULT);
185 maIdle.SetInvokeHandler(LINK(this, CustomAnimationPane, SelectionHandler)::tools::detail::makeLink( ::tools::detail::castTo<CustomAnimationPane
*>(this), &CustomAnimationPane::LinkStubSelectionHandler
)
);
186
187 maStrModify = mxFTEffect->get_label();
188
189 // get current controller and initialize listeners
190 try
191 {
192 mxView.set(mrBase.GetController(), UNO_QUERY);
193 addListener();
194 }
195 catch( Exception& )
196 {
197 OSL_FAIL( "sd::CustomAnimationPane::CustomAnimationPane(), Exception caught!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sd/source/ui/animations/CustomAnimationPane.cxx"
":" "197" ": "), "%s", "sd::CustomAnimationPane::CustomAnimationPane(), Exception caught!"
); } } while (false)
;
198 }
199
200 // get current page and update custom animation list
201 onChangeCurrentPage();
202
203 // Wait a short time before the presets list is created. This gives the
204 // system time to paint the control.
205 maLateInitTimer.SetTimeout(100);
206 maLateInitTimer.SetInvokeHandler(LINK(this, CustomAnimationPane, lateInitCallback)::tools::detail::makeLink( ::tools::detail::castTo<CustomAnimationPane
*>(this), &CustomAnimationPane::LinkStublateInitCallback
)
);
207 maLateInitTimer.Start();
208 UpdateLook();
209}
210
211CustomAnimationPane::~CustomAnimationPane()
212{
213 disposeOnce();
214}
215
216void CustomAnimationPane::dispose()
217{
218 maLateInitTimer.Stop();
219
220 removeListener();
221
222 MotionPathTagVector aTags;
223 aTags.swap( maMotionPathTags );
224 for (auto const& tag : aTags)
225 tag->Dispose();
226
227 mxPBAddEffect.reset();
228 mxPBRemoveEffect.reset();
229 mxFTEffect.reset();
230 mxFTStart.reset();
231 mxLBStart.reset();
232 mxLBSubControl.reset();
233 mxFTProperty.reset();
234 mxPlaceholderBox.reset();
235 mxPBPropertyMore.reset();
236 mxFTDuration.reset();
237 mxCBXDuration.reset();
238 mxFTStartDelay.reset();
239 mxMFStartDelay.reset();
240 mxCustomAnimationList.reset();
241 mxPBMoveUp.reset();
242 mxPBMoveDown.reset();
243 mxPBPlay.reset();
244 mxCBAutoPreview.reset();
245 mxFTCategory.reset();
246 mxLBCategory.reset();
247 mxFTAnimation.reset();
248 mxLBAnimation.reset();
249
250 PanelLayout::dispose();
251}
252
253void CustomAnimationPane::addUndo()
254{
255 SfxUndoManager* pManager = mrBase.GetDocShell()->GetUndoManager();
256 if( pManager )
257 {
258 SdPage* pPage = SdPage::getImplementation( mxCurrentPage );
259 if( pPage )
260 pManager->AddUndoAction( std::make_unique<UndoAnimation>( mrBase.GetDocShell()->GetDoc(), pPage ) );
261 }
262}
263
264void CustomAnimationPane::StateChanged( StateChangedType nStateChange )
265{
266 Control::StateChanged( nStateChange );
267
268 if( nStateChange == StateChangedType::Visible )
269 updateMotionPathTags();
270}
271
272void CustomAnimationPane::KeyInput( const KeyEvent& rKEvt )
273{
274 if (mxCustomAnimationList)
275 mxCustomAnimationList->KeyInputHdl(rKEvt);
276}
277
278void CustomAnimationPane::addListener()
279{
280 Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,CustomAnimationPane,EventMultiplexerListener)::tools::detail::makeLink( ::tools::detail::castTo<CustomAnimationPane
*>(this), &CustomAnimationPane::LinkStubEventMultiplexerListener
)
);
281 mrBase.GetEventMultiplexer()->AddEventListener(aLink);
282}
283
284void CustomAnimationPane::removeListener()
285{
286 Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,CustomAnimationPane,EventMultiplexerListener)::tools::detail::makeLink( ::tools::detail::castTo<CustomAnimationPane
*>(this), &CustomAnimationPane::LinkStubEventMultiplexerListener
)
);
287 mrBase.GetEventMultiplexer()->RemoveEventListener( aLink );
288}
289
290IMPL_LINK(CustomAnimationPane,EventMultiplexerListener,void CustomAnimationPane::LinkStubEventMultiplexerListener(void
* instance, tools::EventMultiplexerEvent& data) { return
static_cast<CustomAnimationPane *>(instance)->EventMultiplexerListener
(data); } void CustomAnimationPane::EventMultiplexerListener(
tools::EventMultiplexerEvent& rEvent)
291 tools::EventMultiplexerEvent&, rEvent, void)void CustomAnimationPane::LinkStubEventMultiplexerListener(void
* instance, tools::EventMultiplexerEvent& data) { return
static_cast<CustomAnimationPane *>(instance)->EventMultiplexerListener
(data); } void CustomAnimationPane::EventMultiplexerListener(
tools::EventMultiplexerEvent& rEvent)
292{
293 switch (rEvent.meEventId)
294 {
295 case EventMultiplexerEventId::EditViewSelection:
296 onSelectionChanged();
297 break;
298
299 case EventMultiplexerEventId::CurrentPageChanged:
300 onChangeCurrentPage();
301 break;
302
303 case EventMultiplexerEventId::MainViewAdded:
304 // At this moment the controller may not yet been set at model
305 // or ViewShellBase. Take it from the view shell passed with
306 // the event.
307 if (mrBase.GetMainViewShell() != nullptr)
308 {
309 if( mrBase.GetMainViewShell()->GetShellType() == ViewShell::ST_IMPRESS )
310 {
311 mxView.set(mrBase.GetDrawController(), UNO_QUERY);
312 onSelectionChanged();
313 onChangeCurrentPage();
314 break;
315 }
316 }
317 [[fallthrough]];
318 case EventMultiplexerEventId::MainViewRemoved:
319 mxView = nullptr;
320 mxCurrentPage = nullptr;
321 updateControls();
322 break;
323
324 case EventMultiplexerEventId::Disposing:
325 mxView.clear();
326 onSelectionChanged();
327 onChangeCurrentPage();
328 break;
329 case EventMultiplexerEventId::EndTextEdit:
330 if (mpMainSequence && rEvent.mpUserData)
331 mxCustomAnimationList->update( mpMainSequence );
332 break;
333 default: break;
334 }
335}
336
337static sal_Int32 getPropertyType( const OUString& rProperty )
338{
339 if ( rProperty == "Direction" )
340 return nPropertyTypeDirection;
341
342 if ( rProperty == "Spokes" )
343 return nPropertyTypeSpokes;
344
345 if ( rProperty == "Zoom" )
346 return nPropertyTypeZoom;
347
348 if ( rProperty == "Accelerate" )
349 return nPropertyTypeAccelerate;
350
351 if ( rProperty == "Decelerate" )
352 return nPropertyTypeDecelerate;
353
354 if ( rProperty == "Color1" )
355 return nPropertyTypeFirstColor;
356
357 if ( rProperty == "Color2" )
358 return nPropertyTypeSecondColor;
359
360 if ( rProperty == "FillColor" )
361 return nPropertyTypeFillColor;
362
363 if ( rProperty == "ColorStyle" )
364 return nPropertyTypeColorStyle;
365
366 if ( rProperty == "AutoReverse" )
367 return nPropertyTypeAutoReverse;
368
369 if ( rProperty == "FontStyle" )
370 return nPropertyTypeFont;
371
372 if ( rProperty == "CharColor" )
373 return nPropertyTypeCharColor;
374
375 if ( rProperty == "CharHeight" )
376 return nPropertyTypeCharHeight;
377
378 if ( rProperty == "CharDecoration" )
379 return nPropertyTypeCharDecoration;
380
381 if ( rProperty == "LineColor" )
382 return nPropertyTypeLineColor;
383
384 if ( rProperty == "Rotate" )
385 return nPropertyTypeRotate;
386
387 if ( rProperty == "Transparency" )
388 return nPropertyTypeTransparency;
389
390 if ( rProperty == "Color" )
391 return nPropertyTypeColor;
392
393 if ( rProperty == "Scale" )
394 return nPropertyTypeScale;
395
396 return nPropertyTypeNone;
397}
398
399OUString getPropertyName( sal_Int32 nPropertyType )
400{
401 switch( nPropertyType )
402 {
403 case nPropertyTypeDirection:
404 return SdResId(STR_CUSTOMANIMATION_DIRECTION_PROPERTYreinterpret_cast<char const *>("STR_CUSTOMANIMATION_DIRECTION_PROPERTY"
"\004" u8"Direction:")
);
405
406 case nPropertyTypeSpokes:
407 return SdResId(STR_CUSTOMANIMATION_SPOKES_PROPERTYreinterpret_cast<char const *>("STR_CUSTOMANIMATION_SPOKES_PROPERTY"
"\004" u8"Spokes:")
);
408
409 case nPropertyTypeFirstColor:
410 return SdResId(STR_CUSTOMANIMATION_FIRST_COLOR_PROPERTYreinterpret_cast<char const *>("STR_CUSTOMANIMATION_FIRST_COLOR_PROPERTY"
"\004" u8"First color:")
);
411
412 case nPropertyTypeSecondColor:
413 return SdResId(STR_CUSTOMANIMATION_SECOND_COLOR_PROPERTYreinterpret_cast<char const *>("STR_CUSTOMANIMATION_SECOND_COLOR_PROPERTY"
"\004" u8"Second color:")
);
414
415 case nPropertyTypeZoom:
416 return SdResId(STR_CUSTOMANIMATION_ZOOM_PROPERTYreinterpret_cast<char const *>("STR_CUSTOMANIMATION_ZOOM_PROPERTY"
"\004" u8"Zoom:")
);
417
418 case nPropertyTypeFillColor:
419 return SdResId(STR_CUSTOMANIMATION_FILL_COLOR_PROPERTYreinterpret_cast<char const *>("STR_CUSTOMANIMATION_FILL_COLOR_PROPERTY"
"\004" u8"Fill color:")
);
420
421 case nPropertyTypeColorStyle:
422 return SdResId(STR_CUSTOMANIMATION_STYLE_PROPERTYreinterpret_cast<char const *>("STR_CUSTOMANIMATION_STYLE_PROPERTY"
"\004" u8"Style:")
);
423
424 case nPropertyTypeFont:
425 return SdResId(STR_CUSTOMANIMATION_FONT_PROPERTYreinterpret_cast<char const *>("STR_CUSTOMANIMATION_FONT_PROPERTY"
"\004" u8"Font:")
);
426
427 case nPropertyTypeCharHeight:
428 return SdResId(STR_CUSTOMANIMATION_SIZE_PROPERTYreinterpret_cast<char const *>("STR_CUSTOMANIMATION_SIZE_PROPERTY"
"\004" u8"Font size:")
);
429
430 case nPropertyTypeCharColor:
431 return SdResId(STR_CUSTOMANIMATION_FONT_COLOR_PROPERTYreinterpret_cast<char const *>("STR_CUSTOMANIMATION_FONT_COLOR_PROPERTY"
"\004" u8"Font color:")
);
432
433 case nPropertyTypeCharHeightStyle:
434 return SdResId(STR_CUSTOMANIMATION_FONT_SIZE_STYLE_PROPERTYreinterpret_cast<char const *>("STR_CUSTOMANIMATION_FONT_SIZE_STYLE_PROPERTY"
"\004" u8"Style:")
);
435
436 case nPropertyTypeCharDecoration:
437 return SdResId(STR_CUSTOMANIMATION_FONT_STYLE_PROPERTYreinterpret_cast<char const *>("STR_CUSTOMANIMATION_FONT_STYLE_PROPERTY"
"\004" u8"Typeface:")
);
438
439 case nPropertyTypeLineColor:
440 return SdResId(STR_CUSTOMANIMATION_LINE_COLOR_PROPERTYreinterpret_cast<char const *>("STR_CUSTOMANIMATION_LINE_COLOR_PROPERTY"
"\004" u8"Line color:")
);
441
442 case nPropertyTypeRotate:
443 return SdResId(STR_CUSTOMANIMATION_AMOUNT_PROPERTYreinterpret_cast<char const *>("STR_CUSTOMANIMATION_AMOUNT_PROPERTY"
"\004" u8"Amount:")
);
444
445 case nPropertyTypeColor:
446 return SdResId(STR_CUSTOMANIMATION_COLOR_PROPERTYreinterpret_cast<char const *>("STR_CUSTOMANIMATION_COLOR_PROPERTY"
"\004" u8"Color:")
);
447
448 case nPropertyTypeTransparency:
449 return SdResId(STR_CUSTOMANIMATION_AMOUNT_PROPERTYreinterpret_cast<char const *>("STR_CUSTOMANIMATION_AMOUNT_PROPERTY"
"\004" u8"Amount:")
);
450
451 case nPropertyTypeScale:
452 return SdResId(STR_CUSTOMANIMATION_SCALE_PROPERTYreinterpret_cast<char const *>("STR_CUSTOMANIMATION_SCALE_PROPERTY"
"\004" u8"Size:")
);
453 }
454
455 return OUString();
456}
457
458void CustomAnimationPane::updateControls()
459{
460 mxFTDuration->set_sensitive(mxView.is());
461 mxCBXDuration->set_sensitive(mxView.is());
462 mxCustomAnimationList->set_sensitive(mxView.is());
463 if (comphelper::LibreOfficeKit::isActive())
464 {
465 mxPBPlay->hide();
466 mxCBAutoPreview->set_active(false);
467 mxCBAutoPreview->hide();
468 }
469 else
470 {
471 mxPBPlay->set_sensitive(mxView.is());
472 mxCBAutoPreview->set_sensitive(mxView.is());
473 }
474
475 if (!mxView.is())
476 {
477 mxPBAddEffect->set_sensitive(false);
478 mxPBRemoveEffect->set_sensitive(false);
479 mxFTStart->set_sensitive(false);
480 mxLBStart->set_sensitive(false);
481 mxPBPropertyMore->set_sensitive(false);
482 mxPlaceholderBox->set_sensitive(false);
483 mxFTProperty->set_sensitive(false);
484 mxFTCategory->set_sensitive(false);
485 mxLBCategory->set_sensitive(false);
486 mxFTAnimation->set_sensitive(false);
487 mxLBAnimation->set_sensitive(false);
488 mxFTStartDelay->set_sensitive(false);
489 mxMFStartDelay->set_sensitive(false);
490 mxLBAnimation->clear();
491 mnLastSelectedAnimation = -1;
492 mxCustomAnimationList->clear();
493 return;
494 }
495
496 const int nSelectionCount = maListSelection.size();
497
498 mxPBAddEffect->set_sensitive( maViewSelection.hasValue() );
499 mxPBRemoveEffect->set_sensitive(nSelectionCount != 0);
500 bool bIsSelected = (nSelectionCount > 0);
501
502 if(bIsSelected)
503 {
504 mxFTAnimation->set_sensitive(true);
505 mxLBAnimation->set_sensitive(true);
506 }
507 else
508 {
509 mxFTAnimation->set_sensitive(false);
510 mxLBAnimation->set_sensitive(false);
511 mxLBAnimation->clear();
512 mnLastSelectedAnimation = -1;
513 }
514
515 mxLBCategory->set_sensitive(bIsSelected);
516 mxFTCategory->set_sensitive(bIsSelected);
517
518 mxFTStart->set_sensitive(nSelectionCount > 0);
519 mxLBStart->set_sensitive(nSelectionCount > 0);
520 mxPlaceholderBox->set_sensitive(nSelectionCount > 0);
521 mxPBPropertyMore->set_sensitive(nSelectionCount > 0);
522 mxFTStartDelay->set_sensitive(nSelectionCount > 0);
523 mxMFStartDelay->set_sensitive(nSelectionCount > 0);
524
525 mxFTProperty->set_label(maStrProperty);
526
527 sal_Int32 nOldPropertyType = mnPropertyType;
528
529 mnPropertyType = nPropertyTypeNone;
530
531 if(bIsSelected)
532 {
533 CustomAnimationEffectPtr pEffect = maListSelection.front();
534
535 OUString aUIName( CustomAnimationPresets::getCustomAnimationPresets().getUINameForPresetId( pEffect->getPresetId() ) );
536
537 OUString aTemp( maStrModify );
538
539 if( !aUIName.isEmpty() )
540 {
541 aTemp += " " + aUIName;
542 mxFTEffect->set_label( aTemp );
543 }
544
545 Any aValue;
546 CustomAnimationPresetPtr pDescriptor = CustomAnimationPresets::getCustomAnimationPresets().getEffectDescriptor( pEffect->getPresetId() );
547 if (pDescriptor)
548 {
549 std::vector<OUString> aProperties( pDescriptor->getProperties() );
550 if( !aProperties.empty() )
551 {
552 mnPropertyType = getPropertyType( aProperties.front() );
553
554 mxFTProperty->set_label( getPropertyName( mnPropertyType ) );
555
556 aValue = getProperty1Value( mnPropertyType, pEffect );
557 }
558 }
559
560 sal_Int32 nNewPropertyType = mnPropertyType;
561 // if there is no value, then the control will be disabled, just show a disabled Direction box in that
562 // case to have something to fill the space
563 if (!aValue.hasValue())
564 nNewPropertyType = nPropertyTypeDirection;
565
566 if (!mxLBSubControl || nOldPropertyType != nNewPropertyType)
567 {
568 mxLBSubControl = SdPropertySubControl::create(nNewPropertyType, mxFTProperty.get(), mxPlaceholderBox.get(), GetFrameWeld(), aValue, pEffect->getPresetId(), LINK(this, CustomAnimationPane, implPropertyHdl)::tools::detail::makeLink( ::tools::detail::castTo<CustomAnimationPane
*>(this), &CustomAnimationPane::LinkStubimplPropertyHdl
)
);
569 }
570 else
571 {
572 mxLBSubControl->setValue(aValue, pEffect->getPresetId());
573 }
574
575 bool bEnable = aValue.hasValue();
576 mxPlaceholderBox->set_sensitive( bEnable );
577 mxFTProperty->set_sensitive( bEnable );
578
579 if (!pDescriptor)
580 {
581 mxPBPropertyMore->set_sensitive( false );
582 mxFTStartDelay->set_sensitive( false );
583 mxMFStartDelay->set_sensitive( false );
584 }
585 sal_Int32 nCategoryPos = -1;
586 switch(pEffect->getPresetClass())
587 {
588 case EffectPresetClass::ENTRANCE: nCategoryPos = 0; break;
589 case EffectPresetClass::EMPHASIS: nCategoryPos = 1; break;
590 case EffectPresetClass::EXIT: nCategoryPos = 2; break;
591 case EffectPresetClass::MOTIONPATH: nCategoryPos = 3; break;
592 default:
593 break;
594 }
595 switch(pEffect->getCommand())
596 {
597 case EffectCommands::TOGGLEPAUSE:
598 case EffectCommands::STOP:
599 case EffectCommands::PLAY:
600 nCategoryPos = 4; break;
601 default:
602 break;
603 }
604 mxLBCategory->set_active(nCategoryPos);
605
606 fillAnimationLB( pEffect->hasText() );
607
608 OUString rsPresetId = pEffect->getPresetId();
609 sal_Int32 nAnimationPos = mxLBAnimation->n_children();
610 while( nAnimationPos-- )
611 {
612 auto nEntryData = mxLBAnimation->get_id(nAnimationPos).toInt64();
613 if (nEntryData)
614 {
615 CustomAnimationPresetPtr& pPtr = *reinterpret_cast<CustomAnimationPresetPtr*>(nEntryData);
616 if( pPtr && pPtr->getPresetId() == rsPresetId )
617 {
618 mxLBAnimation->select( nAnimationPos );
619 mnLastSelectedAnimation = nAnimationPos;
620 break;
621 }
622 }
623 }
624
625 // If preset id is missing and category is motion path.
626 if (nAnimationPos < 0 && nCategoryPos == 3)
627 {
628 if (rsPresetId == "libo-motionpath-curve")
629 {
630 mxLBAnimation->select(mnCurvePathPos);
631 mnLastSelectedAnimation = mnCurvePathPos;
632 }
633 else if (rsPresetId == "libo-motionpath-polygon")
634 {
635 mxLBAnimation->select(mnPolygonPathPos);
636 mnLastSelectedAnimation = mnPolygonPathPos;
637 }
638 else if (rsPresetId == "libo-motionpath-freeform-line")
639 {
640 mxLBAnimation->select(mnFreeformPathPos);
641 mnLastSelectedAnimation = mnFreeformPathPos;
642 }
643 }
644
645 sal_uInt16 nPos = 0xffff;
646
647 sal_Int16 nNodeType = pEffect->getNodeType();
648 switch( nNodeType )
649 {
650 case EffectNodeType::ON_CLICK: nPos = 0; break;
651 case EffectNodeType::WITH_PREVIOUS: nPos = 1; break;
652 case EffectNodeType::AFTER_PREVIOUS: nPos = 2; break;
653 }
654
655 mxLBStart->set_active( nPos );
656
657 double fDuration = pEffect->getDuration();
658 const bool bHasSpeed = fDuration > 0.001;
659
660 mxFTDuration->set_sensitive(bHasSpeed);
661 mxCBXDuration->set_sensitive(bHasSpeed);
662
663 if( bHasSpeed )
664 {
665 mxCBXDuration->set_value(fDuration*100.0, FieldUnit::NONE);
666 }
667
668 mxPBPropertyMore->set_sensitive(true);
669
670 mxFTStartDelay->set_sensitive(true);
671 mxMFStartDelay->set_sensitive(true);
672 double fBegin = pEffect->getBegin();
673 mxMFStartDelay->set_value(fBegin*10.0, FieldUnit::NONE);
674 }
675 else
676 {
677 // use an empty direction box to fill the space
678 mxLBSubControl = SdPropertySubControl::create(nPropertyTypeDirection, mxFTProperty.get(), mxPlaceholderBox.get(), GetFrameWeld(), uno::Any(), OUString(), LINK(this, CustomAnimationPane, implPropertyHdl)::tools::detail::makeLink( ::tools::detail::castTo<CustomAnimationPane
*>(this), &CustomAnimationPane::LinkStubimplPropertyHdl
)
);
679 mxPlaceholderBox->set_sensitive(false);
680 mxFTProperty->set_sensitive(false);
681 mxFTStartDelay->set_sensitive(false);
682 mxMFStartDelay->set_sensitive(false);
683 mxPBPropertyMore->set_sensitive(false);
684 mxFTDuration->set_sensitive(false);
685 mxCBXDuration->set_sensitive(false);
686 mxCBXDuration->set_text(OUString());
687 mxFTEffect->set_label(maStrModify);
688 }
689
690 bool bEnableUp = true;
691 bool bEnableDown = true;
692 if( nSelectionCount == 0 )
693 {
694 bEnableUp = false;
695 bEnableDown = false;
696 }
697 else
698 {
699 if( mpMainSequence->find( maListSelection.front() ) == mpMainSequence->getBegin() )
700 bEnableUp = false;
701
702 EffectSequence::iterator aIter( mpMainSequence->find( maListSelection.back() ) );
703 if( aIter == mpMainSequence->getEnd() )
704 {
705 bEnableDown = false;
706 }
707 else
708 {
709 do
710 {
711 ++aIter;
712 }
713 while( (aIter != mpMainSequence->getEnd()) && !(mxCustomAnimationList->isExpanded(*aIter) ) );
714
715 if( aIter == mpMainSequence->getEnd() )
716 bEnableDown = false;
717 }
718
719 if( bEnableUp || bEnableDown )
720 {
721 MainSequenceRebuildGuard aGuard( mpMainSequence );
722
723 EffectSequenceHelper* pSequence = nullptr;
724 for( const CustomAnimationEffectPtr& pEffect : maListSelection )
725 {
726 if( pEffect )
727 {
728 if( pSequence == nullptr )
729 {
730 pSequence = pEffect->getEffectSequence();
731 }
732 else
733 {
734 if( pSequence != pEffect->getEffectSequence() )
735 {
736 bEnableUp = false;
737 bEnableDown = false;
738 break;
739 }
740 }
741 }
742 }
743 }
744 }
745
746 mxPBMoveUp->set_sensitive(mxView.is() && bEnableUp);
747 mxPBMoveDown->set_sensitive(mxView.is() && bEnableDown);
748
749 SdOptions* pOptions = SD_MOD()( static_cast<SdModule*>(SfxApplication::GetModule(SfxToolsModule
::Draw)) )
->GetSdOptions(DocumentType::Impress);
750 mxCBAutoPreview->set_active(pOptions->IsPreviewChangedEffects());
751
752 updateMotionPathTags();
753}
754
755static bool updateMotionPathImpl( CustomAnimationPane& rPane, ::sd::View& rView, EffectSequence::iterator aIter, const EffectSequence::iterator& aEnd, MotionPathTagVector& rOldTags, MotionPathTagVector& rNewTags )
756{
757 bool bChanges = false;
758 while( aIter != aEnd )
759 {
760 CustomAnimationEffectPtr pEffect( *aIter++ );
761 if( pEffect && pEffect->getPresetClass() == css::presentation::EffectPresetClass::MOTIONPATH )
762 {
763 rtl::Reference< MotionPathTag > xMotionPathTag;
764 // first try to find if there is already a tag for this
765 auto aMIter = std::find_if(rOldTags.begin(), rOldTags.end(),
766 [&pEffect](const rtl::Reference<MotionPathTag>& xTag) { return xTag->getEffect() == pEffect; });
767 if (aMIter != rOldTags.end())
768 {
769 rtl::Reference< MotionPathTag > xTag( *aMIter );
770 if( !xTag->isDisposed() )
771 {
772 xMotionPathTag = xTag;
773 rOldTags.erase( aMIter );
774 }
775 }
776
777 // if not found, create new one
778 if( !xMotionPathTag.is() )
779 {
780 xMotionPathTag.set( new MotionPathTag( rPane, rView, pEffect ) );
781 bChanges = true;
782 }
783
784 if( xMotionPathTag.is() )
785 rNewTags.push_back( xMotionPathTag );
786 }
787 }
788
789 return bChanges;
790}
791
792void CustomAnimationPane::updateMotionPathTags()
793{
794 bool bChanges = false;
795
796 MotionPathTagVector aTags;
797 aTags.swap( maMotionPathTags );
798
799 ::sd::View* pView = nullptr;
800
801 if( mxView.is() )
802 {
803 std::shared_ptr<ViewShell> xViewShell( mrBase.GetMainViewShell() );
804 if( xViewShell )
805 pView = xViewShell->GetView();
806 }
807
808 if( IsVisible() && mpMainSequence && pView )
809 {
810 bChanges = updateMotionPathImpl( *this, *pView, mpMainSequence->getBegin(), mpMainSequence->getEnd(), aTags, maMotionPathTags );
811
812 auto rInteractiveSequenceVector = mpMainSequence->getInteractiveSequenceVector();
813 for (InteractiveSequencePtr const& pIS : rInteractiveSequenceVector)
814 {
815 bChanges |= updateMotionPathImpl( *this, *pView, pIS->getBegin(), pIS->getEnd(), aTags, maMotionPathTags );
816 }
817 }
818
819 if( !aTags.empty() )
820 {
821 bChanges = true;
822 for( rtl::Reference< MotionPathTag >& xTag : aTags )
823 {
824 xTag->Dispose();
825 }
826 }
827
828 if( bChanges && pView )
829 pView->updateHandles();
830}
831
832void CustomAnimationPane::onSelectionChanged()
833{
834 if( maSelectionLock.isLocked() )
835 return;
836
837 ScopeLockGuard aGuard( maSelectionLock );
838
839 if( mxView.is() ) try
840 {
841 Reference< XSelectionSupplier > xSel( mxView, UNO_QUERY_THROW );
842 maViewSelection = xSel->getSelection();
843 mxCustomAnimationList->onSelectionChanged( maViewSelection );
844 updateControls();
845 }
846 catch( Exception& )
847 {
848 OSL_FAIL( "sd::CustomAnimationPane::onSelectionChanged(), Exception caught!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sd/source/ui/animations/CustomAnimationPane.cxx"
":" "848" ": "), "%s", "sd::CustomAnimationPane::onSelectionChanged(), Exception caught!"
); } } while (false)
;
849 }
850}
851
852void CustomAnimationPane::onDoubleClick()
853{
854 showOptions();
855}
856
857void CustomAnimationPane::onContextMenu(const OString &rIdent)
858{
859 if (rIdent == "onclick")
860 onChangeStart( EffectNodeType::ON_CLICK );
861 else if (rIdent == "withprev")
862 onChangeStart( EffectNodeType::WITH_PREVIOUS );
863 else if (rIdent == "afterprev")
864 onChangeStart( EffectNodeType::AFTER_PREVIOUS );
865 else if (rIdent == "options")
866 showOptions();
867 else if (rIdent == "timing")
868 showOptions("timing");
869 else if (rIdent == "remove")
870 onRemove();
871 else if (rIdent == "create" && maViewSelection.hasValue())
872 onAdd();
873 updateControls();
874}
875
876void CustomAnimationPane::DataChanged (const DataChangedEvent&)
877{
878 UpdateLook();
879}
880
881void CustomAnimationPane::UpdateLook()
882{
883 Wallpaper aBackground (
884 ::sfx2::sidebar::Theme::GetWallpaper(
885 ::sfx2::sidebar::Theme::Paint_PanelBackground));
886 SetBackground(aBackground);
887}
888
889static void addValue( const std::unique_ptr<STLPropertySet>& pSet, sal_Int32 nHandle, const Any& rValue )
890{
891 switch( pSet->getPropertyState( nHandle ) )
892 {
893 case STLPropertyState::Ambiguous:
894 // value is already ambiguous, do nothing
895 break;
896 case STLPropertyState::Direct:
897 // set to ambiguous if existing value is different
898 if( rValue != pSet->getPropertyValue( nHandle ) )
899 pSet->setPropertyState( nHandle, STLPropertyState::Ambiguous );
900 break;
901 case STLPropertyState::Default:
902 // just set new value
903 pSet->setPropertyValue( nHandle, rValue );
904 break;
905 }
906}
907
908static sal_Int32 calcMaxParaDepth( const Reference< XShape >& xTargetShape )
909{
910 sal_Int32 nMaxParaDepth = -1;
911
912 if( xTargetShape.is() )
913 {
914 Reference< XEnumerationAccess > xText( xTargetShape, UNO_QUERY );
915 if( xText.is() )
916 {
917 Reference< XPropertySet > xParaSet;
918
919 Reference< XEnumeration > xEnumeration( xText->createEnumeration(), UNO_SET_THROW );
920 while( xEnumeration->hasMoreElements() )
921 {
922 xEnumeration->nextElement() >>= xParaSet;
923 if( xParaSet.is() )
924 {
925 sal_Int32 nParaDepth = 0;
926 xParaSet->getPropertyValue( "NumberingLevel" ) >>= nParaDepth;
927
928 if( nParaDepth > nMaxParaDepth )
929 nMaxParaDepth = nParaDepth;
930 }
931 }
932 }
933 }
934
935 return nMaxParaDepth + 1;
936}
937
938Any CustomAnimationPane::getProperty1Value( sal_Int32 nType, const CustomAnimationEffectPtr& pEffect )
939{
940 switch( nType )
941 {
942 case nPropertyTypeDirection:
943 case nPropertyTypeSpokes:
944 case nPropertyTypeZoom:
945 return makeAny( pEffect->getPresetSubType() );
946
947 case nPropertyTypeColor:
948 case nPropertyTypeFillColor:
949 case nPropertyTypeFirstColor:
950 case nPropertyTypeSecondColor:
951 case nPropertyTypeCharColor:
952 case nPropertyTypeLineColor:
953 {
954 const sal_Int32 nIndex = (nPropertyTypeFirstColor == nType) ? 0 : 1;
955 return pEffect->getColor( nIndex );
956 }
957
958 case nPropertyTypeFont:
959 return pEffect->getProperty( AnimationNodeType::SET, "CharFontName" , EValue::To );
960
961 case nPropertyTypeCharHeight:
962 {
963 const OUString aAttributeName( "CharHeight" );
964 Any aValue( pEffect->getProperty( AnimationNodeType::SET, aAttributeName, EValue::To ) );
965 if( !aValue.hasValue() )
966 aValue = pEffect->getProperty( AnimationNodeType::ANIMATE, aAttributeName, EValue::To );
967 return aValue;
968 }
969
970 case nPropertyTypeRotate:
971 return pEffect->getTransformationProperty( AnimationTransformType::ROTATE, EValue::By);
972
973 case nPropertyTypeTransparency:
974 return pEffect->getProperty( AnimationNodeType::SET, "Opacity" , EValue::To );
975
976 case nPropertyTypeScale:
977 return pEffect->getTransformationProperty( AnimationTransformType::SCALE, EValue::By );
978
979 case nPropertyTypeCharDecoration:
980 {
981 Sequence< Any > aValues(3);
982 aValues[0] = pEffect->getProperty( AnimationNodeType::SET, "CharWeight" , EValue::To );
983 aValues[1] = pEffect->getProperty( AnimationNodeType::SET, "CharPosture" , EValue::To );
984 aValues[2] = pEffect->getProperty( AnimationNodeType::SET, "CharUnderline" , EValue::To );
985 return makeAny( aValues );
986 }
987 }
988
989 Any aAny;
990 return aAny;
991}
992
993bool CustomAnimationPane::setProperty1Value( sal_Int32 nType, const CustomAnimationEffectPtr& pEffect, const Any& rValue )
994{
995 bool bEffectChanged = false;
996 switch( nType )
997 {
998 case nPropertyTypeDirection:
999 case nPropertyTypeSpokes:
1000 case nPropertyTypeZoom:
1001 {
1002 OUString aPresetSubType;
1003 rValue >>= aPresetSubType;
1004 if( aPresetSubType != pEffect->getPresetSubType() )
1005 {
1006 CustomAnimationPresets::getCustomAnimationPresets().changePresetSubType( pEffect, aPresetSubType );
1007 bEffectChanged = true;
1008 }
1009 }
1010 break;
1011
1012 case nPropertyTypeFillColor:
1013 case nPropertyTypeColor:
1014 case nPropertyTypeFirstColor:
1015 case nPropertyTypeSecondColor:
1016 case nPropertyTypeCharColor:
1017 case nPropertyTypeLineColor:
1018 {
1019 const sal_Int32 nIndex = (nPropertyTypeFirstColor == nType) ? 0 : 1;
1020 Any aOldColor( pEffect->getColor( nIndex ) );
1021 if( aOldColor != rValue )
1022 {
1023 pEffect->setColor( nIndex, rValue );
1024 bEffectChanged = true;
1025 }
1026 }
1027 break;
1028
1029 case nPropertyTypeFont:
1030 bEffectChanged = pEffect->setProperty( AnimationNodeType::SET, "CharFontName" , EValue::To, rValue );
1031 break;
1032
1033 case nPropertyTypeCharHeight:
1034 {
1035 const OUString aAttributeName( "CharHeight" );
1036 bEffectChanged = pEffect->setProperty( AnimationNodeType::SET, aAttributeName, EValue::To, rValue );
1037 if( !bEffectChanged )
1038 bEffectChanged = pEffect->setProperty( AnimationNodeType::ANIMATE, aAttributeName, EValue::To, rValue );
1039 }
1040 break;
1041 case nPropertyTypeRotate:
1042 bEffectChanged = pEffect->setTransformationProperty( AnimationTransformType::ROTATE, EValue::By , rValue );
1043 break;
1044
1045 case nPropertyTypeTransparency:
1046 bEffectChanged = pEffect->setProperty( AnimationNodeType::SET, "Opacity" , EValue::To, rValue );
1047 break;
1048
1049 case nPropertyTypeScale:
1050 bEffectChanged = pEffect->setTransformationProperty( AnimationTransformType::SCALE, EValue::By, rValue );
1051 break;
1052
1053 case nPropertyTypeCharDecoration:
1054 {
1055 Sequence< Any > aValues(3);
1056 rValue >>= aValues;
1057 bEffectChanged = pEffect->setProperty( AnimationNodeType::SET, "CharWeight" , EValue::To, aValues[0] );
1058 bEffectChanged |= pEffect->setProperty( AnimationNodeType::SET, "CharPosture" , EValue::To, aValues[1] );
1059 bEffectChanged |= pEffect->setProperty( AnimationNodeType::SET, "CharUnderline" , EValue::To, aValues[2] );
1060 }
1061 break;
1062
1063 }
1064
1065 return bEffectChanged;
1066}
1067
1068static bool hasVisibleShape( const Reference< XShape >& xShape )
1069{
1070 try
1071 {
1072 const OUString sShapeType( xShape->getShapeType() );
1073
1074 if( sShapeType == "com.sun.star.presentation.TitleTextShape" || sShapeType == "com.sun.star.presentation.OutlinerShape" ||
1075 sShapeType == "com.sun.star.presentation.SubtitleShape" || sShapeType == "com.sun.star.drawing.TextShape" )
1076 {
1077 Reference< XPropertySet > xSet( xShape, UNO_QUERY_THROW );
1078
1079 FillStyle eFillStyle;
1080 xSet->getPropertyValue( "FillStyle" ) >>= eFillStyle;
1081
1082 css::drawing::LineStyle eLineStyle;
1083 xSet->getPropertyValue( "LineStyle" ) >>= eLineStyle;
1084
1085 return eFillStyle != FillStyle_NONE || eLineStyle != css::drawing::LineStyle_NONE;
1086 }
1087 }
1088 catch( Exception& )
1089 {
1090 }
1091 return true;
1092}
1093
1094std::unique_ptr<STLPropertySet> CustomAnimationPane::createSelectionSet()
1095{
1096 std::unique_ptr<STLPropertySet> pSet = CustomAnimationDialog::createDefaultSet();
1097
1098 pSet->setPropertyValue( nHandleCurrentPage, makeAny( mxCurrentPage ) );
1099
1100 sal_Int32 nMaxParaDepth = 0;
1101
1102 // get options from selected effects
1103 const CustomAnimationPresets& rPresets (CustomAnimationPresets::getCustomAnimationPresets());
1104 for( CustomAnimationEffectPtr& pEffect : maListSelection )
1105 {
1106 EffectSequenceHelper* pEffectSequence = pEffect->getEffectSequence();
1107 if( !pEffectSequence )
1108 pEffectSequence = mpMainSequence.get();
1109
1110 if( pEffect->hasText() )
1111 {
1112 sal_Int32 n = calcMaxParaDepth(pEffect->getTargetShape());
1113 if( n > nMaxParaDepth )
1114 nMaxParaDepth = n;
1115 }
1116
1117 addValue( pSet, nHandleHasAfterEffect, makeAny( pEffect->hasAfterEffect() ) );
1118 addValue( pSet, nHandleAfterEffectOnNextEffect, makeAny( pEffect->IsAfterEffectOnNext() ) );
1119 addValue( pSet, nHandleDimColor, pEffect->getDimColor() );
1120 addValue( pSet, nHandleIterateType, makeAny( pEffect->getIterateType() ) );
1121
1122 // convert absolute time to percentage value
1123 // This calculation is done in float to avoid some rounding artifacts.
1124 float fIterateInterval = static_cast<float>(pEffect->getIterateInterval());
1125 if( pEffect->getDuration() )
1126 fIterateInterval = static_cast<float>(fIterateInterval / pEffect->getDuration() );
1127 fIterateInterval *= 100.0;
1128 addValue( pSet, nHandleIterateInterval, makeAny( static_cast<double>(fIterateInterval) ) );
1129
1130 addValue( pSet, nHandleBegin, makeAny( pEffect->getBegin() ) );
1131 addValue( pSet, nHandleDuration, makeAny( pEffect->getDuration() ) );
1132 addValue( pSet, nHandleStart, makeAny( pEffect->getNodeType() ) );
1133 addValue( pSet, nHandleRepeat, pEffect->getRepeatCount() );
1134 addValue( pSet, nHandleEnd, pEffect->getEnd() );
1135 addValue( pSet, nHandleRewind, makeAny( pEffect->getFill() ) );
1136
1137 addValue( pSet, nHandlePresetId, makeAny( pEffect->getPresetId() ) );
1138
1139 addValue( pSet, nHandleHasText, makeAny( pEffect->hasText() ) );
1140
1141 addValue( pSet, nHandleHasVisibleShape, Any( hasVisibleShape( pEffect->getTargetShape() ) ) );
1142
1143 Any aSoundSource;
1144 if( pEffect->getAudio().is() )
1145 {
1146 aSoundSource = pEffect->getAudio()->getSource();
1147 addValue( pSet, nHandleSoundVolume, makeAny( pEffect->getAudio()->getVolume() ) );
1148// todo addValue( pSet, nHandleSoundEndAfterSlide, makeAny( pEffect->getAudio()->getEndAfterSlide() ) );
1149// this is now stored at the XCommand parameter sequence
1150 }
1151 else if( pEffect->getCommand() == EffectCommands::STOPAUDIO )
1152 {
1153 aSoundSource <<= true;
1154 }
1155 addValue( pSet, nHandleSoundURL, aSoundSource );
1156
1157 sal_Int32 nGroupId = pEffect->getGroupId();
1158 CustomAnimationTextGroupPtr pTextGroup;
1159 if( nGroupId != -1 )
1160 pTextGroup = pEffectSequence->findGroup( nGroupId );
1161
1162 addValue( pSet, nHandleTextGrouping, makeAny( pTextGroup ? pTextGroup->getTextGrouping() : sal_Int32(-1) ) );
1163 addValue( pSet, nHandleAnimateForm, makeAny( !pTextGroup || pTextGroup->getAnimateForm() ) );
1164 addValue( pSet, nHandleTextGroupingAuto, makeAny( pTextGroup ? pTextGroup->getTextGroupingAuto() : -1.0 ) );
1165 addValue( pSet, nHandleTextReverse, makeAny( pTextGroup && pTextGroup->getTextReverse() ) );
1166
1167 if( pEffectSequence->getSequenceType() == EffectNodeType::INTERACTIVE_SEQUENCE )
1168 {
1169 InteractiveSequence* pIS = static_cast< InteractiveSequence* >( pEffectSequence );
1170 addValue( pSet, nHandleTrigger, makeAny( pIS->getTriggerShape() ) );
1171 }
1172
1173 CustomAnimationPresetPtr pDescriptor = rPresets.getEffectDescriptor( pEffect->getPresetId() );
1174 if( pDescriptor )
1175 {
1176 sal_Int32 nType = nPropertyTypeNone;
1177
1178 std::vector<OUString> aProperties( pDescriptor->getProperties() );
1179 if( !aProperties.empty() )
1180 nType = getPropertyType( aProperties.front() );
1181
1182 if( nType != nPropertyTypeNone )
1183 {
1184 addValue( pSet, nHandleProperty1Type, makeAny( nType ) );
1185 addValue( pSet, nHandleProperty1Value, getProperty1Value( nType, pEffect ) );
1186 }
1187
1188 if( pDescriptor->hasProperty( "Accelerate" ) )
1189 {
1190 addValue( pSet, nHandleAccelerate, makeAny( pEffect->getAcceleration() ) );
1191 }
1192
1193 if( pDescriptor->hasProperty( "Decelerate" ) )
1194 {
1195 addValue( pSet, nHandleDecelerate, makeAny( pEffect->getDecelerate() ) );
1196 }
1197
1198 if( pDescriptor->hasProperty( "AutoReverse" ) )
1199 {
1200 addValue( pSet, nHandleAutoReverse, makeAny( pEffect->getAutoReverse() ) );
1201 }
1202 }
1203 }
1204
1205 addValue( pSet, nHandleMaxParaDepth, makeAny( nMaxParaDepth ) );
1206
1207 return pSet;
1208}
1209
1210void CustomAnimationPane::changeSelection( STLPropertySet const * pResultSet, STLPropertySet const * pOldSet )
1211{
1212 // change selected effect
1213 bool bChanged = false;
1214
1215 MainSequenceRebuildGuard aGuard( mpMainSequence );
1216
1217 for( CustomAnimationEffectPtr& pEffect : maListSelection )
1218 {
1219 DBG_ASSERT( pEffect->getEffectSequence(), "sd::CustomAnimationPane::changeSelection(), dead effect in selection!" )do { if (true && (!(pEffect->getEffectSequence()))
) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/sd/source/ui/animations/CustomAnimationPane.cxx"
":" "1219" ": "), "%s", "sd::CustomAnimationPane::changeSelection(), dead effect in selection!"
); } } while (false)
;
1220 if( !pEffect->getEffectSequence() )
1221 continue;
1222
1223 double fDuration = 0.0; // we might need this for iterate-interval
1224 if( pResultSet->getPropertyState( nHandleDuration ) == STLPropertyState::Direct )
1225 {
1226 pResultSet->getPropertyValue( nHandleDuration ) >>= fDuration;
1227 }
1228 else
1229 {
1230 fDuration = pEffect->getDuration();
1231 }
1232
1233 if( pResultSet->getPropertyState( nHandleIterateType ) == STLPropertyState::Direct )
1234 {
1235 sal_Int16 nIterateType = 0;
1236 pResultSet->getPropertyValue( nHandleIterateType ) >>= nIterateType;
1237 if( pEffect->getIterateType() != nIterateType )
1238 {
1239 pEffect->setIterateType( nIterateType );
1240 bChanged = true;
1241 }
1242 }
1243
1244 if( pEffect->getIterateType() )
1245 {
1246 if( pResultSet->getPropertyState( nHandleIterateInterval ) == STLPropertyState::Direct )
1247 {
1248 double fIterateInterval = 0.0;
1249 pResultSet->getPropertyValue( nHandleIterateInterval ) >>= fIterateInterval;
1250 if( pEffect->getIterateInterval() != fIterateInterval )
1251 {
1252 const double f = fIterateInterval * pEffect->getDuration() / 100;
1253 pEffect->setIterateInterval( f );
1254 bChanged = true;
1255 }
1256 }
1257 }
1258
1259 double fBegin = 0.0;
1260
1261 if( pResultSet->getPropertyState( nHandleBegin ) == STLPropertyState::Direct )
1262 pResultSet->getPropertyValue( nHandleBegin ) >>= fBegin;
1263 else
1264 fBegin = pEffect->getBegin();
1265
1266 if( pEffect->getBegin() != fBegin && pResultSet->getPropertyState( nHandleBegin ) == STLPropertyState::Direct)
1267 {
1268 pEffect->setBegin( fBegin );
1269 bChanged = true;
1270 }
1271
1272 if( pResultSet->getPropertyState( nHandleDuration ) == STLPropertyState::Direct )
1273 {
1274 if( pEffect->getDuration() != fDuration )
1275 {
1276 pEffect->setDuration( fDuration );
1277 bChanged = true;
1278 }
1279 }
1280
1281 if( pResultSet->getPropertyState( nHandleStart ) == STLPropertyState::Direct )
1282 {
1283 sal_Int16 nNodeType = 0;
1284 pResultSet->getPropertyValue( nHandleStart ) >>= nNodeType;
1285 if( pEffect->getNodeType() != nNodeType )
1286 {
1287 pEffect->setNodeType( nNodeType );
1288 bChanged = true;
1289 }
1290 }
1291
1292 if( pResultSet->getPropertyState( nHandleRepeat ) == STLPropertyState::Direct )
1293 {
1294 Any aRepeatCount( pResultSet->getPropertyValue( nHandleRepeat ) );
1295 if( aRepeatCount != pEffect->getRepeatCount() )
1296 {
1297 pEffect->setRepeatCount( aRepeatCount );
1298 bChanged = true;
1299 }
1300 }
1301
1302 if( pResultSet->getPropertyState( nHandleEnd ) == STLPropertyState::Direct )
1303 {
1304 Any aEndValue( pResultSet->getPropertyValue( nHandleEnd ) );
1305 if( pEffect->getEnd() != aEndValue )
1306 {
1307 pEffect->setEnd( aEndValue );
1308 bChanged = true;
1309 }
1310 }
1311
1312 if( pResultSet->getPropertyState( nHandleRewind ) == STLPropertyState::Direct )
1313 {
1314 sal_Int16 nFill = 0;
1315 pResultSet->getPropertyValue( nHandleRewind ) >>= nFill;
1316 if( pEffect->getFill() != nFill )
1317 {
1318 pEffect->setFill( nFill );
1319 bChanged = true;
1320 }
1321 }
1322
1323 if( pResultSet->getPropertyState( nHandleHasAfterEffect ) == STLPropertyState::Direct )
1324 {
1325 bool bHasAfterEffect = false;
1326 if( pResultSet->getPropertyValue( nHandleHasAfterEffect ) >>= bHasAfterEffect )
1327 {
1328 if( pEffect->hasAfterEffect() != bHasAfterEffect )
1329 {
1330 pEffect->setHasAfterEffect( bHasAfterEffect );
1331 bChanged = true;
1332 }
1333 }
1334 }
1335
1336 if( pResultSet->getPropertyState( nHandleAfterEffectOnNextEffect ) == STLPropertyState::Direct )
1337 {
1338 bool bAfterEffectOnNextEffect = false;
1339 if( (pResultSet->getPropertyValue( nHandleAfterEffectOnNextEffect ) >>= bAfterEffectOnNextEffect)
1340 && (pEffect->IsAfterEffectOnNext() != bAfterEffectOnNextEffect) )
1341 {
1342 pEffect->setAfterEffectOnNext( bAfterEffectOnNextEffect );
1343 bChanged = true;
1344 }
1345 }
1346
1347 if( pResultSet->getPropertyState( nHandleDimColor ) == STLPropertyState::Direct )
1348 {
1349 Any aDimColor( pResultSet->getPropertyValue( nHandleDimColor ) );
1350 if( pEffect->getDimColor() != aDimColor )
1351 {
1352 pEffect->setDimColor( aDimColor );
1353 bChanged = true;
1354 }
1355 }
1356
1357 if( pResultSet->getPropertyState( nHandleAccelerate ) == STLPropertyState::Direct )
1358 {
1359 double fAccelerate = 0.0;
1360 pResultSet->getPropertyValue( nHandleAccelerate ) >>= fAccelerate;
1361 if( pEffect->getAcceleration() != fAccelerate )
1362 {
1363 pEffect->setAcceleration( fAccelerate );
1364 bChanged = true;
1365 }
1366 }
1367
1368 if( pResultSet->getPropertyState( nHandleDecelerate ) == STLPropertyState::Direct )
1369 {
1370 double fDecelerate = 0.0;
1371 pResultSet->getPropertyValue( nHandleDecelerate ) >>= fDecelerate;
1372 if( pEffect->getDecelerate() != fDecelerate )
1373 {
1374 pEffect->setDecelerate( fDecelerate );
1375 bChanged = true;
1376 }
1377 }
1378
1379 if( pResultSet->getPropertyState( nHandleAutoReverse ) == STLPropertyState::Direct )
1380 {
1381 bool bAutoReverse = false;
1382 pResultSet->getPropertyValue( nHandleAutoReverse ) >>= bAutoReverse;
1383 if( pEffect->getAutoReverse() != bAutoReverse )
1384 {
1385 pEffect->setAutoReverse( bAutoReverse );
1386 bChanged = true;
1387 }
1388 }
1389
1390 if( pResultSet->getPropertyState( nHandleProperty1Value ) == STLPropertyState::Direct )
1391 {
1392 sal_Int32 nType = 0;
1393 pOldSet->getPropertyValue( nHandleProperty1Type ) >>= nType;
1394
1395 bChanged |= setProperty1Value( nType, pEffect, pResultSet->getPropertyValue( nHandleProperty1Value ) );
1396 }
1397
1398 if( pResultSet->getPropertyState( nHandleSoundURL ) == STLPropertyState::Direct )
1399 {
1400 const Any aSoundSource( pResultSet->getPropertyValue( nHandleSoundURL ) );
1401
1402 if( aSoundSource.getValueType() == ::cppu::UnoType<sal_Bool>::get() )
1403 {
1404 pEffect->setStopAudio();
1405 bChanged = true;
1406 }
1407 else
1408 {
1409 OUString aSoundURL;
1410 aSoundSource >>= aSoundURL;
1411
1412 if( !aSoundURL.isEmpty() )
1413 {
1414 if( !pEffect->getAudio().is() )
1415 {
1416 pEffect->createAudio( aSoundSource );
1417 bChanged = true;
1418 }
1419 else
1420 {
1421 if( pEffect->getAudio()->getSource() != aSoundSource )
1422 {
1423 pEffect->getAudio()->setSource( aSoundSource );
1424 bChanged = true;
1425 }
1426 }
1427 }
1428 else
1429 {
1430 if( pEffect->getAudio().is() || pEffect->getStopAudio() )
1431 {
1432 pEffect->removeAudio();
1433 bChanged = true;
1434 }
1435 }
1436 }
1437 }
1438
1439 if( pResultSet->getPropertyState( nHandleTrigger ) == STLPropertyState::Direct )
1440 {
1441 Reference< XShape > xTriggerShape;
1442 pResultSet->getPropertyValue( nHandleTrigger ) >>= xTriggerShape;
1443 bChanged |= mpMainSequence->setTrigger( pEffect, xTriggerShape );
1444 }
1445 }
1446
1447 const bool bHasTextGrouping = pResultSet->getPropertyState( nHandleTextGrouping ) == STLPropertyState::Direct;
1448 const bool bHasAnimateForm = pResultSet->getPropertyState( nHandleAnimateForm ) == STLPropertyState::Direct;
1449 const bool bHasTextGroupingAuto = pResultSet->getPropertyState( nHandleTextGroupingAuto ) == STLPropertyState::Direct;
1450 const bool bHasTextReverse = pResultSet->getPropertyState( nHandleTextReverse ) == STLPropertyState::Direct;
1451
1452 if( bHasTextGrouping || bHasAnimateForm || bHasTextGroupingAuto || bHasTextReverse )
1453 {
1454 // we need to do a second pass for text grouping options
1455 // since changing them can cause effects to be removed
1456 // or replaced, we do this after we applied all other options
1457 // above
1458
1459 sal_Int32 nTextGrouping = 0;
1460 bool bAnimateForm = true, bTextReverse = false;
1461 double fTextGroupingAuto = -1.0;
1462
1463 if( bHasTextGrouping )
1464 pResultSet->getPropertyValue(nHandleTextGrouping) >>= nTextGrouping;
1465 else
1466 pOldSet->getPropertyValue(nHandleTextGrouping) >>= nTextGrouping;
1467
1468 if( bHasAnimateForm )
1469 pResultSet->getPropertyValue(nHandleAnimateForm) >>= bAnimateForm;
1470 else
1471 pOldSet->getPropertyValue(nHandleAnimateForm) >>= bAnimateForm;
1472
1473 if( bHasTextGroupingAuto )
1474 pResultSet->getPropertyValue(nHandleTextGroupingAuto) >>= fTextGroupingAuto;
1475 else
1476 pOldSet->getPropertyValue(nHandleTextGroupingAuto) >>= fTextGroupingAuto;
1477
1478 if( bHasTextReverse )
1479 pResultSet->getPropertyValue(nHandleTextReverse) >>= bTextReverse;
1480 else
1481 pOldSet->getPropertyValue(nHandleTextReverse) >>= bTextReverse;
1482
1483 EffectSequence const aSelectedEffects( maListSelection );
1484 for( CustomAnimationEffectPtr const& pEffect : aSelectedEffects )
1485 {
1486 EffectSequenceHelper* pEffectSequence = pEffect->getEffectSequence();
1487 if( !pEffectSequence )
1488 pEffectSequence = mpMainSequence.get();
1489
1490 sal_Int32 nGroupId = pEffect->getGroupId();
1491 CustomAnimationTextGroupPtr pTextGroup;
1492 if( nGroupId != -1 )
1493 {
1494 // use existing group
1495 pTextGroup = pEffectSequence->findGroup( nGroupId );
1496 }
1497 else
1498 {
1499 // somethings changed so we need a group now
1500 pTextGroup = pEffectSequence->createTextGroup( pEffect, nTextGrouping, fTextGroupingAuto, bAnimateForm, bTextReverse );
1501 bChanged = true;
1502 }
1503
1504 //#i119988#
1505 /************************************************************************/
1506 /*
1507 Note, the setAnimateForm means set the animation from TextGroup to Object's Shape
1508 And on the UI in means "Animate attached shape" in "Effect Option" dialog
1509 The setTextGrouping means set animation to Object's Text,
1510 the nTextGrouping is Text Animation Type
1511 nTextGrouping = -1 is "As one Object", means no text animation.
1512
1513 The previous call order first do the setTextGrouping and then do the setAnimateForm,
1514 that will cause such defect: in the setTextGrouping, the effect has been removed,
1515 but in setAnimateForm still need this effect, then a NULL pointer of that effect will
1516 be gotten, and cause crash.
1517
1518 []bHasAnimateForm means the UI has changed, bAnimateForm is it value
1519
1520 So if create a new textgroup animation, the following animation will never be run!
1521 Since the \A1\B0Animate attached shape\A1\B1 is default checked.
1522 And the bHasAnimateForm default is false, and if user uncheck it the value bAnimateForm will be false,
1523 it same as the TextGroup\A1\AFs default value, also could not be run setAnimateForm.
1524 if( bHasAnimateForm )
1525 {
1526 if( pTextGroup->getAnimateForm() != bAnimateForm )
1527 {
1528 pEffectSequence->setAnimateForm( pTextGroup, bAnimateForm );
1529 bChanged = true;
1530 }
1531 }
1532
1533 In setTextGrouping, there are three case:
1534 1. Create new text effects for empty TextGroup
1535 2. Remove all text effects of TextGroup (nTextGrouping == -1)
1536 3. Change all the text effects\A1\AF start type
1537
1538 So here is the right logic:
1539 If set the animation from text to shape and remove text animation,
1540 should do setAnimateForm first, then do setTextGrouping.
1541 Other case,do setTextGrouping first, then do setAnimateForm.
1542
1543 */
1544 /************************************************************************/
1545
1546 bool bDoSetAnimateFormFirst = false;
1547 bool bNeedDoSetAnimateForm = false;
1548
1549 if( bHasAnimateForm )
1550 {
1551 if( pTextGroup && pTextGroup->getAnimateForm() != bAnimateForm )
1552 {
1553 if( (pTextGroup->getTextGrouping() >= 0) && (nTextGrouping == -1 ) )
1554 {
1555 bDoSetAnimateFormFirst = true;
1556 }
1557 bNeedDoSetAnimateForm = true;
1558 }
1559 }
1560
1561 if (bDoSetAnimateFormFirst)
1562 {
1563 pEffectSequence->setAnimateForm( pTextGroup, bAnimateForm );
1564 bChanged = true;
1565 }
1566
1567 if( bHasTextGrouping )
1568 {
1569 if( pTextGroup && pTextGroup->getTextGrouping() != nTextGrouping )
1570 {
1571 pEffectSequence->setTextGrouping( pTextGroup, nTextGrouping );
1572
1573 // All the effects of the outline object is removed so we need to
1574 // put it back. OTOH, the shape object that still has effects
1575 // in the text group is fine.
1576 if (nTextGrouping == -1 && pTextGroup->getEffects().empty())
1577 {
1578 pEffect->setTarget(makeAny(pEffect->getTargetShape()));
1579 pEffect->setGroupId(-1);
1580 mpMainSequence->append(pEffect);
1581 }
1582
1583 bChanged = true;
1584 }
1585 }
1586
1587 if (!bDoSetAnimateFormFirst && bNeedDoSetAnimateForm)
1588 {
1589 if( pTextGroup )
1590 {
1591 pEffectSequence->setAnimateForm( pTextGroup, bAnimateForm );
1592 bChanged = true;
1593 }
1594 }
1595
1596 if( bHasTextGroupingAuto )
1597 {
1598 if( pTextGroup && pTextGroup->getTextGroupingAuto() != fTextGroupingAuto )
1599 {
1600 pEffectSequence->setTextGroupingAuto( pTextGroup, fTextGroupingAuto );
1601 bChanged = true;
1602 }
1603 }
1604
1605 if( bHasTextReverse )
1606 {
1607 if( pTextGroup && pTextGroup->getTextReverse() != bTextReverse )
1608 {
1609 pEffectSequence->setTextReverse( pTextGroup, bTextReverse );
1610 bChanged = true;
1611 }
1612 }
1613 }
1614 }
1615
1616 if( bChanged )
1617 {
1618 mpMainSequence->rebuild();
1619 updateControls();
1620 mrBase.GetDocShell()->SetModified();
1621 }
1622}
1623
1624void CustomAnimationPane::showOptions(const OString& rPage)
1625{
1626 std::unique_ptr<STLPropertySet> xSet = createSelectionSet();
1627
1628 auto xDlg = std::make_shared<CustomAnimationDialog>(GetFrameWeld(), std::move(xSet), rPage);
1629
1630 weld::DialogController::runAsync(xDlg, [xDlg, this](sal_Int32 nResult){
1631 if (nResult )
1632 {
1633 addUndo();
1634 changeSelection(xDlg->getResultSet(), xDlg->getPropertySet());
1635 updateControls();
1636 }
1637 });
1638}
1639
1640void CustomAnimationPane::onChangeCurrentPage()
1641{
1642 if( !mxView.is() )
1643 return;
1644
1645 try
1646 {
1647 Reference< XDrawPage > xNewPage( mxView->getCurrentPage() );
1648 if( xNewPage != mxCurrentPage )
1649 {
1650 mxCurrentPage = xNewPage;
1651 SdPage* pPage = SdPage::getImplementation( mxCurrentPage );
1652 if( pPage )
1653 {
1654 mpMainSequence = pPage->getMainSequence();
1655 mxCustomAnimationList->update( mpMainSequence );
1656 }
1657 updateControls();
1658 }
1659 }
1660 catch( Exception& )
1661 {
1662 OSL_FAIL( "sd::CustomAnimationPane::onChangeCurrentPage(), exception caught!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sd/source/ui/animations/CustomAnimationPane.cxx"
":" "1662" ": "), "%s", "sd::CustomAnimationPane::onChangeCurrentPage(), exception caught!"
); } } while (false)
;
1663 }
1664}
1665
1666static bool getTextSelection( const Any& rSelection, Reference< XShape >& xShape, std::vector< sal_Int16 >& rParaList )
1667{
1668 Reference< XTextRange > xSelectedText;
1669 rSelection >>= xSelectedText;
1670 if( xSelectedText.is() ) try
1671 {
1672 xShape.set( xSelectedText->getText(), UNO_QUERY_THROW );
1673
1674 Reference< XTextRangeCompare > xTextRangeCompare( xShape, UNO_QUERY_THROW );
1675 Reference< XEnumerationAccess > xParaEnumAccess( xShape, UNO_QUERY_THROW );
1676 Reference< XEnumeration > xParaEnum( xParaEnumAccess->createEnumeration(), UNO_SET_THROW );
1677 Reference< XTextRange > xRange;
1678 Reference< XTextRange > xStart( xSelectedText->getStart() );
1679 Reference< XTextRange > xEnd( xSelectedText->getEnd() );
1680
1681 if( xTextRangeCompare->compareRegionEnds( xStart, xEnd ) < 0 )
1682 {
1683 Reference< XTextRange > xTemp( xStart );
1684 xStart = xEnd;
1685 xEnd = xTemp;
1686 }
1687
1688 sal_Int16 nPara = 0;
1689 while( xParaEnum->hasMoreElements() )
1690 {
1691 xParaEnum->nextElement() >>= xRange;
1692
1693 // break if start of selection is prior to end of current paragraph
1694 if( xRange.is() && (xTextRangeCompare->compareRegionEnds( xStart, xRange ) >= 0 ) )
1695 break;
1696
1697 nPara++;
1698 }
1699
1700 while( xRange.is() )
1701 {
1702 if( xRange.is() && !xRange->getString().isEmpty() )
1703 rParaList.push_back( nPara );
1704
1705 // break if end of selection is before or at end of current paragraph
1706 if( xRange.is() && xTextRangeCompare->compareRegionEnds( xEnd, xRange ) >= 0 )
1707 break;
1708
1709 nPara++;
1710
1711 if( xParaEnum->hasMoreElements() )
1712 xParaEnum->nextElement() >>= xRange;
1713 else
1714 xRange.clear();
1715 }
1716
1717 return true;
1718 }
1719 catch( Exception& )
1720 {
1721 OSL_FAIL( "sd::CustomAnimationPane::getTextSelection(), exception caught!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sd/source/ui/animations/CustomAnimationPane.cxx"
":" "1721" ": "), "%s", "sd::CustomAnimationPane::getTextSelection(), exception caught!"
); } } while (false)
;
1722 }
1723
1724 return false;
1725}
1726
1727void CustomAnimationPane::onAdd()
1728{
1729 bool bHasText = true;
1730
1731 // first create vector of targets for dialog preview
1732 std::vector< Any > aTargets;
1733
1734 // gather shapes from the selection
1735 Reference< XSelectionSupplier > xSel( mxView, UNO_QUERY_THROW );
1736 maViewSelection = xSel->getSelection();
1737
1738 if( maViewSelection.getValueType() == cppu::UnoType<XShapes>::get())
1739 {
1740 Reference< XIndexAccess > xShapes;
1741 maViewSelection >>= xShapes;
1742
1743 sal_Int32 nCount = xShapes->getCount();
1744 aTargets.reserve( nCount );
1745 for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
1746 {
1747 Any aTarget( xShapes->getByIndex( nIndex ) );
1748 aTargets.push_back( aTarget );
1749 if( bHasText )
1750 {
1751 Reference< XText > xText;
1752 aTarget >>= xText;
1753 if( !xText.is() || xText->getString().isEmpty() )
1754 bHasText = false;
1755 }
1756 }
1757 }
1758 else if ( maViewSelection.getValueType() == cppu::UnoType<XShape>::get())
1759 {
1760 aTargets.push_back( maViewSelection );
1761 Reference< XText > xText;
1762 maViewSelection >>= xText;
1763 if( !xText.is() || xText->getString().isEmpty() )
1764 bHasText = false;
1765 }
1766 else if ( maViewSelection.getValueType() == cppu::UnoType<XTextCursor>::get())
1767 {
1768 Reference< XShape > xShape;
1769 std::vector< sal_Int16 > aParaList;
1770 if( getTextSelection( maViewSelection, xShape, aParaList ) )
1771 {
1772 ParagraphTarget aParaTarget;
1773 aParaTarget.Shape = xShape;
1774
1775 for( const auto& rPara : aParaList )
1776 {
1777 aParaTarget.Paragraph = rPara;
1778 aTargets.push_back( makeAny( aParaTarget ) );
1779 }
1780 }
1781 }
1782 else
1783 {
1784 OSL_FAIL("sd::CustomAnimationPane::onAdd(), unknown view selection!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sd/source/ui/animations/CustomAnimationPane.cxx"
":" "1784" ": "), "%s", "sd::CustomAnimationPane::onAdd(), unknown view selection!"
); } } while (false)
;
1785 return;
1786 }
1787
1788 CustomAnimationPresetPtr pDescriptor;
1789 mxFTCategory->set_sensitive(true);
1790 mxFTAnimation->set_sensitive(true);
1791
1792 bool bCategoryReset = false;
1793
1794 if (!mxLBCategory->get_sensitive() || mxLBCategory->get_active() == -1)
1795 {
1796 mxLBCategory->set_sensitive(true);
1797 mxLBCategory->set_active(0);
1798 bCategoryReset = true;
1799 }
1800
1801 if (bCategoryReset || !mxLBAnimation->get_sensitive() ||
1802 mxLBAnimation->get_selected_index() == -1)
1803 {
1804 mxLBAnimation->set_sensitive(true);
1805
1806 sal_Int32 nFirstEffect = fillAnimationLB(bHasText);
1807 if (nFirstEffect == -1)
1808 return;
1809
1810 mxLBAnimation->select(nFirstEffect);
1811 mnLastSelectedAnimation = nFirstEffect;
1812 }
1813
1814 auto nEntryData = mxLBAnimation->get_selected_id().toInt64();
1815 if (nEntryData)
1816 pDescriptor = *reinterpret_cast<CustomAnimationPresetPtr*>(nEntryData);
1817
1818 const double fDuration = pDescriptor->getDuration();
1819 mxCBXDuration->set_value(fDuration*100.0, FieldUnit::NONE);
1820 bool bHasSpeed = pDescriptor->getDuration() > 0.001;
1821 mxCBXDuration->set_sensitive( bHasSpeed );
1822 mxFTDuration->set_sensitive( bHasSpeed );
1823
1824 if( pDescriptor )
1825 {
1826 mxCustomAnimationList->unselect_all();
1827
1828 // gather shapes from the selection
1829 bool bFirst = true;
1830 for( const auto& rTarget : aTargets )
1831 {
1832 CustomAnimationEffectPtr pCreated = mpMainSequence->append( pDescriptor, rTarget, fDuration );
1833
1834 // if only one shape with text and no fill or outline is selected, animate only by first level paragraphs
1835 if( bHasText && (aTargets.size() == 1) )
1836 {
1837 Reference< XShape > xShape( rTarget, UNO_QUERY );
1838 if( xShape.is() && !hasVisibleShape( xShape ) )
1839 {
1840 mpMainSequence->createTextGroup( pCreated, 1, -1.0, false, false );
1841 }
1842 }
1843
1844 if( bFirst )
1845 bFirst = false;
1846 else
1847 pCreated->setNodeType( EffectNodeType::WITH_PREVIOUS );
1848
1849 if( pCreated )
1850 mxCustomAnimationList->select( pCreated );
1851 }
1852 }
1853
1854 mrBase.GetDocShell()->SetModified();
1855
1856 updateControls();
1857
1858 SlideShow::Stop( mrBase );
1859}
1860
1861void CustomAnimationPane::onRemove()
1862{
1863 if( maListSelection.empty() )
1864 return;
1865
1866 addUndo();
1867
1868 MainSequenceRebuildGuard aGuard( mpMainSequence );
1869
1870 EffectSequence aList( maListSelection );
1871
1872 for( CustomAnimationEffectPtr& pEffect : aList )
1873 {
1874 if( pEffect->getEffectSequence() )
1875 pEffect->getEffectSequence()->remove( pEffect );
1876 }
1877
1878 maListSelection.clear();
1879 mrBase.GetDocShell()->SetModified();
1880}
1881
1882void CustomAnimationPane::remove( CustomAnimationEffectPtr const & pEffect )
1883{
1884 if( pEffect->getEffectSequence() )
1885 {
1886 addUndo();
1887 pEffect->getEffectSequence()->remove( pEffect );
1888 mrBase.GetDocShell()->SetModified();
1889 }
1890}
1891
1892void CustomAnimationPane::onChangeStart()
1893{
1894 sal_Int16 nNodeType;
1895 switch( mxLBStart->get_active() )
1896 {
1897 case 0: nNodeType = EffectNodeType::ON_CLICK; break;
1898 case 1: nNodeType = EffectNodeType::WITH_PREVIOUS; break;
1899 case 2: nNodeType = EffectNodeType::AFTER_PREVIOUS; break;
1900 default:
1901 return;
1902 }
1903
1904 onChangeStart( nNodeType );
1905}
1906
1907void CustomAnimationPane::onChangeStart( sal_Int16 nNodeType )
1908{
1909 addUndo();
1910
1911 MainSequenceRebuildGuard aGuard( mpMainSequence );
1912
1913 bool bNeedRebuild = false;
1914
1915 for( CustomAnimationEffectPtr& pEffect : maListSelection )
1916 {
1917 if( pEffect->getNodeType() != nNodeType )
1918 {
1919 pEffect->setNodeType( nNodeType );
1920 bNeedRebuild = true;
1921 }
1922 }
1923
1924 if( bNeedRebuild )
1925 {
1926 mpMainSequence->rebuild();
1927 updateControls();
1928 mrBase.GetDocShell()->SetModified();
1929 }
1930}
1931
1932void CustomAnimationPane::onChangeSpeed()
1933{
1934 double fDuration = getDuration();
1935
1936 if(fDuration < 0)
1937 return;
1938 else
1939 {
1940 addUndo();
1941
1942 MainSequenceRebuildGuard aGuard( mpMainSequence );
1943
1944 // change selected effect
1945 for( CustomAnimationEffectPtr& pEffect : maListSelection )
1946 {
1947 pEffect->setDuration( fDuration );
1948 }
1949
1950 mpMainSequence->rebuild();
1951 updateControls();
1952 mrBase.GetDocShell()->SetModified();
1953 }
1954}
1955
1956double CustomAnimationPane::getDuration() const
1957{
1958 double fDuration = 0;
1959
1960 if (!mxCBXDuration->get_text().isEmpty())
1961 fDuration = mxCBXDuration->get_value(FieldUnit::NONE) / 100.0;
1962
1963 return fDuration;
1964}
1965
1966PathKind CustomAnimationPane::getCreatePathKind() const
1967{
1968 PathKind eKind = PathKind::NONE;
1969
1970 if (mxLBAnimation->count_selected_rows() == 1 &&
1971 mxLBCategory->get_active() == gnMotionPathPos)
1972 {
1973 const sal_Int32 nPos = mxLBAnimation->get_selected_index();
1974 if( nPos == mnCurvePathPos )
1975 {
1976 eKind = PathKind::CURVE;
1977 }
1978 else if( nPos == mnPolygonPathPos )
1979 {
1980 eKind = PathKind::POLYGON;
1981 }
1982 else if( nPos == mnFreeformPathPos )
1983 {
1984 eKind = PathKind::FREEFORM;
1985 }
1986 }
1987
1988 return eKind;
1989}
1990
1991void CustomAnimationPane::createPath( PathKind eKind, std::vector< Any >& rTargets, double fDuration)
1992{
1993 sal_uInt16 nSID = 0;
1994
1995 switch( eKind )
1996 {
1997 case PathKind::CURVE: nSID = SID_DRAW_BEZIER_NOFILL( 10000 + 397 ); break;
1998 case PathKind::POLYGON: nSID = SID_DRAW_POLYGON_NOFILL( 10000 + 395 ); break;
1999 case PathKind::FREEFORM: nSID = SID_DRAW_FREELINE_NOFILL( 10000 + 464 ); break;
2000 default: break;
2001 }
2002
2003 if( !nSID )
2004 return;
2005
2006 DrawViewShell* pViewShell = dynamic_cast< DrawViewShell* >(
2007 FrameworkHelper::Instance(mrBase)->GetViewShell(FrameworkHelper::msCenterPaneURL).get());
2008
2009 if( pViewShell )
2010 {
2011 DrawView* pView = pViewShell->GetDrawView();
2012 if( pView )
2013 pView->UnmarkAllObj();
2014
2015 std::vector< Any > aTargets( 1, Any( fDuration ) );
2016 aTargets.insert( aTargets.end(), rTargets.begin(), rTargets.end() );
2017 Sequence< Any > aTargetSequence( comphelper::containerToSequence( aTargets ) );
2018 const SfxUnoAnyItem aItem( SID_ADD_MOTION_PATH(27000 +442), Any( aTargetSequence ) );
2019 pViewShell->GetViewFrame()->GetDispatcher()->ExecuteList( nSID, SfxCallMode::ASYNCHRON, {&aItem} );
2020 }
2021}
2022
2023
2024/// this link is called when the property box is modified by the user
2025IMPL_LINK_NOARG(CustomAnimationPane, implPropertyHdl, LinkParamNone*, void)void CustomAnimationPane::LinkStubimplPropertyHdl(void * instance
, LinkParamNone* data) { return static_cast<CustomAnimationPane
*>(instance)->implPropertyHdl(data); } void CustomAnimationPane
::implPropertyHdl(__attribute__ ((unused)) LinkParamNone*)
2026{
2027 if (!mxLBSubControl)
2028 return;
2029
2030 addUndo();
2031
2032 MainSequenceRebuildGuard aGuard( mpMainSequence );
2033
2034 const Any aValue(mxLBSubControl->getValue());
2035
2036 bool bNeedUpdate = false;
2037
2038 // change selected effect
2039 for( const CustomAnimationEffectPtr& pEffect : maListSelection )
2040 {
2041 if( setProperty1Value( mnPropertyType, pEffect, aValue ) )
2042 bNeedUpdate = true;
2043 }
2044
2045 if( bNeedUpdate )
2046 {
2047 mpMainSequence->rebuild();
2048 updateControls();
2049 mrBase.GetDocShell()->SetModified();
2050 }
2051
2052 onPreview( false );
2053}
2054
2055IMPL_LINK_NOARG(CustomAnimationPane, DelayModifiedHdl, weld::MetricSpinButton&, void)void CustomAnimationPane::LinkStubDelayModifiedHdl(void * instance
, weld::MetricSpinButton& data) { return static_cast<CustomAnimationPane
*>(instance)->DelayModifiedHdl(data); } void CustomAnimationPane
::DelayModifiedHdl(__attribute__ ((unused)) weld::MetricSpinButton
&)
2056{
2057 addUndo();
2058}
2059
2060IMPL_LINK_NOARG(CustomAnimationPane, DelayLoseFocusHdl, weld::Widget&, void)void CustomAnimationPane::LinkStubDelayLoseFocusHdl(void * instance
, weld::Widget& data) { return static_cast<CustomAnimationPane
*>(instance)->DelayLoseFocusHdl(data); } void CustomAnimationPane
::DelayLoseFocusHdl(__attribute__ ((unused)) weld::Widget&
)
2061{
2062 double fBegin = mxMFStartDelay->get_value(FieldUnit::NONE);
2063
2064 //sequence rebuild only when the control loses focus
2065 MainSequenceRebuildGuard aGuard( mpMainSequence );
2066
2067 // change selected effect
2068 for( CustomAnimationEffectPtr& pEffect : maListSelection )
2069 {
2070 pEffect->setBegin( fBegin/10.0 );
2071 }
2072
2073 mpMainSequence->rebuild();
2074 updateControls();
2075 mrBase.GetDocShell()->SetModified();
2076}
2077
2078IMPL_LINK_NOARG(CustomAnimationPane, AnimationSelectHdl, weld::TreeView&, void)void CustomAnimationPane::LinkStubAnimationSelectHdl(void * instance
, weld::TreeView& data) { return static_cast<CustomAnimationPane
*>(instance)->AnimationSelectHdl(data); } void CustomAnimationPane
::AnimationSelectHdl(__attribute__ ((unused)) weld::TreeView&
)
2079{
2080 maIdle.Start();
2081}
2082
2083IMPL_LINK_NOARG(CustomAnimationPane, SelectionHandler, Timer*, void)void CustomAnimationPane::LinkStubSelectionHandler(void * instance
, Timer* data) { return static_cast<CustomAnimationPane *>
(instance)->SelectionHandler(data); } void CustomAnimationPane
::SelectionHandler(__attribute__ ((unused)) Timer*)
2084{
2085 if (mxLBAnimation->has_grab()) // tdf#136474 try again later
2086 {
2087 maIdle.Start();
2088 return;
2089 }
2090
2091 int nSelected = mxLBAnimation->get_selected_index();
2092
2093 // tdf#99137, the selected entry may also be a subcategory title, so not an effect
2094 // just skip it and move to the next one in this case
2095 if (mxLBAnimation->get_text_emphasis(nSelected, 0))
2096 {
2097 if (nSelected == 0 || nSelected > mnLastSelectedAnimation)
2098 mxLBAnimation->select(++nSelected);
2099 else
2100 mxLBAnimation->select(--nSelected);
2101 }
2102
2103 mnLastSelectedAnimation = nSelected;
2104
2105 CustomAnimationPresetPtr* pPreset = reinterpret_cast<CustomAnimationPresetPtr*>(mxLBAnimation->get_id(nSelected).toInt64());
2106 PathKind ePathKind = getCreatePathKind();
2107
2108 if ( ePathKind != PathKind::NONE )
2109 {
2110 std::vector< Any > aTargets;
2111 MainSequenceRebuildGuard aGuard( mpMainSequence );
2112
2113 for( const CustomAnimationEffectPtr& pEffect : maListSelection )
2114 {
2115 aTargets.push_back( pEffect->getTarget() );
2116
2117 EffectSequenceHelper* pEffectSequence = pEffect->getEffectSequence();
2118 if( !pEffectSequence )
2119 pEffectSequence = mpMainSequence.get();
2120
2121 // delete the old animation, new one will be appended
2122 // by createPath and SID_ADD_MOTION_PATH therein
2123 pEffectSequence->remove( pEffect );
2124 }
2125
2126 createPath( ePathKind, aTargets, 0.0 );
2127 updateMotionPathTags();
2128 return;
2129 }
2130
2131 CustomAnimationPresetPtr pDescriptor(*pPreset);
2132 const double fDuration = (*pPreset)->getDuration();
2133 MainSequenceRebuildGuard aGuard( mpMainSequence );
2134
2135 // get selected effect
2136 for( const CustomAnimationEffectPtr& pEffect : maListSelection )
2137 {
2138 // Dispose the deprecated motion path tag. It will be rebuilt later.
2139 if (pEffect->getPresetClass() == css::presentation::EffectPresetClass::MOTIONPATH)
2140 {
2141 for (auto const& xTag: maMotionPathTags)
2142 {
2143 if(xTag->getEffect() == pEffect && !xTag->isDisposed())
2144 xTag->Dispose();
2145 }
2146 }
2147
2148 EffectSequenceHelper* pEffectSequence = pEffect->getEffectSequence();
2149 if( !pEffectSequence )
2150 pEffectSequence = mpMainSequence.get();
2151
2152 pEffectSequence->replace( pEffect, pDescriptor, fDuration );
2153 }
2154
2155 onPreview(false);
2156}
2157
2158IMPL_LINK_NOARG(CustomAnimationPane, UpdateAnimationLB, weld::ComboBox&, void)void CustomAnimationPane::LinkStubUpdateAnimationLB(void * instance
, weld::ComboBox& data) { return static_cast<CustomAnimationPane
*>(instance)->UpdateAnimationLB(data); } void CustomAnimationPane
::UpdateAnimationLB(__attribute__ ((unused)) weld::ComboBox&
)
2159{
2160 //FIXME: first effect only? what if there is more?
2161 CustomAnimationEffectPtr pEffect = maListSelection.front();
2162 fillAnimationLB( pEffect->hasText() );
2163}
2164
2165IMPL_LINK_NOARG(CustomAnimationPane, DurationModifiedHdl, weld::MetricSpinButton&, void)void CustomAnimationPane::LinkStubDurationModifiedHdl(void * instance
, weld::MetricSpinButton& data) { return static_cast<CustomAnimationPane
*>(instance)->DurationModifiedHdl(data); } void CustomAnimationPane
::DurationModifiedHdl(__attribute__ ((unused)) weld::MetricSpinButton
&)
2166{
2167 if (!mxCBXDuration->get_text().isEmpty())
2168 {
2169 double duration_value = static_cast<double>(mxCBXDuration->get_value(FieldUnit::NONE));
2170 if(duration_value <= 0.0)
2171 {
2172 mxCBXDuration->set_value(1, FieldUnit::NONE);
2173 }
2174 onChangeSpeed();
2175 }
2176}
2177
2178namespace
2179{
2180 void InsertCategory(weld::TreeView& rLBAnimation, const OUString& rMotionPathLabel)
2181 {
2182 int nRow = rLBAnimation.n_children();
2183 rLBAnimation.append_text(rMotionPathLabel);
2184 rLBAnimation.set_text_emphasis(nRow, true, 0);
2185 rLBAnimation.set_text_align(nRow, 0.5, 0);
2186 }
2187}
2188
2189sal_Int32 CustomAnimationPane::fillAnimationLB( bool bHasText )
2190{
2191 PresetCategoryList rCategoryList;
2192 sal_uInt16 nPosition = mxLBCategory->get_active();
2193 const CustomAnimationPresets& rPresets (CustomAnimationPresets::getCustomAnimationPresets());
2194 switch(nPosition)
2195 {
2196 case 0:rCategoryList = rPresets.getEntrancePresets();break;
2197 case 1:rCategoryList = rPresets.getEmphasisPresets();break;
2198 case 2:rCategoryList = rPresets.getExitPresets();break;
2199 case 3:rCategoryList = rPresets.getMotionPathsPresets();break;
2200 case 4:rCategoryList = rPresets.getMiscPresets();break;
2201 }
2202
2203 sal_Int32 nFirstEffect = -1;
2204
2205 int nOldEntryCount = mxLBAnimation->n_children();
2206 int nOldScrollPos = mxLBAnimation->vadjustment_get_value();
2207
2208 mxLBAnimation->freeze();
2209 mxLBAnimation->clear();
2210 mnLastSelectedAnimation = -1;
2211
2212 if (nPosition == gnMotionPathPos)
2213 {
2214 OUString sMotionPathLabel( SdResId( STR_CUSTOMANIMATION_USERPATHreinterpret_cast<char const *>("STR_CUSTOMANIMATION_USERPATH"
"\004" u8"User paths")
) );
2215 InsertCategory(*mxLBAnimation, sMotionPathLabel);
2216 mnCurvePathPos = mxLBAnimation->n_children();
2217 mxLBAnimation->append_text( SvxResId(STR_ObjNameSingulCOMBLINEreinterpret_cast<char const *>("STR_ObjNameSingulCOMBLINE"
"\004" u8"Curve")
) );
2218 mxLBAnimation->set_text_emphasis(mnCurvePathPos, false, 0);
2219 mnPolygonPathPos = mnCurvePathPos + 1;
2220 mxLBAnimation->append_text( SvxResId(STR_ObjNameSingulPOLYreinterpret_cast<char const *>("STR_ObjNameSingulPOLY" "\004"
u8"Polygon")
) );
2221 mxLBAnimation->set_text_emphasis(mnPolygonPathPos, false, 0);
2222 mnFreeformPathPos = mnPolygonPathPos + 1;
2223 mxLBAnimation->append_text( SvxResId(STR_ObjNameSingulFREELINEreinterpret_cast<char const *>("STR_ObjNameSingulFREELINE"
"\004" u8"Freeform Line")
) );
2224 mxLBAnimation->set_text_emphasis(mnFreeformPathPos, false, 0);
2225 }
2226
2227 for (PresetCategoryPtr& pCategory : rCategoryList)
2228 {
2229 if( pCategory )
2230 {
2231 InsertCategory(*mxLBAnimation, pCategory->maLabel);
2232
2233 int nPos = mxLBAnimation->n_children();
2234
2235 std::vector< CustomAnimationPresetPtr > aSortedVector =
2236 pCategory->maEffects;
2237
2238 for( CustomAnimationPresetPtr& pDescriptor : aSortedVector )
2239 {
2240 // ( !isTextOnly || ( isTextOnly && bHasText ) ) <=> !isTextOnly || bHasText
2241 if( pDescriptor && ( !pDescriptor->isTextOnly() || bHasText ) )
2242 {
2243 auto pCustomPtr = new CustomAnimationPresetPtr(pDescriptor);
2244 OUString sId = OUString::number(reinterpret_cast<sal_Int64>(pCustomPtr));
2245 mxLBAnimation->append(sId, pDescriptor->getLabel());
2246 mxLBAnimation->set_text_emphasis(nPos, false, 0);
2247
2248 if (nFirstEffect == -1)
2249 nFirstEffect = nPos;
2250
2251 ++nPos;
2252 }
2253 }
2254 }
2255 }
2256
2257 mxLBAnimation->thaw();
2258
2259 if (mxLBAnimation->n_children() == nOldEntryCount)
2260 mxLBAnimation->vadjustment_set_value(nOldScrollPos);
2261
2262 return nFirstEffect;
2263}
2264
2265IMPL_LINK(CustomAnimationPane, implClickHdl, weld::Button&, rBtn, void)void CustomAnimationPane::LinkStubimplClickHdl(void * instance
, weld::Button& data) { return static_cast<CustomAnimationPane
*>(instance)->implClickHdl(data); } void CustomAnimationPane
::implClickHdl(weld::Button& rBtn)
2266{
2267 implControlHdl(&rBtn);
2268}
2269
2270IMPL_LINK( CustomAnimationPane, implControlListBoxHdl, weld::ComboBox&, rListBox, void )void CustomAnimationPane::LinkStubimplControlListBoxHdl(void *
instance, weld::ComboBox& data) { return static_cast<
CustomAnimationPane *>(instance)->implControlListBoxHdl
(data); } void CustomAnimationPane::implControlListBoxHdl(weld
::ComboBox& rListBox)
2271{
2272 implControlHdl(&rListBox);
2273}
2274
2275/// this link is called when one of the controls is modified
2276void CustomAnimationPane::implControlHdl(const weld::Widget* pControl)
2277{
2278 if (pControl == mxPBAddEffect.get())
2279 onAdd();
2280 else if (pControl == mxPBRemoveEffect.get())
2281 onRemove();
2282 else if (pControl == mxLBStart.get())
2283 onChangeStart();
2284 else if (pControl == mxPBPropertyMore.get())
2285 showOptions();
2286 else if (pControl == mxPBMoveUp.get())
2287 moveSelection( true );
2288 else if (pControl == mxPBMoveDown.get())
2289 moveSelection( false );
2290 else if (pControl == mxPBPlay.get())
2291 onPreview( true );
2292 else if (pControl == mxCBAutoPreview.get())
2293 {
2294 SdOptions* pOptions = SD_MOD()( static_cast<SdModule*>(SfxApplication::GetModule(SfxToolsModule
::Draw)) )
->GetSdOptions(DocumentType::Impress);
2295 pOptions->SetPreviewChangedEffects(mxCBAutoPreview->get_active());
2296 }
2297}
2298
2299IMPL_LINK_NOARG(CustomAnimationPane, lateInitCallback, Timer *, void)void CustomAnimationPane::LinkStublateInitCallback(void * instance
, Timer * data) { return static_cast<CustomAnimationPane *
>(instance)->lateInitCallback(data); } void CustomAnimationPane
::lateInitCallback(__attribute__ ((unused)) Timer *)
2300{
2301 // Call getPresets() to initiate the (expensive) construction of the
2302 // presets list.
2303 CustomAnimationPresets::getCustomAnimationPresets();
2304
2305 // update selection and control states
2306 onSelectionChanged();
2307}
2308
2309void CustomAnimationPane::moveSelection( bool bUp )
2310{
2311 if( maListSelection.empty() )
2312 return;
2313
2314 EffectSequenceHelper* pSequence = maListSelection.front()->getEffectSequence();
2315 if( pSequence == nullptr )
2316 return;
2317
2318 addUndo();
2319
2320 bool bChanged = false;
2321
2322 MainSequenceRebuildGuard aGuard( mpMainSequence );
2323 EffectSequence& rEffectSequence = pSequence->getSequence();
2324
2325 if( bUp )
2326 {
2327 for( const CustomAnimationEffectPtr& pEffect : maListSelection )
2328 {
2329 EffectSequence::iterator aUpEffectPos( pSequence->find( pEffect ) );
2330 // coverity[copy_paste_error : FALSE] - this is correct, checking if it exists
2331 if( aUpEffectPos != rEffectSequence.end() )
2332 {
2333 EffectSequence::iterator aInsertPos( rEffectSequence.erase( aUpEffectPos ) );
2334
2335 if( aInsertPos != rEffectSequence.begin() )
2336 {
2337 --aInsertPos;
2338 while( (aInsertPos != rEffectSequence.begin()) && !mxCustomAnimationList->isExpanded(*aInsertPos))
2339 --aInsertPos;
2340 rEffectSequence.insert( aInsertPos, pEffect );
2341 }
2342 else
2343 {
2344 rEffectSequence.push_front( pEffect );
2345 }
2346 bChanged = true;
2347 }
2348 }
2349 }
2350 else
2351 {
2352 EffectSequence::reverse_iterator aIter( maListSelection.rbegin() );
2353 const EffectSequence::reverse_iterator aEnd( maListSelection.rend() );
2354
2355 while( aIter != aEnd )
2356 {
2357 CustomAnimationEffectPtr pEffect = *aIter++;
2358
2359 EffectSequence::iterator aDownEffectPos( pSequence->find( pEffect ) );
2360 // coverity[copy_paste_error : FALSE] - this is correct, checking if it exists
2361 if( aDownEffectPos != rEffectSequence.end() )
2362 {
2363 EffectSequence::iterator aInsertPos( rEffectSequence.erase( aDownEffectPos ) );
2364
2365 if( aInsertPos != rEffectSequence.end() )
2366 {
2367 ++aInsertPos;
2368 // Advance over rolled-up (un-expanded) items, unless we just moved it there.
2369 while( (aInsertPos != rEffectSequence.end())
2370 && !mxCustomAnimationList->isExpanded(*aInsertPos)
2371 && (std::find(maListSelection.begin(), maListSelection.end(), *aInsertPos)
2372 == maListSelection.end())
2373 )
2374 ++aInsertPos;
2375 rEffectSequence.insert( aInsertPos, pEffect );
2376 }
2377 else
2378 {
2379 rEffectSequence.push_back( pEffect );
2380 }
2381 bChanged = true;
2382 }
2383 }
2384 }
2385
2386 if( bChanged )
2387 {
2388 mpMainSequence->rebuild();
2389 updateControls();
2390 mrBase.GetDocShell()->SetModified();
2391 }
2392}
2393
2394void CustomAnimationPane::onPreview( bool bForcePreview )
2395{
2396 if (!bForcePreview && !mxCBAutoPreview->get_active())
2397 return;
2398
2399 // No preview in LOK.
2400 if (comphelper::LibreOfficeKit::isActive())
2401 return;
2402
2403 if( maListSelection.empty() )
2404 {
2405 rtl::Reference< MotionPathTag > xMotionPathTag;
2406 auto aIter = std::find_if(maMotionPathTags.begin(), maMotionPathTags.end(),
2407 [](const MotionPathTagVector::value_type& rxMotionPathTag) { return rxMotionPathTag->isSelected(); });
2408 if (aIter != maMotionPathTags.end())
2409 xMotionPathTag = *aIter;
2410
2411 if( xMotionPathTag.is() )
2412 {
2413 MainSequencePtr pSequence = std::make_shared<MainSequence>();
2414 pSequence->append( xMotionPathTag->getEffect()->clone() );
2415 preview( pSequence->getRootNode() );
2416 }
2417 else
2418 {
2419 Reference< XAnimationNodeSupplier > xNodeSupplier( mxCurrentPage, UNO_QUERY );
2420 if( !xNodeSupplier.is() )
2421 return;
2422
2423 preview( xNodeSupplier->getAnimationNode() );
2424 }
2425 }
2426 else
2427 {
2428 MainSequencePtr pSequence = std::make_shared<MainSequence>();
2429
2430 for( const CustomAnimationEffectPtr& pEffect : maListSelection )
2431 {
2432 pSequence->append( pEffect->clone() );
2433 }
2434
2435 preview( pSequence->getRootNode() );
2436 }
2437}
2438
2439void CustomAnimationPane::preview( const Reference< XAnimationNode >& xAnimationNode )
2440{
2441 Reference< XParallelTimeContainer > xRoot = ParallelTimeContainer::create( ::comphelper::getProcessComponentContext() );
2442 Sequence< css::beans::NamedValue > aUserData
2443 { { "node-type", css::uno::makeAny(css::presentation::EffectNodeType::TIMING_ROOT) } };
2444 xRoot->setUserData( aUserData );
2445 xRoot->appendChild( xAnimationNode );
2446
2447 SlideShow::StartPreview( mrBase, mxCurrentPage, xRoot );
2448}
2449
2450// ICustomAnimationListController
2451void CustomAnimationPane::onSelect()
2452{
2453 maListSelection = mxCustomAnimationList->getSelection();
2454 updateControls();
2455
2456 // mark shapes from selected effects
2457 if( maSelectionLock.isLocked() )
2458 return;
2459
2460 ScopeLockGuard aGuard( maSelectionLock );
2461 DrawViewShell* pViewShell = dynamic_cast< DrawViewShell* >(
2462 FrameworkHelper::Instance(mrBase)->GetViewShell(FrameworkHelper::msCenterPaneURL).get());
2463 DrawView* pView = pViewShell ? pViewShell->GetDrawView() : nullptr;
2464
2465 if( pView )
2466 {
2467 pView->UnmarkAllObj();
2468 for( const CustomAnimationEffectPtr& pEffect : maListSelection )
2469 {
2470 Reference< XShape > xShape( pEffect->getTargetShape() );
2471 SdrObject* pObj = GetSdrObjectFromXShape( xShape );
2472 if( pObj )
2473 pView->MarkObj(pObj, pView->GetSdrPageView());
2474 }
2475 }
2476}
2477
2478// ICustomAnimationListController
2479// pEffectInsertBefore may be null if moving to end of list.
2480void CustomAnimationPane::onDragNDropComplete(std::vector< CustomAnimationEffectPtr > pEffectsDragged, CustomAnimationEffectPtr pEffectInsertBefore)
2481{
2482 if ( !mpMainSequence )
2483 return;
2484
2485 addUndo();
2486
2487 MainSequenceRebuildGuard aGuard( mpMainSequence );
2488
2489 // Move all selected effects
2490 for( auto const& pEffectDragged : pEffectsDragged )
2491 {
2492 // Move this dragged effect and any hidden sub-effects
2493 EffectSequence::iterator aIter = mpMainSequence->find( pEffectDragged );
2494 const EffectSequence::iterator aEnd( mpMainSequence->getEnd() );
2495
2496 while( aIter != aEnd )
2497 {
2498 CustomAnimationEffectPtr pEffect = *aIter++;
2499
2500 // Update model with new location (function triggers a rebuild)
2501 // target may be null, which will insert at the end.
2502 mpMainSequence->moveToBeforeEffect( pEffect, pEffectInsertBefore );
2503 // Done moving effect and its hidden sub-effects when *next* effect is visible.
2504 if (aIter != aEnd && mxCustomAnimationList->isVisible(*aIter))
2505 break;
2506 }
2507 }
2508
2509 updateControls();
2510 mrBase.GetDocShell()->SetModified();
2511}
2512
2513void CustomAnimationPane::updatePathFromMotionPathTag( const rtl::Reference< MotionPathTag >& xTag )
2514{
2515 MainSequenceRebuildGuard aGuard( mpMainSequence );
2516 if( !xTag.is() )
2517 return;
2518
2519 SdrPathObj* pPathObj = xTag->getPathObj();
2520 CustomAnimationEffectPtr pEffect = xTag->getEffect();
2521 if( (pPathObj != nullptr) && pEffect )
2522 {
2523 SfxUndoManager* pManager = mrBase.GetDocShell()->GetUndoManager();
2524 if( pManager )
2525 {
2526 SdPage* pPage = SdPage::getImplementation( mxCurrentPage );
2527 if( pPage )
2528 pManager->AddUndoAction( std::make_unique<UndoAnimationPath>( mrBase.GetDocShell()->GetDoc(), pPage, pEffect->getNode() ) );
2529 }
2530
2531 pEffect->updatePathFromSdrPathObj( *pPathObj );
2532 }
2533}
2534
2535vcl::Window * createCustomAnimationPanel( vcl::Window* pParent, ViewShellBase& rBase, const css::uno::Reference<css::frame::XFrame>& rxFrame )
2536{
2537 vcl::Window* pWindow = nullptr;
2538
2539 DrawDocShell* pDocSh = rBase.GetDocShell();
2540 if( pDocSh )
1
Assuming 'pDocSh' is non-null
2
Taking true branch
2541 {
2542 pWindow = VclPtr<CustomAnimationPane>::Create( pParent, rBase, rxFrame );
3
Calling 'VclPtr::Create'
5
Returned allocated memory
6
Calling implicit destructor for 'VclPtr<sd::CustomAnimationPane>'
7
Calling '~Reference'
14
Returning from '~Reference'
15
Returning from destructor for 'VclPtr<sd::CustomAnimationPane>'
2543 }
2544
2545 return pWindow;
16
Use of memory after it is freed
2546}
2547
2548}
2549
2550/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#ifndef INCLUDED_VCL_PTR_HXX
21#define INCLUDED_VCL_PTR_HXX
22
23#include <sal/config.h>
24
25#include <rtl/ref.hxx>
26
27#include <utility>
28#include <type_traits>
29
30#ifdef DBG_UTIL
31#ifndef _WIN32
32#include <vcl/vclmain.hxx>
33#endif
34#endif
35
36class VclReferenceBase;
37
38namespace vcl::detail {
39
40template<typename>
41constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; }
42
43template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase(
44 int (*)[sizeof(T)])
45{ return std::is_base_of<VclReferenceBase, T>::value; }
46
47} // namespace vcl::detail
48
49/**
50 * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses.
51 *
52 * For more details on the design please see vcl/README.lifecycle
53 *
54 * @param reference_type must be a subclass of vcl::Window
55 */
56template <class reference_type>
57class VclPtr
58{
59 static_assert(
60 vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>(
61 nullptr),
62 "template argument type must be derived from VclReferenceBase");
63
64 ::rtl::Reference<reference_type> m_rInnerRef;
65
66public:
67 /** Constructor...
68 */
69 VclPtr()
70 : m_rInnerRef()
71 {}
72
73 /** Constructor...
74 */
75 VclPtr (reference_type * pBody)
76 : m_rInnerRef(pBody)
77 {}
78
79 /** Constructor... that doesn't take a ref.
80 */
81 VclPtr (reference_type * pBody, __sal_NoAcquire)
82 : m_rInnerRef(pBody, SAL_NO_ACQUIRE)
83 {}
84
85 /** Up-casting conversion constructor: Copies interface reference.
86
87 Does not work for up-casts to ambiguous bases. For the special case of
88 up-casting to Reference< XInterface >, see the corresponding conversion
89 operator.
90
91 @param rRef another reference
92 */
93 template< class derived_type >
94 VclPtr(
95 const VclPtr< derived_type > & rRef,
96 typename std::enable_if<
97 std::is_base_of<reference_type, derived_type>::value, int>::type
98 = 0 )
99 : m_rInnerRef( static_cast<reference_type*>(rRef) )
100 {
101 }
102
103#if defined(DBG_UTIL) && !defined(_WIN32)
104 virtual ~VclPtr()
105 {
106 assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain
::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 106, __extension__ __PRETTY_FUNCTION__))
;
107 // We can be one of the intermediate counts, but if we are the last
108 // VclPtr keeping this object alive, then something forgot to call dispose().
109 assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
110 && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
;
111 }
112 VclPtr(VclPtr const &) = default;
113 VclPtr(VclPtr &&) = default;
114 VclPtr & operator =(VclPtr const &) = default;
115 VclPtr & operator =(VclPtr &&) = default;
116#endif
117
118 /**
119 * A construction helper for VclPtr. Since VclPtr types are created
120 * with a reference-count of one - to help fit into the existing
121 * code-flow; this helps us to construct them easily.
122 *
123 * For more details on the design please see vcl/README.lifecycle
124 *
125 * @tparam reference_type must be a subclass of vcl::Window
126 */
127 template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg)
128 {
129 return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE );
4
Memory is allocated
130 }
131
132 /** Probably most common used: handle->someBodyOp().
133 */
134 reference_type * operator->() const
135 {
136 return m_rInnerRef.get();
137 }
138
139 /** Get the body. Can be used instead of operator->().
140 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
141 are the same.
142 */
143 reference_type * get() const
144 {
145 return m_rInnerRef.get();
146 }
147
148 void set(reference_type *pBody)
149 {
150 m_rInnerRef.set(pBody);
151 }
152
153 void reset(reference_type *pBody)
154 {
155 m_rInnerRef.set(pBody);
156 }
157
158 /** Up-casting copy assignment operator.
159
160 Does not work for up-casts to ambiguous bases.
161
162 @param rRef another reference
163 */
164 template<typename derived_type>
165 typename std::enable_if<
166 std::is_base_of<reference_type, derived_type>::value,
167 VclPtr &>::type
168 operator =(VclPtr<derived_type> const & rRef)
169 {
170 m_rInnerRef.set(rRef.get());
171 return *this;
172 }
173
174 VclPtr & operator =(reference_type * pBody)
175 {
176 m_rInnerRef.set(pBody);
177 return *this;
178 }
179
180 operator reference_type * () const
181 {
182 return m_rInnerRef.get();
183 }
184
185 explicit operator bool () const
186 {
187 return m_rInnerRef.get() != nullptr;
188 }
189
190 void clear()
191 {
192 m_rInnerRef.clear();
193 }
194
195 void reset()
196 {
197 m_rInnerRef.clear();
198 }
199
200 void disposeAndClear()
201 {
202 // hold it alive for the lifetime of this method
203 ::rtl::Reference<reference_type> aTmp(m_rInnerRef);
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
205 if (aTmp.get()) {
206 aTmp->disposeOnce();
207 }
208 }
209
210 /** Needed to place VclPtr's into STL collection.
211 */
212 bool operator< (const VclPtr<reference_type> & handle) const
213 {
214 return (m_rInnerRef < handle.m_rInnerRef);
215 }
216}; // class VclPtr
217
218template<typename T1, typename T2>
219inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
220 return p1.get() == p2.get();
221}
222
223template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2)
224{
225 return p1.get() == p2;
226}
227
228template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) {
229 return p1.get() == p2;
230}
231
232template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2)
233{
234 return p1 == p2.get();
235}
236
237template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) {
238 return p1 == p2.get();
239}
240
241template<typename T1, typename T2>
242inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
243 return !(p1 == p2);
244}
245
246template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2)
247{
248 return !(p1 == p2);
249}
250
251template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) {
252 return !(p1 == p2);
253}
254
255template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2)
256{
257 return !(p1 == p2);
258}
259
260template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) {
261 return !(p1 == p2);
262}
263
264/**
265 * A construction helper for a temporary VclPtr. Since VclPtr types
266 * are created with a reference-count of one - to help fit into
267 * the existing code-flow; this helps us to construct them easily.
268 * see also VclPtr::Create and ScopedVclPtr
269 *
270 * For more details on the design please see vcl/README.lifecycle
271 *
272 * @param reference_type must be a subclass of vcl::Window
273 */
274template <class reference_type>
275class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type>
276{
277public:
278 template<typename... Arg> VclPtrInstance(Arg &&... arg)
279 : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
280 {
281 }
282
283 /**
284 * Override and disallow this, to prevent people accidentally calling it and actually
285 * getting VclPtr::Create and getting a naked VclPtr<> instance
286 */
287 template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete;
288};
289
290template <class reference_type>
291class ScopedVclPtr : public VclPtr<reference_type>
292{
293public:
294 /** Constructor...
295 */
296 ScopedVclPtr()
297 : VclPtr<reference_type>()
298 {}
299
300 /** Constructor
301 */
302 ScopedVclPtr (reference_type * pBody)
303 : VclPtr<reference_type>(pBody)
304 {}
305
306 /** Copy constructor...
307 */
308 ScopedVclPtr (const VclPtr<reference_type> & handle)
309 : VclPtr<reference_type>(handle)
310 {}
311
312 /**
313 Assignment that releases the last reference.
314 */
315 void disposeAndReset(reference_type *pBody)
316 {
317 if (pBody != this->get()) {
318 VclPtr<reference_type>::disposeAndClear();
319 VclPtr<reference_type>::set(pBody);
320 }
321 }
322
323 /**
324 Assignment that releases the last reference.
325 */
326 ScopedVclPtr<reference_type>& operator = (reference_type * pBody)
327 {
328 disposeAndReset(pBody);
329 return *this;
330 }
331
332 /** Up-casting conversion constructor: Copies interface reference.
333
334 Does not work for up-casts to ambiguous bases. For the special case of
335 up-casting to Reference< XInterface >, see the corresponding conversion
336 operator.
337
338 @param rRef another reference
339 */
340 template< class derived_type >
341 ScopedVclPtr(
342 const VclPtr< derived_type > & rRef,
343 typename std::enable_if<
344 std::is_base_of<reference_type, derived_type>::value, int>::type
345 = 0 )
346 : VclPtr<reference_type>( rRef )
347 {
348 }
349
350 /** Up-casting assignment operator.
351
352 Does not work for up-casts to ambiguous bases.
353
354 @param rRef another VclPtr
355 */
356 template<typename derived_type>
357 typename std::enable_if<
358 std::is_base_of<reference_type, derived_type>::value,
359 ScopedVclPtr &>::type
360 operator =(VclPtr<derived_type> const & rRef)
361 {
362 disposeAndReset(rRef.get());
363 return *this;
364 }
365
366 /**
367 * Override and disallow this, to prevent people accidentally calling it and actually
368 * getting VclPtr::Create and getting a naked VclPtr<> instance
369 */
370 template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete;
371
372 ~ScopedVclPtr()
373 {
374 VclPtr<reference_type>::disposeAndClear();
375 assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get(
) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 375, __extension__ __PRETTY_FUNCTION__))
; // make sure there are no lingering references
376 }
377
378private:
379 // Most likely we don't want this default copy-constructor.
380 ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete;
381 // And certainly we don't want a default assignment operator.
382 ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete;
383 // And disallow reset as that doesn't call disposeAndClear on the original reference
384 void reset() = delete;
385 void reset(reference_type *pBody) = delete;
386
387protected:
388 ScopedVclPtr (reference_type * pBody, __sal_NoAcquire)
389 : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE)
390 {}
391};
392
393/**
394 * A construction helper for ScopedVclPtr. Since VclPtr types are created
395 * with a reference-count of one - to help fit into the existing
396 * code-flow; this helps us to construct them easily.
397 *
398 * For more details on the design please see vcl/README.lifecycle
399 *
400 * @param reference_type must be a subclass of vcl::Window
401 */
402#if defined _MSC_VER
403#pragma warning(push)
404#pragma warning(disable: 4521) // " multiple copy constructors specified"
405#endif
406template <class reference_type>
407class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type>
408{
409public:
410 template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg)
411 : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
412 {
413 }
414
415 /**
416 * Override and disallow this, to prevent people accidentally calling it and actually
417 * getting VclPtr::Create and getting a naked VclPtr<> instance
418 */
419 template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete;
420
421private:
422 // Prevent the above perfect forwarding ctor from hijacking (accidental)
423 // attempts at ScopedVclPtrInstance copy construction (where the hijacking
424 // would typically lead to somewhat obscure error messages); both non-const
425 // and const variants are needed here, as the ScopedVclPtr base class has a
426 // const--variant copy ctor, so the implicitly declared copy ctor for
427 // ScopedVclPtrInstance would also be the const variant, so non-const copy
428 // construction attempts would be hijacked by the perfect forwarding ctor;
429 // but if we only declared a non-const variant here, the const variant would
430 // no longer be implicitly declared (as there would already be an explicitly
431 // declared copy ctor), so const copy construction attempts would then be
432 // hijacked by the perfect forwarding ctor:
433 ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete;
434 ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete;
435};
436#if defined _MSC_VER
437#pragma warning(pop)
438#endif
439
440#endif // INCLUDED_VCL_PTR_HXX
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/rtl/ref.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#ifndef INCLUDED_RTL_REF_HXX
21#define INCLUDED_RTL_REF_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <functional>
28#ifdef LIBO_INTERNAL_ONLY1
29#include <type_traits>
30#endif
31
32#include "sal/types.h"
33
34namespace rtl
35{
36
37/** Template reference class for reference type.
38*/
39template <class reference_type>
40class Reference
41{
42 /** The <b>reference_type</b> body pointer.
43 */
44 reference_type * m_pBody;
45
46
47public:
48 /** Constructor...
49 */
50 Reference()
51 : m_pBody (NULL__null)
52 {}
53
54
55 /** Constructor...
56 */
57 Reference (reference_type * pBody, __sal_NoAcquire)
58 : m_pBody (pBody)
59 {
60 }
61
62 /** Constructor...
63 */
64 Reference (reference_type * pBody)
65 : m_pBody (pBody)
66 {
67 if (m_pBody)
68 m_pBody->acquire();
69 }
70
71 /** Copy constructor...
72 */
73 Reference (const Reference<reference_type> & handle)
74 : m_pBody (handle.m_pBody)
75 {
76 if (m_pBody)
77 m_pBody->acquire();
78 }
79
80#ifdef LIBO_INTERNAL_ONLY1
81 /** Move constructor...
82 */
83 Reference (Reference<reference_type> && handle) noexcept
84 : m_pBody (handle.m_pBody)
85 {
86 handle.m_pBody = nullptr;
87 }
88#endif
89
90#if defined LIBO_INTERNAL_ONLY1
91 /** Up-casting conversion constructor: Copies interface reference.
92
93 Does not work for up-casts to ambiguous bases.
94
95 @param rRef another reference
96 */
97 template< class derived_type >
98 inline Reference(
99 const Reference< derived_type > & rRef,
100 std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 )
101 : m_pBody (rRef.get())
102 {
103 if (m_pBody)
104 m_pBody->acquire();
105 }
106#endif
107
108 /** Destructor...
109 */
110 ~Reference() COVERITY_NOEXCEPT_FALSE
111 {
112 if (m_pBody
7.1
Field 'm_pBody' is non-null
7.1
Field 'm_pBody' is non-null
7.1
Field 'm_pBody' is non-null
7.1
Field 'm_pBody' is non-null
)
8
Taking true branch
113 m_pBody->release();
9
Calling 'VclReferenceBase::release'
13
Returning; memory was released
114 }
115
116 /** Set...
117 Similar to assignment.
118 */
119 Reference<reference_type> &
120 SAL_CALL set (reference_type * pBody)
121 {
122 if (pBody)
123 pBody->acquire();
124 reference_type * const pOld = m_pBody;
125 m_pBody = pBody;
126 if (pOld)
127 pOld->release();
128 return *this;
129 }
130
131 /** Assignment.
132 Unbinds this instance from its body (if bound) and
133 bind it to the body represented by the handle.
134 */
135 Reference<reference_type> &
136 SAL_CALL operator= (const Reference<reference_type> & handle)
137 {
138 return set( handle.m_pBody );
139 }
140
141#ifdef LIBO_INTERNAL_ONLY1
142 /** Assignment.
143 * Unbinds this instance from its body (if bound),
144 * bind it to the body represented by the handle, and
145 * set the body represented by the handle to nullptr.
146 */
147 Reference<reference_type> &
148 operator= (Reference<reference_type> && handle)
149 {
150 // self-movement guts ourself
151 if (m_pBody)
152 m_pBody->release();
153 m_pBody = handle.m_pBody;
154 handle.m_pBody = nullptr;
155 return *this;
156 }
157#endif
158
159 /** Assignment...
160 */
161 Reference<reference_type> &
162 SAL_CALL operator= (reference_type * pBody)
163 {
164 return set( pBody );
165 }
166
167 /** Unbind the body from this handle.
168 Note that for a handle representing a large body,
169 "handle.clear().set(new body());" _might_
170 perform a little bit better than "handle.set(new body());",
171 since in the second case two large objects exist in memory
172 (the old body and the new body).
173 */
174 Reference<reference_type> & SAL_CALL clear()
175 {
176 if (m_pBody)
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
181 }
182 return *this;
183 }
184
185
186 /** Get the body. Can be used instead of operator->().
187 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
188 are the same.
189 */
190 reference_type * SAL_CALL get() const
191 {
192 return m_pBody;
193 }
194
195
196 /** Probably most common used: handle->someBodyOp().
197 */
198 reference_type * SAL_CALL operator->() const
199 {
200 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 200, __extension__ __PRETTY_FUNCTION__))
;
201 return m_pBody;
202 }
203
204
205 /** Allows (*handle).someBodyOp().
206 */
207 reference_type & SAL_CALL operator*() const
208 {
209 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 209, __extension__ __PRETTY_FUNCTION__))
;
210 return *m_pBody;
211 }
212
213
214 /** Returns True if the handle does point to a valid body.
215 */
216 bool SAL_CALL is() const
217 {
218 return (m_pBody != NULL__null);
219 }
220
221#if defined LIBO_INTERNAL_ONLY1
222 /** Returns True if the handle does point to a valid body.
223 */
224 explicit operator bool() const
225 {
226 return is();
227 }
228#endif
229
230 /** Returns True if this points to pBody.
231 */
232 bool SAL_CALL operator== (const reference_type * pBody) const
233 {
234 return (m_pBody == pBody);
235 }
236
237
238 /** Returns True if handle points to the same body.
239 */
240 bool
241 SAL_CALL operator== (const Reference<reference_type> & handle) const
242 {
243 return (m_pBody == handle.m_pBody);
244 }
245
246
247 /** Needed to place References into STL collection.
248 */
249 bool
250 SAL_CALL operator!= (const Reference<reference_type> & handle) const
251 {
252 return (m_pBody != handle.m_pBody);
253 }
254
255
256 /** Needed to place References into STL collection.
257 */
258 bool
259 SAL_CALL operator< (const Reference<reference_type> & handle) const
260 {
261 return (m_pBody < handle.m_pBody);
262 }
263
264
265 /** Needed to place References into STL collection.
266 */
267 bool
268 SAL_CALL operator> (const Reference<reference_type> & handle) const
269 {
270 return (m_pBody > handle.m_pBody);
271 }
272};
273
274} // namespace rtl
275
276#if defined LIBO_INTERNAL_ONLY1
277namespace std
278{
279
280/// @cond INTERNAL
281/**
282 Make rtl::Reference hashable by default for use in STL containers.
283
284 @since LibreOffice 6.3
285*/
286template<typename T>
287struct hash<::rtl::Reference<T>>
288{
289 std::size_t operator()(::rtl::Reference<T> const & s) const
290 { return std::size_t(s.get()); }
291};
292/// @endcond
293
294}
295
296#endif
297
298#endif /* ! INCLUDED_RTL_REF_HXX */
299
300/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclreferencebase.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19#ifndef INCLUDED_VCL_Reference_HXX
20#define INCLUDED_VCL_Reference_HXX
21
22#include <vcl/dllapi.h>
23#include <osl/interlck.h>
24
25class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase
26{
27 mutable oslInterlockedCount mnRefCnt;
28
29 template<typename T> friend class VclPtr;
30
31public:
32 void acquire() const
33 {
34 osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1);
35 }
36
37 void release() const
38 {
39 if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0)
10
Assuming the condition is true
11
Taking true branch
40 delete this;
12
Memory is released
41 }
42#ifdef DBG_UTIL
43#ifndef _WIN32
44 sal_Int32 getRefCount() const { return mnRefCnt; }
45#endif
46#endif
47
48
49private:
50 VclReferenceBase(const VclReferenceBase&) = delete;
51 VclReferenceBase& operator=(const VclReferenceBase&) = delete;
52
53 bool mbDisposed : 1;
54
55protected:
56 VclReferenceBase();
57protected:
58 virtual ~VclReferenceBase();
59
60protected:
61 virtual void dispose();
62
63public:
64 void disposeOnce();
65 bool isDisposed() const { return mbDisposed; }
66
67};
68#endif