8#include "TourItemDelegate.h"
10#include <QAbstractTextDocumentLayout>
11#include <QApplication>
15#include <QStyleOptionButton>
17#include "EditPlacemarkDialog.h"
18#include "FlyToEditWidget.h"
19#include "GeoDataChange.h"
20#include "GeoDataCreate.h"
21#include "GeoDataDelete.h"
22#include "GeoDataPlacemark.h"
23#include "GeoDataPlaylist.h"
24#include "GeoDataUpdate.h"
25#include "MarblePlacemarkModel.h"
27#include "RemoveItemEditWidget.h"
28#include "SoundCueEditWidget.h"
29#include "TourControlEditWidget.h"
30#include "TourWidget.h"
31#include "WaitEditWidget.h"
32#include "geodata/data/GeoDataAnimatedUpdate.h"
33#include "geodata/data/GeoDataContainer.h"
34#include "geodata/data/GeoDataCoordinates.h"
35#include "geodata/data/GeoDataFlyTo.h"
36#include "geodata/data/GeoDataObject.h"
37#include "geodata/data/GeoDataSoundCue.h"
38#include "geodata/data/GeoDataTourControl.h"
39#include "geodata/data/GeoDataWait.h"
44TourItemDelegate::TourItemDelegate(
QListView *view, MarbleWidget *widget, TourWidget *tour)
65 if (m_listView->currentIndex() == index && m_tourWidget->isPlaying()) {
71 QRect const labelRect = position(Label, option);
73 label.setDefaultFont(option.font);
76 button.state = option.state;
77 button.palette = option.palette;
79 button.iconSize =
QSize(16, 16);
80 button.state &=
~QStyle::State_HasFocus;
82 button.state &=
~QStyle::State_Enabled;
85 QRect const iconRect = position(GeoDataElementIcon, option);
87 const GeoDataObject *
object = qvariant_cast<GeoDataObject *>(index.
data(MarblePlacemarkModel::ObjectPointerRole));
88 if (!m_editingIndices.contains(index)) {
89 if (
const auto tourControl = geodata_cast<GeoDataTourControl>(
object)) {
90 GeoDataTourControl::PlayMode
const playMode = tourControl->playMode();
92 if (playMode == GeoDataTourControl::Play) {
93 label.setHtml(tr(
"Play the tour"));
94 }
else if (playMode == GeoDataTourControl::Pause) {
95 label.setHtml(tr(
"Pause the tour"));
100 label.documentLayout()->draw(painter, paintContext);
102 button.icon =
QIcon(QStringLiteral(
":/marble/document-edit.png"));
104 QRect const buttonRect = position(EditButton, option);
105 button.rect = buttonRect;
107 QIcon const icon =
QIcon(QStringLiteral(
":/marble/media-playback-pause.png"));
110 }
else if (geodata_cast<GeoDataFlyTo>(
object)) {
111 auto const flyToCoords = index.
data(MarblePlacemarkModel::CoordinateRole).
value<GeoDataCoordinates>();
112 label.setHtml(flyToCoords.toString());
113 button.icon =
QIcon(QStringLiteral(
":/marble/document-edit.png"));
118 label.documentLayout()->draw(painter, paintContext);
121 QRect const buttonRect = position(EditButton, option);
122 button.rect = buttonRect;
124 QIcon const icon =
QIcon(QStringLiteral(
":/marble/flag.png"));
126 }
else if (
const auto wait = geodata_cast<GeoDataWait>(
object)) {
132 label.documentLayout()->draw(painter, paintContext);
135 button.icon =
QIcon(QStringLiteral(
":/marble/document-edit.png"));
137 QRect const buttonRect = position(EditButton, option);
138 button.rect = buttonRect;
140 QIcon const icon =
QIcon(QStringLiteral(
":/marble/player-time.png"));
142 }
else if (
const auto soundCue = geodata_cast<GeoDataSoundCue>(
object)) {
148 label.documentLayout()->draw(painter, paintContext);
153 button.icon =
QIcon(QStringLiteral(
":/marble/document-edit.png"));
154 QRect const buttonRect = position(EditButton, option);
155 button.rect = buttonRect;
157 playButton.icon =
QIcon(QStringLiteral(
":/marble/playback-play.png"));
158 QRect const playButtonRect = position(ActionButton, option);
159 playButton.rect = playButtonRect;
162 QIcon const icon =
QIcon(QStringLiteral(
":/marble/audio-x-generic.png"));
164 }
else if (
const auto animUpdate = geodata_cast<GeoDataAnimatedUpdate>(
object)) {
165 const GeoDataUpdate *
update = animUpdate->update();
168 if (update &&
update->create() &&
update->create()->size() != 0 && (
dynamic_cast<const GeoDataContainer *
>(&
update->create()->first()))) {
169 const auto container =
static_cast<const GeoDataContainer *
>(
update->create()->child(0));
170 if (container->size() > 0) {
171 label.setHtml(tr(
"Create item %1").arg(container->first().id()));
173 iconString = QStringLiteral(
":/icons/add-placemark.png");
175 }
else if (update &&
update->getDelete() &&
update->getDelete()->size() != 0) {
176 label.setHtml(tr(
"Remove item %1").arg(
update->getDelete()->first().targetId()));
178 iconString = QStringLiteral(
":/icons/remove.png");
179 }
else if (update &&
update->change() &&
update->change()->size() != 0) {
180 label.setHtml(tr(
"Change item %1").arg(
update->change()->first().targetId()));
182 iconString = QStringLiteral(
":/marble/document-edit.png");
185 label.setHtml(tr(
"Update items"));
192 label.documentLayout()->draw(painter, paintContext);
195 button.icon =
QIcon(QStringLiteral(
":/marble/document-edit.png"));
196 QRect const buttonRect = position(EditButton, option);
197 button.rect = buttonRect;
209 QPoint const topCol1 = option.rect.topLeft() +
QPoint(10, 10);
217 case GeoDataElementIcon:
218 return QRect(topCol1, iconsSize);
220 return QRect(topCol2, labelSize);
222 return QRect(topCol3, iconsSize);
224 return QRect(topCol4, iconsSize);
229QStringList TourItemDelegate::findIds(
const GeoDataPlaylist &playlist,
bool onlyFeatures)
232 for (
int i = 0; i < playlist.size(); ++i) {
233 const GeoDataTourPrimitive *primitive = playlist.primitive(i);
234 if (!primitive->id().isEmpty() && !onlyFeatures) {
235 result << primitive->id();
237 if (
const auto animatedUpdate = geodata_cast<GeoDataAnimatedUpdate>(primitive)) {
238 if (animatedUpdate->update() !=
nullptr) {
239 const GeoDataUpdate *
update = animatedUpdate->update();
240 if (!
update->id().isEmpty() && !onlyFeatures) {
243 if (
update->create() !=
nullptr) {
244 if (!
update->create()->id().isEmpty() && !onlyFeatures) {
245 result <<
update->create()->id();
247 for (
int j = 0; j <
update->create()->size(); ++j) {
248 if (!
update->create()->at(j).id().isEmpty()) {
249 result <<
update->create()->at(j).id();
253 if (
update->change() !=
nullptr) {
254 if (!
update->change()->id().isEmpty() && !onlyFeatures) {
255 result <<
update->change()->id();
257 for (
int j = 0; j <
update->change()->size(); ++j) {
258 if (!
update->change()->at(j).id().isEmpty()) {
259 result <<
update->change()->at(j).id();
263 if (
update->getDelete() !=
nullptr) {
264 if (!
update->getDelete()->id().isEmpty() && !onlyFeatures) {
265 result <<
update->getDelete()->id();
267 for (
int j = 0; j <
update->getDelete()->size(); ++j) {
268 if (!
update->getDelete()->at(j).id().isEmpty()) {
269 result <<
update->getDelete()->at(j).id();
279GeoDataPlaylist *TourItemDelegate::playlist()
const
281 QModelIndex const rootIndex = m_listView->rootIndex();
283 auto rootObject =
static_cast<GeoDataObject *
>(rootIndex.
internalPointer());
284 if (
auto playlist = geodata_cast<GeoDataPlaylist>(rootObject)) {
301 auto object = qvariant_cast<GeoDataObject *>(index.
data(MarblePlacemarkModel::ObjectPointerRole));
302 if (geodata_cast<GeoDataFlyTo>(
object)) {
303 auto widget =
new FlyToEditWidget(index, m_widget, parent);
304 widget->setFirstFlyTo(m_firstFlyTo);
306 connect(
this, SIGNAL(editableChanged(
bool)), widget, SLOT(setEditable(
bool)));
310 }
else if (geodata_cast<GeoDataTourControl>(
object)) {
311 auto widget =
new TourControlEditWidget(index, parent);
313 connect(
this, SIGNAL(editableChanged(
bool)), widget, SLOT(setEditable(
bool)));
316 }
else if (geodata_cast<GeoDataWait>(
object)) {
317 auto widget =
new WaitEditWidget(index, parent);
319 connect(
this, SIGNAL(editableChanged(
bool)), widget, SLOT(setEditable(
bool)));
322 }
else if (geodata_cast<GeoDataSoundCue>(
object)) {
323 auto widget =
new SoundCueEditWidget(index, parent);
325 connect(
this, SIGNAL(editableChanged(
bool)), widget, SLOT(setEditable(
bool)));
328 }
else if (geodata_cast<GeoDataAnimatedUpdate>(
object)) {
329 auto widget =
new RemoveItemEditWidget(index, parent);
330 GeoDataPlaylist *playlistObject = playlist();
331 if (playlistObject !=
nullptr) {
332 widget->setFeatureIds(findIds(*playlistObject));
334 widget->setDefaultFeatureId(m_defaultFeatureId);
336 connect(
this, SIGNAL(editableChanged(
bool)), widget, SLOT(setEditable(
bool)));
344bool TourItemDelegate::editable()
const
349void TourItemDelegate::setEditable(
bool editable)
351 if (m_editable != editable) {
352 m_editable = editable;
353 Q_EMIT editableChanged(m_editable);
362bool TourItemDelegate::editAnimatedUpdate(GeoDataAnimatedUpdate *animatedUpdate,
bool create)
364 if (animatedUpdate->update() ==
nullptr) {
367 GeoDataFeature *feature =
nullptr;
368 if (create && !(animatedUpdate->update()->create() ==
nullptr || animatedUpdate->update()->create()->size() == 0)) {
369 auto container =
dynamic_cast<GeoDataContainer *
>(animatedUpdate->update()->
create()->child(0));
370 if (container !=
nullptr && container->size()) {
371 feature = container->child(0);
373 }
else if (!create && !(animatedUpdate->update()->change() ==
nullptr || animatedUpdate->update()->change()->size() == 0)) {
374 auto container =
dynamic_cast<GeoDataContainer *
>(animatedUpdate->update()->change()->child(0));
375 if (container !=
nullptr && container->size()) {
376 feature = container->child(0);
379 if (feature ==
nullptr) {
385 auto placemark =
static_cast<GeoDataPlacemark *
>(feature);
388 if (placemark->targetId().isEmpty() && !defaultFeatureId().isEmpty()) {
389 GeoDataFeature *feature = findFeature(defaultFeatureId());
390 if (GeoDataPlacemark *targetPlacemark = (feature !=
nullptr ? geodata_cast<GeoDataPlacemark>(feature) :
nullptr)) {
391 animatedUpdate->update()->change()->placemarkList().remove(0);
393 placemark =
new GeoDataPlacemark(*targetPlacemark);
394 animatedUpdate->update()->change()->placemarkList().insert(0, placemark);
395 placemark->setTargetId(defaultFeatureId());
403 dialog->setWindowTitle(
QObject::tr(
"Add Placemark to Tour"));
405 dialog->setWindowTitle(
QObject::tr(
"Change Placemark in Tour"));
406 dialog->setTargetIdFieldVisible(
true);
407 dialog->setIdFieldVisible(
false);
409 GeoDataPlaylist *playlistObject = playlist();
410 if (playlistObject !=
nullptr) {
411 ids.
append(findIds(*playlistObject,
true));
415 dialog->setIdFilter(ids);
417 dialog->setTargetIds(ids);
419 bool status = dialog->exec();
426QString TourItemDelegate::defaultFeatureId()
const
428 return m_defaultFeatureId;
431GeoDataFeature *TourItemDelegate::findFeature(
const QString &
id)
const
433 GeoDataPlaylist *playlistObject = playlist();
434 if (playlistObject ==
nullptr) {
437 GeoDataFeature *result =
nullptr;
438 for (
int i = 0; i < playlistObject->size(); ++i) {
439 GeoDataTourPrimitive *primitive = playlistObject->primitive(i);
440 if (
auto animatedUpdate = geodata_cast<GeoDataAnimatedUpdate>(primitive)) {
441 if (animatedUpdate->update() !=
nullptr) {
442 GeoDataUpdate *
update = animatedUpdate->update();
443 if (
update->create() !=
nullptr) {
444 for (
int j = 0; j <
update->create()->featureList().size(); ++j) {
445 if (
update->create()->at(j).id() ==
id) {
446 result =
update->create()->featureList().at(j);
450 if (
update->change() !=
nullptr) {
451 for (
int j = 0; j <
update->change()->featureList().size(); ++j) {
452 if (
update->change()->at(j).id() ==
id) {
453 result =
update->change()->featureList().at(j);
457 if (
update->getDelete() !=
nullptr) {
458 for (
int j = 0; j <
update->getDelete()->featureList().size(); ++j) {
459 if (
update->getDelete()->at(j).id() ==
id) {
460 result =
update->getDelete()->featureList().at(j);
472 m_firstFlyTo = index;
473 Q_EMIT firstFlyToChanged(m_firstFlyTo);
476void TourItemDelegate::setDefaultFeatureId(
const QString &
id)
478 m_defaultFeatureId = id;
480 Q_EMIT featureIdsChanged(ids);
481 Q_EMIT defaultFeatureIdChanged(
id);
489 QRect editRect = position(EditButton, option);
490 if (editRect.
contains(mouseEvent->pos())) {
491 if (m_editingIndices.contains(index)) {
492 m_editingIndices.removeOne(index);
493 Q_EMIT editingChanged(index);
496 auto object = qvariant_cast<GeoDataObject *>(index.
data(MarblePlacemarkModel::ObjectPointerRole));
497 if (
auto animatedUpdate = geodata_cast<GeoDataAnimatedUpdate>(
object)) {
498 if (animatedUpdate->update() && animatedUpdate->update()->create()) {
499 if (editAnimatedUpdate(animatedUpdate)) {
500 setDefaultFeatureId(m_defaultFeatureId);
502 }
else if (animatedUpdate->update() && animatedUpdate->update()->change()) {
503 editAnimatedUpdate(animatedUpdate,
false);
504 }
else if (animatedUpdate->update() && animatedUpdate->update()->getDelete()) {
505 m_editingIndices.append(index);
506 m_listView->openPersistentEditor(index);
509 m_editingIndices.append(index);
510 m_listView->openPersistentEditor(index);
513 Q_EMIT editingChanged(index);
520void TourItemDelegate::closeEditor(
const QModelIndex &index)
522 Q_EMIT edited(index);
523 m_listView->closePersistentEditor(index);
524 m_editingIndices.removeOne(index);
529#include "moc_TourItemDelegate.cpp"
Q_SCRIPTABLE CaptureState status()
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
void update(Part *part, const QByteArray &data, qint64 dataSize)
QAction * create(StandardAction id, const Receiver *recvr, Func slot, QObject *parent, std::optional< Qt::ConnectionType > connectionType=std::nullopt)
QString label(StandardShortcut id)
Binds a QML item to a specific geodetic location in screen coordinates.
QPixmap pixmap(QWindow *window, const QSize &size, Mode mode, State state) const const
void append(QList< T > &&value)
bool removeOne(const AT &t)
QVariant data(int role) const const
void * internalPointer() const const
bool isValid() const const
QString tr(const char *sourceText, const char *disambiguation, int n)
void drawPixmap(const QPoint &point, const QPixmap &pixmap)
void fillRect(const QRect &rectangle, QGradient::Preset preset)
void setClipRect(const QRect &rectangle, Qt::ClipOperation operation)
void translate(const QPoint &offset)
bool contains(const QPoint &point, bool proper) const const
QPoint topLeft() const const
QString number(double n, char format, int precision)
virtual void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const const=0
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const const override
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)