cid#1607171 Data race condition
[LibreOffice.git] / sd / source / ui / animations / SlideTransitionPane.cxx
blob1ab9ca44ab0c076a58027d2b6ff8e50d709969f8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <com/sun/star/drawing/XDrawView.hpp>
21 #include <SlideTransitionPane.hxx>
23 #include <TransitionPreset.hxx>
24 #include <sdresid.hxx>
25 #include <ViewShellBase.hxx>
26 #include <DrawDocShell.hxx>
27 #include <SlideSorterViewShell.hxx>
28 #include <unomodel.hxx>
29 #include <drawdoc.hxx>
30 #include <sdmod.hxx>
31 #include <sdpage.hxx>
32 #include <filedlg.hxx>
33 #include <strings.hrc>
34 #include <EventMultiplexer.hxx>
36 #include <comphelper/lok.hxx>
37 #include <sal/log.hxx>
38 #include <tools/debug.hxx>
39 #include <svx/gallery.hxx>
40 #include <utility>
41 #include <vcl/stdtext.hxx>
42 #include <vcl/svapp.hxx>
43 #include <vcl/weld.hxx>
44 #include <tools/urlobj.hxx>
45 #include <slideshow.hxx>
46 #include <sdundogr.hxx>
47 #include <undoanim.hxx>
48 #include <optsitem.hxx>
50 #include <o3tl/safeint.hxx>
52 #include <algorithm>
54 using namespace ::com::sun::star;
56 using ::com::sun::star::uno::Reference;
59 namespace sd::impl
61 struct TransitionEffect
63 TransitionEffect() :
64 mnType( 0 ),
65 mnSubType( 0 ),
66 mbDirection( true ),
67 mnFadeColor( 0 )
69 init();
71 explicit TransitionEffect( const ::sd::TransitionPreset & rPreset ) :
72 mnType( rPreset.getTransition()),
73 mnSubType( rPreset.getSubtype()),
74 mbDirection( rPreset.getDirection()),
75 mnFadeColor( rPreset.getFadeColor())
77 init();
79 explicit TransitionEffect( const SdPage & rPage ) :
80 mnType( rPage.getTransitionType() ),
81 mnSubType( rPage.getTransitionSubtype() ),
82 mbDirection( rPage.getTransitionDirection() ),
83 mnFadeColor( rPage.getTransitionFadeColor() )
85 init();
87 mfDuration = rPage.getTransitionDuration();
88 mfTime = rPage.GetTime();
89 mePresChange = rPage.GetPresChange();
90 mbSoundOn = rPage.IsSoundOn();
91 maSound = rPage.GetSoundFile();
92 mbLoopSound = rPage.IsLoopSound();
93 mbStopSound = rPage.IsStopSound();
96 void init()
98 mfDuration = 2.0;
99 mfTime = 0.0;
100 mePresChange = PresChange::Manual;
101 mbSoundOn = false;
102 mbLoopSound = false;
103 mbStopSound = false;
105 mbEffectAmbiguous = false;
106 mbDurationAmbiguous = false;
107 mbTimeAmbiguous = false;
108 mbPresChangeAmbiguous = false;
109 mbSoundAmbiguous = false;
110 mbLoopSoundAmbiguous = false;
113 void setAllAmbiguous()
115 mbEffectAmbiguous = true;
116 mbDurationAmbiguous = true;
117 mbTimeAmbiguous = true;
118 mbPresChangeAmbiguous = true;
119 mbSoundAmbiguous = true;
120 mbLoopSoundAmbiguous = true;
123 bool operator == ( const ::sd::TransitionPreset & rPreset ) const
125 return
126 (mnType == rPreset.getTransition()) &&
127 (mnSubType == rPreset.getSubtype()) &&
128 (mbDirection == rPreset.getDirection()) &&
129 (mnFadeColor == rPreset.getFadeColor());
132 void applyTo( SdPage & rOutPage ) const
134 if( ! mbEffectAmbiguous )
136 rOutPage.setTransitionType( mnType );
137 rOutPage.setTransitionSubtype( mnSubType );
138 rOutPage.setTransitionDirection( mbDirection );
139 rOutPage.setTransitionFadeColor( mnFadeColor );
142 if( ! mbDurationAmbiguous )
143 rOutPage.setTransitionDuration( mfDuration );
144 if( ! mbTimeAmbiguous )
145 rOutPage.SetTime( mfTime );
146 if( ! mbPresChangeAmbiguous )
147 rOutPage.SetPresChange( mePresChange );
148 if( ! mbSoundAmbiguous )
150 if( mbStopSound )
152 rOutPage.SetStopSound( true );
153 rOutPage.SetSound( false );
155 else
157 rOutPage.SetStopSound( false );
158 rOutPage.SetSound( mbSoundOn );
159 rOutPage.SetSoundFile( maSound );
162 if( ! mbLoopSoundAmbiguous )
163 rOutPage.SetLoopSound( mbLoopSound );
166 void compareWith( const SdPage & rPage )
168 TransitionEffect aOtherEffect( rPage );
169 mbEffectAmbiguous = mbEffectAmbiguous || aOtherEffect.mbEffectAmbiguous
170 || (mnType != aOtherEffect.mnType)
171 || (mnSubType != aOtherEffect.mnSubType)
172 || (mbDirection != aOtherEffect.mbDirection)
173 || (mnFadeColor != aOtherEffect.mnFadeColor);
175 mbDurationAmbiguous = mbDurationAmbiguous || aOtherEffect.mbDurationAmbiguous || mfDuration != aOtherEffect.mfDuration;
176 mbTimeAmbiguous = mbTimeAmbiguous || aOtherEffect.mbTimeAmbiguous || mfTime != aOtherEffect.mfTime;
177 mbPresChangeAmbiguous = mbPresChangeAmbiguous || aOtherEffect.mbPresChangeAmbiguous || mePresChange != aOtherEffect.mePresChange;
178 mbSoundAmbiguous = mbSoundAmbiguous || aOtherEffect.mbSoundAmbiguous || mbSoundOn != aOtherEffect.mbSoundOn;
179 #if 0
180 // Weird leftover isolated expression with no effect, introduced in 2007 in
181 // CWS impress122. Ifdeffed out to avoid compiler warning, kept here in case
182 // somebody who understands this code notices and understands what the
183 // "right" thing to do might be.
184 (!mbStopSound && !aOtherEffect.mbStopSound && maSound != aOtherEffect.maSound) || (mbStopSound != aOtherEffect.mbStopSound);
185 #endif
186 mbLoopSoundAmbiguous = mbLoopSoundAmbiguous || aOtherEffect.mbLoopSoundAmbiguous || mbLoopSound != aOtherEffect.mbLoopSound;
189 // effect
190 sal_Int16 mnType;
191 sal_Int16 mnSubType;
192 bool mbDirection;
193 sal_Int32 mnFadeColor;
195 // other settings
196 double mfDuration;
197 double mfTime;
198 PresChange mePresChange;
199 bool mbSoundOn;
200 OUString maSound;
201 bool mbLoopSound;
202 bool mbStopSound;
204 bool mbEffectAmbiguous;
205 bool mbDurationAmbiguous;
206 bool mbTimeAmbiguous;
207 bool mbPresChangeAmbiguous;
208 bool mbSoundAmbiguous;
209 bool mbLoopSoundAmbiguous;
212 } // namespace sd::impl
214 namespace sd
217 // Local Helper Functions
218 namespace
221 void lcl_ApplyToPages(
222 const ::sd::slidesorter::SharedPageSelection& rpPages,
223 const ::sd::impl::TransitionEffect & rEffect )
225 for( const auto& rpPage : *rpPages )
227 rEffect.applyTo( *rpPage );
231 void lcl_CreateUndoForPages(
232 const ::sd::slidesorter::SharedPageSelection& rpPages,
233 ::sd::ViewShellBase const & rBase )
235 ::sd::DrawDocShell* pDocSh = rBase.GetDocShell();
236 if (!pDocSh)
237 return;
238 SfxUndoManager* pManager = pDocSh->GetUndoManager();
239 if (!pManager)
240 return;
241 SdDrawDocument* pDoc = pDocSh->GetDoc();
242 if (!pDoc)
243 return;
245 OUString aComment( SdResId(STR_UNDO_SLIDE_PARAMS) );
246 pManager->EnterListAction(aComment, aComment, 0, rBase.GetViewShellId());
247 std::unique_ptr<SdUndoGroup> pUndoGroup(new SdUndoGroup( pDoc ));
248 pUndoGroup->SetComment( aComment );
250 for( const auto& rpPage : *rpPages )
252 pUndoGroup->AddAction( new sd::UndoTransition( pDoc, rpPage ) );
255 pManager->AddUndoAction( std::move(pUndoGroup) );
256 pManager->LeaveListAction();
259 struct lcl_EqualsSoundFileName
261 explicit lcl_EqualsSoundFileName( OUString aStr ) :
262 maStr(std::move( aStr ))
265 bool operator() ( const OUString & rStr ) const
267 // note: formerly this was a case insensitive search for all
268 // platforms. It seems more sensible to do this platform-dependent
269 INetURLObject aURL(rStr);
270 #if defined(_WIN32)
271 return maStr.equalsIgnoreAsciiCase( aURL.GetBase() );
272 #else
273 return maStr == aURL.GetBase();
274 #endif
277 private:
278 OUString maStr;
281 // returns -1 if no object was found
282 bool lcl_findSoundInList( const ::std::vector< OUString > & rSoundList,
283 std::u16string_view rFileName,
284 ::std::vector< OUString >::size_type & rOutPosition )
286 INetURLObject aURL(rFileName);
287 ::std::vector< OUString >::const_iterator aIt =
288 ::std::find_if( rSoundList.begin(), rSoundList.end(),
289 lcl_EqualsSoundFileName( aURL.GetBase()));
290 if( aIt != rSoundList.end())
292 rOutPosition = ::std::distance( rSoundList.begin(), aIt );
293 return true;
296 return false;
299 OUString lcl_getSoundFileURL(
300 const ::std::vector< OUString > & rSoundList,
301 const weld::ComboBox& rListBox )
303 sal_Int32 nPos = rListBox.get_active();
304 // the first three entries are no actual sounds
305 if( nPos >= 3 )
307 DBG_ASSERT( static_cast<sal_uInt32>(rListBox.get_count() - 3) == rSoundList.size(),
308 "Sound list-box is not synchronized to sound list" );
309 nPos -= 3;
310 if( rSoundList.size() > o3tl::make_unsigned(nPos) )
311 return rSoundList[ nPos ];
314 return OUString();
317 struct lcl_AppendSoundToListBox
319 explicit lcl_AppendSoundToListBox(weld::ComboBox& rListBox)
320 : mrListBox( rListBox )
323 void operator() ( std::u16string_view rString ) const
325 INetURLObject aURL( rString );
326 mrListBox.append_text( aURL.GetBase() );
329 private:
330 weld::ComboBox& mrListBox;
333 void lcl_FillSoundListBox(
334 const ::std::vector< OUString > & rSoundList,
335 weld::ComboBox& rOutListBox )
337 sal_Int32 nCount = rOutListBox.get_count();
339 // keep first three entries
340 for( sal_Int32 i=nCount - 1; i>=3; --i )
341 rOutListBox.remove( i );
343 ::std::for_each( rSoundList.begin(), rSoundList.end(),
344 lcl_AppendSoundToListBox( rOutListBox ));
347 /// Returns an offset into the list of transition presets
348 sd::TransitionPresetPtr getPreset(const sd::impl::TransitionEffect &rEffect)
350 const sd::TransitionPresetList& rPresetList = sd::TransitionPreset::getTransitionPresetList();
352 for (const auto& pPreset: rPresetList)
354 if (rEffect.operator==(*pPreset))
355 return pPreset;
357 return sd::TransitionPresetPtr();
360 } // anonymous namespace
362 // SlideTransitionPane
363 SlideTransitionPane::SlideTransitionPane(
364 weld::Widget* pParent,
365 ViewShellBase & rBase) :
366 PanelLayout( pParent, u"SlideTransitionsPanel"_ustr, u"modules/simpress/ui/slidetransitionspanel.ui"_ustr ),
367 mrBase( rBase ),
368 mpDrawDoc( rBase.GetDocShell() ? rBase.GetDocShell()->GetDoc() : nullptr ),
369 mxTransitionsIconView(m_xBuilder->weld_icon_view("transitions_icons")),
370 mxTransitionsScrollWindow(m_xBuilder->weld_scrolled_window("transitions_icons_scrolled_window")),
371 mxRepeatAutoFrame(m_xBuilder->weld_frame("repeat_after_frame")),
372 mbHasSelection( false ),
373 mbUpdatingControls( false ),
374 mbIsMainViewChangePending( false ),
375 maLateInitTimer("sd SlideTransitionPane maLateInitTimer")
377 Initialize(mpDrawDoc);
380 css::ui::LayoutSize SlideTransitionPane::GetHeightForWidth(const sal_Int32 /*nWidth*/)
382 sal_Int32 nMinimumHeight = get_preferred_size().Height();
383 return css::ui::LayoutSize(nMinimumHeight, -1, nMinimumHeight);
386 void SlideTransitionPane::Initialize(SdDrawDocument* pDoc)
388 mxLB_VARIANT = m_xBuilder->weld_combo_box(u"variant_list"_ustr);
389 mxCBX_duration = m_xBuilder->weld_metric_spin_button(u"transition_duration"_ustr, FieldUnit::SECOND);
390 mxFT_SOUND = m_xBuilder->weld_label(u"sound_label"_ustr);
391 mxLB_SOUND = m_xBuilder->weld_combo_box(u"sound_list"_ustr);
392 mxCB_LOOP_SOUND = m_xBuilder->weld_check_button(u"loop_sound"_ustr);
393 mxRB_ADVANCE_ON_MOUSE = m_xBuilder->weld_radio_button(u"rb_mouse_click"_ustr);
394 mxRB_ADVANCE_AUTO = m_xBuilder->weld_radio_button(u"rb_auto_after"_ustr);
395 mxMF_ADVANCE_AUTO_AFTER = m_xBuilder->weld_metric_spin_button(u"auto_after_value"_ustr, FieldUnit::SECOND);
396 mxRB_REPEAT_DISABLED = m_xBuilder->weld_radio_button(u"rb_disabled"_ustr);
397 mxRB_REPEAT_AUTO = m_xBuilder->weld_radio_button(u"rb_auto_repeat"_ustr);
398 mxMF_REPEAT_AUTO_AFTER = m_xBuilder->weld_metric_spin_button(u"rb_auto_repeat_value"_ustr, FieldUnit::SECOND);
399 mxPB_APPLY_TO_ALL = m_xBuilder->weld_button(u"apply_to_all"_ustr);
400 mxPB_PLAY = m_xBuilder->weld_button(u"play"_ustr);
401 mxCB_AUTO_PREVIEW = m_xBuilder->weld_check_button(u"auto_preview"_ustr);
403 auto nMax = mxMF_ADVANCE_AUTO_AFTER->get_max(FieldUnit::SECOND);
404 mxMF_ADVANCE_AUTO_AFTER->set_max(99, FieldUnit::SECOND);
405 int nWidthChars = mxMF_ADVANCE_AUTO_AFTER->get_width_chars();
406 mxMF_ADVANCE_AUTO_AFTER->set_max(nMax, FieldUnit::SECOND);
407 mxMF_ADVANCE_AUTO_AFTER->set_width_chars(nWidthChars);
408 mxMF_REPEAT_AUTO_AFTER->set_max(nMax, FieldUnit::SECOND);
409 mxMF_REPEAT_AUTO_AFTER->set_width_chars(nWidthChars);
410 mxCBX_duration->set_width_chars(nWidthChars);
412 if( pDoc )
413 mxModel = pDoc->getUnoModel();
414 // TODO: get correct view
415 if( mxModel.is())
416 mxView.set( mxModel->getCurrentController(), uno::UNO_QUERY );
418 // set defaults
419 mxCB_AUTO_PREVIEW->set_active(true); // automatic preview on
421 // update control states before adding handlers
422 updateControls();
424 // set handlers
425 mxPB_APPLY_TO_ALL->connect_clicked( LINK( this, SlideTransitionPane, ApplyToAllButtonClicked ));
426 mxPB_PLAY->connect_clicked( LINK( this, SlideTransitionPane, PlayButtonClicked ));
428 mxTransitionsIconView->connect_item_activated(LINK(this, SlideTransitionPane, TransitionSelected));
430 mxLB_VARIANT->connect_changed( LINK( this, SlideTransitionPane, VariantListBoxSelected ));
431 mxCBX_duration->connect_value_changed(LINK( this, SlideTransitionPane, DurationModifiedHdl));
432 mxCBX_duration->connect_focus_out(LINK( this, SlideTransitionPane, DurationLoseFocusHdl));
433 mxLB_SOUND->connect_changed( LINK( this, SlideTransitionPane, SoundListBoxSelected ));
434 mxCB_LOOP_SOUND->connect_toggled( LINK( this, SlideTransitionPane, LoopSoundBoxChecked ));
436 mxRB_ADVANCE_ON_MOUSE->connect_toggled( LINK( this, SlideTransitionPane, AdvanceSlideRadioButtonToggled ));
437 mxRB_ADVANCE_AUTO->connect_toggled( LINK( this, SlideTransitionPane, AdvanceSlideRadioButtonToggled ));
438 mxMF_ADVANCE_AUTO_AFTER->connect_value_changed( LINK( this, SlideTransitionPane, AdvanceTimeModified ));
439 mxRB_REPEAT_DISABLED->connect_toggled( LINK( this, SlideTransitionPane, RepeatAfterRadioButtonToggled ));
440 mxRB_REPEAT_AUTO->connect_toggled( LINK( this, SlideTransitionPane, RepeatAfterRadioButtonToggled ));
441 mxMF_REPEAT_AUTO_AFTER->connect_value_changed( LINK( this, SlideTransitionPane, RepeatAfterTimeModified ));
442 mxCB_AUTO_PREVIEW->connect_toggled( LINK( this, SlideTransitionPane, AutoPreviewClicked ));
443 addListener();
445 mxRB_REPEAT_DISABLED->set_active( true );
447 maLateInitTimer.SetTimeout(200);
448 maLateInitTimer.SetInvokeHandler(LINK(this, SlideTransitionPane, LateInitCallback));
449 maLateInitTimer.Start();
452 SlideTransitionPane::~SlideTransitionPane()
454 maLateInitTimer.Stop();
455 removeListener();
456 mxTransitionsScrollWindow.reset();
457 mxTransitionsIconView.reset();
458 mxRepeatAutoFrame.reset();
459 mxLB_VARIANT.reset();
460 mxCBX_duration.reset();
461 mxFT_SOUND.reset();
462 mxLB_SOUND.reset();
463 mxCB_LOOP_SOUND.reset();
464 mxRB_ADVANCE_ON_MOUSE.reset();
465 mxRB_ADVANCE_AUTO.reset();
466 mxMF_ADVANCE_AUTO_AFTER.reset();
467 mxRB_REPEAT_DISABLED.reset();
468 mxRB_REPEAT_AUTO.reset();
469 mxMF_REPEAT_AUTO_AFTER.reset();
470 mxPB_APPLY_TO_ALL.reset();
471 mxPB_PLAY.reset();
472 mxCB_AUTO_PREVIEW.reset();
475 void SlideTransitionPane::onSelectionChanged()
477 updateControls();
480 void SlideTransitionPane::onChangeCurrentPage()
482 updateControls();
485 ::sd::slidesorter::SharedPageSelection SlideTransitionPane::getSelectedPages() const
487 ::sd::slidesorter::SlideSorterViewShell * pSlideSorterViewShell
488 = ::sd::slidesorter::SlideSorterViewShell::GetSlideSorter(mrBase);
489 std::shared_ptr<sd::slidesorter::SlideSorterViewShell::PageSelection> pSelection;
491 if( pSlideSorterViewShell )
493 pSelection = pSlideSorterViewShell->GetPageSelection();
495 else
497 pSelection = std::make_shared<sd::slidesorter::SlideSorterViewShell::PageSelection>();
498 if( mxView.is() )
500 SdPage* pPage = SdPage::getImplementation( mxView->getCurrentPage() );
501 if( pPage )
502 pSelection->push_back(pPage);
506 return pSelection;
509 void SlideTransitionPane::updateControls()
511 ::sd::slidesorter::SharedPageSelection pSelectedPages(getSelectedPages());
512 if( pSelectedPages->empty())
514 mbHasSelection = false;
515 return;
517 mbHasSelection = true;
519 DBG_ASSERT( ! mbUpdatingControls, "Multiple Control Updates" );
520 mbUpdatingControls = true;
522 // get model data for first page
523 SdPage * pFirstPage = pSelectedPages->front();
524 DBG_ASSERT( pFirstPage, "Invalid Page" );
526 impl::TransitionEffect aEffect( *pFirstPage );
528 // merge with other pages
530 // start with second page (note aIt != aEndIt, because ! aSelectedPages.empty())
531 for( const auto& rpPage : *pSelectedPages )
533 if( rpPage )
534 aEffect.compareWith( *rpPage );
537 // detect current slide effect
538 if( aEffect.mbEffectAmbiguous )
540 SAL_WARN( "sd.transitions", "Unusual, ambiguous transition effect" );
541 mxTransitionsIconView->select(0);
543 else
545 // ToDo: That 0 is "no transition" is documented nowhere except in the
546 // CTOR of sdpage
547 if( aEffect.mnType == 0 )
548 mxTransitionsIconView->select(0);
549 else
550 updateVariants(getPreset(aEffect));
553 if( aEffect.mbDurationAmbiguous )
555 mxCBX_duration->set_text(u""_ustr);
556 //TODO mxCBX_duration->SetNoSelection();
558 else
560 mxCBX_duration->set_value( (aEffect.mfDuration)*100.0, FieldUnit::SECOND );
563 if( aEffect.mbSoundAmbiguous )
565 mxLB_SOUND->set_active(-1);
566 maCurrentSoundFile.clear();
568 else
570 maCurrentSoundFile.clear();
571 if( aEffect.mbStopSound )
573 mxLB_SOUND->set_active( 1 );
575 else if( aEffect.mbSoundOn && !aEffect.maSound.isEmpty() )
577 std::vector<OUString>::size_type nPos = 0;
578 if( lcl_findSoundInList( maSoundList, aEffect.maSound, nPos ))
580 mxLB_SOUND->set_active( nPos + 3 );
581 maCurrentSoundFile = aEffect.maSound;
584 else
586 mxLB_SOUND->set_active( 0 );
590 if( aEffect.mbLoopSoundAmbiguous )
592 mxCB_LOOP_SOUND->set_state(TRISTATE_INDET);
594 else
596 mxCB_LOOP_SOUND->set_active(aEffect.mbLoopSound);
599 if( aEffect.mbPresChangeAmbiguous )
601 mxRB_ADVANCE_ON_MOUSE->set_active( false );
602 mxRB_ADVANCE_AUTO->set_active( false );
604 else
606 mxRB_ADVANCE_ON_MOUSE->set_active( aEffect.mePresChange == PresChange::Manual );
607 mxRB_ADVANCE_AUTO->set_active( aEffect.mePresChange == PresChange::Auto );
608 mxMF_ADVANCE_AUTO_AFTER->set_value(aEffect.mfTime * 100.0, FieldUnit::SECOND);
611 sd::PresentationSettings& rSettings = mpDrawDoc->getPresentationSettings();
613 if ( !rSettings.mbEndless )
615 mxRB_REPEAT_DISABLED->set_active( true );
616 mxRB_REPEAT_AUTO->set_active( false );
618 else
620 mxRB_REPEAT_DISABLED->set_active( false );
621 mxRB_REPEAT_AUTO->set_active( true );
622 mxMF_REPEAT_AUTO_AFTER->set_value(rSettings.mnPauseTimeout * 100.0, FieldUnit::SECOND);
625 if (comphelper::LibreOfficeKit::isActive())
627 mxPB_PLAY->hide();
628 mxCB_AUTO_PREVIEW->set_active(false);
629 mxCB_AUTO_PREVIEW->hide();
630 mxFT_SOUND->hide();
631 mxLB_SOUND->hide();
632 mxCB_LOOP_SOUND->hide();
634 else
636 mxRepeatAutoFrame->hide();
637 SdOptions* pOptions = SdModule::get()->GetSdOptions(DocumentType::Impress);
638 mxCB_AUTO_PREVIEW->set_active( pOptions->IsPreviewTransitions() );
641 mbUpdatingControls = false;
643 updateControlState();
646 void SlideTransitionPane::updateControlState()
648 if (mxTransitionsScrollWindow)
649 mxTransitionsScrollWindow->set_sensitive(mbHasSelection);
650 mxLB_VARIANT->set_sensitive( mbHasSelection && mxLB_VARIANT->get_count() > 0 );
651 mxCBX_duration->set_sensitive( mbHasSelection );
652 mxLB_SOUND->set_sensitive( mbHasSelection );
653 mxCB_LOOP_SOUND->set_sensitive( mbHasSelection && (mxLB_SOUND->get_active() > 2));
654 mxRB_ADVANCE_ON_MOUSE->set_sensitive( mbHasSelection );
655 mxRB_ADVANCE_AUTO->set_sensitive( mbHasSelection );
656 mxMF_ADVANCE_AUTO_AFTER->set_sensitive( mbHasSelection && mxRB_ADVANCE_AUTO->get_active());
657 mxRB_REPEAT_DISABLED->set_sensitive( mbHasSelection );
658 mxRB_REPEAT_AUTO->set_sensitive( mbHasSelection );
659 mxMF_REPEAT_AUTO_AFTER->set_sensitive( mbHasSelection && mxRB_REPEAT_AUTO->get_active());
661 mxPB_APPLY_TO_ALL->set_sensitive( mbHasSelection );
662 mxPB_PLAY->set_sensitive( mbHasSelection );
663 mxCB_AUTO_PREVIEW->set_sensitive( mbHasSelection );
666 void SlideTransitionPane::updateSoundList()
668 maSoundList.clear();
670 GalleryExplorer::FillObjList( GALLERY_THEME_SOUNDS, maSoundList );
671 GalleryExplorer::FillObjList( GALLERY_THEME_USERSOUNDS, maSoundList );
673 lcl_FillSoundListBox( maSoundList, *mxLB_SOUND );
676 void SlideTransitionPane::openSoundFileDialog()
678 if( ! mxLB_SOUND->get_sensitive())
679 return;
681 weld::Window* pDialogParent(GetFrameWeld());
682 SdOpenSoundFileDialog aFileDialog(pDialogParent);
684 DBG_ASSERT( mxLB_SOUND->get_active() == 2,
685 "Dialog should only open when \"Other sound\" is selected" );
687 bool bValidSoundFile( false );
688 bool bQuitLoop( false );
690 while( ! bQuitLoop &&
691 aFileDialog.Execute() == ERRCODE_NONE )
693 OUString aFile = aFileDialog.GetPath();
694 std::vector<OUString>::size_type nPos = 0;
695 bValidSoundFile = lcl_findSoundInList( maSoundList, aFile, nPos );
697 if( bValidSoundFile )
699 bQuitLoop = true;
701 else // not in sound list
703 // try to insert into gallery
704 if( GalleryExplorer::InsertURL( GALLERY_THEME_USERSOUNDS, aFile ) )
706 updateSoundList();
707 bValidSoundFile = lcl_findSoundInList( maSoundList, aFile, nPos );
708 DBG_ASSERT( bValidSoundFile, "Adding sound to gallery failed" );
710 bQuitLoop = true;
712 else
714 OUString aStrWarning(SdResId(STR_WARNING_NOSOUNDFILE));
715 aStrWarning = aStrWarning.replaceFirst("%", aFile);
716 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(pDialogParent,
717 VclMessageType::Warning, VclButtonsType::NONE,
718 aStrWarning));
719 xWarn->add_button(GetStandardText(StandardButtonType::Retry), RET_RETRY);
720 xWarn->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
721 bQuitLoop = (xWarn->run() != RET_RETRY);
723 bValidSoundFile = false;
727 if( bValidSoundFile )
728 // skip first three entries in list
729 mxLB_SOUND->set_active( nPos + 3 );
732 if( bValidSoundFile )
733 return;
735 if( !maCurrentSoundFile.isEmpty() )
737 std::vector<OUString>::size_type nPos = 0;
738 if( lcl_findSoundInList( maSoundList, maCurrentSoundFile, nPos ))
739 mxLB_SOUND->set_active( nPos + 3 );
740 else
741 mxLB_SOUND->set_active( 0 ); // NONE
743 else
744 mxLB_SOUND->set_active( 0 ); // NONE
747 impl::TransitionEffect SlideTransitionPane::getTransitionEffectFromControls() const
749 impl::TransitionEffect aResult;
750 aResult.setAllAmbiguous();
752 OUString sSelectedId = mxTransitionsIconView->get_selected_id();
753 auto* pTransitionEntry = weld::fromId<TransitionEntry*>(sSelectedId);
754 if (!pTransitionEntry)
755 return aResult;
757 const sd::TransitionPresetList& rPresetList = sd::TransitionPreset::getTransitionPresetList();
759 if (pTransitionEntry->mpPreset)
761 auto pSelectedPreset = pTransitionEntry->mpPreset;
763 if (mxLB_VARIANT->get_active() == -1)
765 // Transition with just one effect.
766 aResult = impl::TransitionEffect(*pSelectedPreset);
767 aResult.setAllAmbiguous();
769 else
771 int nVariant = 0;
772 bool bFound = false;
773 for(const auto& rPreset: rPresetList)
775 if (rPreset->getSetId() == pSelectedPreset->getSetId() )
777 if( mxLB_VARIANT->get_active() == nVariant)
779 aResult = impl::TransitionEffect(*rPreset);
780 aResult.setAllAmbiguous();
781 bFound = true;
782 break;
784 else
786 nVariant++;
790 if( !bFound )
792 aResult.mnType = 0;
795 aResult.mbEffectAmbiguous = false;
797 else
799 aResult.mbEffectAmbiguous = false;
802 //duration
804 if( mxCBX_duration->get_sensitive() && (!(mxCBX_duration->get_text()).isEmpty()) )
806 aResult.mfDuration = static_cast<double>(mxCBX_duration->get_value(FieldUnit::SECOND))/100.0;
807 aResult.mbDurationAmbiguous = false;
810 // slide-advance mode
811 if( mxRB_ADVANCE_ON_MOUSE->get_sensitive() && mxRB_ADVANCE_AUTO->get_sensitive() &&
812 (mxRB_ADVANCE_ON_MOUSE->get_active() || mxRB_ADVANCE_AUTO->get_active()))
814 if( mxRB_ADVANCE_ON_MOUSE->get_active())
815 aResult.mePresChange = PresChange::Manual;
816 else
818 aResult.mePresChange = PresChange::Auto;
819 if( mxMF_ADVANCE_AUTO_AFTER->get_sensitive())
821 aResult.mfTime = static_cast<double>(mxMF_ADVANCE_AUTO_AFTER->get_value(FieldUnit::SECOND) ) / 100.0 ;
822 aResult.mbTimeAmbiguous = false;
826 aResult.mbPresChangeAmbiguous = false;
829 // transition repeat after
830 if (mxRB_REPEAT_DISABLED->get_sensitive() && mxRB_REPEAT_AUTO->get_sensitive()
831 && (mxRB_REPEAT_DISABLED->get_active() || mxRB_REPEAT_AUTO->get_active()))
833 sd::PresentationSettings& rSettings = mpDrawDoc->getPresentationSettings();
835 if ( mxRB_REPEAT_DISABLED->get_active() )
837 rSettings.mbEndless = false;
838 rSettings.mnPauseTimeout = 0;
840 else
842 if ( mxMF_REPEAT_AUTO_AFTER->get_sensitive() )
844 rSettings.mbEndless = true;
845 rSettings.mnPauseTimeout = static_cast<sal_uInt32>(mxMF_REPEAT_AUTO_AFTER->get_value(FieldUnit::SECOND) / 100.0) ;
850 // sound
851 if( mxLB_SOUND->get_sensitive())
853 maCurrentSoundFile.clear();
854 sal_Int32 nPos = mxLB_SOUND->get_active();
855 if (nPos != -1)
857 aResult.mbStopSound = nPos == 1;
858 aResult.mbSoundOn = nPos > 1;
859 if( aResult.mbStopSound )
861 aResult.maSound.clear();
862 aResult.mbSoundAmbiguous = false;
864 else
866 aResult.maSound = lcl_getSoundFileURL(maSoundList, *mxLB_SOUND);
867 aResult.mbSoundAmbiguous = false;
868 maCurrentSoundFile = aResult.maSound;
873 // sound loop
874 if( mxCB_LOOP_SOUND->get_sensitive() )
876 aResult.mbLoopSound = mxCB_LOOP_SOUND->get_active();
877 aResult.mbLoopSoundAmbiguous = false;
880 return aResult;
883 void SlideTransitionPane::applyToSelectedPages(bool bPreview = true)
885 if( mbUpdatingControls )
886 return;
888 vcl::Window *pFocusWindow = Application::GetFocusWindow();
890 ::sd::slidesorter::SharedPageSelection pSelectedPages( getSelectedPages());
891 impl::TransitionEffect aEffect = getTransitionEffectFromControls();
892 if( ! pSelectedPages->empty())
894 lcl_CreateUndoForPages( pSelectedPages, mrBase );
895 lcl_ApplyToPages( pSelectedPages, aEffect );
896 mrBase.GetDocShell()->SetModified();
898 if( mxCB_AUTO_PREVIEW->get_sensitive() &&
899 mxCB_AUTO_PREVIEW->get_active() && bPreview)
901 if (aEffect.mnType) // mnType = 0 denotes no transition
902 playCurrentEffect();
903 else if( mxView.is() && !SlideShow::IsInteractiveSlideshow(&mrBase)) // IASS
904 SlideShow::Stop( mrBase );
907 if (pFocusWindow)
908 pFocusWindow->GrabFocus();
911 void SlideTransitionPane::playCurrentEffect()
913 if( mxView.is() )
916 Reference< css::animations::XAnimationNode > xNode;
917 SlideShow::StartPreview( mrBase, mxView->getCurrentPage(), xNode );
921 void SlideTransitionPane::addListener()
923 Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,SlideTransitionPane,EventMultiplexerListener) );
924 mrBase.GetEventMultiplexer()->AddEventListener( aLink );
927 void SlideTransitionPane::removeListener()
929 Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,SlideTransitionPane,EventMultiplexerListener) );
930 mrBase.GetEventMultiplexer()->RemoveEventListener( aLink );
933 IMPL_LINK(SlideTransitionPane,EventMultiplexerListener,
934 tools::EventMultiplexerEvent&, rEvent, void)
936 switch (rEvent.meEventId)
938 case EventMultiplexerEventId::EditViewSelection:
939 onSelectionChanged();
940 break;
942 case EventMultiplexerEventId::CurrentPageChanged:
943 case EventMultiplexerEventId::SlideSortedSelection:
944 onChangeCurrentPage();
945 break;
947 case EventMultiplexerEventId::MainViewRemoved:
948 mxView.clear();
949 onSelectionChanged();
950 onChangeCurrentPage();
951 break;
953 case EventMultiplexerEventId::MainViewAdded:
954 mbIsMainViewChangePending = true;
955 break;
957 case EventMultiplexerEventId::ConfigurationUpdated:
958 if (mbIsMainViewChangePending)
960 mbIsMainViewChangePending = false;
962 // At this moment the controller may not yet been set at
963 // model or ViewShellBase. Take it from the view shell
964 // passed with the event.
965 if (mrBase.GetMainViewShell() != nullptr)
967 mxView.set(mrBase.GetController(), css::uno::UNO_QUERY);
968 onSelectionChanged();
969 onChangeCurrentPage();
972 break;
974 default:
975 if (rEvent.meEventId != EventMultiplexerEventId::Disposing)
977 onSelectionChanged();
978 onChangeCurrentPage();
980 break;
984 IMPL_LINK_NOARG(SlideTransitionPane, ApplyToAllButtonClicked, weld::Button&, void)
986 DBG_ASSERT( mpDrawDoc, "Invalid Draw Document!" );
987 if( !mpDrawDoc )
988 return;
990 ::sd::slidesorter::SharedPageSelection pPages =
991 std::make_shared<::sd::slidesorter::SlideSorterViewShell::PageSelection>();
993 sal_uInt16 nPageCount = mpDrawDoc->GetSdPageCount( PageKind::Standard );
994 pPages->reserve( nPageCount );
995 for( sal_uInt16 i=0; i<nPageCount; ++i )
997 SdPage * pPage = mpDrawDoc->GetSdPage( i, PageKind::Standard );
998 if( pPage )
999 pPages->push_back( pPage );
1002 if( ! pPages->empty())
1004 lcl_CreateUndoForPages( pPages, mrBase );
1005 lcl_ApplyToPages( pPages, getTransitionEffectFromControls() );
1009 IMPL_LINK_NOARG(SlideTransitionPane, PlayButtonClicked, weld::Button&, void)
1011 playCurrentEffect();
1014 IMPL_LINK_NOARG(SlideTransitionPane, TransitionSelected, weld::IconView&, bool)
1016 OUString sSelectedId = mxTransitionsIconView->get_selected_id();
1017 auto* pTransitionEntry = weld::fromId<TransitionEntry*>(sSelectedId);
1018 updateVariants(pTransitionEntry->mpPreset);
1019 applyToSelectedPages();
1020 return true;
1023 /// we use an integer offset into the list of transition presets
1024 void SlideTransitionPane::updateVariants(TransitionPresetPtr const& pPreset)
1026 mxLB_VARIANT->clear();
1027 mxLB_VARIANT->set_sensitive(false);
1028 mxLB_VARIANT->set_active(0);
1030 if (!pPreset)
1032 mxTransitionsIconView->select(0);
1034 else
1036 auto iterator = maTranstionMap.find(pPreset->getSetId());
1037 if (iterator != maTranstionMap.end())
1039 auto& pTransitionEntry = iterator->second;
1040 if (!pTransitionEntry->mnVariants.empty())
1042 for (OUString const& rCurrentVariant : pTransitionEntry->mnVariants)
1044 mxLB_VARIANT->append_text(rCurrentVariant);
1045 if (pPreset->getVariantLabel() == rCurrentVariant)
1046 mxLB_VARIANT->set_active(mxLB_VARIANT->get_count() - 1);
1048 mxLB_VARIANT->set_sensitive(true);
1051 mxTransitionsIconView->select(pTransitionEntry->mnIndex);
1056 IMPL_LINK_NOARG(SlideTransitionPane, AdvanceSlideRadioButtonToggled, weld::Toggleable&, void)
1058 updateControlState();
1059 applyToSelectedPages(false);
1062 IMPL_LINK_NOARG(SlideTransitionPane, RepeatAfterRadioButtonToggled, weld::Toggleable&, void)
1064 updateControlState();
1065 applyToSelectedPages(false);
1068 IMPL_LINK_NOARG(SlideTransitionPane, AdvanceTimeModified, weld::MetricSpinButton&, void)
1070 applyToSelectedPages(false);
1073 IMPL_LINK_NOARG(SlideTransitionPane, RepeatAfterTimeModified, weld::MetricSpinButton&, void)
1075 applyToSelectedPages(false);
1078 IMPL_LINK_NOARG(SlideTransitionPane, VariantListBoxSelected, weld::ComboBox&, void)
1080 applyToSelectedPages();
1083 IMPL_LINK_NOARG(SlideTransitionPane, DurationModifiedHdl, weld::MetricSpinButton&, void)
1085 double duration_value = static_cast<double>(mxCBX_duration->get_value(FieldUnit::SECOND));
1086 if (duration_value <= 0.0)
1087 mxCBX_duration->set_value(0, FieldUnit::SECOND);
1088 else
1089 mxCBX_duration->set_value(duration_value, FieldUnit::SECOND);
1091 applyToSelectedPages();
1094 IMPL_LINK_NOARG(SlideTransitionPane, DurationLoseFocusHdl, weld::Widget&, void)
1096 applyToSelectedPages();
1099 IMPL_LINK_NOARG(SlideTransitionPane, SoundListBoxSelected, weld::ComboBox&, void)
1101 sal_Int32 nPos = mxLB_SOUND->get_active();
1102 if( nPos == 2 )
1104 // other sound...
1105 openSoundFileDialog();
1107 updateControlState();
1108 applyToSelectedPages();
1111 IMPL_LINK_NOARG(SlideTransitionPane, LoopSoundBoxChecked, weld::Toggleable&, void)
1113 applyToSelectedPages();
1116 IMPL_LINK_NOARG(SlideTransitionPane, AutoPreviewClicked, weld::Toggleable&, void)
1118 SdOptions* pOptions = SdModule::get()->GetSdOptions(DocumentType::Impress);
1119 pOptions->SetPreviewTransitions( mxCB_AUTO_PREVIEW->get_active() );
1122 IMPL_LINK_NOARG(SlideTransitionPane, LateInitCallback, Timer *, void)
1124 mxTransitionsIconView->freeze();
1127 auto pTransition = std::make_unique<TransitionEntry>();
1128 const OUString aId = weld::toId(pTransition.get());
1129 pTransition->msIcon = u"sd/cmd/transition-none.png"_ustr;
1130 pTransition->msLabel = SdResId(STR_SLIDETRANSITION_NONE);
1131 pTransition->mnIndex = 0;
1132 mxTransitionsIconView->append(aId, pTransition->msLabel, pTransition->msIcon);
1133 maTranstionMap.emplace(u"None"_ustr, std::move(pTransition));
1136 const TransitionPresetList& rPresetList = TransitionPreset::getTransitionPresetList();
1137 size_t nIndex = 1;
1138 for (TransitionPresetPtr const& pPreset: rPresetList)
1140 const OUString aLabel = pPreset->getSetLabel();
1141 if (!aLabel.isEmpty())
1143 auto aIterator = maTranstionMap.find(pPreset->getSetId());
1144 if (aIterator == maTranstionMap.end())
1146 auto pTransition = std::make_unique<TransitionEntry>();
1147 const OUString aId = weld::toId(pTransition.get());
1149 pTransition->msIcon = u"sd/cmd/transition-"_ustr + pPreset->getSetId() + u".png"_ustr;
1150 pTransition->msLabel = aLabel;
1151 pTransition->mpPreset = pPreset;
1152 if (!pPreset->getVariantLabel().isEmpty())
1153 pTransition->mnVariants.push_back(pPreset->getVariantLabel());
1154 pTransition->mnIndex = nIndex;
1155 nIndex++;
1157 mxTransitionsIconView->append(aId, pTransition->msLabel, pTransition->msIcon);
1158 maTranstionMap.emplace(pPreset->getSetId(), std::move(pTransition));
1160 else
1162 auto& pTransition = aIterator->second;
1163 pTransition->mnVariants.push_back(pPreset->getVariantLabel());
1167 mxTransitionsIconView->set_size_request(0, 0);
1168 mxTransitionsIconView->thaw();
1170 updateSoundList();
1171 updateControls();
1174 } // namespace sd
1176 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */