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 <config_features.h>
21 
22 #include <com/sun/star/presentation/EffectNodeType.hpp>
23 #include <com/sun/star/animations/Timing.hpp>
24 #include <com/sun/star/animations/Event.hpp>
25 #include <com/sun/star/animations/EventTrigger.hpp>
26 #include <com/sun/star/animations/AnimationFill.hpp>
27 #include <com/sun/star/presentation/TextAnimationType.hpp>
28 #include <com/sun/star/animations/ValuePair.hpp>
29 #include <com/sun/star/awt/FontSlant.hpp>
30 #include <com/sun/star/awt/FontWeight.hpp>
31 #include <com/sun/star/awt/FontUnderline.hpp>
32 #include <com/sun/star/drawing/XDrawPage.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/media/XPlayer.hpp>
35 
36 #include <memory>
37 
38 #include <comphelper/lok.hxx>
39 #include <i18nutil/unicode.hxx>
40 #include <vcl/svapp.hxx>
41 #include <vcl/stdtext.hxx>
42 #include <vcl/weld.hxx>
43 #include <vcl/settings.hxx>
44 
45 #include <svtools/ctrltool.hxx>
46 #include <sfx2/objsh.hxx>
47 #include <tools/debug.hxx>
48 #include <tools/urlobj.hxx>
49 #include <tools/diagnose_ex.h>
50 
51 #include <editeng/flstitem.hxx>
52 
53 #include <svx/colorbox.hxx>
54 #include <svx/gallery.hxx>
55 
56 #include <editeng/editids.hrc>
57 #include <sdresid.hxx>
58 
59 #include "CustomAnimationDialog.hxx"
60 #include <CustomAnimationPane.hxx>
61 #include "STLPropertySet.hxx"
62 #include <CustomAnimationPreset.hxx>
63 
64 #include <avmedia/mediawindow.hxx>
65 
66 #include <filedlg.hxx>
67 #include <strings.hrc>
68 #include <helpids.h>
69 
70 using namespace ::com::sun::star;
71 using namespace ::com::sun::star::animations;
72 using namespace ::com::sun::star::presentation;
73 
74 using ::com::sun::star::uno::UNO_QUERY;
75 using ::com::sun::star::uno::Any;
76 using ::com::sun::star::uno::makeAny;
77 using ::com::sun::star::uno::Sequence;
78 using ::com::sun::star::uno::Reference;
79 using ::com::sun::star::uno::Exception;
80 using ::com::sun::star::drawing::XShape;
81 using ::com::sun::star::drawing::XDrawPage;
82 using ::com::sun::star::beans::XPropertySet;
83 
84 namespace sd {
85 
SdPropertySubControl(weld::Container * pParent)86 SdPropertySubControl::SdPropertySubControl(weld::Container* pParent)
87     : mxBuilder(Application::CreateBuilder(pParent, "modules/simpress/ui/customanimationfragment.ui"))
88     , mxContainer(mxBuilder->weld_container("EffectFragment"))
89     , mpParent(pParent)
90 {
91 }
92 
~SdPropertySubControl()93 SdPropertySubControl::~SdPropertySubControl()
94 {
95     mpParent->move(mxContainer.get(), nullptr);
96 }
97 
98 namespace {
99 
100 class SdPresetPropertyBox  : public SdPropertySubControl
101 {
102 public:
103     SdPresetPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const OUString& aPresetId, const Link<LinkParamNone*,void>& rModifyHdl);
104 
105     virtual Any getValue() override;
106     virtual void setValue( const Any& rValue, const OUString& rPresetId ) override;
107 
108 private:
109     std::vector<OUString> maPropertyValues;
110     Link<LinkParamNone*,void> maModifyLink;
111     std::unique_ptr<weld::ComboBox> mxControl;
112 
113     DECL_LINK(OnSelect, weld::ComboBox&, void);
114 };
115 
116 }
117 
SdPresetPropertyBox(weld::Label * pLabel,weld::Container * pParent,const Any & rValue,const OUString & aPresetId,const Link<LinkParamNone *,void> & rModifyHdl)118 SdPresetPropertyBox::SdPresetPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const OUString& aPresetId, const Link<LinkParamNone*,void>& rModifyHdl)
119     : SdPropertySubControl(pParent)
120     , maModifyLink(rModifyHdl)
121     , mxControl(mxBuilder->weld_combo_box("combo"))
122 {
123     mxControl->connect_changed(LINK(this, SdPresetPropertyBox, OnSelect));
124     mxControl->set_help_id(HID_SD_CUSTOMANIMATIONPANE_PRESETPROPERTYBOX);
125     mxControl->show();
126     pLabel->set_mnemonic_widget(mxControl.get());
127     setValue(rValue, aPresetId);
128 }
129 
IMPL_LINK_NOARG(SdPresetPropertyBox,OnSelect,weld::ComboBox &,void)130 IMPL_LINK_NOARG(SdPresetPropertyBox, OnSelect, weld::ComboBox&, void)
131 {
132     maModifyLink.Call(nullptr);
133 }
134 
setValue(const Any & rValue,const OUString & rPresetId)135 void SdPresetPropertyBox::setValue( const Any& rValue, const OUString& rPresetId )
136 {
137     if (!mxControl)
138         return;
139 
140     mxControl->freeze();
141     mxControl->clear();
142     maPropertyValues.clear();
143     int nPos = -1;
144 
145     const CustomAnimationPresets& rPresets = CustomAnimationPresets::getCustomAnimationPresets();
146     CustomAnimationPresetPtr pDescriptor = rPresets.getEffectDescriptor( rPresetId );
147     if( pDescriptor )
148     {
149 
150         OUString aPropertyValue;
151         rValue >>= aPropertyValue;
152 
153         std::vector<OUString> aSubTypes( pDescriptor->getSubTypes() );
154 
155         mxControl->set_sensitive(!aSubTypes.empty());
156 
157         for( const auto& aSubType : aSubTypes )
158         {
159             mxControl->append_text(rPresets.getUINameForProperty(aSubType));
160             maPropertyValues.push_back(aSubType);
161             if (aSubType == aPropertyValue)
162                 nPos = maPropertyValues.size() - 1;
163         }
164     }
165     else
166     {
167         mxControl->set_sensitive(false);
168     }
169     mxControl->thaw();
170     if (nPos != -1)
171         mxControl->set_active(nPos);
172 }
173 
getValue()174 Any SdPresetPropertyBox::getValue()
175 {
176     const int nIndex = mxControl->get_active();
177     if (nIndex == -1)
178         return Any();
179     return makeAny(maPropertyValues[nIndex]);
180 }
181 
182 namespace {
183 
184 class SdColorPropertyBox : public SdPropertySubControl
185 {
186 public:
187     SdColorPropertyBox(weld::Label* pLabel, weld::Container* pParent, weld::Window* pTopLevel, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl);
188 
189     virtual Any getValue() override;
190     virtual void setValue( const Any& rValue, const OUString& rPresetId  ) override;
191 
192 private:
193     Link<LinkParamNone*,void> maModifyLink;
194     std::unique_ptr<ColorListBox> mxControl;
195 
196     DECL_LINK(OnSelect, ColorListBox&, void);
197 };
198 
199 }
200 
SdColorPropertyBox(weld::Label * pLabel,weld::Container * pParent,weld::Window * pTopLevel,const Any & rValue,const Link<LinkParamNone *,void> & rModifyHdl)201 SdColorPropertyBox::SdColorPropertyBox(weld::Label* pLabel, weld::Container* pParent, weld::Window* pTopLevel, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl)
202     : SdPropertySubControl(pParent)
203     , maModifyLink(rModifyHdl)
204     , mxControl(new ColorListBox(mxBuilder->weld_menu_button("color"), [pTopLevel]{ return pTopLevel; }))
205 {
206     mxControl->SetSelectHdl(LINK(this, SdColorPropertyBox, OnSelect));
207     mxControl->set_help_id(HID_SD_CUSTOMANIMATIONPANE_COLORPROPERTYBOX);
208     pLabel->set_mnemonic_widget(&mxControl->get_widget());
209     mxControl->show();
210 
211     Color nColor;
212     rValue >>= nColor;
213     mxControl->SelectEntry(nColor);
214 }
215 
IMPL_LINK_NOARG(SdColorPropertyBox,OnSelect,ColorListBox &,void)216 IMPL_LINK_NOARG(SdColorPropertyBox, OnSelect, ColorListBox&, void)
217 {
218     maModifyLink.Call(nullptr);
219 }
220 
setValue(const Any & rValue,const OUString &)221 void SdColorPropertyBox::setValue( const Any& rValue, const OUString& )
222 {
223     if (mxControl)
224     {
225         Color nColor;
226         rValue >>= nColor;
227 
228         mxControl->SetNoSelection();
229         mxControl->SelectEntry(nColor);
230     }
231 }
232 
getValue()233 Any SdColorPropertyBox::getValue()
234 {
235     return makeAny(sal_Int32(mxControl->GetSelectEntryColor().GetRGBColor()));
236 }
237 
238 namespace {
239 
240 class SdFontPropertyBox : public SdPropertySubControl
241 {
242 public:
243     SdFontPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl);
244 
245     virtual Any getValue() override;
246     virtual void setValue(const Any& rValue, const OUString& rPresetId) override;
247 
248 private:
249     Link<LinkParamNone*,void>   maModifyHdl;
250     std::unique_ptr<weld::ComboBox> mxControl;
251 
252     DECL_LINK(ControlSelectHdl, weld::ComboBox&, void);
253 };
254 
255 }
256 
SdFontPropertyBox(weld::Label * pLabel,weld::Container * pParent,const Any & rValue,const Link<LinkParamNone *,void> & rModifyHdl)257 SdFontPropertyBox::SdFontPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl)
258     : SdPropertySubControl(pParent)
259     , maModifyHdl(rModifyHdl)
260     , mxControl(mxBuilder->weld_combo_box("fontname"))
261 {
262     mxControl->connect_changed(LINK(this, SdFontPropertyBox, ControlSelectHdl));
263     mxControl->set_help_id(HID_SD_CUSTOMANIMATIONPANE_FONTPROPERTYBOX);
264     mxControl->show();
265     pLabel->set_mnemonic_widget(mxControl.get());
266 
267     SfxObjectShell* pDocSh = SfxObjectShell::Current();
268     const FontList* pFontList = nullptr;
269     bool bMustDelete = false;
270 
271     if (pDocSh)
272     {
273         auto pItem = pDocSh->GetItem( SID_ATTR_CHAR_FONTLIST );
274         if (pItem)
275             pFontList = static_cast<const SvxFontListItem*>(pItem)->GetFontList();
276     }
277 
278     if (!pFontList)
279     {
280         pFontList = new FontList(Application::GetDefaultDevice(), nullptr);
281         bMustDelete = true;
282     }
283 
284     mxControl->freeze();
285 
286     sal_uInt16 nFontCount = pFontList->GetFontNameCount();
287     for (sal_uInt16 i = 0; i < nFontCount; ++i)
288     {
289         const FontMetric& rFontMetric = pFontList->GetFontName(i);
290         mxControl->append_text(rFontMetric.GetFamilyName());
291     }
292 
293     mxControl->thaw();
294 
295     if( bMustDelete )
296         delete pFontList;
297 
298     setValue( rValue, OUString() );
299 }
300 
IMPL_LINK_NOARG(SdFontPropertyBox,ControlSelectHdl,weld::ComboBox &,void)301 IMPL_LINK_NOARG(SdFontPropertyBox, ControlSelectHdl, weld::ComboBox&, void)
302 {
303     maModifyHdl.Call(nullptr);
304 }
305 
setValue(const Any & rValue,const OUString &)306 void SdFontPropertyBox::setValue( const Any& rValue, const OUString& )
307 {
308     if (mxControl)
309     {
310         OUString aFontName;
311         rValue >>= aFontName;
312         mxControl->set_entry_text(aFontName);
313     }
314 }
315 
getValue()316 Any SdFontPropertyBox::getValue()
317 {
318     OUString aFontName(mxControl->get_active_text());
319     return makeAny(aFontName);
320 }
321 
322 namespace {
323 
324 class SdCharHeightPropertyBox : public SdPropertySubControl
325 {
326 public:
327     SdCharHeightPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl);
328 
329     virtual Any getValue() override;
330     virtual void setValue( const Any& rValue, const OUString& ) override;
331 
332     DECL_LINK(implMenuSelectHdl, const OString& rIdent, void);
333 
334 private:
335     Link<LinkParamNone*,void> maModifyHdl;
336     std::unique_ptr<weld::MetricSpinButton> mxMetric;
337     std::unique_ptr<weld::MenuButton> mxControl;
338 
339     DECL_LINK(EditModifyHdl, weld::MetricSpinButton&, void);
340 };
341 
342 }
343 
SdCharHeightPropertyBox(weld::Label * pLabel,weld::Container * pParent,const Any & rValue,const Link<LinkParamNone *,void> & rModifyHdl)344 SdCharHeightPropertyBox::SdCharHeightPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl)
345     : SdPropertySubControl(pParent)
346     , maModifyHdl(rModifyHdl)
347     , mxMetric(mxBuilder->weld_metric_spin_button("fontsize", FieldUnit::PERCENT))
348     , mxControl(mxBuilder->weld_menu_button("fontsizemenu"))
349 {
350     mxMetric->connect_value_changed(LINK(this, SdCharHeightPropertyBox, EditModifyHdl));
351     mxMetric->set_help_id(HID_SD_CUSTOMANIMATIONPANE_CHARHEIGHTPROPERTYBOX);
352     mxMetric->show();
353     pLabel->set_mnemonic_widget(&mxMetric->get_widget());
354 
355     mxControl->connect_selected(LINK(this, SdCharHeightPropertyBox, implMenuSelectHdl));
356     mxControl->set_help_id(HID_SD_CUSTOMANIMATIONPANE_CHARHEIGHTPROPERTYBOX);
357     mxControl->show();
358 
359     setValue(rValue, OUString());
360 }
361 
IMPL_LINK_NOARG(SdCharHeightPropertyBox,EditModifyHdl,weld::MetricSpinButton &,void)362 IMPL_LINK_NOARG(SdCharHeightPropertyBox, EditModifyHdl, weld::MetricSpinButton&, void)
363 {
364     maModifyHdl.Call(nullptr);
365 }
366 
IMPL_LINK(SdCharHeightPropertyBox,implMenuSelectHdl,const OString &,rIdent,void)367 IMPL_LINK(SdCharHeightPropertyBox, implMenuSelectHdl, const OString&, rIdent, void)
368 {
369     sal_Int32 nValue = rIdent.toInt32();
370     mxMetric->set_value(nValue, FieldUnit::PERCENT);
371     EditModifyHdl(*mxMetric);
372 }
373 
setValue(const Any & rValue,const OUString &)374 void SdCharHeightPropertyBox::setValue( const Any& rValue, const OUString& )
375 {
376     if (mxMetric)
377     {
378         double fValue = 0.0;
379         rValue >>= fValue;
380         mxMetric->set_value(static_cast<::tools::Long>(fValue * 100.0), FieldUnit::PERCENT);
381     }
382 }
383 
getValue()384 Any SdCharHeightPropertyBox::getValue()
385 {
386     return makeAny(static_cast<double>(mxMetric->get_value(FieldUnit::PERCENT)) / 100.0);
387 }
388 
389 namespace {
390 
391 class SdTransparencyPropertyBox : public SdPropertySubControl
392 {
393 public:
394     SdTransparencyPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl);
395 
396     virtual Any getValue() override;
397     virtual void setValue( const Any& rValue, const OUString& rPresetId  ) override;
398 
399     DECL_LINK(implMenuSelectHdl, const OString&, void);
400     DECL_LINK(implModifyHdl, weld::MetricSpinButton&, void);
401 
402     void updateMenu();
403 
404 private:
405     Link<LinkParamNone*,void> maModifyHdl;
406 
407     std::unique_ptr<weld::MetricSpinButton> mxMetric;
408     std::unique_ptr<weld::MenuButton> mxControl;
409 };
410 
411 }
412 
SdTransparencyPropertyBox(weld::Label * pLabel,weld::Container * pParent,const Any & rValue,const Link<LinkParamNone *,void> & rModifyHdl)413 SdTransparencyPropertyBox::SdTransparencyPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl)
414     : SdPropertySubControl(pParent)
415     , maModifyHdl(rModifyHdl)
416     , mxMetric(mxBuilder->weld_metric_spin_button("transparent", FieldUnit::PERCENT))
417     , mxControl(mxBuilder->weld_menu_button("transparentmenu"))
418 {
419     for (sal_Int32 i = 25; i < 101; i += 25)
420     {
421         OUString aStr(unicode::formatPercent(i,
422             Application::GetSettings().GetUILanguageTag()));
423         mxControl->append_item_check(OUString::number(i), aStr);
424     }
425 
426     mxControl->connect_selected(LINK(this, SdTransparencyPropertyBox, implMenuSelectHdl));
427     mxControl->set_help_id(HID_SD_CUSTOMANIMATIONPANE_TRANSPARENCYPROPERTYBOX);
428     mxControl->show();
429 
430     mxMetric->connect_value_changed(LINK(this, SdTransparencyPropertyBox, implModifyHdl));
431     mxMetric->set_help_id(HID_SD_CUSTOMANIMATIONPANE_TRANSPARENCYPROPERTYBOX);
432     mxMetric->show();
433     pLabel->set_mnemonic_widget(&mxMetric->get_widget());
434 
435     setValue(rValue, OUString());
436 }
437 
updateMenu()438 void SdTransparencyPropertyBox::updateMenu()
439 {
440     sal_Int64 nValue = mxMetric->get_value(FieldUnit::PERCENT);
441     for (sal_uInt16 i = 25; i < 101; i += 25)
442         mxControl->set_item_active(OString::number(i), nValue == i);
443 }
444 
IMPL_LINK_NOARG(SdTransparencyPropertyBox,implModifyHdl,weld::MetricSpinButton &,void)445 IMPL_LINK_NOARG(SdTransparencyPropertyBox, implModifyHdl, weld::MetricSpinButton&, void)
446 {
447     updateMenu();
448     maModifyHdl.Call(nullptr);
449 }
450 
IMPL_LINK(SdTransparencyPropertyBox,implMenuSelectHdl,const OString &,rIdent,void)451 IMPL_LINK(SdTransparencyPropertyBox, implMenuSelectHdl, const OString&, rIdent, void)
452 {
453     auto nValue = rIdent.toInt32();
454     if (nValue != mxMetric->get_value(FieldUnit::PERCENT))
455     {
456         mxMetric->set_value(nValue, FieldUnit::PERCENT);
457         implModifyHdl(*mxMetric);
458     }
459 }
460 
setValue(const Any & rValue,const OUString &)461 void SdTransparencyPropertyBox::setValue(const Any& rValue, const OUString&)
462 {
463     if (mxMetric)
464     {
465         double fValue = 0.0;
466         rValue >>= fValue;
467         ::tools::Long nValue = static_cast<::tools::Long>(fValue * 100);
468         mxMetric->set_value(nValue, FieldUnit::PERCENT);
469         updateMenu();
470     }
471 }
472 
getValue()473 Any SdTransparencyPropertyBox::getValue()
474 {
475     return makeAny(static_cast<double>(mxMetric->get_value(FieldUnit::PERCENT)) / 100.0);
476 }
477 
478 namespace {
479 
480 class SdRotationPropertyBox : public SdPropertySubControl
481 {
482 public:
483     SdRotationPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl);
484 
485     virtual Any getValue() override;
486     virtual void setValue( const Any& rValue, const OUString& ) override;
487 
488     DECL_LINK(implMenuSelectHdl, const OString&, void);
489     DECL_LINK(implModifyHdl, weld::MetricSpinButton&, void);
490 
491     void updateMenu();
492 
493 private:
494     Link<LinkParamNone*,void> maModifyHdl;
495 
496     std::unique_ptr<weld::MetricSpinButton> mxMetric;
497     std::unique_ptr<weld::MenuButton> mxControl;
498 };
499 
500 }
501 
SdRotationPropertyBox(weld::Label * pLabel,weld::Container * pParent,const Any & rValue,const Link<LinkParamNone *,void> & rModifyHdl)502 SdRotationPropertyBox::SdRotationPropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl)
503     : SdPropertySubControl(pParent)
504     , maModifyHdl(rModifyHdl)
505     , mxMetric(mxBuilder->weld_metric_spin_button("rotate", FieldUnit::DEGREE))
506     , mxControl(mxBuilder->weld_menu_button("rotatemenu"))
507 {
508     mxMetric->connect_value_changed(LINK( this, SdRotationPropertyBox, implModifyHdl));
509     mxMetric->set_help_id(HID_SD_CUSTOMANIMATIONPANE_ROTATIONPROPERTYBOX);
510     mxMetric->show();
511     pLabel->set_mnemonic_widget(&mxMetric->get_widget());
512 
513     mxControl->connect_selected(LINK(this, SdRotationPropertyBox, implMenuSelectHdl));
514     mxControl->set_help_id(HID_SD_CUSTOMANIMATIONPANE_ROTATIONPROPERTYBOX);
515     mxControl->show();
516 
517     setValue(rValue, OUString());
518 }
519 
updateMenu()520 void SdRotationPropertyBox::updateMenu()
521 {
522     sal_Int64 nValue = mxMetric->get_value(FieldUnit::DEGREE);
523     bool bDirection = nValue >= 0;
524     nValue = (nValue < 0 ? -nValue : nValue);
525 
526     mxControl->set_item_active("90", nValue == 90);
527     mxControl->set_item_active("180", nValue == 180);
528     mxControl->set_item_active("360", nValue == 360);
529     mxControl->set_item_active("720", nValue == 720);
530 
531     mxControl->set_item_active("closewise", bDirection);
532     mxControl->set_item_active("counterclock", !bDirection);
533 }
534 
IMPL_LINK_NOARG(SdRotationPropertyBox,implModifyHdl,weld::MetricSpinButton &,void)535 IMPL_LINK_NOARG(SdRotationPropertyBox, implModifyHdl, weld::MetricSpinButton&, void)
536 {
537     updateMenu();
538     maModifyHdl.Call(nullptr);
539 }
540 
IMPL_LINK(SdRotationPropertyBox,implMenuSelectHdl,const OString &,rIdent,void)541 IMPL_LINK(SdRotationPropertyBox, implMenuSelectHdl, const OString&, rIdent, void)
542 {
543     auto nValue = mxMetric->get_value(FieldUnit::DEGREE);
544     bool bDirection = nValue >= 0;
545     nValue = (nValue < 0 ? -nValue : nValue);
546 
547     if (rIdent == "clockwise")
548         bDirection = true;
549     else if (rIdent == "counterclock")
550         bDirection = false;
551     else
552         nValue = rIdent.toInt32();
553 
554     if( !bDirection )
555         nValue = -nValue;
556 
557     if (nValue != mxMetric->get_value(FieldUnit::DEGREE))
558     {
559         mxMetric->set_value(nValue, FieldUnit::DEGREE);
560         implModifyHdl(*mxMetric);
561     }
562 }
563 
setValue(const Any & rValue,const OUString &)564 void SdRotationPropertyBox::setValue( const Any& rValue, const OUString& )
565 {
566     if (mxMetric)
567     {
568         double fValue = 0.0;
569         rValue >>= fValue;
570         ::tools::Long nValue = static_cast<::tools::Long>(fValue);
571         mxMetric->set_value(nValue, FieldUnit::DEGREE);
572         updateMenu();
573     }
574 }
575 
getValue()576 Any SdRotationPropertyBox::getValue()
577 {
578     return makeAny(static_cast<double>(mxMetric->get_value(FieldUnit::DEGREE)));
579 }
580 
581 namespace {
582 
583 class SdScalePropertyBox : public SdPropertySubControl
584 {
585 public:
586     SdScalePropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl);
587 
588     virtual Any getValue() override;
589     virtual void setValue( const Any& rValue, const OUString& ) override;
590 
591     DECL_LINK(implMenuSelectHdl, const OString&, void);
592     DECL_LINK(implModifyHdl, weld::MetricSpinButton&, void);
593 
594     void updateMenu();
595 
596 private:
597     Link<LinkParamNone*,void> maModifyHdl;
598     int                       mnDirection;
599 
600     std::unique_ptr<weld::MetricSpinButton> mxMetric;
601     std::unique_ptr<weld::MenuButton> mxControl;
602 };
603 
604 }
605 
SdScalePropertyBox(weld::Label * pLabel,weld::Container * pParent,const Any & rValue,const Link<LinkParamNone *,void> & rModifyHdl)606 SdScalePropertyBox::SdScalePropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl)
607     : SdPropertySubControl(pParent)
608     , maModifyHdl( rModifyHdl )
609     , mxMetric(mxBuilder->weld_metric_spin_button("scale", FieldUnit::PERCENT))
610     , mxControl(mxBuilder->weld_menu_button("scalemenu"))
611 {
612     mxControl->connect_selected(LINK(this, SdScalePropertyBox, implMenuSelectHdl));
613     mxControl->set_help_id(HID_SD_CUSTOMANIMATIONPANE_SCALEPROPERTYBOX);
614     mxControl->show();
615 
616     mxMetric->connect_value_changed(LINK(this, SdScalePropertyBox, implModifyHdl));
617     mxMetric->set_help_id(HID_SD_CUSTOMANIMATIONPANE_SCALEPROPERTYBOX);
618     mxMetric->show();
619     pLabel->set_mnemonic_widget(&mxMetric->get_widget());
620 
621     setValue(rValue, OUString());
622 }
623 
updateMenu()624 void SdScalePropertyBox::updateMenu()
625 {
626     auto nValue = mxMetric->get_value(FieldUnit::PERCENT);
627 
628     mxControl->set_item_active("25scale", nValue == 25);
629     mxControl->set_item_active("50scale", nValue == 50);
630     mxControl->set_item_active("150scale", nValue == 150);
631     mxControl->set_item_active("400scale", nValue == 400);
632 
633     mxControl->set_item_active("hori", mnDirection == 1);
634     mxControl->set_item_active("vert", mnDirection == 2);
635     mxControl->set_item_active("both", mnDirection == 3);
636 }
637 
IMPL_LINK_NOARG(SdScalePropertyBox,implModifyHdl,weld::MetricSpinButton &,void)638 IMPL_LINK_NOARG(SdScalePropertyBox, implModifyHdl, weld::MetricSpinButton&, void)
639 {
640     updateMenu();
641     maModifyHdl.Call(nullptr);
642 }
643 
IMPL_LINK(SdScalePropertyBox,implMenuSelectHdl,const OString &,rIdent,void)644 IMPL_LINK(SdScalePropertyBox, implMenuSelectHdl, const OString&, rIdent, void)
645 {
646     auto nValue = mxMetric->get_value(FieldUnit::PERCENT);
647 
648     int nDirection = mnDirection;
649 
650     if (rIdent == "hori")
651         nDirection = 1;
652     else if (rIdent == "vert")
653         nDirection = 2;
654     else if (rIdent == "both")
655         nDirection = 3;
656     else
657         nValue = rIdent.toInt32(); // Getting here indicates a UI bug and should be handled better
658 
659     bool bModified = false;
660 
661     if( nDirection != mnDirection )
662     {
663         mnDirection = nDirection;
664         bModified = true;
665     }
666 
667     if (nValue != mxMetric->get_value(FieldUnit::PERCENT))
668     {
669         mxMetric->set_value(nValue, FieldUnit::PERCENT);
670         bModified = true;
671     }
672 
673     if(bModified)
674     {
675         implModifyHdl(*mxMetric);
676         updateMenu();
677     }
678 }
679 
setValue(const Any & rValue,const OUString &)680 void SdScalePropertyBox::setValue(const Any& rValue, const OUString&)
681 {
682     if (!mxMetric)
683         return;
684 
685     ValuePair aValues;
686     rValue >>= aValues;
687 
688     double fValue1 = 0.0;
689     double fValue2 = 0.0;
690 
691     aValues.First >>= fValue1;
692     aValues.Second >>= fValue2;
693 
694     // 'Size' drop down menu set by mnDirection when loading Grow and Shrink Animation
695     // Shouldn't compare a float directly to zero... should be fixed with delta epsilon compare
696     // Might be better to just have a flag in the content.xml for this
697     if( (fValue1 == 0.0) && (fValue2 == 0.0) )
698         mnDirection = 3; // assume 'Both' scaling option when both are zero
699     else if( (fValue1 != 0.0) && (fValue2 == 0.0) )
700         mnDirection = 1;
701     else if( (fValue1 == 0.0) && (fValue2 != 0.0) )
702         mnDirection = 2;
703     else
704         mnDirection = 3;
705 
706     // Grow and Shrink Animation is a relative change with value stored in content.xml under tag
707     // smil:by=*,*
708     // An offset of 1 must be added to properly translate from content.xml to UI value displayed
709     // e.g. if in content.xml smil:by=0.5,0.5 then 1 + (0.5,0.5) = (1.5,1.5) => grow by 150% of the
710     // size horizontal and vertical
711     // e.g. if in content.xml smil:by=-0.5,-0.5 then 1 + (-0.5,-0.5) = (0.5,0.5) => shrink by 50%
712     // of the size horizontal and vertical
713     fValue1 += 1;
714     fValue2 += 1;
715 
716     // Determine value from file for UI 'Size' field based on determined mnDirection
717     ::tools::Long nValue;
718     if( mnDirection == 1 )
719         nValue = static_cast<::tools::Long>(fValue1 * 100.0);
720     else if( mnDirection == 2 )
721         nValue = static_cast<::tools::Long>(fValue2 * 100.0);
722     else if( mnDirection == 3 ){
723         if (fValue1 >= fValue2)
724             nValue = static_cast<::tools::Long>(fValue1 * 100.0);
725         else
726             nValue = static_cast<::tools::Long>(fValue2 * 100.0);
727     }
728     else
729         nValue = static_cast<::tools::Long>(100.0); // default to 100% in UI if something goes wrong
730 
731     mxMetric->set_value(nValue, FieldUnit::PERCENT);
732     updateMenu();
733 }
734 
getValue()735 Any SdScalePropertyBox::getValue()
736 {
737     double fValue1 = static_cast<double>(mxMetric->get_value(FieldUnit::PERCENT)) / 100.0;
738 
739     // Grow and Shrink Animation is a relative change with value stored in content.xml under tag
740     // smil:by=*,*
741     // An offset of 1 must be subtracted to properly translate UI value displayed and save to
742     // content.xml
743     // e.g. if UI value is 150% then  1.5 - 1 = 0.5 and is set to smil:by=0.5,0.5 in content.xml
744     // e.g. if UI value is 50% then  0.5 - 1 = -0.5 and is set to smil:by=-0.5,-0.5 in content.xml
745     fValue1 -= 1;
746 
747     double fValue2 = fValue1;
748 
749     // mnDirection set by 'Size' drop down menu and used to zero out either horizontal or vertical
750     // scaling depending on what option is selected
751     if( mnDirection == 1 )
752         fValue2 = 0.0;
753     else if( mnDirection == 2 )
754         fValue1 = 0.0;
755 
756     ValuePair aValues;
757     aValues.First <<= fValue1;
758     aValues.Second <<= fValue2;
759 
760     return makeAny( aValues );
761 }
762 
763 namespace {
764 
765 class SdFontStylePropertyBox : public SdPropertySubControl
766 {
767 public:
768     SdFontStylePropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl);
769 
770     virtual Any getValue() override;
771     virtual void setValue( const Any& rValue, const OUString& ) override;
772 
773     DECL_LINK(implMenuSelectHdl, const OString&, void);
774 
775     void update();
776 
777 private:
778     float mfFontWeight;
779     awt::FontSlant meFontSlant;
780     sal_Int16 mnFontUnderline;
781     Link<LinkParamNone*,void> maModifyHdl;
782 
783     std::unique_ptr<weld::Entry> mxEdit;
784     std::unique_ptr<weld::MenuButton> mxControl;
785 };
786 
787 }
788 
SdFontStylePropertyBox(weld::Label * pLabel,weld::Container * pParent,const Any & rValue,const Link<LinkParamNone *,void> & rModifyHdl)789 SdFontStylePropertyBox::SdFontStylePropertyBox(weld::Label* pLabel, weld::Container* pParent, const Any& rValue, const Link<LinkParamNone*,void>& rModifyHdl )
790     : SdPropertySubControl(pParent)
791     , maModifyHdl( rModifyHdl )
792     , mxEdit(mxBuilder->weld_entry("entry"))
793     , mxControl(mxBuilder->weld_menu_button("entrymenu"))
794 {
795     mxEdit->set_text(SdResId(STR_CUSTOMANIMATION_SAMPLE));
796     mxEdit->set_help_id(HID_SD_CUSTOMANIMATIONPANE_FONTSTYLEPROPERTYBOX);
797     pLabel->set_mnemonic_widget(mxEdit.get());
798     mxEdit->show();
799 
800     mxControl->connect_selected(LINK(this, SdFontStylePropertyBox, implMenuSelectHdl));
801     mxControl->set_help_id(HID_SD_CUSTOMANIMATIONPANE_FONTSTYLEPROPERTYBOX);
802     mxControl->show();
803 
804     setValue(rValue, OUString());
805 }
806 
update()807 void SdFontStylePropertyBox::update()
808 {
809     // update menu
810     mxControl->set_item_active("bold", mfFontWeight == awt::FontWeight::BOLD);
811     mxControl->set_item_active("italic", meFontSlant == awt::FontSlant_ITALIC);
812     mxControl->set_item_active("underline", mnFontUnderline != awt::FontUnderline::NONE );
813 
814     // update sample edit
815     vcl::Font aFont(mxEdit->get_font());
816     aFont.SetWeight(mfFontWeight == awt::FontWeight::BOLD ? WEIGHT_BOLD : WEIGHT_NORMAL);
817     aFont.SetItalic(meFontSlant == awt::FontSlant_ITALIC ? ITALIC_NORMAL : ITALIC_NONE);
818     aFont.SetUnderline(mnFontUnderline == awt::FontUnderline::NONE ? LINESTYLE_NONE : LINESTYLE_SINGLE);
819     mxEdit->set_font(aFont);
820 }
821 
IMPL_LINK(SdFontStylePropertyBox,implMenuSelectHdl,const OString &,rIdent,void)822 IMPL_LINK(SdFontStylePropertyBox, implMenuSelectHdl, const OString&, rIdent, void)
823 {
824     if (rIdent == "bold")
825     {
826         if( mfFontWeight == awt::FontWeight::BOLD )
827             mfFontWeight = awt::FontWeight::NORMAL;
828         else
829             mfFontWeight = awt::FontWeight::BOLD;
830     }
831     else if (rIdent == "italic")
832     {
833         if( meFontSlant == awt::FontSlant_ITALIC )
834             meFontSlant = awt::FontSlant_NONE;
835         else
836             meFontSlant = awt::FontSlant_ITALIC;
837     }
838     else if (rIdent == "underline")
839     {
840         if( mnFontUnderline == awt::FontUnderline::SINGLE )
841             mnFontUnderline = awt::FontUnderline::NONE;
842         else
843             mnFontUnderline = awt::FontUnderline::SINGLE;
844     }
845 
846     update();
847     maModifyHdl.Call(nullptr);
848 }
849 
setValue(const Any & rValue,const OUString &)850 void SdFontStylePropertyBox::setValue( const Any& rValue, const OUString& )
851 {
852     Sequence<Any> aValues;
853     rValue >>= aValues;
854 
855     aValues[0] >>= mfFontWeight;
856     aValues[1] >>= meFontSlant;
857     aValues[2] >>= mnFontUnderline;
858 
859     update();
860 }
861 
getValue()862 Any SdFontStylePropertyBox::getValue()
863 {
864     Sequence<Any> aValues(3);
865     aValues[0] <<= mfFontWeight;
866     aValues[1] <<= meFontSlant;
867     aValues[2] <<= mnFontUnderline;
868     return makeAny( aValues );
869 }
870 
871 class CustomAnimationEffectTabPage
872 {
873 public:
874     CustomAnimationEffectTabPage(weld::Container* pParent, weld::Window* pDialog, const STLPropertySet* pSet);
875 
876     void update( STLPropertySet* pSet );
877     DECL_LINK(implSelectHdl, weld::ComboBox&, void);
878     DECL_LINK(implClickHdl, weld::Button&, void);
879     void implHdl(const weld::Widget*);
880 
881 private:
882     void updateControlStates();
883     void fillSoundListBox();
884     void clearSoundListBox();
885     sal_Int32 getSoundObject( std::u16string_view rStr );
886     void openSoundFileDialog();
887     void onSoundPreview();
GetFrameWeld() const888     weld::Window* GetFrameWeld() const { return mpDialog; }
889 
890 private:
891     ::std::vector< OUString > maSoundList;
892     bool mbHasText;
893     const STLPropertySet* mpSet;
894     css::uno::Reference<css::media::XPlayer> mxPlayer;
895 
896     weld::Window* mpDialog;
897     std::unique_ptr<weld::Builder> mxBuilder;
898     std::unique_ptr<weld::Container> mxContainer;
899     std::unique_ptr<weld::Widget> mxSettings;
900     std::unique_ptr<weld::Label> mxFTProperty1;
901     std::unique_ptr<weld::Container> mxPlaceholderBox;
902     std::unique_ptr<weld::CheckButton> mxCBSmoothStart;
903     std::unique_ptr<weld::CheckButton> mxCBSmoothEnd;
904     std::unique_ptr<weld::Label> mxFTSound;
905     std::unique_ptr<weld::ComboBox> mxLBSound;
906     std::unique_ptr<weld::Button> mxPBSoundPreview;
907     std::unique_ptr<weld::Label> mxFTAfterEffect;
908     std::unique_ptr<weld::ComboBox> mxLBAfterEffect;
909     std::unique_ptr<weld::Label> mxFTDimColor;
910     std::unique_ptr<ColorListBox> mxCLBDimColor;
911     std::unique_ptr<weld::Label> mxFTTextAnim;
912     std::unique_ptr<weld::ComboBox> mxLBTextAnim;
913     std::unique_ptr<weld::MetricSpinButton> mxMFTextDelay;
914     std::unique_ptr<weld::Label> mxFTTextDelay;
915     std::unique_ptr<SdPropertySubControl> mxLBSubControl;
916 };
917 
CustomAnimationEffectTabPage(weld::Container * pParent,weld::Window * pDialog,const STLPropertySet * pSet)918 CustomAnimationEffectTabPage::CustomAnimationEffectTabPage(weld::Container* pParent, weld::Window* pDialog, const STLPropertySet* pSet)
919     : mbHasText(false)
920     , mpSet(pSet)
921     , mpDialog(pDialog)
922     , mxBuilder(Application::CreateBuilder(pParent, "modules/simpress/ui/customanimationeffecttab.ui"))
923     , mxContainer(mxBuilder->weld_container("EffectTab"))
924     , mxSettings(mxBuilder->weld_widget("settings"))
925     , mxFTProperty1(mxBuilder->weld_label("prop_label1"))
926     , mxPlaceholderBox(mxBuilder->weld_container("placeholder"))
927     , mxCBSmoothStart(mxBuilder->weld_check_button("smooth_start"))
928     , mxCBSmoothEnd(mxBuilder->weld_check_button("smooth_end"))
929     , mxFTSound(mxBuilder->weld_label("sound_label"))
930     , mxLBSound(mxBuilder->weld_combo_box("sound_list"))
931     , mxPBSoundPreview(mxBuilder->weld_button("sound_preview"))
932     , mxFTAfterEffect(mxBuilder->weld_label("aeffect_label"))
933     , mxLBAfterEffect(mxBuilder->weld_combo_box("aeffect_list"))
934     , mxFTDimColor(mxBuilder->weld_label("dim_color_label"))
935     , mxCLBDimColor(new ColorListBox(mxBuilder->weld_menu_button("dim_color_list"), [pDialog]{ return pDialog; }))
936     , mxFTTextAnim(mxBuilder->weld_label("text_animation_label"))
937     , mxLBTextAnim(mxBuilder->weld_combo_box("text_animation_list"))
938     , mxMFTextDelay(mxBuilder->weld_metric_spin_button("text_delay", FieldUnit::PERCENT))
939     , mxFTTextDelay(mxBuilder->weld_label("text_delay_label"))
940 {
941     mxCLBDimColor->SelectEntry(COL_BLACK);
942 
943     // fill the soundbox
944     fillSoundListBox();
945 
946     mxLBSound->connect_changed(LINK(this, CustomAnimationEffectTabPage, implSelectHdl));
947     mxPBSoundPreview->connect_clicked(LINK(this, CustomAnimationEffectTabPage, implClickHdl));
948 
949     // only show settings if all selected effects have the same preset-id
950     if( pSet->getPropertyState( nHandlePresetId ) != STLPropertyState::Ambiguous )
951     {
952         OUString aPresetId;
953         pSet->getPropertyValue( nHandlePresetId ) >>= aPresetId;
954 
955         // property 1
956 
957         if( pSet->getPropertyState( nHandleProperty1Type ) != STLPropertyState::Ambiguous )
958         {
959             sal_Int32 nType = 0;
960             pSet->getPropertyValue( nHandleProperty1Type ) >>= nType;
961 
962             if( nType != nPropertyTypeNone )
963             {
964                 // set ui name for property at fixed text
965                 OUString aPropertyName( getPropertyName( nType ) );
966 
967                 if( !aPropertyName.isEmpty() )
968                 {
969                     mxSettings->show();
970                     mxFTProperty1->set_label(aPropertyName);
971                 }
972 
973                 // get property value
974                 const Any aValue( pSet->getPropertyValue( nHandleProperty1Value ) );
975 
976                 // create property sub control
977                 mxLBSubControl = SdPropertySubControl::create(nType, mxFTProperty1.get(), mxPlaceholderBox.get(), mpDialog, aValue, aPresetId, Link<LinkParamNone*,void>());
978             }
979         }
980 
981         mxFTProperty1->set_sensitive(mxPlaceholderBox->get_sensitive());
982 
983         // accelerate & decelerate
984 
985         if( pSet->getPropertyState( nHandleAccelerate ) == STLPropertyState::Direct )
986         {
987             mxCBSmoothStart->show();
988             mxCBSmoothEnd->show();
989 
990             double fTemp = 0.0;
991             pSet->getPropertyValue( nHandleAccelerate ) >>= fTemp;
992             mxCBSmoothStart->set_active( fTemp > 0.0 );
993 
994             pSet->getPropertyValue( nHandleDecelerate ) >>= fTemp;
995             mxCBSmoothEnd->set_active( fTemp > 0.0 );
996         }
997     }
998 
999     // init after effect controls
1000 
1001     mxLBAfterEffect->connect_changed(LINK(this, CustomAnimationEffectTabPage, implSelectHdl));
1002     mxLBTextAnim->connect_changed(LINK(this, CustomAnimationEffectTabPage, implSelectHdl));
1003 
1004     if( (pSet->getPropertyState( nHandleHasAfterEffect ) != STLPropertyState::Ambiguous) &&
1005         (pSet->getPropertyState( nHandleAfterEffectOnNextEffect ) != STLPropertyState::Ambiguous) &&
1006         (pSet->getPropertyState( nHandleDimColor ) != STLPropertyState::Ambiguous))
1007     {
1008         bool bHasAfterEffect = false;
1009         pSet->getPropertyValue( nHandleHasAfterEffect ) >>= bHasAfterEffect;
1010 
1011         sal_Int32 nPos = 0;
1012         if( bHasAfterEffect )
1013         {
1014             nPos++;
1015 
1016             bool bAfterEffectOnNextClick = false;
1017             pSet->getPropertyValue( nHandleAfterEffectOnNextEffect ) >>= bAfterEffectOnNextClick;
1018             Any aDimColor( pSet->getPropertyValue( nHandleDimColor ) );
1019 
1020             if( aDimColor.hasValue() )
1021             {
1022                 Color aColor;
1023                 aDimColor >>= aColor;
1024                 mxCLBDimColor->SelectEntry(aColor);
1025             }
1026             else
1027             {
1028                 nPos++;
1029                 if( bAfterEffectOnNextClick )
1030                     nPos++;
1031             }
1032         }
1033 
1034         mxLBAfterEffect->set_active(nPos);
1035     }
1036 
1037     if( pSet->getPropertyState( nHandleHasText ) != STLPropertyState::Ambiguous )
1038         pSet->getPropertyValue( nHandleHasText ) >>= mbHasText;
1039 
1040     if( mbHasText )
1041     {
1042         if( pSet->getPropertyState( nHandleIterateType ) != STLPropertyState::Ambiguous)
1043         {
1044             int nPos = -1;
1045 
1046             sal_Int32 nIterateType = 0;
1047             pSet->getPropertyValue( nHandleIterateType ) >>= nIterateType;
1048             switch( nIterateType )
1049             {
1050             case TextAnimationType::BY_PARAGRAPH:   nPos = 0; break;
1051             case TextAnimationType::BY_WORD:        nPos = 1; break;
1052             case TextAnimationType::BY_LETTER:      nPos = 2; break;
1053             }
1054 
1055             mxLBTextAnim->set_active(nPos);
1056         }
1057 
1058         if( pSet->getPropertyState( nHandleIterateInterval ) != STLPropertyState::Default )
1059         {
1060             double fIterateInterval = 0.0;
1061             pSet->getPropertyValue( nHandleIterateInterval ) >>= fIterateInterval;
1062             mxMFTextDelay->set_value(static_cast<::tools::Long>(fIterateInterval*10), FieldUnit::NONE);
1063         }
1064     }
1065     else
1066     {
1067         mxFTTextAnim->set_sensitive(false);
1068         mxLBTextAnim->set_sensitive(false);
1069         mxMFTextDelay->set_sensitive(false);
1070         mxFTTextDelay->set_sensitive(false);
1071 
1072     }
1073 
1074     if( pSet->getPropertyState( nHandleSoundURL ) != STLPropertyState::Ambiguous )
1075     {
1076         sal_Int32 nPos = 0;
1077 
1078         const Any aValue( pSet->getPropertyValue( nHandleSoundURL ) );
1079 
1080         if( aValue.getValueType() == ::cppu::UnoType<sal_Bool>::get() )
1081         {
1082             nPos = 1;
1083         }
1084         else
1085         {
1086             OUString aSoundURL;
1087             aValue >>= aSoundURL;
1088 
1089             if( !aSoundURL.isEmpty() )
1090             {
1091                 sal_uLong i;
1092                 for( i = 0; i < maSoundList.size(); i++ )
1093                 {
1094                     OUString aString = maSoundList[ i ];
1095                     if( aString == aSoundURL )
1096                     {
1097                         nPos = static_cast<sal_Int32>(i)+2;
1098                         break;
1099                     }
1100                 }
1101 
1102                 if( nPos == 0 )
1103                 {
1104                     nPos = static_cast<sal_Int32>(maSoundList.size())+2;
1105                     maSoundList.push_back( aSoundURL );
1106                     INetURLObject aURL( aSoundURL );
1107                     mxLBSound->insert_text(nPos, aURL.GetBase());
1108                 }
1109             }
1110         }
1111 
1112         if( nPos != -1)
1113             mxLBSound->set_active(nPos);
1114     }
1115 
1116     updateControlStates();
1117 
1118 }
1119 
updateControlStates()1120 void CustomAnimationEffectTabPage::updateControlStates()
1121 {
1122     auto nPos = mxLBAfterEffect->get_active();
1123     mxCLBDimColor->set_sensitive( nPos == 1 );
1124     mxFTDimColor->set_sensitive( nPos == 1 );
1125 
1126     if( mbHasText )
1127     {
1128         nPos = mxLBTextAnim->get_active();
1129         mxMFTextDelay->set_sensitive( nPos != 0 );
1130         mxFTTextDelay->set_sensitive( nPos != 0 );
1131     }
1132 
1133     if (comphelper::LibreOfficeKit::isActive())
1134     {
1135         mxFTSound->hide();
1136         mxLBSound->hide();
1137         mxPBSoundPreview->hide();
1138     }
1139     else
1140     {
1141         nPos = mxLBSound->get_active();
1142         mxPBSoundPreview->set_sensitive( nPos >= 2 );
1143     }
1144 
1145 }
1146 
IMPL_LINK(CustomAnimationEffectTabPage,implClickHdl,weld::Button &,rBtn,void)1147 IMPL_LINK(CustomAnimationEffectTabPage, implClickHdl, weld::Button&, rBtn, void)
1148 {
1149     implHdl(&rBtn);
1150 }
1151 
IMPL_LINK(CustomAnimationEffectTabPage,implSelectHdl,weld::ComboBox &,rListBox,void)1152 IMPL_LINK(CustomAnimationEffectTabPage, implSelectHdl, weld::ComboBox&, rListBox, void)
1153 {
1154     implHdl(&rListBox);
1155 }
1156 
implHdl(const weld::Widget * pControl)1157 void CustomAnimationEffectTabPage::implHdl(const weld::Widget* pControl)
1158 {
1159     if (pControl == mxLBTextAnim.get())
1160     {
1161         if (mxMFTextDelay->get_value(FieldUnit::NONE) == 0)
1162             mxMFTextDelay->set_value(100, FieldUnit::NONE);
1163     }
1164     else if (pControl == mxLBSound.get())
1165     {
1166         auto nPos = mxLBSound->get_active();
1167         if (nPos == (mxLBSound->get_count() - 1))
1168         {
1169             openSoundFileDialog();
1170         }
1171     }
1172     else if (pControl == mxPBSoundPreview.get())
1173     {
1174         onSoundPreview();
1175     }
1176 
1177     updateControlStates();
1178 }
1179 
update(STLPropertySet * pSet)1180 void CustomAnimationEffectTabPage::update( STLPropertySet* pSet )
1181 {
1182     if (mxLBSubControl)
1183     {
1184         Any aNewValue(mxLBSubControl->getValue());
1185         Any aOldValue;
1186         if( mpSet->getPropertyState( nHandleProperty1Value ) != STLPropertyState::Ambiguous)
1187             aOldValue = mpSet->getPropertyValue( nHandleProperty1Value );
1188 
1189         if( aOldValue != aNewValue )
1190             pSet->setPropertyValue( nHandleProperty1Value, aNewValue );
1191     }
1192 
1193     if (mxCBSmoothStart->get_visible())
1194     {
1195         // set selected value for accelerate if different than in original set
1196 
1197         double fTemp = mxCBSmoothStart->get_active() ? 0.5 : 0.0;
1198 
1199         double fOldTemp = 0.0;
1200         if(mpSet->getPropertyState( nHandleAccelerate ) != STLPropertyState::Ambiguous)
1201             mpSet->getPropertyValue( nHandleAccelerate ) >>= fOldTemp;
1202         else
1203             fOldTemp = -2.0;
1204 
1205         if( fOldTemp != fTemp )
1206             pSet->setPropertyValue( nHandleAccelerate, makeAny( fTemp ) );
1207 
1208         // set selected value for decelerate if different than in original set
1209         fTemp = mxCBSmoothEnd->get_active() ? 0.5 : 0.0;
1210 
1211         if(mpSet->getPropertyState( nHandleDecelerate ) != STLPropertyState::Ambiguous)
1212             mpSet->getPropertyValue( nHandleDecelerate ) >>= fOldTemp;
1213         else
1214             fOldTemp = -2.0;
1215 
1216         if( fOldTemp != fTemp )
1217             pSet->setPropertyValue( nHandleDecelerate, makeAny( fTemp ) );
1218     }
1219 
1220     auto nPos = mxLBAfterEffect->get_active();
1221     if (nPos != -1)
1222     {
1223         bool bAfterEffect = nPos != 0;
1224 
1225         bool bOldAfterEffect = false;
1226 
1227         if(mpSet->getPropertyState( nHandleHasAfterEffect ) != STLPropertyState::Ambiguous)
1228             mpSet->getPropertyValue( nHandleHasAfterEffect ) >>= bOldAfterEffect;
1229         else
1230             bOldAfterEffect = !bAfterEffect;
1231 
1232         if( bOldAfterEffect != bAfterEffect )
1233             pSet->setPropertyValue( nHandleHasAfterEffect, makeAny( bAfterEffect ) );
1234 
1235         Any aDimColor;
1236         if( nPos == 1 )
1237         {
1238             Color aSelectedColor = mxCLBDimColor->GetSelectEntryColor();
1239             aDimColor <<= aSelectedColor.GetRGBColor();
1240         }
1241 
1242         if( (mpSet->getPropertyState( nHandleDimColor ) == STLPropertyState::Ambiguous) ||
1243             (mpSet->getPropertyValue( nHandleDimColor ) != aDimColor) )
1244             pSet->setPropertyValue( nHandleDimColor, aDimColor );
1245 
1246         bool bAfterEffectOnNextEffect = nPos != 2;
1247         bool bOldAfterEffectOnNextEffect = !bAfterEffectOnNextEffect;
1248 
1249         if( mpSet->getPropertyState( nHandleAfterEffectOnNextEffect ) != STLPropertyState::Ambiguous)
1250             mpSet->getPropertyValue( nHandleAfterEffectOnNextEffect ) >>= bOldAfterEffectOnNextEffect;
1251 
1252         if( bAfterEffectOnNextEffect != bOldAfterEffectOnNextEffect )
1253             pSet->setPropertyValue( nHandleAfterEffectOnNextEffect, makeAny( bAfterEffectOnNextEffect ) );
1254     }
1255 
1256     nPos = mxLBTextAnim->get_active();
1257     if (nPos != -1)
1258     {
1259         sal_Int16 nIterateType;
1260 
1261         switch( nPos )
1262         {
1263         case 1: nIterateType = TextAnimationType::BY_WORD; break;
1264         case 2: nIterateType = TextAnimationType::BY_LETTER; break;
1265         default:
1266             nIterateType = TextAnimationType::BY_PARAGRAPH;
1267         }
1268 
1269         sal_Int16 nOldIterateType = nIterateType-1;
1270 
1271         if(mpSet->getPropertyState( nHandleIterateType ) != STLPropertyState::Ambiguous)
1272             mpSet->getPropertyValue( nHandleIterateType ) >>= nOldIterateType;
1273 
1274         if( nIterateType != nOldIterateType )
1275             pSet->setPropertyValue( nHandleIterateType, makeAny( nIterateType ) );
1276     }
1277 
1278     {
1279         double fIterateInterval = static_cast<double>(mxMFTextDelay->get_value(FieldUnit::NONE)) / 10;
1280         double fOldIterateInterval = -1.0;
1281 
1282         if( mpSet->getPropertyState( nHandleIterateInterval ) != STLPropertyState::Ambiguous )
1283             mpSet->getPropertyValue( nHandleIterateInterval ) >>= fOldIterateInterval;
1284 
1285         if( fIterateInterval != fOldIterateInterval )
1286             pSet->setPropertyValue( nHandleIterateInterval, makeAny( fIterateInterval ) );
1287     }
1288 
1289     nPos = mxLBSound->get_active();
1290     if (nPos == -1)
1291         return;
1292 
1293     Any aNewSoundURL, aOldSoundURL( makeAny( sal_Int32(0) ) );
1294 
1295     if( nPos == 0 )
1296     {
1297         // 0 means no sound, so leave any empty
1298     }
1299     else if( nPos == 1 )
1300     {
1301         // this means stop sound
1302         aNewSoundURL <<= true;
1303     }
1304     else
1305     {
1306         OUString aSoundURL( maSoundList[ nPos-2 ] );
1307         aNewSoundURL <<= aSoundURL;
1308     }
1309 
1310     if( mpSet->getPropertyState( nHandleSoundURL ) != STLPropertyState::Ambiguous )
1311         aOldSoundURL = mpSet->getPropertyValue( nHandleSoundURL  );
1312 
1313     if( aNewSoundURL != aOldSoundURL )
1314         pSet->setPropertyValue( nHandleSoundURL, aNewSoundURL );
1315 }
1316 
fillSoundListBox()1317 void CustomAnimationEffectTabPage::fillSoundListBox()
1318 {
1319     GalleryExplorer::FillObjList( GALLERY_THEME_SOUNDS, maSoundList );
1320     GalleryExplorer::FillObjList( GALLERY_THEME_USERSOUNDS, maSoundList );
1321 
1322     mxLBSound->append_text( SdResId(STR_CUSTOMANIMATION_NO_SOUND) );
1323     mxLBSound->append_text( SdResId(STR_CUSTOMANIMATION_STOP_PREVIOUS_SOUND) );
1324     for(const OUString & rString : maSoundList)
1325     {
1326         INetURLObject aURL( rString );
1327         mxLBSound->append_text( aURL.GetBase() );
1328     }
1329     mxLBSound->append_text( SdResId(STR_CUSTOMANIMATION_BROWSE_SOUND) );
1330 }
1331 
clearSoundListBox()1332 void CustomAnimationEffectTabPage::clearSoundListBox()
1333 {
1334     maSoundList.clear();
1335     mxLBSound->clear();
1336 }
1337 
getSoundObject(std::u16string_view rStr)1338 sal_Int32 CustomAnimationEffectTabPage::getSoundObject( std::u16string_view rStr )
1339 {
1340     size_t i;
1341     const size_t nCount = maSoundList.size();
1342     for( i = 0; i < nCount; i++ )
1343     {
1344         if( maSoundList[ i ].equalsIgnoreAsciiCase(rStr) )
1345             return i+2;
1346     }
1347 
1348     return -1;
1349 }
1350 
openSoundFileDialog()1351 void CustomAnimationEffectTabPage::openSoundFileDialog()
1352 {
1353     SdOpenSoundFileDialog aFileDialog(GetFrameWeld());
1354 
1355     bool bValidSoundFile = false;
1356     bool bQuitLoop = false;
1357     ::tools::Long nPos = 0;
1358 
1359     while( !bQuitLoop && (aFileDialog.Execute() == ERRCODE_NONE) )
1360     {
1361         OUString aFile = aFileDialog.GetPath();
1362         nPos = getSoundObject( aFile );
1363 
1364         if( nPos < 0 ) // not in Soundliste
1365         {
1366             // try to insert in Gallery
1367             if( GalleryExplorer::InsertURL( GALLERY_THEME_USERSOUNDS, aFile ) )
1368             {
1369                 clearSoundListBox();
1370                 fillSoundListBox();
1371 
1372                 nPos = getSoundObject( aFile );
1373                 DBG_ASSERT( nPos >= 0, "sd::CustomAnimationEffectTabPage::openSoundFileDialog(), Recently inserted sound not in list!" );
1374 
1375                 bValidSoundFile=true;
1376                 bQuitLoop=true;
1377             }
1378             else
1379             {
1380                 OUString aStrWarning(SdResId(STR_WARNING_NOSOUNDFILE));
1381                 aStrWarning = aStrWarning.replaceFirst("%", aFile);
1382                 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(nullptr,
1383                                                            VclMessageType::Warning, VclButtonsType::NONE,
1384                                                            aStrWarning));
1385                 xWarn->add_button(GetStandardText(StandardButtonType::Retry), RET_RETRY);
1386                 xWarn->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
1387                 bQuitLoop = xWarn->run() != RET_RETRY;
1388 
1389                 bValidSoundFile=false;
1390             }
1391         }
1392         else
1393         {
1394             bValidSoundFile=true;
1395             bQuitLoop=true;
1396         }
1397     }
1398 
1399     if( !bValidSoundFile )
1400         nPos = 0;
1401 
1402     mxLBSound->set_active(nPos);
1403 }
1404 
onSoundPreview()1405 void CustomAnimationEffectTabPage::onSoundPreview()
1406 {
1407 #if HAVE_FEATURE_AVMEDIA
1408     const auto nPos = mxLBSound->get_active();
1409 
1410     if( nPos >= 2 ) try
1411     {
1412         const OUString aSoundURL( maSoundList[ nPos-2 ] );
1413         mxPlayer.set( avmedia::MediaWindow::createPlayer( aSoundURL, "" ), uno::UNO_SET_THROW );
1414         mxPlayer->start();
1415     }
1416     catch( uno::Exception& )
1417     {
1418         TOOLS_WARN_EXCEPTION( "sd", "CustomAnimationEffectTabPage::onSoundPreview()" );
1419     }
1420 #endif
1421 }
1422 
1423 class CustomAnimationDurationTabPage
1424 {
1425 public:
1426     CustomAnimationDurationTabPage(weld::Container* pParent, const STLPropertySet* pSet);
1427 
1428     void update( STLPropertySet* pSet );
1429 
1430     DECL_LINK(implControlHdl, weld::ComboBox&, void);
1431     DECL_LINK(DurationModifiedHdl, weld::MetricSpinButton&, void);
1432 
1433 private:
1434     const STLPropertySet* mpSet;
1435 
1436     std::unique_ptr<weld::Builder> mxBuilder;
1437     std::unique_ptr<weld::Container> mxContainer;
1438     std::unique_ptr<weld::Label> mxFTStart;
1439     std::unique_ptr<weld::ComboBox> mxLBStart;
1440     std::unique_ptr<weld::Label> mxFTStartDelay;
1441     std::unique_ptr<weld::MetricSpinButton> mxMFStartDelay;
1442     std::unique_ptr<weld::Label> mxFTDuration;
1443     std::unique_ptr<weld::MetricSpinButton> mxCBXDuration;
1444     std::unique_ptr<weld::Label> mxFTRepeat;
1445     std::unique_ptr<weld::ComboBox> mxCBRepeat;
1446     std::unique_ptr<weld::CheckButton> mxCBXRewind;
1447     std::unique_ptr<weld::RadioButton> mxRBClickSequence;
1448     std::unique_ptr<weld::RadioButton> mxRBInteractive;
1449     std::unique_ptr<weld::ComboBox> mxLBTrigger;
1450 };
1451 
CustomAnimationDurationTabPage(weld::Container * pParent,const STLPropertySet * pSet)1452 CustomAnimationDurationTabPage::CustomAnimationDurationTabPage(weld::Container* pParent, const STLPropertySet* pSet)
1453     : mpSet(pSet)
1454     , mxBuilder(Application::CreateBuilder(pParent, "modules/simpress/ui/customanimationtimingtab.ui"))
1455     , mxContainer(mxBuilder->weld_container("TimingTab"))
1456     , mxFTStart(mxBuilder->weld_label("start_label"))
1457     , mxLBStart(mxBuilder->weld_combo_box("start_list"))
1458     , mxFTStartDelay(mxBuilder->weld_label("delay_label"))
1459     , mxMFStartDelay(mxBuilder->weld_metric_spin_button("delay_value", FieldUnit::SECOND))
1460     , mxFTDuration(mxBuilder->weld_label("duration_label"))
1461     , mxCBXDuration(mxBuilder->weld_metric_spin_button("anim_duration", FieldUnit::SECOND))
1462     , mxFTRepeat(mxBuilder->weld_label("repeat_label"))
1463     , mxCBRepeat(mxBuilder->weld_combo_box("repeat_list"))
1464     , mxCBXRewind(mxBuilder->weld_check_button("rewind"))
1465     , mxRBClickSequence(mxBuilder->weld_radio_button("rb_click_sequence"))
1466     , mxRBInteractive(mxBuilder->weld_radio_button("rb_interactive"))
1467     , mxLBTrigger(mxBuilder->weld_combo_box("trigger_list"))
1468 {
1469     mxLBTrigger->set_size_request(mxLBTrigger->get_approximate_digit_width() * 20, -1);
1470 
1471     fillRepeatComboBox(*mxCBRepeat);
1472 
1473     mxLBTrigger->connect_changed(LINK(this, CustomAnimationDurationTabPage, implControlHdl));
1474     mxCBXDuration->connect_value_changed(LINK( this, CustomAnimationDurationTabPage, DurationModifiedHdl));
1475 
1476     if( pSet->getPropertyState( nHandleStart ) != STLPropertyState::Ambiguous )
1477     {
1478         sal_Int16 nStart = 0;
1479         pSet->getPropertyValue( nHandleStart ) >>= nStart;
1480         sal_Int32 nPos = 0;
1481         switch( nStart )
1482         {
1483             case EffectNodeType::WITH_PREVIOUS:     nPos = 1; break;
1484             case EffectNodeType::AFTER_PREVIOUS:    nPos = 2; break;
1485         }
1486         mxLBStart->set_active(nPos);
1487     }
1488 
1489     if( pSet->getPropertyState( nHandleBegin ) != STLPropertyState::Ambiguous )
1490     {
1491         double fBegin = 0.0;
1492         pSet->getPropertyValue( nHandleBegin ) >>= fBegin;
1493         mxMFStartDelay->set_value(static_cast<::tools::Long>(fBegin*10), FieldUnit::NONE);
1494     }
1495 
1496     if( pSet->getPropertyState( nHandleDuration ) != STLPropertyState::Ambiguous )
1497     {
1498         double fDuration = 0.0;
1499         pSet->getPropertyValue( nHandleDuration ) >>= fDuration;
1500 
1501         if( fDuration == 0.001 )
1502         {
1503             mxFTDuration->set_sensitive(false);
1504             mxCBXDuration->set_sensitive(false);
1505             mxFTRepeat->set_sensitive(false);
1506             mxCBRepeat->set_sensitive(false);
1507             mxCBXRewind->set_sensitive(false);
1508         }
1509         else
1510         {
1511             mxCBXDuration->set_value(fDuration * 100.0, FieldUnit::NONE);
1512         }
1513     }
1514 
1515     if( pSet->getPropertyState( nHandleRepeat ) != STLPropertyState::Ambiguous )
1516     {
1517         Any aRepeatCount( pSet->getPropertyValue( nHandleRepeat ) );
1518         if( (aRepeatCount.getValueType() == ::cppu::UnoType<double>::get()) || !aRepeatCount.hasValue() )
1519         {
1520             double fRepeat = 0.0;
1521             if( aRepeatCount.hasValue() )
1522                 aRepeatCount >>= fRepeat;
1523 
1524             auto nPos = -1;
1525 
1526             if( fRepeat == 0 )
1527                 nPos = 0;
1528             else if( fRepeat == 2.0 )
1529                 nPos = 1;
1530             else if( fRepeat == 3.0 )
1531                 nPos = 2;
1532             else if( fRepeat == 4.0 )
1533                 nPos = 3;
1534             else if( fRepeat == 5.0 )
1535                 nPos = 4;
1536             else if( fRepeat == 10.0 )
1537                 nPos = 5;
1538 
1539             if (nPos != -1)
1540                 mxCBRepeat->set_active(nPos);
1541             else
1542                 mxCBRepeat->set_entry_text(OUString::number(fRepeat));
1543         }
1544         else if( aRepeatCount.getValueType() == ::cppu::UnoType<Timing>::get() )
1545         {
1546             Any aEnd;
1547             if( pSet->getPropertyState( nHandleEnd ) != STLPropertyState::Ambiguous )
1548                 aEnd = pSet->getPropertyValue( nHandleEnd );
1549 
1550             mxCBRepeat->set_active(aEnd.hasValue() ? 6 : 7);
1551         }
1552     }
1553 
1554     if( pSet->getPropertyState( nHandleRewind ) != STLPropertyState::Ambiguous )
1555     {
1556         sal_Int16 nFill = 0;
1557         if( pSet->getPropertyValue( nHandleRewind ) >>= nFill )
1558         {
1559             mxCBXRewind->set_active(nFill == AnimationFill::REMOVE);
1560         }
1561         else
1562         {
1563             mxCBXRewind->set_state(TRISTATE_INDET);
1564         }
1565     }
1566 
1567     Reference< XShape > xTrigger;
1568 
1569     if( pSet->getPropertyState( nHandleTrigger ) != STLPropertyState::Ambiguous )
1570     {
1571         pSet->getPropertyValue( nHandleTrigger ) >>= xTrigger;
1572 
1573         mxRBInteractive->set_active(xTrigger.is());
1574         mxRBClickSequence->set_active(!xTrigger.is());
1575     }
1576 
1577     Reference< XDrawPage > xCurrentPage;
1578     pSet->getPropertyValue( nHandleCurrentPage ) >>= xCurrentPage;
1579     if( !xCurrentPage.is() )
1580         return;
1581 
1582     static const OUStringLiteral aStrIsEmptyPresObj( u"IsEmptyPresentationObject" );
1583 
1584     sal_Int32 nShape, nCount = xCurrentPage->getCount();
1585     for( nShape = 0; nShape < nCount; nShape++ )
1586     {
1587         Reference< XShape > xShape( xCurrentPage->getByIndex( nShape ), UNO_QUERY );
1588 
1589         if( !xShape.is() )
1590             continue;
1591 
1592         Reference< XPropertySet > xSet( xShape, UNO_QUERY );
1593         if( xSet.is() && xSet->getPropertySetInfo()->hasPropertyByName( aStrIsEmptyPresObj ) )
1594         {
1595             bool bIsEmpty = false;
1596             xSet->getPropertyValue( aStrIsEmptyPresObj ) >>= bIsEmpty;
1597             if( bIsEmpty )
1598                 continue;
1599         }
1600 
1601         OUString aDescription( getShapeDescription( xShape, true ) );
1602         mxLBTrigger->append(OUString::number(nShape), aDescription);
1603         auto nPos = mxLBTrigger->get_count() - 1;
1604         if (xShape == xTrigger)
1605             mxLBTrigger->set_active(nPos);
1606     }
1607 }
1608 
IMPL_LINK_NOARG(CustomAnimationDurationTabPage,implControlHdl,weld::ComboBox &,void)1609 IMPL_LINK_NOARG(CustomAnimationDurationTabPage, implControlHdl, weld::ComboBox&, void)
1610 {
1611     mxRBInteractive->set_active(true);
1612     assert(!mxRBClickSequence->get_active());
1613 }
1614 
IMPL_LINK_NOARG(CustomAnimationDurationTabPage,DurationModifiedHdl,weld::MetricSpinButton &,void)1615 IMPL_LINK_NOARG(CustomAnimationDurationTabPage, DurationModifiedHdl, weld::MetricSpinButton&, void)
1616 {
1617     if (!mxCBXDuration->get_text().isEmpty())
1618     {
1619         double duration_value = static_cast<double>(mxCBXDuration->get_value(FieldUnit::NONE));
1620         if(duration_value <= 0.0)
1621             mxCBXDuration->set_value(1, FieldUnit::NONE);
1622         else
1623             mxCBXDuration->set_value(duration_value, FieldUnit::NONE);
1624     }
1625 }
1626 
update(STLPropertySet * pSet)1627 void CustomAnimationDurationTabPage::update( STLPropertySet* pSet )
1628 {
1629     auto nPos = mxLBStart->get_active();
1630     if (nPos != -1)
1631     {
1632         sal_Int16 nStart;
1633         sal_Int16 nOldStart = -1;
1634 
1635         switch( nPos )
1636         {
1637         case 1: nStart = EffectNodeType::WITH_PREVIOUS; break;
1638         case 2: nStart = EffectNodeType::AFTER_PREVIOUS; break;
1639         default:
1640             nStart = EffectNodeType::ON_CLICK; break;
1641         }
1642 
1643         if(mpSet->getPropertyState( nHandleStart ) != STLPropertyState::Ambiguous)
1644             mpSet->getPropertyValue( nHandleStart ) >>= nOldStart;
1645 
1646         if( nStart != nOldStart )
1647             pSet->setPropertyValue( nHandleStart, makeAny( nStart ) );
1648     }
1649 
1650     {
1651         double fBegin = static_cast<double>(mxMFStartDelay->get_value(FieldUnit::NONE)) / 10.0;
1652         double fOldBegin = -1.0;
1653 
1654         if( mpSet->getPropertyState( nHandleBegin ) != STLPropertyState::Ambiguous )
1655             mpSet->getPropertyValue( nHandleBegin ) >>= fOldBegin;
1656 
1657         if( fBegin != fOldBegin )
1658             pSet->setPropertyValue( nHandleBegin, makeAny( fBegin ) );
1659     }
1660 
1661     nPos = mxCBRepeat->get_active();
1662     if (nPos != -1 || !mxCBRepeat->get_active_text().isEmpty())
1663     {
1664         Any aRepeatCount;
1665         Any aEnd;
1666 
1667         switch( nPos )
1668         {
1669         case 0:
1670             break;
1671 
1672         case 6:
1673             {
1674                 Event aEvent;
1675                 aEvent.Trigger = EventTrigger::ON_NEXT;
1676                 aEvent.Repeat = 0;
1677                 aEnd <<= aEvent;
1678             }
1679             [[fallthrough]];
1680         case 7:
1681             aRepeatCount <<= Timing_INDEFINITE;
1682             break;
1683         default:
1684             {
1685                 OUString aText(mxCBRepeat->get_text(nPos));
1686                 if( !aText.isEmpty() )
1687                     aRepeatCount <<= aText.toDouble();
1688             }
1689         }
1690 
1691         Any aOldRepeatCount( aRepeatCount );
1692         if( mpSet->getPropertyState( nHandleRepeat ) != STLPropertyState::Ambiguous )
1693             aOldRepeatCount = mpSet->getPropertyValue( nHandleRepeat );
1694 
1695         if( aRepeatCount != aOldRepeatCount )
1696             pSet->setPropertyValue( nHandleRepeat, aRepeatCount );
1697 
1698         Any aOldEnd( aEnd );
1699         if( mpSet->getPropertyState( nHandleEnd ) != STLPropertyState::Ambiguous )
1700             aOldEnd = mpSet->getPropertyValue( nHandleEnd );
1701 
1702         if( aEnd != aOldEnd )
1703             pSet->setPropertyValue( nHandleEnd, aEnd );
1704     }
1705 
1706     double fDuration = -1.0;
1707 
1708     if (!mxCBXDuration->get_text().isEmpty())
1709     {
1710         double duration_value = static_cast<double>(mxCBXDuration->get_value(FieldUnit::NONE));
1711 
1712         if(duration_value > 0)
1713             fDuration = duration_value/100.0;
1714     }
1715 
1716     if( fDuration != -1.0 )
1717     {
1718         double fOldDuration = -1;
1719 
1720         if( mpSet->getPropertyState( nHandleDuration ) != STLPropertyState::Ambiguous )
1721             mpSet->getPropertyValue( nHandleDuration ) >>= fOldDuration;
1722 
1723         if( fDuration != fOldDuration )
1724             pSet->setPropertyValue( nHandleDuration, makeAny( fDuration ) );
1725     }
1726 
1727     if (mxCBXRewind->get_state() != TRISTATE_INDET)
1728     {
1729         sal_Int16 nFill = mxCBXRewind->get_active() ? AnimationFill::REMOVE : AnimationFill::HOLD;
1730 
1731         bool bSet = true;
1732 
1733         if( mpSet->getPropertyState( nHandleRewind ) != STLPropertyState::Ambiguous )
1734         {
1735             sal_Int16 nOldFill = 0;
1736             mpSet->getPropertyValue( nHandleRewind ) >>= nOldFill;
1737             bSet = nFill != nOldFill;
1738         }
1739 
1740         if( bSet )
1741             pSet->setPropertyValue( nHandleRewind, makeAny( nFill ) );
1742     }
1743 
1744     Reference< XShape > xTrigger;
1745 
1746     if (mxRBInteractive->get_active())
1747     {
1748         nPos = mxLBTrigger->get_active();
1749         if (nPos != -1)
1750         {
1751             sal_Int32 nShape = mxLBTrigger->get_id(nPos).toInt32();
1752 
1753             Reference< XDrawPage > xCurrentPage;
1754             mpSet->getPropertyValue( nHandleCurrentPage ) >>= xCurrentPage;
1755 
1756             if( xCurrentPage.is() && (nShape >= 0) && (nShape < xCurrentPage->getCount()) )
1757                 xCurrentPage->getByIndex( nShape ) >>= xTrigger;
1758         }
1759     }
1760 
1761     if (xTrigger.is() || mxRBClickSequence->get_active())
1762     {
1763         Any aNewValue( makeAny( xTrigger ) );
1764         Any aOldValue;
1765 
1766         if( mpSet->getPropertyState( nHandleTrigger ) != STLPropertyState::Ambiguous )
1767             aOldValue = mpSet->getPropertyValue( nHandleTrigger );
1768 
1769         if( aNewValue != aOldValue )
1770             pSet->setPropertyValue( nHandleTrigger, aNewValue );
1771     }
1772 }
1773 
1774 class CustomAnimationTextAnimTabPage
1775 {
1776 public:
1777     CustomAnimationTextAnimTabPage(weld::Container* pParent, const STLPropertySet* pSet);
1778 
1779     void update( STLPropertySet* pSet );
1780 
1781     void updateControlStates();
1782     DECL_LINK(implSelectHdl, weld::ComboBox&, void);
1783 
1784 private:
1785     const STLPropertySet* mpSet;
1786     bool mbHasVisibleShapes;
1787 
1788     std::unique_ptr<weld::Builder> mxBuilder;
1789     std::unique_ptr<weld::Container> mxContainer;
1790     std::unique_ptr<weld::Label> mxFTGroupText;
1791     std::unique_ptr<weld::ComboBox> mxLBGroupText;
1792     std::unique_ptr<weld::CheckButton> mxCBXGroupAuto;
1793     std::unique_ptr<weld::MetricSpinButton> mxMFGroupAuto;
1794     std::unique_ptr<weld::CheckButton> mxCBXAnimateForm;
1795     std::unique_ptr<weld::CheckButton> mxCBXReverse;
1796 };
1797 
CustomAnimationTextAnimTabPage(weld::Container * pParent,const STLPropertySet * pSet)1798 CustomAnimationTextAnimTabPage::CustomAnimationTextAnimTabPage(weld::Container* pParent, const STLPropertySet* pSet)
1799     : mpSet(pSet)
1800     , mbHasVisibleShapes(true)
1801     , mxBuilder(Application::CreateBuilder(pParent, "modules/simpress/ui/customanimationtexttab.ui"))
1802     , mxContainer(mxBuilder->weld_container("TextAnimationTab"))
1803     , mxFTGroupText(mxBuilder->weld_label("group_text_label"))
1804     , mxLBGroupText(mxBuilder->weld_combo_box("group_text_list"))
1805     , mxCBXGroupAuto(mxBuilder->weld_check_button("auto_after"))
1806     , mxMFGroupAuto(mxBuilder->weld_metric_spin_button("auto_after_value",FieldUnit::SECOND))
1807     , mxCBXAnimateForm(mxBuilder->weld_check_button("animate_shape"))
1808     , mxCBXReverse(mxBuilder->weld_check_button("reverse_order"))
1809 {
1810     mxLBGroupText->connect_changed(LINK(this, CustomAnimationTextAnimTabPage, implSelectHdl));
1811 
1812     if( pSet->getPropertyState( nHandleTextGrouping ) != STLPropertyState::Ambiguous )
1813     {
1814         sal_Int32 nTextGrouping = 0;
1815         if( pSet->getPropertyValue( nHandleTextGrouping ) >>= nTextGrouping )
1816             mxLBGroupText->set_active(nTextGrouping + 1);
1817     }
1818 
1819     if( pSet->getPropertyState( nHandleHasVisibleShape ) != STLPropertyState::Ambiguous )
1820         pSet->getPropertyValue( nHandleHasVisibleShape ) >>= mbHasVisibleShapes;
1821 
1822     if( pSet->getPropertyState( nHandleTextGroupingAuto ) != STLPropertyState::Ambiguous )
1823     {
1824         double fTextGroupingAuto = 0.0;
1825         if( pSet->getPropertyValue( nHandleTextGroupingAuto ) >>= fTextGroupingAuto )
1826         {
1827             mxCBXGroupAuto->set_active(fTextGroupingAuto >= 0.0);
1828             if( fTextGroupingAuto >= 0.0 )
1829                 mxMFGroupAuto->set_value(static_cast<::tools::Long>(fTextGroupingAuto*10), FieldUnit::NONE);
1830         }
1831     }
1832     else
1833     {
1834         mxCBXGroupAuto->set_state( TRISTATE_INDET );
1835     }
1836 
1837     mxCBXAnimateForm->set_state( TRISTATE_INDET );
1838     if( pSet->getPropertyState( nHandleAnimateForm ) != STLPropertyState::Ambiguous )
1839     {
1840         bool bAnimateForm = false;
1841         if( pSet->getPropertyValue( nHandleAnimateForm ) >>= bAnimateForm )
1842         {
1843             mxCBXAnimateForm->set_active( bAnimateForm );
1844         }
1845     }
1846     else
1847     {
1848         mxCBXAnimateForm->set_sensitive(false);
1849     }
1850 
1851     mxCBXReverse->set_state(TRISTATE_INDET);
1852     if( pSet->getPropertyState( nHandleTextReverse ) != STLPropertyState::Ambiguous )
1853     {
1854         bool bTextReverse = false;
1855         if( pSet->getPropertyValue( nHandleTextReverse ) >>= bTextReverse )
1856         {
1857             mxCBXReverse->set_active( bTextReverse );
1858         }
1859     }
1860 
1861     if( pSet->getPropertyState( nHandleMaxParaDepth ) == STLPropertyState::Direct )
1862     {
1863         sal_Int32 nMaxParaDepth = 0;
1864         pSet->getPropertyValue( nHandleMaxParaDepth ) >>= nMaxParaDepth;
1865         nMaxParaDepth += 1;
1866 
1867         sal_Int32 nPos = 6;
1868         while( (nPos > 2) && (nPos > nMaxParaDepth) )
1869         {
1870             mxLBGroupText->remove(nPos);
1871             nPos--;
1872         }
1873     }
1874 
1875     updateControlStates();
1876 }
1877 
update(STLPropertySet * pSet)1878 void CustomAnimationTextAnimTabPage::update( STLPropertySet* pSet )
1879 {
1880     auto nPos = mxLBGroupText->get_active();
1881     if (nPos != -1)
1882     {
1883         sal_Int32 nTextGrouping = nPos - 1;
1884         sal_Int32 nOldGrouping = -2;
1885 
1886         if(mpSet->getPropertyState( nHandleTextGrouping ) != STLPropertyState::Ambiguous)
1887             mpSet->getPropertyValue( nHandleTextGrouping ) >>= nOldGrouping;
1888 
1889         if( nTextGrouping != nOldGrouping )
1890             pSet->setPropertyValue( nHandleTextGrouping, makeAny( nTextGrouping ) );
1891     }
1892 
1893     if (nPos != 0)
1894     {
1895         bool bTextReverse = mxCBXReverse->get_active();
1896         bool bOldTextReverse = !bTextReverse;
1897 
1898         if(mpSet->getPropertyState( nHandleTextReverse ) != STLPropertyState::Ambiguous)
1899             mpSet->getPropertyValue( nHandleTextReverse ) >>= bOldTextReverse;
1900 
1901         if( bTextReverse != bOldTextReverse )
1902             pSet->setPropertyValue( nHandleTextReverse, makeAny( bTextReverse ) );
1903 
1904         if( nPos > 1 )
1905         {
1906             double fTextGroupingAuto = mxCBXGroupAuto->get_active() ? mxMFGroupAuto->get_value(FieldUnit::NONE) / 10.0 : -1.0;
1907             double fOldTextGroupingAuto = -2.0;
1908 
1909             if(mpSet->getPropertyState( nHandleTextGroupingAuto ) != STLPropertyState::Ambiguous)
1910                 mpSet->getPropertyValue( nHandleTextGroupingAuto ) >>= fOldTextGroupingAuto;
1911 
1912             if( fTextGroupingAuto != fOldTextGroupingAuto )
1913                 pSet->setPropertyValue( nHandleTextGroupingAuto, makeAny( fTextGroupingAuto ) );
1914         }
1915     }
1916     //#i120049# impress crashes when modifying the "Random effects" animation
1917     //effect's trigger condition to "Start effect on click of".
1918     //If this control is disabled, we should ignore its value
1919     if (mxCBXAnimateForm->get_sensitive())
1920     {
1921         bool bAnimateForm = mxCBXAnimateForm->get_active();
1922         bool bOldAnimateForm = !bAnimateForm;
1923 
1924         if(mpSet->getPropertyState( nHandleAnimateForm ) != STLPropertyState::Ambiguous)
1925             mpSet->getPropertyValue( nHandleAnimateForm ) >>= bOldAnimateForm;
1926 
1927         if( bAnimateForm != bOldAnimateForm )
1928             pSet->setPropertyValue( nHandleAnimateForm, makeAny( bAnimateForm ) );
1929     }
1930 }
1931 
updateControlStates()1932 void CustomAnimationTextAnimTabPage::updateControlStates()
1933 {
1934     auto nPos = mxLBGroupText->get_active();
1935 
1936     mxCBXGroupAuto->set_sensitive( nPos > 1 );
1937     mxMFGroupAuto->set_sensitive( nPos > 1 );
1938     mxCBXReverse->set_sensitive( nPos > 0 );
1939 
1940     if( !mbHasVisibleShapes && nPos > 0 )
1941     {
1942         mxCBXAnimateForm->set_active(false);
1943         mxCBXAnimateForm->set_sensitive(false);
1944     }
1945     else
1946     {
1947         mxCBXAnimateForm->set_sensitive(true);
1948     }
1949 }
1950 
IMPL_LINK_NOARG(CustomAnimationTextAnimTabPage,implSelectHdl,weld::ComboBox &,void)1951 IMPL_LINK_NOARG(CustomAnimationTextAnimTabPage, implSelectHdl, weld::ComboBox&, void)
1952 {
1953     updateControlStates();
1954 }
1955 
CustomAnimationDialog(weld::Window * pParent,std::unique_ptr<STLPropertySet> pSet,const OString & rPage)1956 CustomAnimationDialog::CustomAnimationDialog(weld::Window* pParent, std::unique_ptr<STLPropertySet> pSet, const OString& rPage)
1957     : GenericDialogController(pParent, "modules/simpress/ui/customanimationproperties.ui", "CustomAnimationProperties")
1958     , mxSet(std::move(pSet))
1959     , mxTabControl(m_xBuilder->weld_notebook("tabcontrol"))
1960     , mxDurationTabPage(new CustomAnimationDurationTabPage(mxTabControl->get_page("timing"), mxSet.get()))
1961     , mxEffectTabPage(new CustomAnimationEffectTabPage(mxTabControl->get_page("effect"), m_xDialog.get(), mxSet.get()))
1962 {
1963     bool bHasText = false;
1964     if( mxSet->getPropertyState( nHandleHasText ) != STLPropertyState::Ambiguous )
1965         mxSet->getPropertyValue( nHandleHasText ) >>= bHasText;
1966 
1967     if( bHasText )
1968     {
1969         mxTextAnimTabPage.reset(new CustomAnimationTextAnimTabPage(mxTabControl->get_page("textanim"), mxSet.get()));
1970     }
1971     else
1972     {
1973         mxTabControl->remove_page("textanim");
1974     }
1975 
1976     if (!rPage.isEmpty())
1977         mxTabControl->set_current_page(rPage);
1978 }
1979 
~CustomAnimationDialog()1980 CustomAnimationDialog::~CustomAnimationDialog()
1981 {
1982 }
1983 
getResultSet()1984 STLPropertySet* CustomAnimationDialog::getResultSet()
1985 {
1986     mxResultSet = createDefaultSet();
1987 
1988     mxEffectTabPage->update( mxResultSet.get() );
1989     mxDurationTabPage->update( mxResultSet.get() );
1990     if (mxTextAnimTabPage)
1991         mxTextAnimTabPage->update( mxResultSet.get() );
1992 
1993     return mxResultSet.get();
1994 }
1995 
createDefaultSet()1996 std::unique_ptr<STLPropertySet> CustomAnimationDialog::createDefaultSet()
1997 {
1998     Any aEmpty;
1999 
2000     std::unique_ptr<STLPropertySet> pSet(new STLPropertySet());
2001     pSet->setPropertyDefaultValue( nHandleMaxParaDepth, makeAny( sal_Int32(-1) ) );
2002 
2003     pSet->setPropertyDefaultValue( nHandleHasAfterEffect, makeAny( false ) );
2004     pSet->setPropertyDefaultValue( nHandleAfterEffectOnNextEffect, makeAny( false ) );
2005     pSet->setPropertyDefaultValue( nHandleDimColor, aEmpty );
2006     pSet->setPropertyDefaultValue( nHandleIterateType, makeAny( sal_Int16(0) ) );
2007     pSet->setPropertyDefaultValue( nHandleIterateInterval, makeAny( 0.0 ) );
2008 
2009     pSet->setPropertyDefaultValue( nHandleStart, makeAny( sal_Int16(EffectNodeType::ON_CLICK) ) );
2010     pSet->setPropertyDefaultValue( nHandleBegin, makeAny( 0.0 ) );
2011     pSet->setPropertyDefaultValue( nHandleDuration, makeAny( 2.0 ) );
2012     pSet->setPropertyDefaultValue( nHandleRepeat, aEmpty );
2013     pSet->setPropertyDefaultValue( nHandleRewind, makeAny( AnimationFill::HOLD ) );
2014 
2015     pSet->setPropertyDefaultValue( nHandleEnd, aEmpty );
2016 
2017     pSet->setPropertyDefaultValue( nHandlePresetId, aEmpty );
2018     pSet->setPropertyDefaultValue( nHandleProperty1Type, makeAny( nPropertyTypeNone ) );
2019     pSet->setPropertyDefaultValue( nHandleProperty1Value, aEmpty );
2020     pSet->setPropertyDefaultValue( nHandleProperty2Type, makeAny( nPropertyTypeNone ) );
2021     pSet->setPropertyDefaultValue( nHandleProperty2Value, aEmpty );
2022     pSet->setPropertyDefaultValue( nHandleAccelerate, aEmpty );
2023     pSet->setPropertyDefaultValue( nHandleDecelerate, aEmpty );
2024     pSet->setPropertyDefaultValue( nHandleAutoReverse, aEmpty );
2025     pSet->setPropertyDefaultValue( nHandleTrigger, aEmpty );
2026 
2027     pSet->setPropertyDefaultValue( nHandleHasText, makeAny( false ) );
2028     pSet->setPropertyDefaultValue( nHandleHasVisibleShape, makeAny( false ) );
2029     pSet->setPropertyDefaultValue( nHandleTextGrouping, makeAny( sal_Int32(-1) ) );
2030     pSet->setPropertyDefaultValue( nHandleAnimateForm, makeAny( true ) );
2031     pSet->setPropertyDefaultValue( nHandleTextGroupingAuto, makeAny( -1.0 ) );
2032     pSet->setPropertyDefaultValue( nHandleTextReverse, makeAny( false ) );
2033 
2034     pSet->setPropertyDefaultValue( nHandleCurrentPage, aEmpty );
2035 
2036     pSet->setPropertyDefaultValue( nHandleSoundURL, aEmpty );
2037     pSet->setPropertyDefaultValue( nHandleSoundVolume, makeAny( 1.0) );
2038     pSet->setPropertyDefaultValue( nHandleSoundEndAfterSlide, makeAny( sal_Int32(0) ) );
2039 
2040     pSet->setPropertyDefaultValue( nHandleCommand, makeAny( sal_Int16(0) ) );
2041     return pSet;
2042 }
2043 
create(sal_Int32 nType,weld::Label * pLabel,weld::Container * pParent,weld::Window * pTopLevel,const Any & rValue,const OUString & rPresetId,const Link<LinkParamNone *,void> & rModifyHdl)2044 std::unique_ptr<SdPropertySubControl> SdPropertySubControl::create(sal_Int32 nType, weld::Label* pLabel, weld::Container* pParent, weld::Window* pTopLevel, const Any& rValue, const OUString& rPresetId, const Link<LinkParamNone*,void>& rModifyHdl)
2045 {
2046     std::unique_ptr<SdPropertySubControl> pSubControl;
2047     switch( nType )
2048     {
2049     case nPropertyTypeDirection:
2050     case nPropertyTypeSpokes:
2051     case nPropertyTypeZoom:
2052         pSubControl.reset( new SdPresetPropertyBox( pLabel, pParent, rValue, rPresetId, rModifyHdl ) );
2053         break;
2054 
2055     case nPropertyTypeColor:
2056     case nPropertyTypeFillColor:
2057     case nPropertyTypeFirstColor:
2058     case nPropertyTypeCharColor:
2059     case nPropertyTypeLineColor:
2060         pSubControl.reset( new SdColorPropertyBox( pLabel, pParent, pTopLevel, rValue, rModifyHdl ) );
2061         break;
2062 
2063     case nPropertyTypeFont:
2064         pSubControl.reset( new SdFontPropertyBox( pLabel, pParent, rValue, rModifyHdl ) );
2065         break;
2066 
2067     case nPropertyTypeCharHeight:
2068         pSubControl.reset( new SdCharHeightPropertyBox( pLabel, pParent, rValue, rModifyHdl ) );
2069         break;
2070 
2071     case nPropertyTypeRotate:
2072         pSubControl.reset( new SdRotationPropertyBox( pLabel, pParent, rValue, rModifyHdl ) );
2073         break;
2074 
2075     case nPropertyTypeTransparency:
2076         pSubControl.reset( new SdTransparencyPropertyBox( pLabel, pParent, rValue, rModifyHdl ) );
2077         break;
2078 
2079     case nPropertyTypeScale:
2080         pSubControl.reset( new SdScalePropertyBox( pLabel, pParent, rValue, rModifyHdl ) );
2081         break;
2082 
2083     case nPropertyTypeCharDecoration:
2084         pSubControl.reset( new SdFontStylePropertyBox( pLabel, pParent, rValue, rModifyHdl ) );
2085         break;
2086     }
2087 
2088     return pSubControl;
2089 }
2090 
2091 }
2092 
2093 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2094