@ -39,8 +39,10 @@
# include <QPainter>
# include <QPainter>
# include <QVariantAnimation>
# include <QVariantAnimation>
# include <cassert>
# include <math.h>
# include <math.h>
// The leftButton is used to accept, pause, or resume a file transfer, as well as to open a
// The leftButton is used to accept, pause, or resume a file transfer, as well as to open a
// received file.
// received file.
// The rightButton is used to cancel a file transfer, or to open the directory a file was
// The rightButton is used to cancel a file transfer, or to open the directory a file was
@ -50,7 +52,6 @@ FileTransferWidget::FileTransferWidget(QWidget* parent, ToxFile file)
: QWidget ( parent )
: QWidget ( parent )
, ui ( new Ui : : FileTransferWidget )
, ui ( new Ui : : FileTransferWidget )
, fileInfo ( file )
, fileInfo ( file )
, lastTick ( QTime : : currentTime ( ) )
, backgroundColor ( Style : : getColor ( Style : : LightGrey ) )
, backgroundColor ( Style : : getColor ( Style : : LightGrey ) )
, buttonColor ( Style : : getColor ( Style : : Yellow ) )
, buttonColor ( Style : : getColor ( Style : : Yellow ) )
, buttonBackgroundColor ( Style : : getColor ( Style : : White ) )
, buttonBackgroundColor ( Style : : getColor ( Style : : White ) )
@ -84,8 +85,6 @@ FileTransferWidget::FileTransferWidget(QWidget* parent, ToxFile file)
update ( ) ;
update ( ) ;
} ) ;
} ) ;
setBackgroundColor ( Style : : getColor ( Style : : LightGrey ) , false ) ;
connect ( Core : : getInstance ( ) , & Core : : fileTransferInfo , this ,
connect ( Core : : getInstance ( ) , & Core : : fileTransferInfo , this ,
& FileTransferWidget : : onFileTransferInfo ) ;
& FileTransferWidget : : onFileTransferInfo ) ;
connect ( Core : : getInstance ( ) , & Core : : fileTransferAccepted , this ,
connect ( Core : : getInstance ( ) , & Core : : fileTransferAccepted , this ,
@ -105,15 +104,9 @@ FileTransferWidget::FileTransferWidget(QWidget* parent, ToxFile file)
connect ( ui - > previewButton , & QPushButton : : clicked , this ,
connect ( ui - > previewButton , & QPushButton : : clicked , this ,
& FileTransferWidget : : onPreviewButtonClicked ) ;
& FileTransferWidget : : onPreviewButtonClicked ) ;
setupButtons ( ) ;
// Set lastStatus to anything but the file's current value, this forces an update
lastStatus = file . status = = ToxFile : : FINISHED ? ToxFile : : INITIALIZING : ToxFile : : FINISHED ;
// preview
updateWidget ( file ) ;
if ( fileInfo . direction = = ToxFile : : SENDING ) {
showPreview ( fileInfo . filePath ) ;
ui - > progressLabel - > setText ( tr ( " Waiting to send... " , " file transfer widget " ) ) ;
} else {
ui - > progressLabel - > setText ( tr ( " Accept to receive this file " , " file transfer widget " ) ) ;
}
setFixedHeight ( 64 ) ;
setFixedHeight ( 64 ) ;
}
}
@ -155,10 +148,11 @@ void FileTransferWidget::autoAcceptTransfer(const QString& path)
// Do not automatically accept the file-transfer if the path is not writable.
// Do not automatically accept the file-transfer if the path is not writable.
// The user can still accept it manually.
// The user can still accept it manually.
if ( tryRemoveFile ( filepath ) )
if ( tryRemoveFile ( filepath ) ) {
Core : : getInstance ( ) - > acceptFileRecvRequest ( fileInfo . friendId , fileInfo . fileNum , filepath ) ;
Core : : getInstance ( ) - > acceptFileRecvRequest ( fileInfo . friendId , fileInfo . fileNum , filepath ) ;
else
} else {
qWarning ( ) < < " Cannot write to " < < filepath ;
qWarning ( ) < < " Cannot write to " < < filepath ;
}
}
}
bool FileTransferWidget : : isActive ( ) const
bool FileTransferWidget : : isActive ( ) const
@ -168,8 +162,9 @@ bool FileTransferWidget::isActive() const
void FileTransferWidget : : acceptTransfer ( const QString & filepath )
void FileTransferWidget : : acceptTransfer ( const QString & filepath )
{
{
if ( filepath . isEmpty ( ) )
if ( filepath . isEmpty ( ) ) {
return ;
return ;
}
// test if writable
// test if writable
if ( ! tryRemoveFile ( filepath ) ) {
if ( ! tryRemoveFile ( filepath ) ) {
@ -267,169 +262,49 @@ void FileTransferWidget::paintEvent(QPaintEvent*)
void FileTransferWidget : : onFileTransferInfo ( ToxFile file )
void FileTransferWidget : : onFileTransferInfo ( ToxFile file )
{
{
QTime now = QTime : : currentTime ( ) ;
updateWidget ( file ) ;
qint64 dt = lastTick . msecsTo ( now ) ; // ms
if ( fileInfo ! = file | | dt < 1000 )
return ;
fileInfo = file ;
if ( fileInfo . status = = ToxFile : : TRANSMITTING ) {
// update progress
qreal progress = static_cast < qreal > ( file . bytesSent ) / static_cast < qreal > ( file . filesize ) ;
ui - > progressBar - > setValue ( static_cast < int > ( progress * 100.0 ) ) ;
// ETA, speed
qreal deltaSecs = dt / 1000.0 ;
// (can't use ::abs or ::max on unsigned types substraction, they'd just overflow)
quint64 deltaBytes = file . bytesSent > lastBytesSent ? file . bytesSent - lastBytesSent
: lastBytesSent - file . bytesSent ;
qreal bytesPerSec = static_cast < int > ( static_cast < qreal > ( deltaBytes ) / deltaSecs ) ;
// calculate mean
meanIndex = meanIndex % TRANSFER_ROLLING_AVG_COUNT ;
meanData [ meanIndex + + ] = bytesPerSec ;
qreal meanBytesPerSec = 0.0 ;
for ( size_t i = 0 ; i < TRANSFER_ROLLING_AVG_COUNT ; + + i )
meanBytesPerSec + = meanData [ i ] ;
meanBytesPerSec / = static_cast < qreal > ( TRANSFER_ROLLING_AVG_COUNT ) ;
// update UI
if ( meanBytesPerSec > 0 ) {
// ETA
QTime toGo = QTime ( 0 , 0 ) . addSecs ( ( file . filesize - file . bytesSent ) / meanBytesPerSec ) ;
QString format = toGo . hour ( ) > 0 ? " hh:mm:ss " : " mm:ss " ;
ui - > etaLabel - > setText ( toGo . toString ( format ) ) ;
} else {
ui - > etaLabel - > setText ( " " ) ;
}
ui - > progressLabel - > setText ( getHumanReadableSize ( meanBytesPerSec ) + " /s " ) ;
lastBytesSent = file . bytesSent ;
}
lastTick = now ;
// trigger repaint
update ( ) ;
}
}
void FileTransferWidget : : onFileTransferAccepted ( ToxFile file )
void FileTransferWidget : : onFileTransferAccepted ( ToxFile file )
{
{
if ( fileInfo ! = file )
updateWidget ( file ) ;
return ;
fileInfo = file ;
setBackgroundColor ( Style : : getColor ( Style : : LightGrey ) , false ) ;
setupButtons ( ) ;
}
}
void FileTransferWidget : : onFileTransferCancelled ( ToxFile file )
void FileTransferWidget : : onFileTransferCancelled ( ToxFile file )
{
{
if ( fileInfo ! = file )
updateWidget ( file ) ;
return ;
fileInfo = file ;
active = false ;
setBackgroundColor ( Style : : getColor ( Style : : Red ) , true ) ;
setupButtons ( ) ;
hideWidgets ( ) ;
disconnect ( Core : : getInstance ( ) , nullptr , this , nullptr ) ;
}
}
void FileTransferWidget : : onFileTransferPaused ( ToxFile file )
void FileTransferWidget : : onFileTransferPaused ( ToxFile file )
{
{
if ( fileInfo ! = file )
updateWidget ( file ) ;
return ;
fileInfo = file ;
ui - > etaLabel - > setText ( " " ) ;
ui - > progressLabel - > setText ( tr ( " Paused " , " file transfer widget " ) ) ;
// reset mean
meanIndex = 0 ;
for ( size_t i = 0 ; i < TRANSFER_ROLLING_AVG_COUNT ; + + i )
meanData [ i ] = 0.0 ;
setBackgroundColor ( Style : : getColor ( Style : : LightGrey ) , false ) ;
setupButtons ( ) ;
}
}
void FileTransferWidget : : onFileTransferResumed ( ToxFile file )
void FileTransferWidget : : onFileTransferResumed ( ToxFile file )
{
{
if ( fileInfo ! = file )
updateWidget ( file ) ;
return ;
fileInfo = file ;
ui - > etaLabel - > setText ( " " ) ;
ui - > progressLabel - > setText ( tr ( " Resuming... " , " file transfer widget " ) ) ;
// reset mean
meanIndex = 0 ;
for ( size_t i = 0 ; i < TRANSFER_ROLLING_AVG_COUNT ; + + i )
meanData [ i ] = 0.0 ;
setBackgroundColor ( Style : : getColor ( Style : : LightGrey ) , false ) ;
setupButtons ( ) ;
}
}
void FileTransferWidget : : onFileTransferFinished ( ToxFile file )
void FileTransferWidget : : onFileTransferFinished ( ToxFile file )
{
{
if ( fileInfo ! = file )
updateWidget ( file ) ;
return ;
fileInfo = file ;
active = false ;
setBackgroundColor ( Style : : getColor ( Style : : Green ) , true ) ;
setupButtons ( ) ;
hideWidgets ( ) ;
ui - > leftButton - > setIcon ( QIcon ( Style : : getImagePath ( " fileTransferInstance/yes.svg " ) ) ) ;
ui - > leftButton - > setObjectName ( " ok " ) ;
ui - > leftButton - > setToolTip ( tr ( " Open file " ) ) ;
ui - > leftButton - > show ( ) ;
ui - > rightButton - > setIcon ( QIcon ( Style : : getImagePath ( " fileTransferInstance/dir.svg " ) ) ) ;
ui - > rightButton - > setObjectName ( " dir " ) ;
ui - > rightButton - > setToolTip ( tr ( " Open file directory " ) ) ;
ui - > rightButton - > show ( ) ;
// preview
if ( fileInfo . direction = = ToxFile : : RECEIVING )
showPreview ( fileInfo . filePath ) ;
disconnect ( Core : : getInstance ( ) , nullptr , this , nullptr ) ;
}
}
void FileTransferWidget : : fileTransferRemotePausedUnpaused ( ToxFile file , bool paused )
void FileTransferWidget : : fileTransferRemotePausedUnpaused ( ToxFile file , bool paused )
{
{
if ( paused )
if ( paused ) {
onFileTransferPaused ( file ) ;
onFileTransferPaused ( file ) ;
else
} else {
onFileTransferResumed ( file ) ;
onFileTransferResumed ( file ) ;
}
}
}
void FileTransferWidget : : fileTransferBrokenUnbroken ( ToxFile file , bool broken )
void FileTransferWidget : : fileTransferBrokenUnbroken ( ToxFile file , bool broken )
{
{
// TODO: Handle broken transfer differently once we have resuming code
// TODO: Handle broken transfer differently once we have resuming code
if ( broken )
if ( broken ) {
onFileTransferCancelled ( file ) ;
onFileTransferCancelled ( file ) ;
}
}
}
QString FileTransferWidget : : getHumanReadableSize ( qint64 size )
QString FileTransferWidget : : getHumanReadableSize ( qint64 size )
@ -437,24 +312,173 @@ QString FileTransferWidget::getHumanReadableSize(qint64 size)
static const char * suffix [ ] = { " B " , " kiB " , " MiB " , " GiB " , " TiB " } ;
static const char * suffix [ ] = { " B " , " kiB " , " MiB " , " GiB " , " TiB " } ;
int exp = 0 ;
int exp = 0 ;
if ( size > 0 )
if ( size > 0 ) {
exp = std : : min ( ( int ) ( log ( size ) / log ( 1024 ) ) , ( int ) ( sizeof ( suffix ) / sizeof ( suffix [ 0 ] ) - 1 ) ) ;
exp = std : : min ( ( int ) ( log ( size ) / log ( 1024 ) ) , ( int ) ( sizeof ( suffix ) / sizeof ( suffix [ 0 ] ) - 1 ) ) ;
}
return QString ( ) . setNum ( size / pow ( 1024 , exp ) , ' f ' , exp > 1 ? 2 : 0 ) . append ( suffix [ exp ] ) ;
return QString ( ) . setNum ( size / pow ( 1024 , exp ) , ' f ' , exp > 1 ? 2 : 0 ) . append ( suffix [ exp ] ) ;
}
}
void FileTransferWidget : : hideWidgets ( )
void FileTransferWidget : : updateWidgetColor ( ToxFile const & file )
{
{
ui - > leftButton - > hide ( ) ;
if ( lastStatus = = file . status ) {
ui - > rightButton - > hide ( ) ;
return ;
ui - > progressBar - > hide ( ) ;
}
ui - > progressLabel - > hide ( ) ;
ui - > etaLabel - > hide ( ) ;
switch ( file . status ) {
case ToxFile : : INITIALIZING :
case ToxFile : : PAUSED :
case ToxFile : : TRANSMITTING :
setBackgroundColor ( Style : : getColor ( Style : : LightGrey ) , false ) ;
break ;
case ToxFile : : BROKEN :
case ToxFile : : CANCELED :
setBackgroundColor ( Style : : getColor ( Style : : Red ) , true ) ;
break ;
case ToxFile : : FINISHED :
setBackgroundColor ( Style : : getColor ( Style : : Green ) , true ) ;
break ;
default :
qCritical ( ) < < " Invalid file status " ;
assert ( false ) ;
}
}
}
void FileTransferWidget : : setupButtons ( )
void FileTransferWidget : : updateWidgetText ( ToxFile const & file )
{
{
switch ( fileInfo . status ) {
if ( lastStatus = = file . status ) {
return ;
}
switch ( file . status ) {
case ToxFile : : INITIALIZING :
if ( file . direction = = ToxFile : : SENDING ) {
ui - > progressLabel - > setText ( tr ( " Waiting to send... " , " file transfer widget " ) ) ;
} else {
ui - > progressLabel - > setText ( tr ( " Accept to receive this file " , " file transfer widget " ) ) ;
}
break ;
case ToxFile : : PAUSED :
ui - > etaLabel - > setText ( " " ) ;
ui - > progressLabel - > setText ( tr ( " Paused " , " file transfer widget " ) ) ;
break ;
case ToxFile : : TRANSMITTING :
ui - > etaLabel - > setText ( " " ) ;
ui - > progressLabel - > setText ( tr ( " Resuming... " , " file transfer widget " ) ) ;
break ;
case ToxFile : : BROKEN :
case ToxFile : : CANCELED :
break ;
case ToxFile : : FINISHED :
break ;
default :
qCritical ( ) < < " Invalid file status " ;
assert ( false ) ;
}
}
void FileTransferWidget : : updatePreview ( ToxFile const & file )
{
if ( lastStatus = = file . status ) {
return ;
}
switch ( file . status ) {
case ToxFile : : INITIALIZING :
case ToxFile : : PAUSED :
case ToxFile : : TRANSMITTING :
case ToxFile : : BROKEN :
case ToxFile : : CANCELED :
if ( file . direction = = ToxFile : : SENDING ) {
showPreview ( file . filePath ) ;
}
break ;
case ToxFile : : FINISHED :
showPreview ( file . filePath ) ;
break ;
default :
qCritical ( ) < < " Invalid file status " ;
assert ( false ) ;
}
}
void FileTransferWidget : : updateFileProgress ( ToxFile const & file )
{
switch ( file . status ) {
case ToxFile : : INITIALIZING :
break ;
case ToxFile : : PAUSED :
fileProgress . resetSpeed ( ) ;
break ;
case ToxFile : : TRANSMITTING : {
if ( ! fileProgress . needsUpdate ( ) ) {
break ;
}
fileProgress . addSample ( file ) ;
auto speed = fileProgress . getSpeed ( ) ;
auto progress = fileProgress . getProgress ( ) ;
auto remainingTime = fileProgress . getTimeLeftSeconds ( ) ;
ui - > progressBar - > setValue ( static_cast < int > ( progress * 100.0 ) ) ;
// update UI
if ( speed > 0 ) {
// ETA
QTime toGo = QTime ( 0 , 0 ) . addSecs ( remainingTime ) ;
QString format = toGo . hour ( ) > 0 ? " hh:mm:ss " : " mm:ss " ;
ui - > etaLabel - > setText ( toGo . toString ( format ) ) ;
} else {
ui - > etaLabel - > setText ( " " ) ;
}
ui - > progressLabel - > setText ( getHumanReadableSize ( speed ) + " /s " ) ;
break ;
}
case ToxFile : : BROKEN :
case ToxFile : : CANCELED :
case ToxFile : : FINISHED : {
ui - > progressBar - > hide ( ) ;
ui - > progressLabel - > hide ( ) ;
ui - > etaLabel - > hide ( ) ;
break ;
}
default :
qCritical ( ) < < " Invalid file status " ;
assert ( false ) ;
}
}
void FileTransferWidget : : updateSignals ( ToxFile const & file )
{
if ( lastStatus = = file . status ) {
return ;
}
switch ( file . status ) {
case ToxFile : : CANCELED :
case ToxFile : : BROKEN :
case ToxFile : : FINISHED :
active = false ;
disconnect ( Core : : getInstance ( ) , nullptr , this , nullptr ) ;
break ;
case ToxFile : : INITIALIZING :
case ToxFile : : PAUSED :
case ToxFile : : TRANSMITTING :
break ;
default :
qCritical ( ) < < " Invalid file status " ;
assert ( false ) ;
}
}
void FileTransferWidget : : setupButtons ( ToxFile const & file )
{
if ( lastStatus = = file . status ) {
return ;
}
switch ( file . status ) {
case ToxFile : : TRANSMITTING :
case ToxFile : : TRANSMITTING :
ui - > leftButton - > setIcon ( QIcon ( Style : : getImagePath ( " fileTransferInstance/pause.svg " ) ) ) ;
ui - > leftButton - > setIcon ( QIcon ( Style : : getImagePath ( " fileTransferInstance/pause.svg " ) ) ) ;
ui - > leftButton - > setObjectName ( " pause " ) ;
ui - > leftButton - > setObjectName ( " pause " ) ;
@ -479,13 +503,12 @@ void FileTransferWidget::setupButtons()
setButtonColor ( Style : : getColor ( Style : : LightGrey ) ) ;
setButtonColor ( Style : : getColor ( Style : : LightGrey ) ) ;
break ;
break ;
case ToxFile : : STOPPED :
case ToxFile : : INITIALIZING :
case ToxFile : : BROKEN :
ui - > rightButton - > setIcon ( QIcon ( Style : : getImagePath ( " fileTransferInstance/no.svg " ) ) ) ;
ui - > rightButton - > setIcon ( QIcon ( Style : : getImagePath ( " fileTransferInstance/no.svg " ) ) ) ;
ui - > rightButton - > setObjectName ( " cancel " ) ;
ui - > rightButton - > setObjectName ( " cancel " ) ;
ui - > rightButton - > setToolTip ( tr ( " Cancel transfer " ) ) ;
ui - > rightButton - > setToolTip ( tr ( " Cancel transfer " ) ) ;
if ( fileInfo . direction = = ToxFile : : SENDING ) {
if ( file . direction = = ToxFile : : SENDING ) {
ui - > leftButton - > setIcon ( QIcon ( Style : : getImagePath ( " fileTransferInstance/pause.svg " ) ) ) ;
ui - > leftButton - > setIcon ( QIcon ( Style : : getImagePath ( " fileTransferInstance/pause.svg " ) ) ) ;
ui - > leftButton - > setObjectName ( " pause " ) ;
ui - > leftButton - > setObjectName ( " pause " ) ;
ui - > leftButton - > setToolTip ( tr ( " Pause transfer " ) ) ;
ui - > leftButton - > setToolTip ( tr ( " Pause transfer " ) ) ;
@ -495,27 +518,48 @@ void FileTransferWidget::setupButtons()
ui - > leftButton - > setToolTip ( tr ( " Accept transfer " ) ) ;
ui - > leftButton - > setToolTip ( tr ( " Accept transfer " ) ) ;
}
}
break ;
break ;
case ToxFile : : CANCELED :
case ToxFile : : BROKEN :
ui - > leftButton - > hide ( ) ;
ui - > rightButton - > hide ( ) ;
break ;
case ToxFile : : FINISHED :
ui - > leftButton - > setIcon ( QIcon ( Style : : getImagePath ( " fileTransferInstance/yes.svg " ) ) ) ;
ui - > leftButton - > setObjectName ( " ok " ) ;
ui - > leftButton - > setToolTip ( tr ( " Open file " ) ) ;
ui - > leftButton - > show ( ) ;
ui - > rightButton - > setIcon ( QIcon ( Style : : getImagePath ( " fileTransferInstance/dir.svg " ) ) ) ;
ui - > rightButton - > setObjectName ( " dir " ) ;
ui - > rightButton - > setToolTip ( tr ( " Open file directory " ) ) ;
ui - > rightButton - > show ( ) ;
break ;
default :
qCritical ( ) < < " Invalid file status " ;
assert ( false ) ;
}
}
}
}
void FileTransferWidget : : handleButton ( QPushButton * btn )
void FileTransferWidget : : handleButton ( QPushButton * btn )
{
{
if ( fileInfo . direction = = ToxFile : : SENDING ) {
if ( fileInfo . direction = = ToxFile : : SENDING ) {
if ( btn - > objectName ( ) = = " cancel " )
if ( btn - > objectName ( ) = = " cancel " ) {
Core : : getInstance ( ) - > cancelFileSend ( fileInfo . friendId , fileInfo . fileNum ) ;
Core : : getInstance ( ) - > cancelFileSend ( fileInfo . friendId , fileInfo . fileNum ) ;
else if ( btn - > objectName ( ) = = " pause " )
} else if ( btn - > objectName ( ) = = " pause " ) {
Core : : getInstance ( ) - > pauseResumeFileSend ( fileInfo . friendId , fileInfo . fileNum ) ;
Core : : getInstance ( ) - > pauseResumeFileSend ( fileInfo . friendId , fileInfo . fileNum ) ;
else if ( btn - > objectName ( ) = = " resume " )
} else if ( btn - > objectName ( ) = = " resume " ) {
Core : : getInstance ( ) - > pauseResumeFileSend ( fileInfo . friendId , fileInfo . fileNum ) ;
Core : : getInstance ( ) - > pauseResumeFileSend ( fileInfo . friendId , fileInfo . fileNum ) ;
}
} else // receiving or paused
} else // receiving or paused
{
{
if ( btn - > objectName ( ) = = " cancel " )
if ( btn - > objectName ( ) = = " cancel " ) {
Core : : getInstance ( ) - > cancelFileRecv ( fileInfo . friendId , fileInfo . fileNum ) ;
Core : : getInstance ( ) - > cancelFileRecv ( fileInfo . friendId , fileInfo . fileNum ) ;
else if ( btn - > objectName ( ) = = " pause " )
} else if ( btn - > objectName ( ) = = " pause " ) {
Core : : getInstance ( ) - > pauseResumeFileRecv ( fileInfo . friendId , fileInfo . fileNum ) ;
Core : : getInstance ( ) - > pauseResumeFileRecv ( fileInfo . friendId , fileInfo . fileNum ) ;
else if ( btn - > objectName ( ) = = " resume " )
} else if ( btn - > objectName ( ) = = " resume " ) {
Core : : getInstance ( ) - > pauseResumeFileRecv ( fileInfo . friendId , fileInfo . fileNum ) ;
Core : : getInstance ( ) - > pauseResumeFileRecv ( fileInfo . friendId , fileInfo . fileNum ) ;
else if ( btn - > objectName ( ) = = " accept " ) {
} else if ( btn - > objectName ( ) = = " accept " ) {
QString path =
QString path =
QFileDialog : : getSaveFileName ( Q_NULLPTR ,
QFileDialog : : getSaveFileName ( Q_NULLPTR ,
tr ( " Save a file " , " Title of the file saving dialog " ) ,
tr ( " Save a file " , " Title of the file saving dialog " ) ,
@ -544,12 +588,12 @@ void FileTransferWidget::showPreview(const QString& filename)
QFile imageFile ( filename ) ;
QFile imageFile ( filename ) ;
if ( ! imageFile . open ( QIODevice : : ReadOnly ) ) {
if ( ! imageFile . open ( QIODevice : : ReadOnly ) ) {
qCritical ( ) < < " Failed to open file for preview " ;
return ;
return ;
}
}
const QByteArray imageFileData = imageFile . readAll ( ) ;
const QByteArray imageFileData = imageFile . readAll ( ) ;
QImage image = QImage : : fromData ( imageFileData ) ;
QImage image = QImage : : fromData ( imageFileData ) ;
const int exifOrientation = getExifOrientation ( imageFileData . constData ( ) , imageFileData . size ( ) ) ;
const int exifOrientation =
getExifOrientation ( imageFileData . constData ( ) , imageFileData . size ( ) ) ;
if ( exifOrientation ) {
if ( exifOrientation ) {
applyTransformation ( exifOrientation , image ) ;
applyTransformation ( exifOrientation , image ) ;
}
}
@ -559,16 +603,16 @@ void FileTransferWidget::showPreview(const QString& filename)
ui - > previewButton - > setIcon ( QIcon ( iconPixmap ) ) ;
ui - > previewButton - > setIcon ( QIcon ( iconPixmap ) ) ;
ui - > previewButton - > setIconSize ( iconPixmap . size ( ) ) ;
ui - > previewButton - > setIconSize ( iconPixmap . size ( ) ) ;
ui - > previewButton - > show ( ) ;
ui - > previewButton - > show ( ) ;
// Show mouseover preview, but make sure it's not larger than 50% of the screen width/height
// Show mouseover preview, but make sure it's not larger than 50% of the screen
// width/height
const QRect desktopSize = QApplication : : desktop ( ) - > screenGeometry ( ) ;
const QRect desktopSize = QApplication : : desktop ( ) - > screenGeometry ( ) ;
const int maxPreviewWidth { desktopSize . width ( ) / 2 } ;
const int maxPreviewWidth { desktopSize . width ( ) / 2 } ;
const int maxPreviewHeight { desktopSize . height ( ) / 2 } ;
const int maxPreviewHeight { desktopSize . height ( ) / 2 } ;
const QImage previewImage = [ & image , maxPreviewWidth , maxPreviewHeight ] ( ) {
const QImage previewImage = [ & image , maxPreviewWidth , maxPreviewHeight ] ( ) {
if ( image . width ( ) > maxPreviewWidth | | image . height ( ) > maxPreviewHeight ) {
if ( image . width ( ) > maxPreviewWidth | | image . height ( ) > maxPreviewHeight ) {
return image . scaled ( maxPreviewWidth , maxPreviewHeight ,
return image . scaled ( maxPreviewWidth , maxPreviewHeight , Qt : : KeepAspectRatio ,
Qt : : KeepAspectRatio , Qt : : SmoothTransformation ) ;
Qt : : SmoothTransformation ) ;
}
} else {
else {
return image ;
return image ;
}
}
} ( ) ;
} ( ) ;
@ -578,8 +622,7 @@ void FileTransferWidget::showPreview(const QString& filename)
buffer . open ( QIODevice : : WriteOnly ) ;
buffer . open ( QIODevice : : WriteOnly ) ;
previewImage . save ( & buffer , " PNG " ) ;
previewImage . save ( & buffer , " PNG " ) ;
buffer . close ( ) ;
buffer . close ( ) ;
ui - > previewButton - > setToolTip ( " <img src=data:image/png;base64, " + imageData . toBase64 ( )
ui - > previewButton - > setToolTip ( " <img src=data:image/png;base64, " + imageData . toBase64 ( ) + " /> " ) ;
+ " /> " ) ;
}
}
}
}
@ -602,7 +645,8 @@ QPixmap FileTransferWidget::scaleCropIntoSquare(const QPixmap& source, const int
{
{
QPixmap result ;
QPixmap result ;
// Make sure smaller-than-icon images (at least one dimension is smaller) will not be upscaled
// Make sure smaller-than-icon images (at least one dimension is smaller) will not be
// upscaled
if ( source . width ( ) < targetSize | | source . height ( ) < targetSize ) {
if ( source . width ( ) < targetSize | | source . height ( ) < targetSize ) {
result = source ;
result = source ;
} else {
} else {
@ -612,10 +656,11 @@ QPixmap FileTransferWidget::scaleCropIntoSquare(const QPixmap& source, const int
// Then, image has to be cropped (if needed) so it will not overflow rectangle
// Then, image has to be cropped (if needed) so it will not overflow rectangle
// Only one dimension will be bigger after Qt::KeepAspectRatioByExpanding
// Only one dimension will be bigger after Qt::KeepAspectRatioByExpanding
if ( result . width ( ) > targetSize )
if ( result . width ( ) > targetSize ) {
return result . copy ( ( result . width ( ) - targetSize ) / 2 , 0 , targetSize , targetSize ) ;
return result . copy ( ( result . width ( ) - targetSize ) / 2 , 0 , targetSize , targetSize ) ;
else if ( result . height ( ) > targetSize )
} else if ( result . height ( ) > targetSize ) {
return result . copy ( 0 , ( result . height ( ) - targetSize ) / 2 , targetSize , targetSize ) ;
return result . copy ( 0 , ( result . height ( ) - targetSize ) / 2 , targetSize , targetSize ) ;
}
// Picture was rectangle in the first place, no cropping
// Picture was rectangle in the first place, no cropping
return result ;
return result ;
@ -625,8 +670,9 @@ int FileTransferWidget::getExifOrientation(const char* data, const int size)
{
{
ExifData * exifData = exif_data_new_from_data ( reinterpret_cast < const unsigned char * > ( data ) , size ) ;
ExifData * exifData = exif_data_new_from_data ( reinterpret_cast < const unsigned char * > ( data ) , size ) ;
if ( ! exifData )
if ( ! exifData ) {
return 0 ;
return 0 ;
}
int orientation = 0 ;
int orientation = 0 ;
const ExifByteOrder byteOrder = exif_data_get_byte_order ( exifData ) ;
const ExifByteOrder byteOrder = exif_data_get_byte_order ( exifData ) ;
@ -641,12 +687,11 @@ int FileTransferWidget::getExifOrientation(const char* data, const int size)
void FileTransferWidget : : applyTransformation ( const int orientation , QImage & image )
void FileTransferWidget : : applyTransformation ( const int orientation , QImage & image )
{
{
QTransform exifTransform ;
QTransform exifTransform ;
switch ( static_cast < ExifOrientation > ( orientation ) )
switch ( static_cast < ExifOrientation > ( orientation ) ) {
{
case ExifOrientation : : TopLeft :
case ExifOrientation : : TopLeft :
break ;
break ;
case ExifOrientation : : TopRight :
case ExifOrientation : : TopRight :
image = image . mirrored ( 1 , 0 ) ;
image = image . mirrored ( 1 , 0 ) ;
break ;
break ;
case ExifOrientation : : BottomRight :
case ExifOrientation : : BottomRight :
exifTransform . rotate ( 180 ) ;
exifTransform . rotate ( 180 ) ;
@ -673,3 +718,35 @@ void FileTransferWidget::applyTransformation(const int orientation, QImage& imag
}
}
image = image . transformed ( exifTransform ) ;
image = image . transformed ( exifTransform ) ;
}
}
void FileTransferWidget : : updateWidget ( ToxFile const & file )
{
if ( fileInfo ! = file ) {
return ;
}
fileInfo = file ;
// If we repainted on every packet our gui would be *very* slow
bool bTransmitNeedsUpdate = fileProgress . needsUpdate ( ) ;
updatePreview ( file ) ;
updateFileProgress ( file ) ;
updateWidgetText ( file ) ;
updateWidgetColor ( file ) ;
setupButtons ( file ) ;
updateSignals ( file ) ;
lastStatus = file . status ;
// trigger repaint
switch ( file . status ) {
case ToxFile : : TRANSMITTING :
if ( ! bTransmitNeedsUpdate ) {
break ;
}
// fallthrough
default :
update ( ) ;
}
}