Commit d0377406 authored by David Barchiesi's avatar David Barchiesi

Permit setting upload size on FileAbstractResumableJob and thus enable progress reporting.

Added job progress status bar in files-example.
parent 7ed26c8e
......@@ -93,15 +93,23 @@ void MainWindow::uploadFile()
uploadFile->setTitle(fileInfo.fileName());
KGAPI2::Drive::FileResumableCreateJob *fileCreateJob = new KGAPI2::Drive::FileResumableCreateJob(uploadFile, m_account, this);
fileCreateJob->setUploadSize(uploadingFile->size());
connect(fileCreateJob, &KGAPI2::Drive::FileResumableCreateJob::finished,
this, &MainWindow::slotFileCreateJobFinished);
connect(fileCreateJob, &KGAPI2::Drive::FileResumableCreateJob::readyWrite,
this, &MainWindow::slotFileCreateJobReadyWrite);
connect(fileCreateJob, &KGAPI2::Drive::FileResumableCreateJob::progress,
this, &MainWindow::slotFileCreateJobProgress);
bytesUploaded = 0;
uploadProgressBar = new QProgressBar(m_ui->statusbar);
uploadProgressBar->setMaximum(uploadingFile->size());
m_ui->statusbar->addWidget(uploadProgressBar);
fileUploadProgressBar = new QProgressBar(m_ui->statusbar);
fileUploadProgressBar->setFormat(QStringLiteral("Sent to Job: %v bytes [%p%]"));
fileUploadProgressBar->setMaximum(uploadingFile->size());
m_ui->statusbar->addWidget(fileUploadProgressBar);
jobUploadProgressBar = new QProgressBar(m_ui->statusbar);
jobUploadProgressBar->setFormat(QStringLiteral("Job progress: %v bytes [%p%]"));
m_ui->statusbar->addWidget(jobUploadProgressBar);
}
void MainWindow::slotFileCreateJobFinished(KGAPI2::Job *job)
......@@ -119,8 +127,11 @@ void MainWindow::slotFileCreateJobFinished(KGAPI2::Job *job)
m_ui->statusbar->showMessage(QStringLiteral("Upload complete, id %1, size %2 (uploaded %3), mimeType %4").arg(file->id()).arg(file->fileSize()).arg(bytesUploaded).arg(file->mimeType()));
}
m_ui->statusbar->removeWidget(uploadProgressBar);
uploadProgressBar->deleteLater();
m_ui->statusbar->removeWidget(fileUploadProgressBar);
fileUploadProgressBar->deleteLater();
m_ui->statusbar->removeWidget(jobUploadProgressBar);
jobUploadProgressBar->deleteLater();
}
......@@ -130,7 +141,13 @@ void MainWindow::slotFileCreateJobReadyWrite(KGAPI2::Drive::FileAbstractResumabl
bytesUploaded += data.size();
job->write(data);
uploadProgressBar->setValue(bytesUploaded);
fileUploadProgressBar->setValue(bytesUploaded);
}
void MainWindow::slotFileCreateJobProgress(KGAPI2::Job *job, int base, int total)
{
jobUploadProgressBar->setValue(base);
jobUploadProgressBar->setMaximum(total);
}
void MainWindow::setInputsEnabled(bool enabled)
......
......@@ -65,6 +65,11 @@ class MainWindow : public QMainWindow
*/
void slotFileCreateJobReadyWrite(KGAPI2::Drive::FileAbstractResumableJob *job);
/**
* FileCreateJob emits progress
*/
void slotFileCreateJobProgress(KGAPI2::Job *job, int base, int total);
private:
Ui::MainWindow *m_ui;
......@@ -72,7 +77,8 @@ class MainWindow : public QMainWindow
QFile *uploadingFile;
int bytesUploaded;
QProgressBar *uploadProgressBar;
QProgressBar *fileUploadProgressBar;
QProgressBar *jobUploadProgressBar;
void setInputsEnabled(bool enabled);
......
......@@ -31,12 +31,16 @@ class Q_DECL_HIDDEN FileAbstractResumableJob::Private
void startUploadSession();
void uploadChunk(bool lastChunk);
void processNext();
bool isTotalSizeKnown() const;
void _k_uploadProgress(qint64 bytesSent, qint64 totalBytes);
FilePtr metaData;
QString sessionPath;
QList<QByteArray> chunks;
int uploadedSize = 0;
int totalUploadSize = 0;
enum SessionState {
ReadyStart,
......@@ -109,8 +113,9 @@ void FileAbstractResumableJob::Private::uploadChunk(bool lastChunk)
// Need to send last chunk, therefore final file size is known now
tempRangeHeader = tempRangeHeader.arg(uploadedSize + partData.size());
} else {
// In the middle of the upload, file size is not yet known so use star
tempRangeHeader = tempRangeHeader.arg(QStringLiteral("*"));
// Use star in the case that total upload size in unknown
QString totalSymbol = isTotalSizeKnown() ? QString::number(totalUploadSize) : QStringLiteral("*");
tempRangeHeader = tempRangeHeader.arg(totalSymbol);
}
rangeHeader = tempRangeHeader;
}
......@@ -158,6 +163,19 @@ void FileAbstractResumableJob::Private::processNext()
}
}
bool FileAbstractResumableJob::Private::isTotalSizeKnown() const
{
return totalUploadSize != 0;
}
void FileAbstractResumableJob::Private::_k_uploadProgress(qint64 bytesSent,
qint64 totalBytes)
{
// uploadedSize corresponds to total bytes enqueued (including current chunk upload)
qint64 totalUploaded = uploadedSize - totalBytes + bytesSent;
q->emitProgress(totalUploaded, totalUploadSize);
}
FileAbstractResumableJob::FileAbstractResumableJob(const AccountPtr &account,
QObject *parent):
......@@ -182,6 +200,16 @@ FilePtr FileAbstractResumableJob::metadata() const
return d->metaData;
}
void FileAbstractResumableJob::setUploadSize(int size)
{
if (isRunning()) {
qCWarning(KGAPIDebug) << "Can't set upload size when the job is already running";
return;
}
d->totalUploadSize = size;
}
void FileAbstractResumableJob::write(const QByteArray &data)
{
qCDebug(KGAPIDebug) << "Received" << data.size() << "bytes to upload";
......@@ -232,12 +260,17 @@ void FileAbstractResumableJob::dispatchRequest(QNetworkAccessManager *accessMana
{
Q_UNUSED(contentType)
QNetworkReply *reply;
if (d->sessionState == Private::ReadyStart) {
accessManager->post(request, data);
reply = accessManager->post(request, data);
} else {
accessManager->put(request, data);
reply = accessManager->put(request, data);
}
if (d->isTotalSizeKnown()) {
connect(reply, &QNetworkReply::uploadProgress,
this, [this](qint64 bytesSent, qint64 totalBytes) {d->_k_uploadProgress(bytesSent, totalBytes); });
}
}
void FileAbstractResumableJob::handleReply(const QNetworkReply *reply,
......@@ -264,6 +297,20 @@ void FileAbstractResumableJob::handleReply(const QNetworkReply *reply,
break;
}
case Private::Started: {
// If during upload total size is declared via Content-Range header, Google will
// respond with 200 on the last chunk upload. The job is complete in that case.
if (d->isTotalSizeKnown() && replyCode == KGAPI2::OK) {
d->sessionState = Private::Completed;
const QString contentType = reply->header(QNetworkRequest::ContentTypeHeader).toString();
ContentType ct = Utils::stringToContentType(contentType);
if (ct == KGAPI2::JSON) {
d->metaData = File::fromJSON(rawData);
}
return;
}
// Google will continue answering ResumeIncomplete until the total upload size is declared
// in the Content-Range header or until last upload range not total upload size.
if (replyCode != KGAPI2::ResumeIncomplete) {
qCWarning(KGAPIDebug) << "Failed uploading chunk" << replyCode;
setError(KGAPI2::UnknownError);
......
......@@ -77,6 +77,12 @@ class KGAPIDRIVE_EXPORT FileAbstractResumableJob : public KGAPI2::Drive::FileAbs
*/
FilePtr metadata() const;
/**
* @brief Sets the total upload size and is required for progress reporting
* via the Job::progress() signal.
*/
void setUploadSize(int size);
/**
* @brief This function writes all the bytes in \p data to the upload session.
*
......@@ -156,6 +162,8 @@ class KGAPIDRIVE_EXPORT FileAbstractResumableJob : public KGAPI2::Drive::FileAbs
class Private;
QScopedPointer<Private> d;
friend class Private;
Q_PRIVATE_SLOT(d, void _k_uploadProgress(qint64 uploadedBytes, qint64 totalBytes))
};
} // namespace Drive
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment