Marble

TourPlayback.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2014 Sanjiban Bairagya <sanjiban22393@gmail.com>
4//
5
6#include "TourPlayback.h"
7
8#include <QList>
9#include <QUrl>
10#include <QPointer>
11
12#include "MarbleDebug.h"
13#include "MarbleWidget.h"
14#include "PopupLayer.h"
15#include "GeoDataPoint.h"
16#include "GeoDataPlacemark.h"
17#include "GeoDataPlaylist.h"
18#include "GeoDataTour.h"
19#include "GeoDataWait.h"
20#include "GeoDataFlyTo.h"
21#include "GeoDataLookAt.h"
22#include "GeoDataTourControl.h"
23#include "GeoDataSoundCue.h"
24#include "GeoDataAnimatedUpdate.h"
25#include "MarbleModel.h"
26#include "GeoDataTreeModel.h"
27#include "PlaybackFlyToItem.h"
28#include "PlaybackAnimatedUpdateItem.h"
29#include "PlaybackWaitItem.h"
30#include "PlaybackTourControlItem.h"
31#include "PlaybackSoundCueItem.h"
32#include "SerialTrack.h"
33#include "SoundTrack.h"
34#include "AnimatedUpdateTrack.h"
35
36namespace Marble
37{
38
39class TourPlaybackPrivate
40{
41public:
42 TourPlaybackPrivate();
43 ~TourPlaybackPrivate();
44
45 GeoDataTour *m_tour;
46 bool m_pause;
47 SerialTrack m_mainTrack;
48 QList<SoundTrack*> m_soundTracks;
49 QList<AnimatedUpdateTrack*> m_animatedUpdateTracks;
50 GeoDataFlyTo m_mapCenter;
52 QUrl m_baseUrl;
53};
54
55TourPlaybackPrivate::TourPlaybackPrivate() :
56 m_tour( nullptr ),
57 m_pause( false ),
58 m_mainTrack(),
59 m_widget( nullptr )
60{
61 // do nothing
62}
63
64TourPlaybackPrivate::~TourPlaybackPrivate()
65{
66 qDeleteAll(m_soundTracks);
67 qDeleteAll(m_animatedUpdateTracks);
68}
69
70TourPlayback::TourPlayback(QObject *parent) :
71 QObject(parent),
72 d(new TourPlaybackPrivate())
73{
74 connect( &d->m_mainTrack, SIGNAL(centerOn(GeoDataCoordinates)), this, SLOT(centerOn(GeoDataCoordinates)) );
75 connect( &d->m_mainTrack, SIGNAL(progressChanged(double)), this, SIGNAL(progressChanged(double)) );
76 connect( &d->m_mainTrack, SIGNAL(finished()), this, SLOT(stopTour()) );
77 connect( &d->m_mainTrack, SIGNAL(itemFinished(int)), this, SLOT(handleFinishedItem(int)) );
78
79
80}
81
82TourPlayback::~TourPlayback()
83{
84 stop();
85 delete d;
86}
87
88void TourPlayback::handleFinishedItem( int index )
89{
90 emit itemFinished( index );
91}
92
93void TourPlayback::stopTour()
94{
95 for( SoundTrack* track: d->m_soundTracks ){
96 track->stop();
97 track->setPaused( false );
98 }
99 for( int i = d->m_animatedUpdateTracks.size()-1; i >= 0; i-- ){
100 d->m_animatedUpdateTracks[ i ]->stop();
101 d->m_animatedUpdateTracks[ i ]->setPaused( false );
102 }
103 emit finished();
104}
105
106void TourPlayback::showBalloon( GeoDataPlacemark* placemark )
107{
108 GeoDataPoint* point = static_cast<GeoDataPoint*>( placemark->geometry() );
109 d->m_widget->popupLayer()->setCoordinates( point->coordinates(), Qt::AlignRight | Qt::AlignVCenter );
110 d->m_widget->popupLayer()->setContent( placemark->description(), d->m_baseUrl );
111 d->m_widget->popupLayer()->setVisible( true );
112 d->m_widget->popupLayer()->setSize(QSizeF(500, 520));
113}
114
115void TourPlayback::hideBalloon()
116{
117 if( d->m_widget ){
118 d->m_widget->popupLayer()->setVisible( false );
119 }
120}
121
122bool TourPlayback::isPlaying() const
123{
124 return !d->m_pause;
125}
126
127void TourPlayback::setMarbleWidget(MarbleWidget* widget)
128{
129 d->m_widget = widget;
130
131 connect( this, SIGNAL(added(GeoDataContainer*,GeoDataFeature*,int)),
132 d->m_widget->model()->treeModel(), SLOT(addFeature(GeoDataContainer*,GeoDataFeature*,int)) );
133 connect( this, SIGNAL(removed(GeoDataFeature*)),
134 d->m_widget->model()->treeModel(), SLOT(removeFeature(GeoDataFeature*)) );
135 connect( this, SIGNAL(updated(GeoDataFeature*)),
136 d->m_widget->model()->treeModel(), SLOT(updateFeature(GeoDataFeature*)) );
137}
138
139void TourPlayback::setBaseUrl( const QUrl &baseUrl )
140{
141 d->m_baseUrl = baseUrl;
142}
143
144QUrl TourPlayback::baseUrl() const
145{
146 return d->m_baseUrl;
147}
148
149void TourPlayback::centerOn( const GeoDataCoordinates &coordinates )
150{
151 if ( d->m_widget ) {
152 GeoDataLookAt lookat;
153 lookat.setCoordinates( coordinates );
154 lookat.setRange( coordinates.altitude() );
155 d->m_widget->flyTo( lookat, Instant );
156 }
157}
158
159void TourPlayback::setTour(GeoDataTour *tour)
160{
161 d->m_tour = tour;
162 if ( !d->m_tour ) {
163 clearTracks();
164 return;
165 }
166
167 updateTracks();
168}
169
170void TourPlayback::play()
171{
172 d->m_pause = false;
173 GeoDataLookAt* lookat = new GeoDataLookAt( d->m_widget->lookAt() );
174 lookat->setAltitude( lookat->range() );
175 d->m_mapCenter.setView( lookat );
176 d->m_mainTrack.play();
177 for( SoundTrack* track: d->m_soundTracks) {
178 track->play();
179 }
180 for( AnimatedUpdateTrack* track: d->m_animatedUpdateTracks) {
181 track->play();
182 }
183}
184
185void TourPlayback::pause()
186{
187 d->m_pause = true;
188 d->m_mainTrack.pause();
189 for( SoundTrack* track: d->m_soundTracks) {
190 track->pause();
191 }
192 for( AnimatedUpdateTrack* track: d->m_animatedUpdateTracks) {
193 track->pause();
194 }
195}
196
197void TourPlayback::stop()
198{
199 d->m_pause = true;
200 d->m_mainTrack.stop();
201 for( SoundTrack* track: d->m_soundTracks) {
202 track->stop();
203 }
204 for( int i = d->m_animatedUpdateTracks.size()-1; i >= 0; i-- ){
205 d->m_animatedUpdateTracks[ i ]->stop();
206 }
207 hideBalloon();
208}
209
210void TourPlayback::seek( double value )
211{
212 double const offset = qBound( 0.0, value, d->m_mainTrack.duration() );
213 d->m_mainTrack.seek( offset );
214 for( SoundTrack* track: d->m_soundTracks ){
215 track->seek( offset );
216 }
217 for( AnimatedUpdateTrack* track: d->m_animatedUpdateTracks ){
218 track->seek( offset );
219 }
220}
221
222int TourPlayback::mainTrackSize()
223{
224 return d->m_mainTrack.size();
225}
226
227PlaybackItem* TourPlayback::mainTrackItemAt( int i )
228{
229 return d->m_mainTrack.at( i );
230}
231
232void TourPlayback::updateTracks()
233{
234 clearTracks();
235 double delay = 0;
236 for( int i = 0; i < d->m_tour->playlist()->size(); i++){
237 GeoDataTourPrimitive* primitive = d->m_tour->playlist()->primitive( i );
238 if (const auto flyTo = geodata_cast<GeoDataFlyTo>(primitive)){
239 d->m_mainTrack.append( new PlaybackFlyToItem( flyTo ) );
240 delay += flyTo->duration();
241 }
242 else if (const auto wait = geodata_cast<GeoDataWait>(primitive)) {
243 d->m_mainTrack.append( new PlaybackWaitItem( wait ) );
244 delay += wait->duration();
245 }
246 else if (const auto tourControl = geodata_cast<GeoDataTourControl>(primitive)) {
247 d->m_mainTrack.append( new PlaybackTourControlItem( tourControl ) );
248 }
249 else if (const auto soundCue = geodata_cast<GeoDataSoundCue>(primitive)) {
250 PlaybackSoundCueItem *item = new PlaybackSoundCueItem( soundCue );
251 SoundTrack *track = new SoundTrack( item );
252 track->setDelayBeforeTrackStarts( delay );
253 d->m_soundTracks.append( track );
254 }
255 else if (const auto animatedUpdate = geodata_cast<GeoDataAnimatedUpdate>(primitive)) {
256 PlaybackAnimatedUpdateItem *item = new PlaybackAnimatedUpdateItem( animatedUpdate );
257 AnimatedUpdateTrack *track = new AnimatedUpdateTrack( item );
258 track->setDelayBeforeTrackStarts( delay + animatedUpdate->delayedStart() );
259 d->m_animatedUpdateTracks.append( track );
260 connect( track, SIGNAL(balloonHidden()), this, SLOT(hideBalloon()) );
261 connect( track, SIGNAL(balloonShown(GeoDataPlacemark*)), this, SLOT(showBalloon(GeoDataPlacemark*)) );
262 connect( track, SIGNAL(updated(GeoDataFeature*)), this, SIGNAL(updated(GeoDataFeature*)) );
263 connect( track, SIGNAL(added(GeoDataContainer*,GeoDataFeature*,int)), this, SIGNAL(added(GeoDataContainer*,GeoDataFeature*,int)) );
264 connect( track, SIGNAL(removed(const GeoDataFeature*)), this, SIGNAL(removed(const GeoDataFeature*)) );
265 }
266 }
267 Q_ASSERT( d->m_widget );
268 GeoDataLookAt* lookat = new GeoDataLookAt( d->m_widget->lookAt() );
269 lookat->setAltitude( lookat->range() );
270 d->m_mapCenter.setView( lookat );
271 PlaybackFlyToItem* mapCenterItem = new PlaybackFlyToItem( &d->m_mapCenter );
272 PlaybackFlyToItem* before = mapCenterItem;
273 for ( int i=0; i<d->m_mainTrack.size(); ++i ) {
274 PlaybackFlyToItem* item = qobject_cast<PlaybackFlyToItem*>( d->m_mainTrack.at(i) );
275 if ( item ) {
276 item->setBefore( before );
277 before = item;
278 }
279 }
280 PlaybackFlyToItem* next = nullptr;
281 for ( int i=d->m_mainTrack.size()-1; i>=0; --i ) {
282 PlaybackFlyToItem* item = qobject_cast<PlaybackFlyToItem*>( d->m_mainTrack.at(i) );
283 if ( item ) {
284 item->setNext( next );
285 next = item;
286 }
287 }
288}
289
290void TourPlayback::clearTracks()
291{
292 d->m_mainTrack.clear();
293 qDeleteAll(d->m_soundTracks);
294 qDeleteAll(d->m_animatedUpdateTracks);
295 d->m_soundTracks.clear();
296 d->m_animatedUpdateTracks.clear();
297}
298
299double TourPlayback::duration() const
300{
301 return d->m_mainTrack.duration();
302}
303
304} // namespace Marble
305
306#include "moc_TourPlayback.cpp"
This file contains the headers for MarbleModel.
This file contains the headers for MarbleWidget.
void stop(Ekos::AlignState mode)
const QList< QKeySequence > & next()
Binds a QML item to a specific geodetic location in screen coordinates.
AlignRight
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:17 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.