2018-02-27 18:06:05 +01:00
/*
* Strawberry Music Player
* This file was part of Clementine .
* Copyright 2010 , David Sansome < me @ davidsansome . com >
2021-03-20 21:14:47 +01:00
* Copyright 2018 - 2021 , Jonas Kvinge < jonas @ jkvinge . net >
2018-02-27 18:06:05 +01:00
*
* Strawberry is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* Strawberry is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with Strawberry . If not , see < http : //www.gnu.org/licenses/>.
2018-08-09 18:10:03 +02:00
*
2018-02-27 18:06:05 +01:00
*/
# include "config.h"
2021-09-14 17:39:19 +02:00
# include <cmath>
2018-05-01 00:41:33 +02:00
# include <QtGlobal>
2019-07-24 19:16:51 +02:00
# include <QApplication>
2018-05-01 00:41:33 +02:00
# include <QObject>
# include <QWidget>
2020-02-08 15:03:11 +01:00
# include <QThread>
2018-05-01 00:41:33 +02:00
# include <QtConcurrentRun>
# include <QFuture>
2021-01-30 21:53:53 +01:00
# include <QFutureWatcher>
2018-05-01 00:41:33 +02:00
# include <QAbstractItemModel>
# include <QAbstractItemView>
# include <QCompleter>
2018-02-27 18:06:05 +01:00
# include <QDateTime>
# include <QDir>
2018-05-01 00:41:33 +02:00
# include <QFont>
# include <QFontMetrics>
2018-02-27 18:06:05 +01:00
# include <QHeaderView>
2018-05-01 00:41:33 +02:00
# include <QLocale>
# include <QMetaType>
# include <QVariant>
# include <QString>
# include <QUrl>
# include <QIcon>
# include <QPixmap>
2021-07-11 01:43:52 +02:00
# include <QPixmapCache>
2018-02-27 18:06:05 +01:00
# include <QPainter>
2018-05-01 00:41:33 +02:00
# include <QColor>
# include <QPen>
# include <QPoint>
# include <QRect>
# include <QSize>
# include <QLineEdit>
2018-02-27 18:06:05 +01:00
# include <QScrollBar>
# include <QToolTip>
2018-05-01 00:41:33 +02:00
# include <QTreeView>
2018-02-27 18:06:05 +01:00
# include <QWhatsThis>
2018-05-01 00:41:33 +02:00
# include <QStyledItemDelegate>
# include <QStyleOptionViewItem>
# include <QtEvents>
# include <QLinearGradient>
2018-02-27 18:06:05 +01:00
# include "core/logging.h"
2018-05-01 00:41:33 +02:00
# include "core/song.h"
2022-12-28 03:12:00 +01:00
# include "utilities/strutils.h"
# include "utilities/timeutils.h"
2018-02-27 18:06:05 +01:00
# include "collection/collectionbackend.h"
2018-05-01 00:41:33 +02:00
# include "playlist/playlist.h"
# include "playlistdelegates.h"
2018-02-27 18:06:05 +01:00
const int QueuedItemDelegate : : kQueueBoxBorder = 1 ;
const int QueuedItemDelegate : : kQueueBoxCornerRadius = 3 ;
const int QueuedItemDelegate : : kQueueBoxLength = 30 ;
const QRgb QueuedItemDelegate : : kQueueBoxGradientColor1 = qRgb ( 102 , 150 , 227 ) ;
const QRgb QueuedItemDelegate : : kQueueBoxGradientColor2 = qRgb ( 77 , 121 , 200 ) ;
const int QueuedItemDelegate : : kQueueOpacitySteps = 10 ;
2022-02-06 04:19:45 +01:00
const float QueuedItemDelegate : : kQueueOpacityLowerBound = 0.4F ;
2018-02-27 18:06:05 +01:00
const int PlaylistDelegateBase : : kMinHeight = 19 ;
QueuedItemDelegate : : QueuedItemDelegate ( QObject * parent , int indicator_column )
2021-07-11 07:40:57 +02:00
: QStyledItemDelegate ( parent ) ,
indicator_column_ ( indicator_column ) { }
2018-02-27 18:06:05 +01:00
2021-01-26 16:48:04 +01:00
void QueuedItemDelegate : : paint ( QPainter * painter , const QStyleOptionViewItem & option , const QModelIndex & idx ) const {
2018-02-27 18:06:05 +01:00
2021-01-26 16:48:04 +01:00
QStyledItemDelegate : : paint ( painter , option , idx ) ;
2018-02-27 18:06:05 +01:00
2021-01-26 16:48:04 +01:00
if ( idx . column ( ) = = indicator_column_ ) {
2018-02-27 18:06:05 +01:00
bool ok = false ;
2021-01-26 16:48:04 +01:00
const int queue_pos = idx . data ( Playlist : : Role_QueuePosition ) . toInt ( & ok ) ;
2018-02-27 18:06:05 +01:00
if ( ok & & queue_pos ! = - 1 ) {
2021-03-21 18:53:02 +01:00
float opacity = static_cast < float > ( kQueueOpacitySteps - qMin ( kQueueOpacitySteps , queue_pos ) ) ;
2018-02-27 18:06:05 +01:00
opacity / = kQueueOpacitySteps ;
2022-02-06 04:19:45 +01:00
opacity * = 1.0F - kQueueOpacityLowerBound ;
2018-02-27 18:06:05 +01:00
opacity + = kQueueOpacityLowerBound ;
2021-04-11 01:03:02 +02:00
DrawBox ( painter , option . rect , option . font , QString : : number ( queue_pos + 1 ) , kQueueBoxLength , opacity ) ;
2018-02-27 18:06:05 +01:00
}
}
}
2021-06-22 13:41:38 +02:00
void QueuedItemDelegate : : DrawBox ( QPainter * painter , const QRect line_rect , const QFont & font , const QString & text , int width , const float opacity ) {
2018-02-27 18:06:05 +01:00
QFont smaller = font ;
smaller . setPointSize ( smaller . pointSize ( ) - 1 ) ;
smaller . setBold ( true ) ;
2019-07-08 23:27:45 +02:00
if ( width = = - 1 ) {
2024-04-11 02:56:01 +02:00
width = QFontMetrics ( font ) . horizontalAdvance ( text + QStringLiteral ( " " ) ) ;
2019-07-08 23:27:45 +02:00
}
2018-02-27 18:06:05 +01:00
QRect rect ( line_rect ) ;
rect . setLeft ( rect . right ( ) - width - kQueueBoxBorder ) ;
rect . setWidth ( width ) ;
rect . setTop ( rect . top ( ) + kQueueBoxBorder ) ;
rect . setBottom ( rect . bottom ( ) - kQueueBoxBorder - 1 ) ;
QRect text_rect ( rect ) ;
text_rect . setBottom ( text_rect . bottom ( ) + 1 ) ;
QLinearGradient gradient ( rect . topLeft ( ) , rect . bottomLeft ( ) ) ;
gradient . setColorAt ( 0.0 , kQueueBoxGradientColor1 ) ;
gradient . setColorAt ( 1.0 , kQueueBoxGradientColor2 ) ;
2021-04-11 01:03:02 +02:00
painter - > save ( ) ;
painter - > setOpacity ( opacity ) ;
2018-02-27 18:06:05 +01:00
// Turn on antialiasing
painter - > setRenderHint ( QPainter : : Antialiasing ) ;
// Draw the box
painter - > translate ( 0.5 , 0.5 ) ;
painter - > setPen ( QPen ( Qt : : white , 1 ) ) ;
painter - > setBrush ( gradient ) ;
painter - > drawRoundedRect ( rect , kQueueBoxCornerRadius , kQueueBoxCornerRadius ) ;
// Draw the text
painter - > setFont ( smaller ) ;
painter - > drawText ( rect , Qt : : AlignCenter , text ) ;
painter - > translate ( - 0.5 , - 0.5 ) ;
2021-04-11 01:03:02 +02:00
painter - > restore ( ) ;
2018-02-27 18:06:05 +01:00
}
2021-01-26 16:48:04 +01:00
int QueuedItemDelegate : : queue_indicator_size ( const QModelIndex & idx ) const {
2018-02-27 18:06:05 +01:00
2021-01-26 16:48:04 +01:00
if ( idx . column ( ) = = indicator_column_ ) {
const int queue_pos = idx . data ( Playlist : : Role_QueuePosition ) . toInt ( ) ;
2018-02-27 18:06:05 +01:00
if ( queue_pos ! = - 1 ) {
return kQueueBoxLength + kQueueBoxBorder * 2 ;
}
}
return 0 ;
}
PlaylistDelegateBase : : PlaylistDelegateBase ( QObject * parent , const QString & suffix )
: QueuedItemDelegate ( parent ) , view_ ( qobject_cast < QTreeView * > ( parent ) ) , suffix_ ( suffix )
{
}
QString PlaylistDelegateBase : : displayText ( const QVariant & value , const QLocale & ) const {
QString text ;
2020-10-24 03:32:40 +02:00
# if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
2021-07-11 09:49:38 +02:00
switch ( value . metaType ( ) . id ( ) ) {
2020-10-24 03:32:40 +02:00
# else
2018-02-27 18:06:05 +01:00
switch ( static_cast < QMetaType : : Type > ( value . type ( ) ) ) {
2020-10-24 03:32:40 +02:00
# endif
2024-04-11 02:56:01 +02:00
case QMetaType : : Int : {
2018-02-27 18:06:05 +01:00
int v = value . toInt ( ) ;
if ( v > 0 ) text = QString : : number ( v ) ;
break ;
}
2021-11-09 21:16:44 +01:00
case QMetaType : : Long :
2024-04-11 02:56:01 +02:00
case QMetaType : : LongLong : {
2021-11-09 21:16:44 +01:00
qint64 v = value . toLongLong ( ) ;
if ( v > 0 ) text = QString : : number ( v ) ;
break ;
}
2018-02-27 18:06:05 +01:00
case QMetaType : : Float :
2024-04-11 02:56:01 +02:00
case QMetaType : : Double : {
2018-02-27 18:06:05 +01:00
double v = value . toDouble ( ) ;
if ( v > 0 ) text = QString : : number ( v ) ;
break ;
}
default :
text = value . toString ( ) ;
break ;
}
2024-04-11 02:56:01 +02:00
if ( ! text . isNull ( ) & & ! suffix_ . isNull ( ) ) text + = QLatin1Char ( ' ' ) + suffix_ ;
2018-02-27 18:06:05 +01:00
return text ;
}
2021-01-26 16:48:04 +01:00
QSize PlaylistDelegateBase : : sizeHint ( const QStyleOptionViewItem & option , const QModelIndex & idx ) const {
2018-02-27 18:06:05 +01:00
2021-01-26 16:48:04 +01:00
QSize size = QueuedItemDelegate : : sizeHint ( option , idx ) ;
2018-02-27 18:06:05 +01:00
if ( size . height ( ) < kMinHeight ) size . setHeight ( kMinHeight ) ;
return size ;
}
2021-01-26 16:48:04 +01:00
void PlaylistDelegateBase : : paint ( QPainter * painter , const QStyleOptionViewItem & option , const QModelIndex & idx ) const {
2018-02-27 18:06:05 +01:00
2021-01-26 16:48:04 +01:00
QueuedItemDelegate : : paint ( painter , Adjusted ( option , idx ) , idx ) ;
2018-02-27 18:06:05 +01:00
// Stop after indicator
2021-01-26 16:48:04 +01:00
if ( idx . column ( ) = = Playlist : : Column_Title ) {
if ( idx . data ( Playlist : : Role_StopAfter ) . toBool ( ) ) {
2018-02-27 18:06:05 +01:00
QRect rect ( option . rect ) ;
2021-01-26 16:48:04 +01:00
rect . setRight ( rect . right ( ) - queue_indicator_size ( idx ) ) ;
2018-02-27 18:06:05 +01:00
DrawBox ( painter , rect , option . font , tr ( " stop " ) ) ;
}
}
}
2021-01-26 16:48:04 +01:00
QStyleOptionViewItem PlaylistDelegateBase : : Adjusted ( const QStyleOptionViewItem & option , const QModelIndex & idx ) const {
2018-02-27 18:06:05 +01:00
if ( ! view_ ) return option ;
QPoint top_left ( - view_ - > horizontalScrollBar ( ) - > value ( ) , - view_ - > verticalScrollBar ( ) - > value ( ) ) ;
2021-08-23 21:21:08 +02:00
if ( view_ - > header ( ) - > logicalIndexAt ( top_left ) ! = idx . column ( ) ) {
2018-02-27 18:06:05 +01:00
return option ;
2021-08-23 21:21:08 +02:00
}
2018-02-27 18:06:05 +01:00
2018-09-18 22:17:28 +02:00
QStyleOptionViewItem ret ( option ) ;
2018-02-27 18:06:05 +01:00
2021-01-26 16:48:04 +01:00
if ( idx . data ( Playlist : : Role_IsCurrent ) . toBool ( ) ) {
2018-05-01 00:41:33 +02:00
// Move the text in a bit on the first column for the song that's currently playing
2018-02-27 18:06:05 +01:00
ret . rect . setLeft ( ret . rect . left ( ) + 20 ) ;
}
return ret ;
}
2021-01-26 16:48:04 +01:00
bool PlaylistDelegateBase : : helpEvent ( QHelpEvent * event , QAbstractItemView * view , const QStyleOptionViewItem & option , const QModelIndex & idx ) {
2018-02-27 18:06:05 +01:00
2018-05-01 00:41:33 +02:00
// This function is copied from QAbstractItemDelegate, and changed to show displayText() in the tooltip, rather than the index's naked Qt::ToolTipRole text.
2018-02-27 18:06:05 +01:00
Q_UNUSED ( option ) ;
if ( ! event | | ! view ) return false ;
2021-01-26 16:48:04 +01:00
QString text = displayText ( idx . data ( ) , QLocale : : system ( ) ) ;
2018-02-27 18:06:05 +01:00
// Special case: we want newlines in the comment tooltip
2021-01-26 16:48:04 +01:00
if ( idx . column ( ) = = Playlist : : Column_Comment ) {
text = idx . data ( Qt : : ToolTipRole ) . toString ( ) . toHtmlEscaped ( ) ;
2024-04-09 23:20:26 +02:00
text . replace ( QLatin1String ( " \\ r \\ n " ) , QLatin1String ( " <br /> " ) ) ;
text . replace ( QLatin1String ( " \\ n " ) , QLatin1String ( " <br /> " ) ) ;
text . replace ( QLatin1String ( " \r \n " ) , QLatin1String ( " <br /> " ) ) ;
text . replace ( QLatin1String ( " \n " ) , QLatin1String ( " <br /> " ) ) ;
2018-02-27 18:06:05 +01:00
}
2021-06-20 19:04:08 +02:00
if ( text . isEmpty ( ) | | ! event ) return false ;
2018-02-27 18:06:05 +01:00
switch ( event - > type ( ) ) {
2024-04-11 02:56:01 +02:00
case QEvent : : ToolTip : {
2021-01-26 16:48:04 +01:00
QSize real_text = sizeHint ( option , idx ) ;
QRect displayed_text = view - > visualRect ( idx ) ;
2019-04-08 18:46:11 +02:00
bool is_elided = displayed_text . width ( ) < real_text . width ( ) ;
2018-02-27 18:06:05 +01:00
if ( is_elided ) {
2021-06-20 19:04:08 +02:00
QToolTip : : showText ( event - > globalPos ( ) , text , view ) ;
2018-05-01 00:41:33 +02:00
}
else { // in case that another text was previously displayed
2018-02-27 18:06:05 +01:00
QToolTip : : hideText ( ) ;
}
return true ;
}
case QEvent : : QueryWhatsThis :
return true ;
case QEvent : : WhatsThis :
2021-06-20 19:04:08 +02:00
QWhatsThis : : showText ( event - > globalPos ( ) , text , view ) ;
2018-02-27 18:06:05 +01:00
return true ;
default :
break ;
}
return false ;
}
QString LengthItemDelegate : : displayText ( const QVariant & value , const QLocale & ) const {
bool ok = false ;
qint64 nanoseconds = value . toLongLong ( & ok ) ;
if ( ok & & nanoseconds > 0 ) return Utilities : : PrettyTimeNanosec ( nanoseconds ) ;
2019-07-08 22:19:14 +02:00
return QString ( ) ;
2018-02-27 18:06:05 +01:00
}
QString SizeItemDelegate : : displayText ( const QVariant & value , const QLocale & ) const {
bool ok = false ;
2021-11-09 21:16:44 +01:00
qint64 bytes = value . toLongLong ( & ok ) ;
2018-02-27 18:06:05 +01:00
2021-11-09 21:16:44 +01:00
if ( ok & & bytes > 0 ) return Utilities : : PrettySize ( static_cast < quint64 > ( bytes ) ) ;
2018-02-27 18:06:05 +01:00
return QString ( ) ;
}
QString DateItemDelegate : : displayText ( const QVariant & value , const QLocale & locale ) const {
2019-09-15 20:27:32 +02:00
Q_UNUSED ( locale ) ;
2018-02-27 18:06:05 +01:00
bool ok = false ;
2021-02-10 18:27:40 +01:00
qint64 time = value . toLongLong ( & ok ) ;
2018-02-27 18:06:05 +01:00
2023-01-20 23:45:19 +01:00
if ( ! ok | | time < = 0 ) {
2019-07-08 22:19:14 +02:00
return QString ( ) ;
2021-08-23 21:21:08 +02:00
}
2018-02-27 18:06:05 +01:00
2020-07-18 03:53:30 +02:00
return QDateTime : : fromSecsSinceEpoch ( time ) . toString ( QLocale : : system ( ) . dateTimeFormat ( QLocale : : ShortFormat ) ) ;
2018-02-27 18:06:05 +01:00
}
QString LastPlayedItemDelegate : : displayText ( const QVariant & value , const QLocale & locale ) const {
bool ok = false ;
2021-02-10 18:27:40 +01:00
const qint64 time = value . toLongLong ( & ok ) ;
2018-02-27 18:06:05 +01:00
2023-01-20 23:45:33 +01:00
if ( ! ok | | time < = 0 ) {
2018-02-27 18:06:05 +01:00
return tr ( " Never " ) ;
2021-08-23 21:21:08 +02:00
}
2018-02-27 18:06:05 +01:00
return Utilities : : Ago ( time , locale ) ;
}
QString FileTypeItemDelegate : : displayText ( const QVariant & value , const QLocale & locale ) const {
2019-09-15 20:27:32 +02:00
Q_UNUSED ( locale ) ;
2018-02-27 18:06:05 +01:00
bool ok = false ;
2022-06-13 00:23:42 +02:00
Song : : FileType type = static_cast < Song : : FileType > ( value . toInt ( & ok ) ) ;
2018-02-27 18:06:05 +01:00
if ( ! ok ) return tr ( " Unknown " ) ;
return Song : : TextForFiletype ( type ) ;
}
2019-09-15 20:27:32 +02:00
QWidget * TextItemDelegate : : createEditor ( QWidget * parent , const QStyleOptionViewItem & option , const QModelIndex & idx ) const {
Q_UNUSED ( option ) ;
Q_UNUSED ( idx ) ;
2018-02-27 18:06:05 +01:00
return new QLineEdit ( parent ) ;
}
2023-07-21 05:55:24 +02:00
TagCompletionModel : : TagCompletionModel ( SharedPtr < CollectionBackend > backend , const Playlist : : Column column , QObject * parent ) : QStringListModel ( parent ) {
2018-02-27 18:06:05 +01:00
QString col = database_column ( column ) ;
if ( ! col . isEmpty ( ) ) {
setStringList ( backend - > GetAll ( col ) ) ;
}
2019-07-24 19:16:51 +02:00
if ( QThread : : currentThread ( ) ! = backend - > thread ( ) & & QThread : : currentThread ( ) ! = qApp - > thread ( ) ) {
backend - > Close ( ) ;
}
2018-02-27 18:06:05 +01:00
}
QString TagCompletionModel : : database_column ( Playlist : : Column column ) {
switch ( column ) {
2024-04-09 23:20:26 +02:00
case Playlist : : Column_Artist : return QStringLiteral ( " artist " ) ;
case Playlist : : Column_Album : return QStringLiteral ( " album " ) ;
case Playlist : : Column_AlbumArtist : return QStringLiteral ( " albumartist " ) ;
case Playlist : : Column_Composer : return QStringLiteral ( " composer " ) ;
case Playlist : : Column_Performer : return QStringLiteral ( " performer " ) ;
case Playlist : : Column_Grouping : return QStringLiteral ( " grouping " ) ;
case Playlist : : Column_Genre : return QStringLiteral ( " genre " ) ;
2018-02-27 18:06:05 +01:00
default :
qLog ( Warning ) < < " Unknown column " < < column ;
return QString ( ) ;
}
}
2023-07-21 05:55:24 +02:00
static TagCompletionModel * InitCompletionModel ( SharedPtr < CollectionBackend > backend , Playlist : : Column column ) {
2018-02-27 18:06:05 +01:00
return new TagCompletionModel ( backend , column ) ;
}
2023-07-21 05:55:24 +02:00
TagCompleter : : TagCompleter ( SharedPtr < CollectionBackend > backend , Playlist : : Column column , QLineEdit * editor ) : QCompleter ( editor ) , editor_ ( editor ) {
2018-02-27 18:06:05 +01:00
QFuture < TagCompletionModel * > future = QtConcurrent : : run ( & InitCompletionModel , backend , column ) ;
2021-01-30 21:53:53 +01:00
QFutureWatcher < TagCompletionModel * > * watcher = new QFutureWatcher < TagCompletionModel * > ( ) ;
QObject : : connect ( watcher , & QFutureWatcher < TagCompletionModel * > : : finished , this , & TagCompleter : : ModelReady ) ;
2021-06-16 00:30:21 +02:00
watcher - > setFuture ( future ) ;
2018-02-27 18:06:05 +01:00
}
2019-07-22 20:53:05 +02:00
TagCompleter : : ~ TagCompleter ( ) {
2021-01-26 00:40:06 +01:00
delete model ( ) ;
2019-07-22 20:53:05 +02:00
}
2021-01-30 21:53:53 +01:00
void TagCompleter : : ModelReady ( ) {
2018-02-27 18:06:05 +01:00
2021-01-30 21:53:53 +01:00
QFutureWatcher < TagCompletionModel * > * watcher = static_cast < QFutureWatcher < TagCompletionModel * > * > ( sender ( ) ) ;
TagCompletionModel * model = watcher - > result ( ) ;
watcher - > deleteLater ( ) ;
2018-02-27 18:06:05 +01:00
setModel ( model ) ;
setCaseSensitivity ( Qt : : CaseInsensitive ) ;
editor_ - > setCompleter ( this ) ;
2019-07-22 20:53:05 +02:00
2018-02-27 18:06:05 +01:00
}
QWidget * TagCompletionItemDelegate : : createEditor ( QWidget * parent , const QStyleOptionViewItem & , const QModelIndex & ) const {
QLineEdit * editor = new QLineEdit ( parent ) ;
new TagCompleter ( backend_ , column_ , editor ) ;
return editor ;
2019-07-22 20:53:05 +02:00
2018-02-27 18:06:05 +01:00
}
QString NativeSeparatorsDelegate : : displayText ( const QVariant & value , const QLocale & ) const {
const QString string_value = value . toString ( ) ;
QUrl url ;
2020-10-24 03:32:40 +02:00
# if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if ( value . metaType ( ) . id ( ) = = QMetaType : : QUrl ) {
# else
2018-02-27 18:06:05 +01:00
if ( value . type ( ) = = QVariant : : Url ) {
2020-10-24 03:32:40 +02:00
# endif
2018-02-27 18:06:05 +01:00
url = value . toUrl ( ) ;
}
2024-04-09 23:20:26 +02:00
else if ( string_value . contains ( QLatin1String ( " :// " ) ) ) {
2018-02-27 18:06:05 +01:00
url = QUrl : : fromEncoded ( string_value . toLatin1 ( ) ) ;
}
else {
return QDir : : toNativeSeparators ( string_value ) ;
}
2019-07-09 21:43:56 +02:00
if ( url . isLocalFile ( ) ) {
2018-02-27 18:06:05 +01:00
return QDir : : toNativeSeparators ( url . toLocalFile ( ) ) ;
}
return string_value ;
}
2018-09-12 22:51:10 +02:00
SongSourceDelegate : : SongSourceDelegate ( QObject * parent ) : PlaylistDelegateBase ( parent ) { }
2018-02-27 18:06:05 +01:00
QString SongSourceDelegate : : displayText ( const QVariant & value , const QLocale & ) const {
2019-09-15 20:27:32 +02:00
Q_UNUSED ( value ) ;
2018-02-27 18:06:05 +01:00
return QString ( ) ;
}
2023-03-29 00:04:34 +02:00
QPixmap SongSourceDelegate : : LookupPixmap ( const Song : : Source source , const QSize size , const qreal device_pixel_ratio ) const {
2018-02-27 18:06:05 +01:00
QPixmap pixmap ;
2024-04-09 23:20:26 +02:00
const QString pixmap_cache_key = QStringLiteral ( " %1-%2x%3-%4 " ) . arg ( Song : : TextForSource ( source ) ) . arg ( size . width ( ) ) . arg ( size . height ( ) ) . arg ( device_pixel_ratio ) ;
2023-03-29 00:04:34 +02:00
if ( QPixmapCache : : find ( pixmap_cache_key , & pixmap ) ) {
2018-02-27 18:06:05 +01:00
return pixmap ;
}
2018-09-08 12:38:02 +02:00
QIcon icon ( Song : : IconForSource ( source ) ) ;
2023-03-29 00:14:21 +02:00
# if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
2023-03-29 00:04:34 +02:00
pixmap = icon . pixmap ( size , device_pixel_ratio ) ;
2023-03-29 00:14:21 +02:00
# else
pixmap = icon . pixmap ( size ) ;
# endif
2023-03-29 00:04:34 +02:00
QPixmapCache : : insert ( pixmap_cache_key , pixmap ) ;
2018-02-27 18:06:05 +01:00
return pixmap ;
}
2020-08-25 21:51:23 +02:00
void SongSourceDelegate : : paint ( QPainter * painter , const QStyleOptionViewItem & option , const QModelIndex & idx ) const {
2018-02-27 18:06:05 +01:00
// Draw the background
2020-08-25 21:51:23 +02:00
PlaylistDelegateBase : : paint ( painter , option , idx ) ;
2018-02-27 18:06:05 +01:00
QStyleOptionViewItem option_copy ( option ) ;
2020-08-25 21:51:23 +02:00
initStyleOption ( & option_copy , idx ) ;
2018-02-27 18:06:05 +01:00
2023-03-29 00:04:34 +02:00
const QPixmap pixmap = LookupPixmap ( idx . data ( ) . value < Song : : Source > ( ) , option_copy . decorationSize , qobject_cast < QWidget * > ( parent ( ) ) - > devicePixelRatioF ( ) ) ;
2018-02-27 18:06:05 +01:00
// Draw the pixmap in the middle of the rectangle
2023-03-29 00:04:34 +02:00
QRect draw_rect ( QPoint ( 0 , 0 ) , option_copy . decorationSize ) ;
2018-02-27 18:06:05 +01:00
draw_rect . moveCenter ( option_copy . rect . center ( ) ) ;
painter - > drawPixmap ( draw_rect , pixmap ) ;
}
2020-09-17 17:50:17 +02:00
RatingItemDelegate : : RatingItemDelegate ( QObject * parent ) : PlaylistDelegateBase ( parent ) { }
void RatingItemDelegate : : paint ( QPainter * painter , const QStyleOptionViewItem & option , const QModelIndex & idx ) const {
// Draw the background
option . widget - > style ( ) - > drawPrimitive ( QStyle : : PE_PanelItemViewItem , & option , painter , option . widget ) ;
// Don't draw anything else if the user can't set the rating of this item
if ( ! idx . data ( Playlist : : Role_CanSetRating ) . toBool ( ) ) return ;
const bool hover = mouse_over_index_ . isValid ( ) & & ( mouse_over_index_ = = idx | | ( selected_indexes_ . contains ( mouse_over_index_ ) & & selected_indexes_ . contains ( idx ) ) ) ;
2021-10-30 18:53:14 +02:00
const float rating = ( hover ? RatingPainter : : RatingForPos ( mouse_over_pos_ , option . rect ) : idx . data ( ) . toFloat ( ) ) ;
2020-09-17 17:50:17 +02:00
painter_ . Paint ( painter , option . rect , rating ) ;
}
QSize RatingItemDelegate : : sizeHint ( const QStyleOptionViewItem & option , const QModelIndex & idx ) const {
QSize size = PlaylistDelegateBase : : sizeHint ( option , idx ) ;
size . setWidth ( size . height ( ) * RatingPainter : : kStarCount ) ;
return size ;
}
QString RatingItemDelegate : : displayText ( const QVariant & value , const QLocale & ) const {
2021-10-30 18:53:14 +02:00
if ( value . isNull ( ) | | value . toFloat ( ) < = 0 ) return QString ( ) ;
2020-09-17 17:50:17 +02:00
// Round to the nearest 0.5
2021-10-30 18:53:14 +02:00
const float rating = static_cast < float > ( lround ( value . toFloat ( ) * RatingPainter : : kStarCount * 2 ) ) / 2 ;
2020-09-17 17:50:17 +02:00
return QString : : number ( rating , ' f ' , 1 ) ;
}
2023-06-27 03:57:35 +02:00
QString Ebur128LoudnessLUFSItemDelegate : : displayText ( const QVariant & value , const QLocale & ) const {
bool ok = false ;
double v = value . toDouble ( & ok ) ;
if ( ok ) return Song : : Ebur128LoudnessLUFSToText ( v ) ;
return QString ( ) ;
}
QString Ebur128LoudnessRangeLUItemDelegate : : displayText ( const QVariant & value , const QLocale & ) const {
bool ok = false ;
double v = value . toDouble ( & ok ) ;
if ( ok ) return Song : : Ebur128LoudnessRangeLUToText ( v ) ;
return QString ( ) ;
}