File indexing completed on 2024-04-28 07:38:18

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2013 Mihail Ivchenko <ematirov@gmail.com>
0004 // SPDX-FileCopyrightText: 2014 Sanjiban Bairagya <sanjiban22393@gmail.com>
0005 // SPDX-FileCopyrightText: 2014 Illya Kovalevskyy <illya.kovalevskyy@gmail.com>
0006 //
0007 
0008 #include "TourItemDelegate.h"
0009 
0010 #include <QAbstractTextDocumentLayout>
0011 #include <QStyleOptionButton>
0012 #include <QPainter>
0013 #include <QApplication>
0014 #include <QListView>
0015 #include <QPointer>
0016 
0017 #include "MarblePlacemarkModel.h"
0018 #include "geodata/data/GeoDataContainer.h"
0019 #include "geodata/data/GeoDataFlyTo.h"
0020 #include "geodata/data/GeoDataObject.h"
0021 #include "geodata/data/GeoDataTourControl.h"
0022 #include "geodata/data/GeoDataWait.h"
0023 #include "geodata/data/GeoDataCoordinates.h"
0024 #include "geodata/data/GeoDataSoundCue.h"
0025 #include "geodata/data/GeoDataAnimatedUpdate.h"
0026 #include "FlyToEditWidget.h"
0027 #include "TourControlEditWidget.h"
0028 #include "SoundCueEditWidget.h"
0029 #include "WaitEditWidget.h"
0030 #include "RemoveItemEditWidget.h"
0031 #include "GeoDataPlacemark.h"
0032 #include "GeoDataCreate.h"
0033 #include "GeoDataUpdate.h"
0034 #include "GeoDataDelete.h"
0035 #include "GeoDataChange.h"
0036 #include "EditPlacemarkDialog.h"
0037 #include "MarbleWidget.h"
0038 #include "GeoDataPlaylist.h"
0039 #include "TourWidget.h"
0040 
0041 namespace Marble
0042 {
0043 
0044 TourItemDelegate::TourItemDelegate( QListView* view, MarbleWidget* widget, TourWidget* tour ):
0045                     m_listView( view ), m_widget( widget ), m_editable( true ), m_tourWidget( tour )
0046 {
0047     QObject::connect( this, SIGNAL(editingChanged(QModelIndex)), m_listView, SLOT(update(QModelIndex)) );
0048     m_listView->setEditTriggers( QAbstractItemView::NoEditTriggers );
0049 }
0050 
0051 void TourItemDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
0052 {
0053     QStyleOptionViewItem styleOption = option;
0054     styleOption.text = QString();
0055     QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &styleOption, painter);
0056 
0057     QAbstractTextDocumentLayout::PaintContext paintContext;
0058     if (styleOption.state & QStyle::State_Selected) {
0059         paintContext.palette.setColor(QPalette::Text,
0060             styleOption.palette.color(QPalette::Active, QPalette::HighlightedText));
0061     }
0062 
0063     if ( m_listView->currentIndex() == index && m_tourWidget->isPlaying() ) {
0064         painter->fillRect( option.rect, paintContext.palette.color( QPalette::Midlight ) );
0065         QStyledItemDelegate::paint( painter, option, index );
0066     }
0067 
0068     QTextDocument label;
0069     QRect const labelRect = position(Label, option);
0070     label.setTextWidth( labelRect.width() );
0071     label.setDefaultFont( option.font );
0072 
0073     QStyleOptionButton button;
0074     button.state = option.state;
0075     button.palette = option.palette;
0076     button.features = QStyleOptionButton::None;
0077     button.iconSize = QSize( 16, 16 );
0078     button.state &= ~QStyle::State_HasFocus;
0079     if( !editable() ) {
0080         button.state &= ~QStyle::State_Enabled;
0081     }
0082 
0083     QRect const iconRect = position( GeoDataElementIcon, option );
0084 
0085     const GeoDataObject *object = qvariant_cast<GeoDataObject*>(index.data(MarblePlacemarkModel::ObjectPointerRole));
0086     if (!m_editingIndices.contains(index)) {
0087         if (const GeoDataTourControl *tourControl = geodata_cast<GeoDataTourControl>(object)) {
0088             GeoDataTourControl::PlayMode const playMode = tourControl->playMode();
0089 
0090             if ( playMode == GeoDataTourControl::Play ) {
0091                 label.setHtml( tr("Play the tour") );
0092             } else if ( playMode == GeoDataTourControl::Pause ) {
0093                 label.setHtml( tr("Pause the tour") );
0094             }
0095             painter->save();
0096             painter->translate( labelRect.topLeft() );
0097             painter->setClipRect( 0, 0, labelRect.width(), labelRect.height() );
0098             label.documentLayout()->draw( painter, paintContext );
0099             painter->restore();
0100             button.icon = QIcon(QStringLiteral(":/marble/document-edit.png"));
0101 
0102             QRect const buttonRect = position( EditButton, option );
0103             button.rect = buttonRect;
0104 
0105             QIcon const icon = QIcon(QStringLiteral(":/marble/media-playback-pause.png"));
0106             painter->drawPixmap( iconRect, icon.pixmap( iconRect.size() ) );
0107 
0108         } else if (geodata_cast<GeoDataFlyTo>(object)) {
0109             GeoDataCoordinates const flyToCoords = index.data( MarblePlacemarkModel::CoordinateRole ).value<GeoDataCoordinates>();
0110             label.setHtml( flyToCoords.toString() );
0111             button.icon = QIcon(QStringLiteral(":/marble/document-edit.png"));
0112 
0113             painter->save();
0114             painter->translate( labelRect.topLeft() );
0115             painter->setClipRect( 0, 0, labelRect.width(), labelRect.height() );
0116             label.documentLayout()->draw( painter, paintContext );
0117             painter->restore();
0118 
0119             QRect const buttonRect = position( EditButton, option );
0120             button.rect = buttonRect;
0121 
0122             QIcon const icon = QIcon(QStringLiteral(":/marble/flag.png"));
0123             painter->drawPixmap( iconRect, icon.pixmap( iconRect.size() ) );
0124         } else if (const GeoDataWait *wait = geodata_cast<GeoDataWait>(object)) {
0125             label.setHtml( tr("Wait for %1 seconds").arg( QString::number( wait->duration() ) ) );
0126 
0127             painter->save();
0128             painter->translate( labelRect.topLeft() );
0129             painter->setClipRect( 0, 0, labelRect.width(), labelRect.height() );
0130             label.documentLayout()->draw( painter, paintContext );
0131             painter->restore();
0132 
0133             button.icon = QIcon(QStringLiteral(":/marble/document-edit.png"));
0134 
0135             QRect const buttonRect = position( EditButton, option );
0136             button.rect = buttonRect;
0137 
0138             QIcon const icon = QIcon(QStringLiteral(":/marble/player-time.png"));
0139             painter->drawPixmap( iconRect, icon.pixmap( iconRect.size() ) );
0140         } else if (const GeoDataSoundCue *soundCue = geodata_cast<GeoDataSoundCue>(object)) {
0141             label.setHtml(soundCue->href().section(QLatin1Char('/'), -1));
0142 
0143             painter->save();
0144             painter->translate( labelRect.topLeft() );
0145             painter->setClipRect( 0, 0, labelRect.width(), labelRect.height() );
0146             label.documentLayout()->draw( painter, paintContext );
0147             painter->restore();
0148 
0149             QStyleOptionButton playButton = button;
0150 
0151             button.icon = QIcon(QStringLiteral(":/marble/document-edit.png"));
0152             QRect const buttonRect = position( EditButton, option );
0153             button.rect = buttonRect;
0154 
0155             playButton.icon = QIcon(QStringLiteral(":/marble/playback-play.png"));
0156             QRect const playButtonRect = position( ActionButton, option );
0157             playButton.rect = playButtonRect;
0158             QApplication::style()->drawControl( QStyle::CE_PushButton, &playButton, painter );
0159 
0160             QIcon const icon = QIcon(QStringLiteral(":/marble/audio-x-generic.png"));
0161             painter->drawPixmap( iconRect, icon.pixmap( iconRect.size() ) );
0162         } else if (const GeoDataAnimatedUpdate *animUpdate = geodata_cast<GeoDataAnimatedUpdate>(object)) {
0163             const GeoDataUpdate *update = animUpdate->update();
0164             bool ok = false;
0165             QString iconString;
0166             if( update && update->create() && update->create()->size() != 0
0167                        && (dynamic_cast<const GeoDataContainer *>(&update->create()->first()))) {
0168                 const GeoDataContainer *container = static_cast<const GeoDataContainer*>(update->create()->child(0));
0169                 if( container->size() > 0 ) {
0170                     label.setHtml( tr( "Create item %1" ).arg( container->first().id() ) );
0171                     ok = true;
0172                     iconString = QStringLiteral(":/icons/add-placemark.png");
0173                 }
0174             } else if( update && update->getDelete() && update->getDelete()->size() != 0 ){
0175                 label.setHtml( tr( "Remove item %1" ).arg( update->getDelete()->first().targetId() ) );
0176                 ok = true;
0177                 iconString = QStringLiteral(":/icons/remove.png");
0178             } else if( update && update->change() && update->change()->size() != 0 ){
0179                 label.setHtml( tr( "Change item %1" ).arg( update->change()->first().targetId() ) );
0180                 ok = true;
0181                 iconString = QStringLiteral(":/marble/document-edit.png");
0182             }
0183             if( update && !ok ) {
0184                 label.setHtml( tr( "Update items" ) );
0185                 button.state &= ~QStyle::State_Enabled & ~QStyle::State_Sunken;
0186             }
0187 
0188             painter->save();
0189             painter->translate( labelRect.topLeft() );
0190             painter->setClipRect( 0, 0, labelRect.width(), labelRect.height() );
0191             label.documentLayout()->draw( painter, paintContext );
0192             painter->restore();
0193 
0194             button.icon = QIcon(QStringLiteral(":/marble/document-edit.png"));
0195             QRect const buttonRect = position( EditButton, option );
0196             button.rect = buttonRect;
0197 
0198             QIcon const icon = QIcon( iconString );
0199             painter->drawPixmap( iconRect, icon.pixmap( iconRect.size() ) );
0200         }
0201     }
0202 
0203     QApplication::style()->drawControl( QStyle::CE_PushButton, &button, painter );
0204 }
0205 
0206 QRect TourItemDelegate::position( Element element, const QStyleOptionViewItem &option )
0207 {
0208     QPoint const topCol1 = option.rect.topLeft() + QPoint(10, 10);
0209     QPoint const topCol2 = topCol1 + QPoint(30, 0);
0210     QPoint const topCol3 = topCol2 + QPoint(210, 0);
0211     QPoint const topCol4 = topCol3 + QPoint(30, 0);
0212     QSize const labelSize = QSize(220, 30);
0213     QSize const iconsSize = QSize(22, 22);
0214 
0215     switch(element)
0216     {
0217     case GeoDataElementIcon:
0218         return QRect( topCol1, iconsSize );
0219     case Label:
0220         return QRect( topCol2, labelSize );
0221     case EditButton:
0222         return QRect( topCol3, iconsSize );
0223     case ActionButton:
0224         return QRect( topCol4, iconsSize );
0225     }
0226     return QRect();
0227 }
0228 
0229 QStringList TourItemDelegate::findIds(const GeoDataPlaylist &playlist, bool onlyFeatures)
0230 {
0231     QStringList result;
0232     for (int i = 0; i < playlist.size(); ++i) {
0233         const GeoDataTourPrimitive *primitive = playlist.primitive(i);
0234         if( !primitive->id().isEmpty() && !onlyFeatures ) {
0235             result << primitive->id();
0236         }
0237         if (const GeoDataAnimatedUpdate *animatedUpdate = geodata_cast<GeoDataAnimatedUpdate>(primitive)) {
0238             if( animatedUpdate->update() != nullptr ) {
0239                 const GeoDataUpdate *update = animatedUpdate->update();
0240                 if( !update->id().isEmpty() && !onlyFeatures ) {
0241                     result << update->id();
0242                 }
0243                 if( update->create() != nullptr ) {
0244                     if( !update->create()->id().isEmpty() && !onlyFeatures ) {
0245                         result << update->create()->id();
0246                     }
0247                     for( int j = 0; j < update->create()->size(); ++j ) {
0248                         if( !update->create()->at( j ).id().isEmpty() ) {
0249                             result << update->create()->at( j ).id();
0250                         }
0251                     }
0252                 }
0253                 if( update->change() != nullptr ) {
0254                     if( !update->change()->id().isEmpty() && !onlyFeatures ) {
0255                         result << update->change()->id();
0256                     }
0257                     for( int j = 0; j < update->change()->size(); ++j ) {
0258                         if( !update->change()->at( j ).id().isEmpty() ) {
0259                             result << update->change()->at( j ).id();
0260                         }
0261                     }
0262                 }
0263                 if( update->getDelete() != nullptr ) {
0264                     if( !update->getDelete()->id().isEmpty() && !onlyFeatures ) {
0265                         result << update->getDelete()->id();
0266                     }
0267                     for( int j = 0; j < update->getDelete()->size(); ++j ) {
0268                         if( !update->getDelete()->at( j ).id().isEmpty() ) {
0269                             result << update->getDelete()->at( j ).id();
0270                         }
0271                     }
0272                 }
0273             }
0274         }
0275     }
0276     return result;
0277 }
0278 
0279 GeoDataPlaylist *TourItemDelegate::playlist() const
0280 {
0281     QModelIndex const rootIndex = m_listView->rootIndex();
0282     if( rootIndex.isValid() ) {
0283         GeoDataObject *rootObject = static_cast<GeoDataObject*>( rootIndex.internalPointer() );
0284         if (GeoDataPlaylist *playlist = geodata_cast<GeoDataPlaylist>(rootObject)) {
0285             return playlist;
0286         }
0287     }
0288     return nullptr;
0289 }
0290 
0291 
0292 QSize TourItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
0293 {
0294     Q_UNUSED( option );
0295     Q_UNUSED( index );
0296     return QSize(290,50);
0297 }
0298 
0299 QWidget* TourItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
0300 {
0301     Q_UNUSED( option );
0302     GeoDataObject *object = qvariant_cast<GeoDataObject*>(index.data( MarblePlacemarkModel::ObjectPointerRole ) );
0303     if (geodata_cast<GeoDataFlyTo>(object)) {
0304         FlyToEditWidget* widget = new FlyToEditWidget(index, m_widget, parent);
0305         widget->setFirstFlyTo( m_firstFlyTo );
0306         connect(widget, SIGNAL(editingDone(QModelIndex)), this, SLOT(closeEditor(QModelIndex)));
0307         connect( this, SIGNAL(editableChanged(bool)), widget, SLOT(setEditable(bool)) );
0308         connect( this, SIGNAL(firstFlyToChanged(QPersistentModelIndex)), widget, SLOT(setFirstFlyTo(QPersistentModelIndex)) );
0309         return widget;
0310 
0311     } else if (geodata_cast<GeoDataTourControl>(object)) {
0312         TourControlEditWidget* widget = new TourControlEditWidget(index, parent);
0313         connect(widget, SIGNAL(editingDone(QModelIndex)), this, SLOT(closeEditor(QModelIndex)));
0314         connect( this, SIGNAL(editableChanged(bool)), widget, SLOT(setEditable(bool)) );
0315         return widget;
0316 
0317     } else if (geodata_cast<GeoDataWait>(object)) {
0318         WaitEditWidget* widget = new WaitEditWidget(index, parent);
0319         connect(widget, SIGNAL(editingDone(QModelIndex)), this, SLOT(closeEditor(QModelIndex)));
0320         connect( this, SIGNAL(editableChanged(bool)), widget, SLOT(setEditable(bool)) );
0321         return widget;
0322 
0323     } else if (geodata_cast<GeoDataSoundCue>(object)) {
0324         SoundCueEditWidget* widget = new SoundCueEditWidget(index, parent);
0325         connect(widget, SIGNAL(editingDone(QModelIndex)), this, SLOT(closeEditor(QModelIndex)));
0326         connect( this, SIGNAL(editableChanged(bool)), widget, SLOT(setEditable(bool)) );
0327         return widget;
0328 
0329     } else if (geodata_cast<GeoDataAnimatedUpdate>(object)) {
0330         RemoveItemEditWidget* widget = new RemoveItemEditWidget(index, parent);
0331         GeoDataPlaylist *playlistObject = playlist();
0332         if( playlistObject != nullptr ) {
0333             widget->setFeatureIds(findIds(*playlistObject));
0334         }
0335         widget->setDefaultFeatureId( m_defaultFeatureId );
0336         connect(widget, SIGNAL(editingDone(QModelIndex)), this, SLOT(closeEditor(QModelIndex)));
0337         connect( this, SIGNAL(editableChanged(bool)), widget, SLOT(setEditable(bool)) );
0338         connect( this, SIGNAL(featureIdsChanged(QStringList)), widget, SLOT(setFeatureIds(QStringList)) );
0339         connect( this, SIGNAL(defaultFeatureIdChanged(QString)), widget, SLOT(setDefaultFeatureId(QString)) );
0340         return widget;
0341 
0342     }
0343     return nullptr;
0344 }
0345 
0346 bool TourItemDelegate::editable() const
0347 {
0348     return m_editable;
0349 }
0350 
0351 void TourItemDelegate::setEditable( bool editable )
0352 {
0353     if( m_editable != editable ) {
0354         m_editable = editable;
0355         emit editableChanged( m_editable );
0356     }
0357 }
0358 
0359 QModelIndex TourItemDelegate::firstFlyTo() const
0360 {
0361     return m_firstFlyTo;
0362 }
0363 
0364 bool TourItemDelegate::editAnimatedUpdate(GeoDataAnimatedUpdate *animatedUpdate, bool create)
0365 {
0366     if( animatedUpdate->update() == nullptr ) {
0367         return false;
0368     }
0369     GeoDataFeature *feature = nullptr;
0370     if( create && !( animatedUpdate->update()->create() == nullptr || animatedUpdate->update()->create()->size() == 0 ) ) {
0371         GeoDataContainer *container = dynamic_cast<GeoDataContainer*>( animatedUpdate->update()->create()->child( 0 ) );
0372         if( container != nullptr && container->size() ) {
0373             feature = container->child( 0 );
0374         }
0375     } else if ( !create && !( animatedUpdate->update()->change() == nullptr || animatedUpdate->update()->change()->size() == 0 ) ) {
0376         GeoDataContainer *container = dynamic_cast<GeoDataContainer*>( animatedUpdate->update()->change()->child( 0 ) );
0377         if( container != nullptr && container->size() ) {
0378             feature = container->child( 0 );
0379         }
0380     }
0381     if( feature == nullptr ) {
0382         return false;
0383     }
0384 
0385     QStringList ids;
0386 
0387     GeoDataPlacemark *placemark = static_cast<GeoDataPlacemark*>( feature );
0388 
0389     if( !create ) {
0390         if( placemark->targetId().isEmpty() && !defaultFeatureId().isEmpty() ) {
0391             GeoDataFeature *feature = findFeature( defaultFeatureId() );
0392             if (GeoDataPlacemark *targetPlacemark = (feature != nullptr ? geodata_cast<GeoDataPlacemark>(feature) : nullptr)) {
0393                 animatedUpdate->update()->change()->placemarkList().remove( 0 );
0394                 delete placemark;
0395                 placemark = new GeoDataPlacemark( *targetPlacemark );
0396                 animatedUpdate->update()->change()->placemarkList().insert( 0, placemark );
0397                 placemark->setTargetId( defaultFeatureId() );
0398                 placemark->setId(QString());
0399             }
0400         }
0401     }
0402 
0403     QPointer<EditPlacemarkDialog> dialog = new EditPlacemarkDialog( placemark, nullptr, m_widget );
0404     if( create ) {
0405         dialog->setWindowTitle( QObject::tr( "Add Placemark to Tour" ) );
0406     } else {
0407         dialog->setWindowTitle( QObject::tr( "Change Placemark in Tour" ) );
0408         dialog->setTargetIdFieldVisible( true );
0409         dialog->setIdFieldVisible( false );
0410     }
0411     GeoDataPlaylist* playlistObject = playlist();
0412     if( playlistObject != nullptr ) {
0413         ids.append(findIds(*playlistObject, true));
0414     }
0415     ids.removeOne( placemark->id() );
0416     if( create ) {
0417         dialog->setIdFilter( ids );
0418     } else {
0419         dialog->setTargetIds( ids );
0420     }
0421     bool status = dialog->exec();
0422     if( !create ) {
0423         placemark->setId(QString());
0424     }
0425     return status;
0426 }
0427 
0428 QString TourItemDelegate::defaultFeatureId() const
0429 {
0430     return m_defaultFeatureId;
0431 }
0432 
0433 
0434 
0435 GeoDataFeature *TourItemDelegate::findFeature(const QString &id) const
0436 {
0437     GeoDataPlaylist *playlistObject = playlist();
0438     if( playlistObject == nullptr ) {
0439         return nullptr;
0440     }
0441     GeoDataFeature *result = nullptr;
0442     for( int i = 0; i < playlistObject->size(); ++i ) {
0443         GeoDataTourPrimitive *primitive = playlistObject->primitive( i );
0444         if (GeoDataAnimatedUpdate *animatedUpdate = geodata_cast<GeoDataAnimatedUpdate>(primitive)) {
0445             if( animatedUpdate->update() != nullptr ) {
0446                 GeoDataUpdate *update = animatedUpdate->update();
0447                 if( update->create() != nullptr ) {
0448                     for( int j = 0; j < update->create()->featureList().size(); ++j ) {
0449                         if( update->create()->at( j ).id() == id ) {
0450                             result = update->create()->featureList().at( j );
0451                         }
0452                     }
0453                 }
0454                 if( update->change() != nullptr ) {
0455                     for( int j = 0; j < update->change()->featureList().size(); ++j ) {
0456                         if( update->change()->at( j ).id() == id ) {
0457                             result = update->change()->featureList().at( j );
0458                         }
0459                     }
0460                 }
0461                 if( update->getDelete() != nullptr ) {
0462                     for( int j = 0; j < update->getDelete()->featureList().size(); ++j ) {
0463                         if( update->getDelete()->at( j ).id() == id ) {
0464                             result = update->getDelete()->featureList().at( j );
0465                         }
0466                     }
0467                 }
0468             }
0469         }
0470     }
0471     return result;
0472 }
0473 
0474 void TourItemDelegate::setFirstFlyTo(const QPersistentModelIndex &index )
0475 {
0476     m_firstFlyTo = index;
0477     emit firstFlyToChanged( m_firstFlyTo );
0478 }
0479 
0480 void TourItemDelegate::setDefaultFeatureId(const QString &id)
0481 {
0482     m_defaultFeatureId = id;
0483     const QStringList ids = playlist() ? findIds(*playlist()) : QStringList();
0484     emit featureIdsChanged( ids );
0485     emit defaultFeatureIdChanged( id );
0486 }
0487 
0488 bool TourItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
0489 {
0490     Q_UNUSED( model );
0491     if ( ( event->type() == QEvent::MouseButtonRelease ) && editable() ) {
0492         QMouseEvent *mouseEvent = static_cast<QMouseEvent*>( event );
0493         QRect editRect = position( EditButton, option );
0494         if ( editRect.contains( mouseEvent->pos() ) ) {
0495             if( m_editingIndices.contains( index ) ) {
0496                 m_editingIndices.removeOne( index );
0497                 emit editingChanged( index );
0498                 return true;
0499             }else{
0500                 GeoDataObject *object = qvariant_cast<GeoDataObject*>(index.data( MarblePlacemarkModel::ObjectPointerRole ) );
0501                 if (GeoDataAnimatedUpdate *animatedUpdate = geodata_cast<GeoDataAnimatedUpdate>(object)) {
0502                     if( animatedUpdate->update() && animatedUpdate->update()->create() ) {
0503                         if( editAnimatedUpdate( animatedUpdate ) ) {
0504                             setDefaultFeatureId( m_defaultFeatureId );
0505                         }
0506                     } else if( animatedUpdate->update() && animatedUpdate->update()->change() ) {
0507                         editAnimatedUpdate( animatedUpdate, false );
0508                     } else if ( animatedUpdate->update() && animatedUpdate->update()->getDelete() ) {
0509                         m_editingIndices.append( index );
0510                         m_listView->openPersistentEditor( index );
0511                     }
0512                 } else {
0513                     m_editingIndices.append( index );
0514                     m_listView->openPersistentEditor( index );
0515                 }
0516             }
0517             emit editingChanged( index );
0518             return true;
0519         }
0520     }
0521     return false;
0522 }
0523 
0524 void TourItemDelegate::closeEditor( const QModelIndex &index )
0525 {
0526     emit edited( index );
0527     m_listView->closePersistentEditor( index );
0528     m_editingIndices.removeOne( index );
0529 }
0530 
0531 }
0532 
0533 #include "moc_TourItemDelegate.cpp"