File indexing completed on 2024-05-05 03:49:15

0001 #include "RouteItemDelegate.h"
0002 
0003 #include "CloudRouteModel.h"
0004 
0005 #ifdef MARBLE_NO_WEBKITWIDGETS
0006 #include <QWidget>
0007 #else
0008 #include <QWebEngineView>
0009 #endif
0010 
0011 #include <QApplication>
0012 #include <QAbstractTextDocumentLayout>
0013 #include <QPainter>
0014 #include <QListView>
0015 
0016 namespace Marble {
0017 
0018 RouteItemDelegate::RouteItemDelegate( QListView *view, CloudRouteModel *model ) :
0019     m_view( view ),
0020     m_model( model ),
0021     m_buttonWidth( 0 ),
0022     m_iconSize( 16 ),
0023     m_previewSize( 128 ),
0024     m_margin( 8 )
0025 {
0026 }
0027 
0028 void RouteItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
0029 {
0030     QStyleOptionViewItem styleOption = option;
0031     styleOption.text = QString();
0032     QApplication::style()->drawControl( QStyle::CE_ItemViewItem, &styleOption, painter );
0033     
0034     QAbstractTextDocumentLayout::PaintContext paintContext;
0035     if ( styleOption.state & QStyle::State_Selected)  {
0036         paintContext.palette.setColor( QPalette::Text, styleOption.palette.color( QPalette::Active, QPalette::HighlightedText ) );
0037     }
0038 
0039     QRect const iconRect = position( Preview, option );
0040     QIcon const icon = index.data( Qt::DecorationRole ).value<QIcon>();
0041     painter->drawPixmap( iconRect, icon.pixmap( iconRect.size() ) );
0042 
0043     QTextDocument document;
0044     QRect const textRect = position( Text, option );
0045     document.setTextWidth( textRect.width() );
0046     document.setDefaultFont( option.font );
0047     document.setHtml( text( index ) );
0048 
0049     painter->save();
0050     painter->translate( textRect.topLeft() );
0051     painter->setClipRect( 0, 0, textRect.width(), textRect.height() );
0052     document.documentLayout()->draw( painter, paintContext );
0053     painter->restore();
0054 
0055     bool cached = index.data( CloudRouteModel::IsCached ).toBool();
0056     bool downloading = index.data( CloudRouteModel::IsDownloading ).toBool();
0057     bool onCloud = index.data( CloudRouteModel::IsOnCloud ).toBool();
0058 
0059     if ( downloading ) {
0060         qint64 total = m_model->totalSize();
0061         qint64 progress = m_model->downloadedSize();
0062 
0063         QStyleOptionProgressBar progressBarOption;
0064         progressBarOption.rect = position( Progressbar, option );
0065         progressBarOption.minimum = 0;
0066         progressBarOption.maximum = 100;
0067         progressBarOption.progress = ( 100.0 * progress / total );
0068         progressBarOption.text = QString::number(progressBarOption.progress) + QLatin1Char('%');
0069         progressBarOption.textVisible = true;
0070         QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter);
0071     } else if ( !cached && onCloud ) {
0072         QStyleOptionButton downloadButton = button( DownloadButton, option );
0073         QRect downloadRect = position( DownloadButton, option );
0074         downloadButton.rect = downloadRect;
0075         QApplication::style()->drawControl( QStyle::CE_PushButton, &downloadButton, painter );
0076 
0077         QStyleOptionButton cloudRemoveButton = button( RemoveFromCloudButton, option );
0078         QRect cloudRemoveRect = position( RemoveFromCloudButton, option );
0079         cloudRemoveButton.rect = cloudRemoveRect;
0080         QApplication::style()->drawControl( QStyle::CE_PushButton, &cloudRemoveButton, painter );
0081     } else if ( cached && !onCloud ) {
0082         QStyleOptionButton openButton = button( OpenButton, option );
0083         QRect openRect = position( OpenButton, option );
0084         openButton.rect = openRect;
0085         QApplication::style()->drawControl( QStyle::CE_PushButton, &openButton, painter );
0086 
0087         QStyleOptionButton cacheRemoveButton = button( RemoveFromCacheButton, option );
0088         QRect cacheRemoveRect = position( RemoveFromCacheButton, option );
0089         cacheRemoveButton.rect = cacheRemoveRect;
0090         QApplication::style()->drawControl( QStyle::CE_PushButton, &cacheRemoveButton, painter );
0091 
0092         QStyleOptionButton uploadButton = button( UploadToCloudButton, option );
0093         QRect uploadRect = position( UploadToCloudButton, option );
0094         uploadButton.rect = uploadRect;
0095         QApplication::style()->drawControl( QStyle::CE_PushButton, &uploadButton, painter );
0096     } else if ( cached && onCloud ) {
0097         QStyleOptionButton openButton = button( OpenButton, option );
0098         QRect openRect = position( OpenButton, option );
0099         openButton.rect = openRect;
0100         QApplication::style()->drawControl( QStyle::CE_PushButton, &openButton, painter );
0101 
0102         QStyleOptionButton cacheRemoveButton = button( RemoveFromCacheButton, option );
0103         QRect cacheRemoveRect = position( RemoveFromCacheButton, option );
0104         cacheRemoveButton.rect = cacheRemoveRect;
0105         QApplication::style()->drawControl( QStyle::CE_PushButton, &cacheRemoveButton, painter );
0106     }
0107 }
0108 
0109 QSize RouteItemDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
0110 {
0111     if ( index.column() == 0 ) {
0112         QTextDocument doc;
0113         doc.setDefaultFont( option.font );
0114         doc.setTextWidth( qMax( 128, m_view->contentsRect().width() - m_previewSize - buttonWidth( option ) ) );
0115         doc.setHtml( text( index ) );
0116         return QSize( qMax( 256, qRound( m_previewSize + buttonWidth( option ) + doc.size().width() + m_margin * 2 ) ),
0117                       qMax( m_previewSize + m_margin * 2, qRound( doc.size().height() ) ) );
0118     }
0119 
0120     return QSize();
0121 }
0122 
0123 bool RouteItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
0124 {
0125     Q_UNUSED( model );
0126 
0127     if ( ( event->type() == QEvent::MouseButtonRelease ) ) {
0128         QMouseEvent *mouseEvent = static_cast<QMouseEvent*>( event );
0129         QPoint pos = mouseEvent->pos();
0130         
0131         bool cached = index.data( CloudRouteModel::IsCached ).toBool();
0132         bool onCloud = index.data( CloudRouteModel::IsOnCloud ).toBool();
0133 
0134         if( cached && !onCloud ) {
0135             QRect uploadRect = position( UploadToCloudButton, option );
0136 
0137             if ( uploadRect.contains( pos ) ) {
0138                 QString timestamp = index.data( CloudRouteModel::Timestamp ).toString();
0139                 emit uploadToCloudButtonClicked( timestamp );
0140                 return true;
0141             }
0142         }
0143 
0144         if ( cached ) {
0145             QRect openRect = position( OpenButton, option );
0146             QRect cacheRemoveRect = position( RemoveFromCacheButton, option );
0147 
0148             if ( openRect.contains( pos ) ) {
0149                 QString timestamp = index.data( CloudRouteModel::Timestamp ).toString();
0150                 emit openButtonClicked( timestamp );
0151                 return true;
0152             } else if ( cacheRemoveRect.contains( pos ) ) {
0153                 QString timestamp = index.data( CloudRouteModel::Timestamp ).toString();
0154                 emit removeFromCacheButtonClicked( timestamp );
0155                 return true;
0156             }
0157         } else {
0158             QRect downloadRect = position( DownloadButton, option );
0159             QRect cloudRemoveRect = position( RemoveFromCloudButton, option );
0160             
0161             if ( downloadRect.contains( pos ) ) {
0162                 QString timestamp = index.data( CloudRouteModel::Timestamp ).toString();
0163                 m_model->setDownloadingItem( index );
0164                 emit downloadButtonClicked( timestamp );
0165                 return true;
0166             }
0167             
0168             if ( cloudRemoveRect.contains( pos ) ) {
0169                 QString timestamp = index.data( CloudRouteModel::Timestamp ).toString();
0170                 emit deleteButtonClicked( timestamp );
0171                 return true;
0172             }
0173         }
0174     }
0175     
0176     return false;
0177 }
0178 
0179 int RouteItemDelegate::buttonWidth( const QStyleOptionViewItem &option ) const
0180 {
0181     if ( m_buttonWidth <= 0 ) {
0182         int const openWidth = option.fontMetrics.size( 0, tr( "Open" ) ).width();
0183         int const downloadWidth = option.fontMetrics.size( 0, tr( "Load" ) ).width();
0184         int const cacheWidth = option.fontMetrics.size( 0, tr( "Remove from device" ) ).width();
0185         int const cloudWidth = option.fontMetrics.size( 0, tr( "Delete from cloud" ) ).width();
0186         m_buttonWidth = 2 * m_iconSize + qMax( qMax( openWidth, downloadWidth ), qMax( cacheWidth, cloudWidth ) );
0187     }
0188 
0189     return m_buttonWidth;
0190 }
0191 
0192 QStyleOptionButton RouteItemDelegate::button( Element element, const QStyleOptionViewItem &option ) const
0193 {
0194     QStyleOptionButton result;
0195     result.state = option.state;
0196     result.state &= ~QStyle::State_HasFocus;
0197 
0198     result.palette = option.palette;
0199     result.features = QStyleOptionButton::None;
0200 
0201     switch ( element ) {
0202     case OpenButton:
0203         result.text = tr( "Open" );
0204         result.icon = QIcon(QStringLiteral(":/marble/document-open.png"));
0205         result.iconSize = QSize( m_iconSize, m_iconSize );
0206         break;
0207     case DownloadButton:
0208         result.text = tr( "Load" );
0209         result.icon = QIcon(QStringLiteral(":/marble/dialog-ok.png"));
0210         result.iconSize = QSize( m_iconSize, m_iconSize );
0211         break;
0212     case RemoveFromCacheButton:
0213         result.text = tr( "Remove from device" );
0214         result.icon = QIcon(QStringLiteral(":/marble/edit-clear.png"));
0215         result.iconSize = QSize( m_iconSize, m_iconSize );
0216         break;
0217     case RemoveFromCloudButton:
0218         result.text = tr( "Delete from cloud" );
0219         result.icon = QIcon(QStringLiteral(":/marble/edit-delete.png"));
0220         result.iconSize = QSize( m_iconSize, m_iconSize );
0221         break;
0222     case UploadToCloudButton:
0223         result.text = tr( "Upload to cloud" );
0224         result.icon = QIcon(QStringLiteral(":/icons/cloud-upload.png"));
0225         result.iconSize = QSize( m_iconSize, m_iconSize );
0226         break;
0227     default:
0228         // Ignored.
0229         break;
0230     }
0231 
0232     return result;
0233 }
0234 
0235 QString RouteItemDelegate::text( const QModelIndex& index )
0236 {
0237     return QString( "%0" ).arg( index.data( CloudRouteModel::Name ).toString() );
0238     // TODO: Show distance and duration
0239     //return QString( "%0<br /><b>Duration:</b> %1<br/><b>Distance:</b> %2" )
0240             //.arg( index.data( CloudRouteModel::Name ).toString() )
0241             //.arg( index.data( CloudRouteModel::Duration ).toString() )
0242             //.arg( index.data( CloudRouteModel::Distance ).toString() );
0243 }
0244 
0245 QRect RouteItemDelegate::position( Element element, const QStyleOptionViewItem& option ) const
0246 {   
0247     int const width = buttonWidth( option );
0248     QPoint const firstColumn = option.rect.topLeft() + QPoint( m_margin, m_margin );
0249     QPoint const secondColumn = firstColumn + QPoint( m_previewSize + m_margin, 0 );
0250     QPoint const thirdColumn = QPoint( option.rect.width() - width - option.decorationSize.width(), firstColumn.y() );
0251 
0252     switch (element) {
0253     case Text:
0254         return QRect( secondColumn, QSize( thirdColumn.x() - secondColumn.x(), option.rect.height() ) );
0255     case OpenButton:
0256     case DownloadButton:
0257     {
0258         QStyleOptionButton optionButton = button( element, option );
0259         QSize size = option.fontMetrics.size( 0, optionButton.text ) + QSize( 4, 4 );
0260         QSize buttonSize = QApplication::style()->sizeFromContents( QStyle::CT_PushButton, &optionButton, size );
0261         buttonSize.setWidth( width );
0262         return QRect( thirdColumn, buttonSize );
0263     }
0264     case RemoveFromCacheButton:
0265     case RemoveFromCloudButton:
0266     {
0267         QStyleOptionButton optionButton = button( element, option );
0268         QSize size = option.fontMetrics.size( 0, optionButton.text ) + QSize( 4, 4 );
0269         QSize buttonSize = QApplication::style()->sizeFromContents( QStyle::CT_PushButton, &optionButton, size );
0270         buttonSize.setWidth( width );
0271         return QRect( thirdColumn + QPoint( 0, buttonSize.height() ), buttonSize );
0272     }
0273     case Progressbar:
0274     {
0275         QSize const progressSize = QSize( width, option.fontMetrics.height() + 4 );
0276         return QRect( thirdColumn + QPoint( 0, 10 ), progressSize );
0277     }
0278     case Preview:
0279     {
0280         return QRect( firstColumn, QSize( m_previewSize, m_previewSize) );
0281     }
0282     case UploadToCloudButton:
0283     {
0284         QStyleOptionButton optionButton = button( element, option );
0285         QSize size = option.fontMetrics.size( 0, optionButton.text ) + QSize( 4, 4 );
0286         QSize buttonSize = QApplication::style()->sizeFromContents( QStyle::CT_PushButton, &optionButton, size );
0287         buttonSize.setWidth( width );
0288         return QRect( thirdColumn + QPoint( 0, buttonSize.height() * 2 ), buttonSize );
0289     }
0290     }
0291     
0292     return QRect();
0293 }
0294 
0295 }
0296 
0297 #include "moc_RouteItemDelegate.cpp"