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

KDE's Doxygen guidelines are available online.