LibreOffice Module sd (master) 1
SlideTransitionPane.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <com/sun/star/drawing/XDrawView.hpp>
22
23#include <TransitionPreset.hxx>
24#include <sdresid.hxx>
25#include <ViewShellBase.hxx>
26#include <DrawDocShell.hxx>
28#include <drawdoc.hxx>
29#include <sdmod.hxx>
30#include <sdpage.hxx>
31#include <filedlg.hxx>
32#include <strings.hrc>
33#include <EventMultiplexer.hxx>
34
35#include <comphelper/lok.hxx>
36#include <sal/log.hxx>
37#include <tools/debug.hxx>
38#include <svx/gallery.hxx>
39#include <utility>
40#include <vcl/stdtext.hxx>
41#include <vcl/svapp.hxx>
42#include <vcl/weld.hxx>
43#include <tools/urlobj.hxx>
44#include <slideshow.hxx>
45#include <sdundogr.hxx>
46#include <undoanim.hxx>
47#include <optsitem.hxx>
48
49#include <o3tl/safeint.hxx>
50
51#include <algorithm>
52
53using namespace ::com::sun::star;
54
55using ::com::sun::star::uno::Reference;
56
57
58namespace sd::impl
59{
61{
63 mnType( 0 ),
64 mnSubType( 0 ),
65 mbDirection( true ),
66 mnFadeColor( 0 )
67 {
68 init();
69 }
70 explicit TransitionEffect( const ::sd::TransitionPreset & rPreset ) :
71 mnType( rPreset.getTransition()),
72 mnSubType( rPreset.getSubtype()),
73 mbDirection( rPreset.getDirection()),
74 mnFadeColor( rPreset.getFadeColor())
75 {
76 init();
77 }
78 explicit TransitionEffect( const SdPage & rPage ) :
79 mnType( rPage.getTransitionType() ),
80 mnSubType( rPage.getTransitionSubtype() ),
81 mbDirection( rPage.getTransitionDirection() ),
82 mnFadeColor( rPage.getTransitionFadeColor() )
83 {
84 init();
85
87 mfTime = rPage.GetTime();
89 mbSoundOn = rPage.IsSoundOn();
90 maSound = rPage.GetSoundFile();
91 mbLoopSound = rPage.IsLoopSound();
92 mbStopSound = rPage.IsStopSound();
93 }
94
95 void init()
96 {
97 mfDuration = 2.0;
98 mfTime = 0.0;
100 mbSoundOn = false;
101 mbLoopSound = false;
102 mbStopSound = false;
103
104 mbEffectAmbiguous = false;
105 mbDurationAmbiguous = false;
106 mbTimeAmbiguous = false;
107 mbPresChangeAmbiguous = false;
108 mbSoundAmbiguous = false;
109 mbLoopSoundAmbiguous = false;
110 }
111
113 {
114 mbEffectAmbiguous = true;
115 mbDurationAmbiguous = true;
116 mbTimeAmbiguous = true;
118 mbSoundAmbiguous = true;
120 }
121
122 bool operator == ( const ::sd::TransitionPreset & rPreset ) const
123 {
124 return
125 (mnType == rPreset.getTransition()) &&
126 (mnSubType == rPreset.getSubtype()) &&
127 (mbDirection == rPreset.getDirection()) &&
128 (mnFadeColor == rPreset.getFadeColor());
129 }
130
131 void applyTo( SdPage & rOutPage ) const
132 {
133 if( ! mbEffectAmbiguous )
134 {
135 rOutPage.setTransitionType( mnType );
139 }
140
141 if( ! mbDurationAmbiguous )
143 if( ! mbTimeAmbiguous )
144 rOutPage.SetTime( mfTime );
146 rOutPage.SetPresChange( mePresChange );
147 if( ! mbSoundAmbiguous )
148 {
149 if( mbStopSound )
150 {
151 rOutPage.SetStopSound( true );
152 rOutPage.SetSound( false );
153 }
154 else
155 {
156 rOutPage.SetStopSound( false );
157 rOutPage.SetSound( mbSoundOn );
158 rOutPage.SetSoundFile( maSound );
159 }
160 }
162 rOutPage.SetLoopSound( mbLoopSound );
163 }
164
165 void compareWith( const SdPage & rPage )
166 {
167 TransitionEffect aOtherEffect( rPage );
169 || (mnType != aOtherEffect.mnType)
170 || (mnSubType != aOtherEffect.mnSubType)
171 || (mbDirection != aOtherEffect.mbDirection)
172 || (mnFadeColor != aOtherEffect.mnFadeColor);
173
175 mbTimeAmbiguous = mbTimeAmbiguous || aOtherEffect.mbTimeAmbiguous || mfTime != aOtherEffect.mfTime;
177 mbSoundAmbiguous = mbSoundAmbiguous || aOtherEffect.mbSoundAmbiguous || mbSoundOn != aOtherEffect.mbSoundOn;
178#if 0
179 // Weird leftover isolated expression with no effect, introduced in 2007 in
180 // CWS impress122. Ifdeffed out to avoid compiler warning, kept here in case
181 // somebody who understands this code notices and understands what the
182 // "right" thing to do might be.
183 (!mbStopSound && !aOtherEffect.mbStopSound && maSound != aOtherEffect.maSound) || (mbStopSound != aOtherEffect.mbStopSound);
184#endif
186 }
187
188 // effect
189 sal_Int16 mnType;
190 sal_Int16 mnSubType;
192 sal_Int32 mnFadeColor;
193
194 // other settings
196 double mfTime;
199 OUString maSound;
202
209};
210
211} // namespace sd::impl
212
213// Local Helper Functions
214namespace
215{
216
217void lcl_ApplyToPages(
219 const ::sd::impl::TransitionEffect & rEffect )
220{
221 for( const auto& rpPage : *rpPages )
222 {
223 rEffect.applyTo( *rpPage );
224 }
225}
226
227void lcl_CreateUndoForPages(
229 ::sd::ViewShellBase const & rBase )
230{
231 ::sd::DrawDocShell* pDocSh = rBase.GetDocShell();
232 if (!pDocSh)
233 return;
234 SfxUndoManager* pManager = pDocSh->GetUndoManager();
235 if (!pManager)
236 return;
237 SdDrawDocument* pDoc = pDocSh->GetDoc();
238 if (!pDoc)
239 return;
240
241 OUString aComment( SdResId(STR_UNDO_SLIDE_PARAMS) );
242 pManager->EnterListAction(aComment, aComment, 0, rBase.GetViewShellId());
243 std::unique_ptr<SdUndoGroup> pUndoGroup(new SdUndoGroup( pDoc ));
244 pUndoGroup->SetComment( aComment );
245
246 for( const auto& rpPage : *rpPages )
247 {
248 pUndoGroup->AddAction( new sd::UndoTransition( pDoc, rpPage ) );
249 }
250
251 pManager->AddUndoAction( std::move(pUndoGroup) );
252 pManager->LeaveListAction();
253}
254
255struct lcl_EqualsSoundFileName
256{
257 explicit lcl_EqualsSoundFileName( OUString aStr ) :
258 maStr(std::move( aStr ))
259 {}
260
261 bool operator() ( const OUString & rStr ) const
262 {
263 // note: formerly this was a case insensitive search for all
264 // platforms. It seems more sensible to do this platform-dependent
265 INetURLObject aURL(rStr);
266#if defined(_WIN32)
267 return maStr.equalsIgnoreAsciiCase( aURL.GetBase() );
268#else
269 return maStr == aURL.GetBase();
270#endif
271 }
272
273private:
274 OUString maStr;
275};
276
277// returns -1 if no object was found
278bool lcl_findSoundInList( const ::std::vector< OUString > & rSoundList,
279 std::u16string_view rFileName,
280 ::std::vector< OUString >::size_type & rOutPosition )
281{
282 INetURLObject aURL(rFileName);
283 ::std::vector< OUString >::const_iterator aIt =
284 ::std::find_if( rSoundList.begin(), rSoundList.end(),
285 lcl_EqualsSoundFileName( aURL.GetBase()));
286 if( aIt != rSoundList.end())
287 {
288 rOutPosition = ::std::distance( rSoundList.begin(), aIt );
289 return true;
290 }
291
292 return false;
293}
294
295OUString lcl_getSoundFileURL(
296 const ::std::vector< OUString > & rSoundList,
297 const weld::ComboBox& rListBox )
298{
299 sal_Int32 nPos = rListBox.get_active();
300 // the first three entries are no actual sounds
301 if( nPos >= 3 )
302 {
303 DBG_ASSERT( static_cast<sal_uInt32>(rListBox.get_count() - 3) == rSoundList.size(),
304 "Sound list-box is not synchronized to sound list" );
305 nPos -= 3;
306 if( rSoundList.size() > o3tl::make_unsigned(nPos) )
307 return rSoundList[ nPos ];
308 }
309
310 return OUString();
311}
312
313struct lcl_AppendSoundToListBox
314{
315 explicit lcl_AppendSoundToListBox(weld::ComboBox& rListBox)
316 : mrListBox( rListBox )
317 {}
318
319 void operator() ( std::u16string_view rString ) const
320 {
321 INetURLObject aURL( rString );
322 mrListBox.append_text( aURL.GetBase() );
323 }
324
325private:
326 weld::ComboBox& mrListBox;
327};
328
329void lcl_FillSoundListBox(
330 const ::std::vector< OUString > & rSoundList,
331 weld::ComboBox& rOutListBox )
332{
333 sal_Int32 nCount = rOutListBox.get_count();
334
335 // keep first three entries
336 for( sal_Int32 i=nCount - 1; i>=3; --i )
337 rOutListBox.remove( i );
338
339 ::std::for_each( rSoundList.begin(), rSoundList.end(),
340 lcl_AppendSoundToListBox( rOutListBox ));
341}
342
344size_t getPresetOffset( const sd::impl::TransitionEffect &rEffect )
345{
346 const sd::TransitionPresetList& rPresetList =
348
349 size_t nIdx = 0;
350 for( const auto& aIt: rPresetList )
351 {
352 if( rEffect.operator==( *aIt ))
353 break;
354 nIdx++;
355 }
356 return nIdx;
357}
358
359} // anonymous namespace
360
361namespace sd
362{
363
365{
366public:
367 explicit TransitionPane(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow)
368 : ValueSet(std::move(pScrolledWindow))
369 {
370 }
371
373 {
374 GetScrollBar()->set_vpolicy(VclPolicyType::AUTOMATIC);
376 }
377
378 virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override
379 {
380 Size aSize = pDrawingArea->get_ref_device().LogicToPixel(Size(70, 88), MapMode(MapUnit::MapAppFont));
381 pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
382 ValueSet::SetDrawingArea(pDrawingArea);
383 SetOutputSizePixel(aSize);
384
386 EnableFullItemMode( false );
387 SetColCount(3);
388 }
389};
390
391// SlideTransitionPane
393 weld::Widget* pParent,
394 ViewShellBase & rBase) :
395 PanelLayout( pParent, "SlideTransitionsPanel", "modules/simpress/ui/slidetransitionspanel.ui" ),
396 mrBase( rBase ),
397 mpDrawDoc( rBase.GetDocShell() ? rBase.GetDocShell()->GetDoc() : nullptr ),
398 mbHasSelection( false ),
399 mbUpdatingControls( false ),
400 mbIsMainViewChangePending( false ),
401 maLateInitTimer("sd SlideTransitionPane maLateInitTimer")
402{
404}
405
406css::ui::LayoutSize SlideTransitionPane::GetHeightForWidth(const sal_Int32 /*nWidth*/)
407{
408 sal_Int32 nMinimumHeight = get_preferred_size().Height();
409 return css::ui::LayoutSize(nMinimumHeight, -1, nMinimumHeight);
410}
411
412constexpr sal_uInt16 nNoneId = std::numeric_limits<sal_uInt16>::max();
413
415{
416 mxLB_VARIANT = m_xBuilder->weld_combo_box("variant_list");
417 mxCBX_duration = m_xBuilder->weld_metric_spin_button("transition_duration", FieldUnit::SECOND);
418 mxFT_SOUND = m_xBuilder->weld_label("sound_label");
419 mxLB_SOUND = m_xBuilder->weld_combo_box("sound_list");
420 mxCB_LOOP_SOUND = m_xBuilder->weld_check_button("loop_sound");
421 mxRB_ADVANCE_ON_MOUSE = m_xBuilder->weld_radio_button("rb_mouse_click");
422 mxRB_ADVANCE_AUTO = m_xBuilder->weld_radio_button("rb_auto_after");
423 mxMF_ADVANCE_AUTO_AFTER = m_xBuilder->weld_metric_spin_button("auto_after_value", FieldUnit::SECOND);
424 mxPB_APPLY_TO_ALL = m_xBuilder->weld_button("apply_to_all");
425 mxPB_PLAY = m_xBuilder->weld_button("play");
426 mxCB_AUTO_PREVIEW = m_xBuilder->weld_check_button("auto_preview");
427
428 auto nMax = mxMF_ADVANCE_AUTO_AFTER->get_max(FieldUnit::SECOND);
429 mxMF_ADVANCE_AUTO_AFTER->set_max(99, FieldUnit::SECOND);
430 int nWidthChars = mxMF_ADVANCE_AUTO_AFTER->get_width_chars();
431 mxMF_ADVANCE_AUTO_AFTER->set_max(nMax, FieldUnit::SECOND);
432 mxMF_ADVANCE_AUTO_AFTER->set_width_chars(nWidthChars);
433 mxCBX_duration->set_width_chars(nWidthChars);
434
435 mxVS_TRANSITION_ICONS.reset(new TransitionPane(m_xBuilder->weld_scrolled_window("transitions_iconswin", true)));
437
438 if( pDoc )
439 mxModel.set( pDoc->getUnoModel(), uno::UNO_QUERY );
440 // TODO: get correct view
441 if( mxModel.is())
442 mxView.set( mxModel->getCurrentController(), uno::UNO_QUERY );
443
444 // dummy list box of slide transitions for startup.
445 mxVS_TRANSITION_ICONS->InsertItem(
446 nNoneId, Image( StockImage::Yes, "sd/cmd/transition-none.png" ),
447 SdResId( STR_SLIDETRANSITION_NONE ),
448 VALUESET_APPEND, /* show legend */ true );
449 mxVS_TRANSITION_ICONS->Recalculate();
450
451 // set defaults
452 mxCB_AUTO_PREVIEW->set_active(true); // automatic preview on
453
454 // update control states before adding handlers
456
457 // set handlers
458 mxPB_APPLY_TO_ALL->connect_clicked( LINK( this, SlideTransitionPane, ApplyToAllButtonClicked ));
459 mxPB_PLAY->connect_clicked( LINK( this, SlideTransitionPane, PlayButtonClicked ));
460
461 mxVS_TRANSITION_ICONS->SetSelectHdl( LINK( this, SlideTransitionPane, TransitionSelected ));
462
463 mxLB_VARIANT->connect_changed( LINK( this, SlideTransitionPane, VariantListBoxSelected ));
464 mxCBX_duration->connect_value_changed(LINK( this, SlideTransitionPane, DurationModifiedHdl));
465 mxCBX_duration->connect_focus_out(LINK( this, SlideTransitionPane, DurationLoseFocusHdl));
466 mxLB_SOUND->connect_changed( LINK( this, SlideTransitionPane, SoundListBoxSelected ));
467 mxCB_LOOP_SOUND->connect_toggled( LINK( this, SlideTransitionPane, LoopSoundBoxChecked ));
468
469 mxRB_ADVANCE_ON_MOUSE->connect_toggled( LINK( this, SlideTransitionPane, AdvanceSlideRadioButtonToggled ));
470 mxRB_ADVANCE_AUTO->connect_toggled( LINK( this, SlideTransitionPane, AdvanceSlideRadioButtonToggled ));
471 mxMF_ADVANCE_AUTO_AFTER->connect_value_changed( LINK( this, SlideTransitionPane, AdvanceTimeModified ));
472 mxCB_AUTO_PREVIEW->connect_toggled( LINK( this, SlideTransitionPane, AutoPreviewClicked ));
473 addListener();
474
478}
479
481{
485 mxVS_TRANSITION_ICONS.reset();
486 mxLB_VARIANT.reset();
487 mxCBX_duration.reset();
488 mxFT_SOUND.reset();
489 mxLB_SOUND.reset();
490 mxCB_LOOP_SOUND.reset();
491 mxRB_ADVANCE_ON_MOUSE.reset();
492 mxRB_ADVANCE_AUTO.reset();
494 mxPB_APPLY_TO_ALL.reset();
495 mxPB_PLAY.reset();
496 mxCB_AUTO_PREVIEW.reset();
497}
498
500{
502}
503
505{
507}
508
510{
511 ::sd::slidesorter::SlideSorterViewShell * pSlideSorterViewShell
513 std::shared_ptr<sd::slidesorter::SlideSorterViewShell::PageSelection> pSelection;
514
515 if( pSlideSorterViewShell )
516 {
517 pSelection = pSlideSorterViewShell->GetPageSelection();
518 }
519 else
520 {
521 pSelection = std::make_shared<sd::slidesorter::SlideSorterViewShell::PageSelection>();
522 if( mxView.is() )
523 {
524 SdPage* pPage = SdPage::getImplementation( mxView->getCurrentPage() );
525 if( pPage )
526 pSelection->push_back(pPage);
527 }
528 }
529
530 return pSelection;
531}
532
534{
536 if( pSelectedPages->empty())
537 {
538 mbHasSelection = false;
539 return;
540 }
541 mbHasSelection = true;
542
543 DBG_ASSERT( ! mbUpdatingControls, "Multiple Control Updates" );
544 mbUpdatingControls = true;
545
546 // get model data for first page
547 SdPage * pFirstPage = pSelectedPages->front();
548 DBG_ASSERT( pFirstPage, "Invalid Page" );
549
550 impl::TransitionEffect aEffect( *pFirstPage );
551
552 // merge with other pages
553
554 // start with second page (note aIt != aEndIt, because ! aSelectedPages.empty())
555 for( const auto& rpPage : *pSelectedPages )
556 {
557 if( rpPage )
558 aEffect.compareWith( *rpPage );
559 }
560
561 // detect current slide effect
562 if( aEffect.mbEffectAmbiguous )
563 {
564 SAL_WARN( "sd.transitions", "Unusual, ambiguous transition effect" );
565 mxVS_TRANSITION_ICONS->SelectItem(nNoneId);
566 }
567 else
568 {
569 // ToDo: That 0 is "no transition" is documented nowhere except in the
570 // CTOR of sdpage
571 if( aEffect.mnType == 0 )
572 mxVS_TRANSITION_ICONS->SelectItem(nNoneId);
573 else
574 updateVariants( getPresetOffset( aEffect ) );
575 }
576
577 if( aEffect.mbDurationAmbiguous )
578 {
579 mxCBX_duration->set_text("");
580//TODO mxCBX_duration->SetNoSelection();
581 }
582 else
583 {
584 mxCBX_duration->set_value( (aEffect.mfDuration)*100.0, FieldUnit::SECOND );
585 }
586
587 if( aEffect.mbSoundAmbiguous )
588 {
589 mxLB_SOUND->set_active(-1);
590 maCurrentSoundFile.clear();
591 }
592 else
593 {
594 maCurrentSoundFile.clear();
595 if( aEffect.mbStopSound )
596 {
597 mxLB_SOUND->set_active( 1 );
598 }
599 else if( aEffect.mbSoundOn && !aEffect.maSound.isEmpty() )
600 {
601 std::vector<OUString>::size_type nPos = 0;
602 if( lcl_findSoundInList( maSoundList, aEffect.maSound, nPos ))
603 {
604 mxLB_SOUND->set_active( nPos + 3 );
605 maCurrentSoundFile = aEffect.maSound;
606 }
607 }
608 else
609 {
610 mxLB_SOUND->set_active( 0 );
611 }
612 }
613
614 if( aEffect.mbLoopSoundAmbiguous )
615 {
617 }
618 else
619 {
620 mxCB_LOOP_SOUND->set_active(aEffect.mbLoopSound);
621 }
622
623 if( aEffect.mbPresChangeAmbiguous )
624 {
625 mxRB_ADVANCE_ON_MOUSE->set_active( false );
626 mxRB_ADVANCE_AUTO->set_active( false );
627 }
628 else
629 {
630 mxRB_ADVANCE_ON_MOUSE->set_active( aEffect.mePresChange == PresChange::Manual );
631 mxRB_ADVANCE_AUTO->set_active( aEffect.mePresChange == PresChange::Auto );
632 mxMF_ADVANCE_AUTO_AFTER->set_value(aEffect.mfTime * 100.0, FieldUnit::SECOND);
633 }
634
636 {
637 mxPB_PLAY->hide();
638 mxCB_AUTO_PREVIEW->set_active(false);
639 mxCB_AUTO_PREVIEW->hide();
640 mxFT_SOUND->hide();
641 mxLB_SOUND->hide();
642 mxCB_LOOP_SOUND->hide();
643 }
644 else
645 {
646 SdOptions* pOptions = SD_MOD()->GetSdOptions(DocumentType::Impress);
647 mxCB_AUTO_PREVIEW->set_active( pOptions->IsPreviewTransitions() );
648 }
649
650 mbUpdatingControls = false;
651
653}
654
656{
658 mxLB_VARIANT->set_sensitive( mbHasSelection && mxLB_VARIANT->get_count() > 0 );
659 mxCBX_duration->set_sensitive( mbHasSelection );
660 mxLB_SOUND->set_sensitive( mbHasSelection );
661 mxCB_LOOP_SOUND->set_sensitive( mbHasSelection && (mxLB_SOUND->get_active() > 2));
662 mxRB_ADVANCE_ON_MOUSE->set_sensitive( mbHasSelection );
663 mxRB_ADVANCE_AUTO->set_sensitive( mbHasSelection );
664 mxMF_ADVANCE_AUTO_AFTER->set_sensitive( mbHasSelection && mxRB_ADVANCE_AUTO->get_active());
665
666 mxPB_APPLY_TO_ALL->set_sensitive( mbHasSelection );
667 mxPB_PLAY->set_sensitive( mbHasSelection );
668 mxCB_AUTO_PREVIEW->set_sensitive( mbHasSelection );
669}
670
672{
673 maSoundList.clear();
674
677
678 lcl_FillSoundListBox( maSoundList, *mxLB_SOUND );
679}
680
682{
683 if( ! mxLB_SOUND->get_sensitive())
684 return;
685
686 weld::Window* pDialogParent(GetFrameWeld());
687 SdOpenSoundFileDialog aFileDialog(pDialogParent);
688
689 DBG_ASSERT( mxLB_SOUND->get_active() == 2,
690 "Dialog should only open when \"Other sound\" is selected" );
691
692 bool bValidSoundFile( false );
693 bool bQuitLoop( false );
694
695 while( ! bQuitLoop &&
696 aFileDialog.Execute() == ERRCODE_NONE )
697 {
698 OUString aFile = aFileDialog.GetPath();
699 std::vector<OUString>::size_type nPos = 0;
700 bValidSoundFile = lcl_findSoundInList( maSoundList, aFile, nPos );
701
702 if( bValidSoundFile )
703 {
704 bQuitLoop = true;
705 }
706 else // not in sound list
707 {
708 // try to insert into gallery
710 {
712 bValidSoundFile = lcl_findSoundInList( maSoundList, aFile, nPos );
713 DBG_ASSERT( bValidSoundFile, "Adding sound to gallery failed" );
714
715 bQuitLoop = true;
716 }
717 else
718 {
719 OUString aStrWarning(SdResId(STR_WARNING_NOSOUNDFILE));
720 aStrWarning = aStrWarning.replaceFirst("%", aFile);
721 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(pDialogParent,
722 VclMessageType::Warning, VclButtonsType::NONE,
723 aStrWarning));
724 xWarn->add_button(GetStandardText(StandardButtonType::Retry), RET_RETRY);
725 xWarn->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
726 bQuitLoop = (xWarn->run() != RET_RETRY);
727
728 bValidSoundFile = false;
729 }
730 }
731
732 if( bValidSoundFile )
733 // skip first three entries in list
734 mxLB_SOUND->set_active( nPos + 3 );
735 }
736
737 if( bValidSoundFile )
738 return;
739
740 if( !maCurrentSoundFile.isEmpty() )
741 {
742 std::vector<OUString>::size_type nPos = 0;
743 if( lcl_findSoundInList( maSoundList, maCurrentSoundFile, nPos ))
744 mxLB_SOUND->set_active( nPos + 3 );
745 else
746 mxLB_SOUND->set_active( 0 ); // NONE
747 }
748 else
749 mxLB_SOUND->set_active( 0 ); // NONE
750}
751
753{
755 aResult.setAllAmbiguous();
756
757 bool bNoneSelected = mxVS_TRANSITION_ICONS->IsNoSelection() || mxVS_TRANSITION_ICONS->GetSelectedItemId() == nNoneId;
758
759 // check first (aResult might be overwritten)
760 if( mxVS_TRANSITION_ICONSWin->get_sensitive() &&
761 !bNoneSelected &&
762 mxVS_TRANSITION_ICONS->GetSelectedItemId() > 0 )
763 {
765 auto aSelected = rPresetList.begin();
766 std::advance( aSelected, mxVS_TRANSITION_ICONS->GetSelectedItemId() - 1);
767
768 if (mxLB_VARIANT->get_active() == -1)
769 {
770 // Transition with just one effect.
771 aResult = impl::TransitionEffect( **aSelected );
772 aResult.setAllAmbiguous();
773 }
774 else
775 {
776 int nVariant = 0;
777 bool bFound = false;
778 for( const auto& aIter: rPresetList )
779 {
780 if( aIter->getSetId() == (*aSelected)->getSetId() )
781 {
782 if( mxLB_VARIANT->get_active() == nVariant)
783 {
784 aResult = impl::TransitionEffect( *aIter );
785 aResult.setAllAmbiguous();
786 bFound = true;
787 break;
788 }
789 else
790 {
791 nVariant++;
792 }
793 }
794 }
795 if( !bFound )
796 {
797 aResult.mnType = 0;
798 }
799 }
800 aResult.mbEffectAmbiguous = false;
801 }
802 else if (bNoneSelected)
803 {
804 aResult.mbEffectAmbiguous = false;
805 }
806
807 //duration
808
809 if( mxCBX_duration->get_sensitive() && (!(mxCBX_duration->get_text()).isEmpty()) )
810 {
811 aResult.mfDuration = static_cast<double>(mxCBX_duration->get_value(FieldUnit::SECOND))/100.0;
812 aResult.mbDurationAmbiguous = false;
813 }
814
815 // slide-advance mode
816 if( mxRB_ADVANCE_ON_MOUSE->get_sensitive() && mxRB_ADVANCE_AUTO->get_sensitive() &&
817 (mxRB_ADVANCE_ON_MOUSE->get_active() || mxRB_ADVANCE_AUTO->get_active()))
818 {
819 if( mxRB_ADVANCE_ON_MOUSE->get_active())
821 else
822 {
824 if( mxMF_ADVANCE_AUTO_AFTER->get_sensitive())
825 {
826 aResult.mfTime = static_cast<double>(mxMF_ADVANCE_AUTO_AFTER->get_value(FieldUnit::SECOND) ) / 100.0 ;
827 aResult.mbTimeAmbiguous = false;
828 }
829 }
830
831 aResult.mbPresChangeAmbiguous = false;
832 }
833
834 // sound
835 if( mxLB_SOUND->get_sensitive())
836 {
837 maCurrentSoundFile.clear();
838 sal_Int32 nPos = mxLB_SOUND->get_active();
839 if (nPos != -1)
840 {
841 aResult.mbStopSound = nPos == 1;
842 aResult.mbSoundOn = nPos > 1;
843 if( aResult.mbStopSound )
844 {
845 aResult.maSound.clear();
846 aResult.mbSoundAmbiguous = false;
847 }
848 else
849 {
850 aResult.maSound = lcl_getSoundFileURL(maSoundList, *mxLB_SOUND);
851 aResult.mbSoundAmbiguous = false;
852 maCurrentSoundFile = aResult.maSound;
853 }
854 }
855 }
856
857 // sound loop
858 if( mxCB_LOOP_SOUND->get_sensitive() )
859 {
860 aResult.mbLoopSound = mxCB_LOOP_SOUND->get_active();
861 aResult.mbLoopSoundAmbiguous = false;
862 }
863
864 return aResult;
865}
866
867void SlideTransitionPane::applyToSelectedPages(bool bPreview = true)
868{
869 if( mbUpdatingControls )
870 return;
871
873
874 ::sd::slidesorter::SharedPageSelection pSelectedPages( getSelectedPages());
875 impl::TransitionEffect aEffect = getTransitionEffectFromControls();
876 if( ! pSelectedPages->empty())
877 {
878 lcl_CreateUndoForPages( pSelectedPages, mrBase );
879 lcl_ApplyToPages( pSelectedPages, aEffect );
880 mrBase.GetDocShell()->SetModified();
881 }
882 if( mxCB_AUTO_PREVIEW->get_sensitive() &&
883 mxCB_AUTO_PREVIEW->get_active() && bPreview)
884 {
885 if (aEffect.mnType) // mnType = 0 denotes no transition
886 playCurrentEffect();
887 else if( mxView.is() )
888 SlideShow::Stop( mrBase );
889 }
890
891 if (pFocusWindow)
892 pFocusWindow->GrabFocus();
893}
894
895void SlideTransitionPane::playCurrentEffect()
896{
897 if( mxView.is() )
898 {
899
900 Reference< css::animations::XAnimationNode > xNode;
901 SlideShow::StartPreview( mrBase, mxView->getCurrentPage(), xNode );
902 }
903}
904
905void SlideTransitionPane::addListener()
906{
907 Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,SlideTransitionPane,EventMultiplexerListener) );
908 mrBase.GetEventMultiplexer()->AddEventListener( aLink );
909}
910
911void SlideTransitionPane::removeListener()
912{
913 Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,SlideTransitionPane,EventMultiplexerListener) );
914 mrBase.GetEventMultiplexer()->RemoveEventListener( aLink );
915}
916
917IMPL_LINK(SlideTransitionPane,EventMultiplexerListener,
918 tools::EventMultiplexerEvent&, rEvent, void)
919{
920 switch (rEvent.meEventId)
921 {
923 onSelectionChanged();
924 break;
925
928 onChangeCurrentPage();
929 break;
930
932 mxView.clear();
933 onSelectionChanged();
934 onChangeCurrentPage();
935 break;
936
938 mbIsMainViewChangePending = true;
939 break;
940
942 if (mbIsMainViewChangePending)
943 {
944 mbIsMainViewChangePending = false;
945
946 // At this moment the controller may not yet been set at
947 // model or ViewShellBase. Take it from the view shell
948 // passed with the event.
949 if (mrBase.GetMainViewShell() != nullptr)
950 {
951 mxView.set(mrBase.GetController(), css::uno::UNO_QUERY);
952 onSelectionChanged();
953 onChangeCurrentPage();
954 }
955 }
956 break;
957
958 default:
959 if (rEvent.meEventId != EventMultiplexerEventId::Disposing)
960 {
961 onSelectionChanged();
962 onChangeCurrentPage();
963 }
964 break;
965 }
966}
967
968IMPL_LINK_NOARG(SlideTransitionPane, ApplyToAllButtonClicked, weld::Button&, void)
969{
970 DBG_ASSERT( mpDrawDoc, "Invalid Draw Document!" );
971 if( !mpDrawDoc )
972 return;
973
975 std::make_shared<::sd::slidesorter::SlideSorterViewShell::PageSelection>();
976
977 sal_uInt16 nPageCount = mpDrawDoc->GetSdPageCount( PageKind::Standard );
978 pPages->reserve( nPageCount );
979 for( sal_uInt16 i=0; i<nPageCount; ++i )
980 {
981 SdPage * pPage = mpDrawDoc->GetSdPage( i, PageKind::Standard );
982 if( pPage )
983 pPages->push_back( pPage );
984 }
985
986 if( ! pPages->empty())
987 {
988 lcl_CreateUndoForPages( pPages, mrBase );
989 lcl_ApplyToPages( pPages, getTransitionEffectFromControls() );
990 }
991}
992
994{
995 playCurrentEffect();
996}
997
998IMPL_LINK_NOARG(SlideTransitionPane, TransitionSelected, ValueSet*, void)
999{
1000 updateVariants( mxVS_TRANSITION_ICONS->GetSelectedItemId() - 1 );
1001 applyToSelectedPages();
1002}
1003
1005void SlideTransitionPane::updateVariants( size_t nPresetOffset )
1006{
1008 mxLB_VARIANT->clear();
1009 mxVS_TRANSITION_ICONS->SelectItem(nNoneId);
1010
1011 if( nPresetOffset >= rPresetList.size() )
1012 {
1013 mxLB_VARIANT->set_sensitive( false );
1014 }
1015 else
1016 {
1017 auto pFound = rPresetList.begin();
1018 std::advance( pFound, nPresetOffset );
1019
1020 // Fill in the variant listbox
1021 size_t nFirstItem = 0, nItem = 1;
1022 for( const auto& aIt: rPresetList )
1023 {
1024 if( aIt->getSetId() == (*pFound)->getSetId() )
1025 {
1026 if (!nFirstItem)
1027 nFirstItem = nItem;
1028 if( !aIt->getVariantLabel().isEmpty() )
1029 {
1030 mxLB_VARIANT->append_text( aIt->getVariantLabel() );
1031 if( *pFound == aIt )
1032 mxLB_VARIANT->set_active( mxLB_VARIANT->get_count()-1 );
1033 }
1034 }
1035 nItem++;
1036 }
1037
1038 if( mxLB_VARIANT->get_count() == 0 )
1039 mxLB_VARIANT->set_sensitive( false );
1040 else
1041 mxLB_VARIANT->set_sensitive(true);
1042
1043 // item has the id of the first transition from this set.
1044 mxVS_TRANSITION_ICONS->SelectItem( nFirstItem );
1045 }
1046}
1047
1048IMPL_LINK_NOARG(SlideTransitionPane, AdvanceSlideRadioButtonToggled, weld::Toggleable&, void)
1049{
1050 updateControlState();
1051 applyToSelectedPages(false);
1052}
1053
1055{
1056 applyToSelectedPages(false);
1057}
1058
1060{
1061 applyToSelectedPages();
1062}
1063
1065{
1066 double duration_value = static_cast<double>(mxCBX_duration->get_value(FieldUnit::SECOND));
1067 if (duration_value <= 0.0)
1068 mxCBX_duration->set_value(0, FieldUnit::SECOND);
1069 else
1070 mxCBX_duration->set_value(duration_value, FieldUnit::SECOND);
1071
1072 applyToSelectedPages();
1073}
1074
1076{
1077 applyToSelectedPages();
1078}
1079
1081{
1082 sal_Int32 nPos = mxLB_SOUND->get_active();
1083 if( nPos == 2 )
1084 {
1085 // other sound...
1086 openSoundFileDialog();
1087 }
1088 updateControlState();
1089 applyToSelectedPages();
1090}
1091
1093{
1094 applyToSelectedPages();
1095}
1096
1098{
1099 SdOptions* pOptions = SD_MOD()->GetSdOptions(DocumentType::Impress);
1100 pOptions->SetPreviewTransitions( mxCB_AUTO_PREVIEW->get_active() );
1101}
1102
1103IMPL_LINK_NOARG(SlideTransitionPane, LateInitCallback, Timer *, void)
1104{
1105 const TransitionPresetList& rPresetList = TransitionPreset::getTransitionPresetList();
1106
1107 size_t nPresetOffset = 0;
1108 for( const TransitionPresetPtr& pPreset: rPresetList )
1109 {
1110 const OUString sLabel( pPreset->getSetLabel() );
1111 if( !sLabel.isEmpty() )
1112 {
1113 if( m_aNumVariants.find( pPreset->getSetId() ) == m_aNumVariants.end() )
1114 {
1115 OUString sImageName("sd/cmd/transition-" + pPreset->getSetId() + ".png");
1116 BitmapEx aIcon( sImageName );
1117 if ( aIcon.IsEmpty() ) // need a fallback
1118 sImageName = "sd/cmd/transition-none.png";
1119
1120 mxVS_TRANSITION_ICONS->InsertItem(
1121 nPresetOffset + 1, Image(StockImage::Yes, sImageName), sLabel,
1122 VALUESET_APPEND, /* show legend */ true );
1123
1124 m_aNumVariants[ pPreset->getSetId() ] = 1;
1125 }
1126 else
1127 {
1128 m_aNumVariants[ pPreset->getSetId() ]++;
1129 }
1130 }
1131 nPresetOffset++;
1132 }
1133 mxVS_TRANSITION_ICONS->Recalculate();
1134
1135 SAL_INFO( "sd.transitions", "Item transition offsets in ValueSet:");
1136 for( size_t i = 0; i < mxVS_TRANSITION_ICONS->GetItemCount(); ++i )
1137 SAL_INFO( "sd.transitions", i << ":" << mxVS_TRANSITION_ICONS->GetItemId( i ) );
1138
1139 nPresetOffset = 0;
1140 SAL_INFO( "sd.transitions", "Transition presets by offsets:");
1141 for( const auto& aIter: rPresetList )
1142 {
1143 SAL_INFO( "sd.transitions", nPresetOffset++ << " " <<
1144 aIter->getPresetId() << ": " << aIter->getSetId() );
1145 }
1146
1147 updateSoundList();
1148 updateControls();
1149}
1150
1151} // namespace sd
1152
1153/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
@ EditViewSelection
The selection in the center pane has changed.
@ SlideSortedSelection
The selection in the slide sorter has changed, regardless of whether the slide sorter is displayed in...
@ Disposing
The EventMultiplexer itself is being disposed.
@ MainViewRemoved
The current MainViewShell (the ViewShell displayed in the center pane) has been removed.
@ MainViewAdded
A new ViewShell has been made the MainViewShell.
@ ConfigurationUpdated
A configuration update has been completed.
@ CurrentPageChanged
The current page has changed.
static weld::MessageDialog * CreateMessageDialog(weld::Widget *pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage, const ILibreOfficeKitNotifier *pNotifier=nullptr)
static vcl::Window * GetFocusWindow()
bool IsEmpty() const
static bool FillObjList(std::u16string_view rThemeName, std::vector< OUString > &rObjList)
static bool InsertURL(std::u16string_view rThemeName, std::u16string_view rURL)
SAL_WARN_UNUSED_RESULT Point LogicToPixel(const Point &rLogicPt) const
virtual weld::Window * GetFrameWeld() const
std::unique_ptr< weld::Builder > m_xBuilder
Size get_preferred_size() const
The class SdOpenSoundFileDialog wraps the FileDialogHelper, displaying the FILEOPEN_PLAY dialog templ...
Definition: filedlg.hxx:40
OUString GetPath() const
Definition: filedlg.cxx:247
bool IsPreviewTransitions() const
Definition: optsitem.hxx:272
void SetPreviewTransitions(bool bOn)
Definition: optsitem.hxx:316
void setTransitionFadeColor(sal_Int32 nTransitionFadeColor)
Definition: sdpage2.cxx:516
bool IsStopSound() const
Definition: sdpage.hxx:234
bool IsLoopSound() const
Definition: sdpage.hxx:231
void SetTime(double fNewTime)
Definition: sdpage.hxx:216
PresChange GetPresChange() const
Definition: sdpage.hxx:214
double GetTime() const
Definition: sdpage.hxx:217
double getTransitionDuration() const
Definition: sdpage.hxx:248
void setTransitionDirection(bool bTransitionbDirection)
Definition: sdpage2.cxx:510
static SdPage * getImplementation(const css::uno::Reference< css::drawing::XDrawPage > &xPage)
returns the SdPage implementation for the given XDrawPage or 0 if not available
Definition: sdpage.cxx:2682
bool IsSoundOn() const
Definition: sdpage.hxx:220
const OUString & GetSoundFile() const
Definition: sdpage.hxx:228
void SetLoopSound(bool bLoopSound)
Definition: sdpage.hxx:230
void setTransitionSubtype(sal_Int16 nTransitionSubtype)
Definition: sdpage2.cxx:504
void SetPresChange(PresChange eChange)
Definition: sdpage.hxx:213
void SetSoundFile(const OUString &rStr)
Definition: sdpage.hxx:227
void SetStopSound(bool bStopSound)
Definition: sdpage.hxx:233
void setTransitionType(sal_Int16 nTransitionType)
Definition: sdpage2.cxx:498
void SetSound(bool bNewSoundOn)
Definition: sdpage.hxx:219
void setTransitionDuration(double fTransitionDuration)
Definition: sdpage2.cxx:522
css::uno::Reference< css::uno::XInterface > const & getUnoModel()
size_t LeaveListAction()
virtual void EnterListAction(const OUString &rComment, const OUString &rRepeatComment, sal_uInt16 nId, ViewShellId nViewShellId)
virtual void AddUndoAction(std::unique_ptr< SfxUndoAction > pAction, bool bTryMerg=false)
ViewShellId GetViewShellId() const override
constexpr tools::Long Height() const
constexpr tools::Long Width() const
void Stop()
void SetTimeout(sal_uInt64 nTimeoutMs)
void SetInvokeHandler(const Link< Timer *, void > &rLink)
virtual void Start(bool bStartTimer=true) override
void RecalculateItemSizes()
void SetStyle(WinBits nStyle)
void EnableFullItemMode(bool bFullMode)
WinBits GetStyle() const
void SetColCount(sal_uInt16 nNewCols=1)
weld::ScrolledWindow * GetScrollBar() const
virtual void SetDrawingArea(weld::DrawingArea *pDrawingArea) override
virtual SfxUndoManager * GetUndoManager() override
Definition: docshell.cxx:363
SdDrawDocument * GetDoc()
virtual ~SlideTransitionPane() override
impl::TransitionEffect getTransitionEffectFromControls() const
::sd::slidesorter::SharedPageSelection getSelectedPages() const
std::unique_ptr< weld::Button > mxPB_PLAY
std::unique_ptr< weld::RadioButton > mxRB_ADVANCE_ON_MOUSE
std::unique_ptr< weld::CustomWeld > mxVS_TRANSITION_ICONSWin
std::unique_ptr< weld::ComboBox > mxLB_SOUND
std::vector< OUString > maSoundList
std::unique_ptr< weld::ComboBox > mxLB_VARIANT
SlideTransitionPane(weld::Widget *pParent, ViewShellBase &rBase)
void Initialize(SdDrawDocument *pDoc)
std::unique_ptr< TransitionPane > mxVS_TRANSITION_ICONS
std::unique_ptr< weld::Label > mxFT_SOUND
std::unique_ptr< weld::CheckButton > mxCB_AUTO_PREVIEW
std::unique_ptr< weld::MetricSpinButton > mxCBX_duration
std::unique_ptr< weld::CheckButton > mxCB_LOOP_SOUND
virtual css::ui::LayoutSize GetHeightForWidth(const sal_Int32 nWidth) override
css::uno::Reference< css::frame::XModel > mxModel
std::unique_ptr< weld::Button > mxPB_APPLY_TO_ALL
std::unique_ptr< weld::MetricSpinButton > mxMF_ADVANCE_AUTO_AFTER
std::unique_ptr< weld::RadioButton > mxRB_ADVANCE_AUTO
void updateVariants(size_t nPresetOffset)
we use an integer offset into the list of transition presets
css::uno::Reference< css::drawing::XDrawView > mxView
virtual void SetDrawingArea(weld::DrawingArea *pDrawingArea) override
TransitionPane(std::unique_ptr< weld::ScrolledWindow > pScrolledWindow)
static const TransitionPresetList & getTransitionPresetList()
SfxViewShell descendant that the stacked Draw/Impress shells are based on.
DrawDocShell * GetDocShell() const
SD_DLLPUBLIC SlideSorter & GetSlideSorter() const
std::shared_ptr< PageSelection > GetPageSelection() const
Return the set of selected pages.
void GrabFocus()
virtual void remove(int pos)=0
virtual int get_active() const=0
virtual int get_count() const=0
virtual OutputDevice & get_ref_device()=0
virtual void set_vpolicy(VclPolicyType eVPolicy)=0
virtual void set_size_request(int nWidth, int nHeight)=0
int nCount
#define DBG_ASSERT(sCon, aError)
PresChange
Definition: diadef.h:23
URL aURL
#define ERRCODE_NONE
#define GALLERY_THEME_USERSOUNDS
#define GALLERY_THEME_SOUNDS
TRISTATE_INDET
sal_uInt16 nPos
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
aStr
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
std::shared_ptr< SlideSorterViewShell::PageSelection > SharedPageSelection
IMPL_LINK_NOARG(SlideTransitionPane, LateInitCallback, Timer *, void)
std::vector< TransitionPresetPtr > TransitionPresetList
std::shared_ptr< TransitionPreset > TransitionPresetPtr
IMPL_LINK(SlideTransitionPane, EventMultiplexerListener, tools::EventMultiplexerEvent &, rEvent, void)
constexpr sal_uInt16 nNoneId
OUString SdResId(TranslateId aId)
Definition: sdmod.cxx:83
#define SD_MOD()
Definition: sdmod.hxx:184
uno::Reference< presentation::XSlideShowView > mxView
OUString VCL_DLLPUBLIC GetStandardText(StandardButtonType eButton)
bool operator==(const ::sd::TransitionPreset &rPreset) const
TransitionEffect(const ::sd::TransitionPreset &rPreset)
TransitionEffect(const SdPage &rPage)
void compareWith(const SdPage &rPage)
void applyTo(SdPage &rOutPage) const
#define WB_FLATVALUESET
#define WB_ITEMBORDER
#define VALUESET_APPEND
RET_CANCEL
RET_RETRY
WinBits const WB_VSCROLL