2 * This file Copyright (C) Mnemosyne LLC
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2
6 * as published by the Free Software Foundation.
8 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10 * $Id: torrent-delegate.cc 11198 2010-09-08 01:09:52Z Longinus00 $
15 #include <QApplication>
18 #include <QFontMetrics>
20 #include <QModelIndex>
23 #include <QPixmapCache>
24 #include <QStyleOptionProgressBarV2>
26 #include "formatter.h"
28 #include "torrent-delegate.h"
29 #include "torrent-model.h"
37 TorrentDelegate :: TorrentDelegate( QObject
* parent
):
38 QItemDelegate( parent
),
39 myProgressBarStyle( new QStyleOptionProgressBarV2
)
41 myProgressBarStyle
->minimum
= 0;
42 myProgressBarStyle
->maximum
= 1000;
45 TorrentDelegate :: ~TorrentDelegate( )
47 delete myProgressBarStyle
;
55 TorrentDelegate :: margin( const QStyle
& style
) const
63 TorrentDelegate :: progressString( const Torrent
& tor
) const
65 const bool isMagnet( !tor
.hasMetadata( ) );
66 const bool isDone( tor
.isDone( ) );
67 const bool isSeed( tor
.isSeed( ) );
68 const uint64_t haveTotal( tor
.haveTotal( ) );
71 const bool hasSeedRatio( tor
.getSeedRatio( seedRatio
) );
73 if( isMagnet
) // magnet link with no metadata
75 /* %1 is the percentage of torrent metadata downloaded */
76 str
= tr( "Magnetized transfer - retrieving metadata (%1%)" )
77 .arg( Formatter::percentToString( tor
.metadataPercentDone() * 100.0 ) );
79 else if( !isDone
) // downloading
81 /* %1 is how much we've got,
82 %2 is how much we'll have when done,
83 %3 is a percentage of the two */
84 str
= tr( "%1 of %2 (%3%)" ).arg( Formatter::sizeToString( haveTotal
) )
85 .arg( Formatter::sizeToString( tor
.sizeWhenDone( ) ) )
86 .arg( Formatter::percentToString( tor
.percentDone( ) * 100.0 ) );
88 else if( !isSeed
) // partial seed
92 /* %1 is how much we've got,
93 %2 is the torrent's total size,
94 %3 is a percentage of the two,
95 %4 is how much we've uploaded,
96 %5 is our upload-to-download ratio
97 %6 is the ratio we want to reach before we stop uploading */
98 str
= tr( "%1 of %2 (%3%), uploaded %4 (Ratio: %5 Goal: %6)" )
99 .arg( Formatter::sizeToString( haveTotal
) )
100 .arg( Formatter::sizeToString( tor
.totalSize( ) ) )
101 .arg( Formatter::percentToString( tor
.percentComplete( ) * 100.0 ) )
102 .arg( Formatter::sizeToString( tor
.uploadedEver( ) ) )
103 .arg( Formatter::ratioToString( tor
.ratio( ) ) )
104 .arg( Formatter::ratioToString( seedRatio
) );
108 /* %1 is how much we've got,
109 %2 is the torrent's total size,
110 %3 is a percentage of the two,
111 %4 is how much we've uploaded,
112 %5 is our upload-to-download ratio */
113 str
= tr( "%1 of %2 (%3%), uploaded %4 (Ratio: %5)" )
114 .arg( Formatter::sizeToString( haveTotal
) )
115 .arg( Formatter::sizeToString( tor
.totalSize( ) ) )
116 .arg( Formatter::percentToString( tor
.percentComplete( ) * 100.0 ) )
117 .arg( Formatter::sizeToString( tor
.uploadedEver( ) ) )
118 .arg( Formatter::ratioToString( tor
.ratio( ) ) );
125 /* %1 is the torrent's total size,
126 %2 is how much we've uploaded,
127 %3 is our upload-to-download ratio,
128 %4 is the ratio we want to reach before we stop uploading */
129 str
= tr( "%1, uploaded %2 (Ratio: %3 Goal: %4)" )
130 .arg( Formatter::sizeToString( haveTotal
) )
131 .arg( Formatter::sizeToString( tor
.uploadedEver( ) ) )
132 .arg( Formatter::ratioToString( tor
.ratio( ) ) )
133 .arg( Formatter::ratioToString( seedRatio
) );
135 else /* seeding w/o a ratio */
137 /* %1 is the torrent's total size,
138 %2 is how much we've uploaded,
139 %3 is our upload-to-download ratio */
140 str
= tr( "%1, uploaded %2 (Ratio: %3)" )
141 .arg( Formatter::sizeToString( haveTotal
) )
142 .arg( Formatter::sizeToString( tor
.uploadedEver( ) ) )
143 .arg( Formatter::ratioToString( tor
.ratio( ) ) );
147 /* add time when downloading */
148 if( ( hasSeedRatio
&& tor
.isSeeding( ) ) || tor
.isDownloading( ) )
152 str
+= tr( "%1 left" ).arg( Formatter::timeToString( tor
.getETA( ) ) );
154 str
+= tr( "Remaining time unknown" );
161 TorrentDelegate :: shortTransferString( const Torrent
& tor
) const
163 static const QChar
upArrow( 0x2191 );
164 static const QChar
downArrow( 0x2193 );
165 const bool haveMeta( tor
.hasMetadata( ) );
166 const bool haveDown( haveMeta
&& tor
.peersWeAreDownloadingFrom( ) > 0 );
167 const bool haveUp( haveMeta
&& tor
.peersWeAreUploadingTo( ) > 0 );
168 QString downStr
, upStr
, str
;
171 downStr
= Formatter::speedToString( tor
.downloadSpeed( ) );
173 upStr
= Formatter::speedToString( tor
.uploadSpeed( ) );
175 if( haveDown
&& haveUp
)
176 str
= tr( "%1 %2, %3 %4" ).arg(downArrow
).arg(downStr
).arg(upArrow
).arg(upStr
);
178 str
= tr( "%1 %2" ).arg(downArrow
).arg(downStr
);
180 str
= tr( "%1 %2" ).arg(upArrow
).arg(upStr
);
181 else if( tor
.hasMetadata( ) )
188 TorrentDelegate :: shortStatusString( const Torrent
& tor
) const
192 switch( tor
.getActivity( ) )
194 case TR_STATUS_CHECK
:
195 str
= tr( "Verifying local data (%1% tested)" ).arg( Formatter::percentToString( tor
.getVerifyProgress()*100.0 ) );
198 case TR_STATUS_DOWNLOAD
:
200 if( !tor
.isDownloading( ) )
201 str
= tr( "Ratio: %1, " ).arg( Formatter::ratioToString( tor
.ratio( ) ) );
202 str
+= shortTransferString( tor
);
206 str
= tor
.activityString( );
214 TorrentDelegate :: statusString( const Torrent
& tor
) const
218 if( tor
.hasError( ) )
220 str
= tor
.getError( );
222 else switch( tor
.getActivity( ) )
224 case TR_STATUS_STOPPED
:
225 case TR_STATUS_CHECK_WAIT
:
226 case TR_STATUS_CHECK
:
227 str
= shortStatusString( tor
);
230 case TR_STATUS_DOWNLOAD
:
231 if( tor
.hasMetadata( ) )
232 str
= tr( "Downloading from %1 of %n connected peer(s)", 0, tor
.connectedPeersAndWebseeds( ) )
233 .arg( tor
.peersWeAreDownloadingFrom( ) );
235 str
= tr( "Downloading metadata from %n peer(s) (%1% done)", 0, tor
.peersWeAreDownloadingFrom( ) )
236 .arg( Formatter::percentToString( 100.0 * tor
.metadataPercentDone( ) ) );
240 str
= tr( "Seeding to %1 of %n connected peer(s)", 0, tor
.connectedPeers( ) )
241 .arg( tor
.peersWeAreUploadingTo( ) );
249 if( tor
.isReadyToTransfer( ) ) {
250 QString s
= shortTransferString( tor
);
252 str
+= tr( " - " ) + s
;
264 int MAX3( int a
, int b
, int c
)
266 const int ab( a
> b
? a
: b
);
267 return ab
> c
? ab
: c
;
272 TorrentDelegate :: sizeHint( const QStyleOptionViewItem
& option
, const Torrent
& tor
) const
274 const QStyle
* style( QApplication::style( ) );
275 static const int iconSize( style
->pixelMetric( QStyle::PM_MessageBoxIconSize
) );
277 QFont
nameFont( option
.font
);
278 nameFont
.setWeight( QFont::Bold
);
279 const QFontMetrics
nameFM( nameFont
);
280 const QString
nameStr( tor
.name( ) );
281 const int nameWidth
= nameFM
.width( nameStr
);
282 QFont
statusFont( option
.font
);
283 statusFont
.setPointSize( int( option
.font
.pointSize( ) * 0.9 ) );
284 const QFontMetrics
statusFM( statusFont
);
285 const QString
statusStr( statusString( tor
) );
286 const int statusWidth
= statusFM
.width( statusStr
);
287 QFont
progressFont( statusFont
);
288 const QFontMetrics
progressFM( progressFont
);
289 const QString
progressStr( progressString( tor
) );
290 const int progressWidth
= progressFM
.width( progressStr
);
291 const QSize
m( margin( *style
) );
292 return QSize( m
.width()*2 + iconSize
+ GUI_PAD
+ MAX3( nameWidth
, statusWidth
, progressWidth
),
293 //m.height()*3 + nameFM.lineSpacing() + statusFM.lineSpacing()*2 + progressFM.lineSpacing() );
294 m
.height()*3 + nameFM
.lineSpacing() + statusFM
.lineSpacing() + BAR_HEIGHT
+ progressFM
.lineSpacing() );
298 TorrentDelegate :: sizeHint( const QStyleOptionViewItem
& option
,
299 const QModelIndex
& index
) const
301 const Torrent
* tor( index
.data( TorrentModel::TorrentRole
).value
<const Torrent
*>() );
302 return sizeHint( option
, *tor
);
306 TorrentDelegate :: paint( QPainter
* painter
,
307 const QStyleOptionViewItem
& option
,
308 const QModelIndex
& index
) const
310 const Torrent
* tor( index
.data( TorrentModel::TorrentRole
).value
<const Torrent
*>() );
312 painter
->setClipRect( option
.rect
);
313 drawBackground( painter
, option
, index
);
314 drawTorrent( painter
, option
, *tor
);
315 drawFocus(painter
, option
, option
.rect
);
320 TorrentDelegate :: drawTorrent( QPainter
* painter
, const QStyleOptionViewItem
& option
, const Torrent
& tor
) const
322 const QStyle
* style( QApplication::style( ) );
323 static const int iconSize( style
->pixelMetric( QStyle::PM_LargeIconSize
) );
324 QFont
nameFont( option
.font
);
325 nameFont
.setWeight( QFont::Bold
);
326 const QFontMetrics
nameFM( nameFont
);
327 const QString
nameStr( tor
.name( ) );
328 const QSize
nameSize( nameFM
.size( 0, nameStr
) );
329 QFont
statusFont( option
.font
);
330 statusFont
.setPointSize( int( option
.font
.pointSize( ) * 0.9 ) );
331 const QFontMetrics
statusFM( statusFont
);
332 const QString
statusStr( progressString( tor
) );
333 QFont
progressFont( statusFont
);
334 const QFontMetrics
progressFM( progressFont
);
335 const QString
progressStr( statusString( tor
) );
336 const bool isPaused( tor
.isPaused( ) );
340 if (option
.state
& QStyle::State_Selected
) {
341 QPalette::ColorGroup cg
= option
.state
& QStyle::State_Enabled
342 ? QPalette::Normal
: QPalette::Disabled
;
343 if (cg
== QPalette::Normal
&& !(option
.state
& QStyle::State_Active
))
344 cg
= QPalette::Inactive
;
346 painter
->fillRect(option
.rect
, option
.palette
.brush(cg
, QPalette::Highlight
));
350 if( isPaused
|| !(option
.state
& QStyle::State_Enabled
) ) im
= QIcon::Disabled
;
351 else if( option
.state
& QStyle::State_Selected
) im
= QIcon::Selected
;
352 else im
= QIcon::Normal
;
355 if( isPaused
) qs
= QIcon::Off
;
358 QPalette::ColorGroup cg
= QPalette::Normal
;
359 if( isPaused
|| !(option
.state
& QStyle::State_Enabled
) ) cg
= QPalette::Disabled
;
360 if( cg
== QPalette::Normal
&& !(option
.state
& QStyle::State_Active
) ) cg
= QPalette::Inactive
;
362 QPalette::ColorRole cr
;
363 if( option
.state
& QStyle::State_Selected
) cr
= QPalette::HighlightedText
;
364 else cr
= QPalette::Text
;
366 QStyle::State
progressBarState( option
.state
);
367 if( isPaused
) progressBarState
= QStyle::State_None
;
368 progressBarState
|= QStyle::State_Small
;
371 const QSize
m( margin( *style
) );
372 QRect
fillArea( option
.rect
);
373 fillArea
.adjust( m
.width(), m
.height(), -m
.width(), -m
.height() );
374 QRect
iconArea( fillArea
.x( ), fillArea
.y( ) + ( fillArea
.height( ) - iconSize
) / 2, iconSize
, iconSize
);
375 QRect
nameArea( iconArea
.x( ) + iconArea
.width( ) + GUI_PAD
, fillArea
.y( ),
376 fillArea
.width( ) - GUI_PAD
- iconArea
.width( ), nameSize
.height( ) );
377 QRect
statusArea( nameArea
);
378 statusArea
.moveTop( nameArea
.y( ) + nameFM
.lineSpacing( ) );
379 statusArea
.setHeight( nameSize
.height( ) );
380 QRect
barArea( statusArea
);
381 barArea
.setHeight( BAR_HEIGHT
);
382 barArea
.moveTop( statusArea
.y( ) + statusFM
.lineSpacing( ) );
383 QRect
progArea( statusArea
);
384 progArea
.moveTop( barArea
.y( ) + barArea
.height( ) );
387 if( tor
.hasError( ) )
388 painter
->setPen( QColor( "red" ) );
390 painter
->setPen( option
.palette
.color( cg
, cr
) );
391 tor
.getMimeTypeIcon().paint( painter
, iconArea
, Qt::AlignCenter
, im
, qs
);
392 painter
->setFont( nameFont
);
393 painter
->drawText( nameArea
, 0, nameFM
.elidedText( nameStr
, Qt::ElideRight
, nameArea
.width( ) ) );
394 painter
->setFont( statusFont
);
395 painter
->drawText( statusArea
, 0, statusFM
.elidedText( statusStr
, Qt::ElideRight
, statusArea
.width( ) ) );
396 painter
->setFont( progressFont
);
397 painter
->drawText( progArea
, 0, progressFM
.elidedText( progressStr
, Qt::ElideRight
, progArea
.width( ) ) );
398 const bool isMagnet( !tor
.hasMetadata( ) );
399 myProgressBarStyle
->rect
= barArea
;
400 myProgressBarStyle
->direction
= option
.direction
;
401 myProgressBarStyle
->palette
= option
.palette
;
402 myProgressBarStyle
->palette
.setCurrentColorGroup( cg
);
403 myProgressBarStyle
->state
= progressBarState
;
404 myProgressBarStyle
->progress
= int(myProgressBarStyle
->minimum
+ (((isMagnet
? tor
.metadataPercentDone() : tor
.percentDone()) * (myProgressBarStyle
->maximum
- myProgressBarStyle
->minimum
))));
405 style
->drawControl( QStyle::CE_ProgressBar
, myProgressBarStyle
, painter
);