/* # Copyright (c) 2009, 2010 - OpenSLX Project, Computer Center University of # Freiburg # # This program is free software distributed under the GPL version 2. # See http://openslx.org/COPYING # # If you have any feedback please consult http://openslx.org/feedback and # send your suggestions, praise, or complaints to feedback@openslx.org # # General information about OpenSLX can be found at http://openslx.org/ # ----------------------------------------------------------------------------- # clientFileReceiveDialog.cpp # - filechooser and progress dialog # ----------------------------------------------------------------------------- */ #include "clientFileReceiveDialog.h" #include #include #include ClientFileReceiveDialog::ClientFileReceiveDialog(QTcpSocket *socket, QWidget *parent) : QDialog(parent) { setupUi(this); _file = NULL; _bytesToRead = 0; _socket = socket; connect(_socket, SIGNAL(readyRead()), this, SLOT(receiveHeader())); connect(_socket, SIGNAL(disconnected()), this, SLOT(close())); connect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError))); qDebug("[%s] New Connection: %s", metaObject()->className(), qPrintable(_socket->peerAddress().toString())); connect(this, SIGNAL(finished(int)), this, SLOT(deleteLater())); } ClientFileReceiveDialog::ClientFileReceiveDialog(QString const& sender, qulonglong transferID, QString const& filename, qulonglong size, OrgOpenslxPvsInterface* ifaceDBus, QWidget* parent) { setupUi(this); _transferID = transferID; _filename = filename; _ifaceDBus = ifaceDBus; _bytesToRead = size; _socket = 0; _file = 0; div = 1; while((size / div) > INT_MAX) { div <<= 1; } connect(ifaceDBus, SIGNAL(incomingMulticastTransferStarted(qulonglong)), SLOT(mcastTransferStarted(qulonglong))); connect(ifaceDBus, SIGNAL(incomingMulticastTransferProgress(qulonglong, qulonglong, qulonglong)), SLOT(mcastTransferProgress(qulonglong, qulonglong, qulonglong))); connect(ifaceDBus, SIGNAL(incomingMulticastTransferFinished(qulonglong)), SLOT(mcastTransferFinished(qulonglong))); connect(ifaceDBus, SIGNAL(incomingMulticastTransferFailed(qulonglong, QString)), SLOT(mcastTransferFailed(qulonglong, QString))); connect(cancelButton, SIGNAL(clicked()), SLOT(cancelTransfer())); qDebug("[%s] New multicast incoming transfer: %s from %s", metaObject()->className(), filename.toLocal8Bit().constData(), sender.toLocal8Bit().constData()); filenameLabel->setText(QFileInfo(filename).baseName()); labelNick->setText(sender); progressBar->setRange(0, 0); } ClientFileReceiveDialog::~ClientFileReceiveDialog() { if(_socket) _socket->deleteLater(); qDebug("[%s] Deleted!", metaObject()->className()); } //////////////////////////////////////////////////////////////////////////////// // Private void ClientFileReceiveDialog::receiveHeader() { // parse header QString header = QString::fromUtf8(_socket->readLine()); QStringList args = header.split(";"); QString nick = args[0]; QString filename = args[1]; _bytesToRead = args[2].toLongLong(); div = 1 + _bytesToRead / 1000000000; // bc. progressBar supports only int qDebug("[%s] Received header.", metaObject()->className()); // ask user QMessageBox::StandardButton result = QMessageBox::question(0, tr("PVS File Transfer"),tr("User '") + nick + tr("' would like to send you a file: ") + filename + " (" + formatSize(_bytesToRead) + ").", QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); if (result != QMessageBox::Ok) { sendAck(false); return; } // open file QString saveAs = QFileDialog::getSaveFileName(this, tr("Open File"), QDir::homePath() + QDir::separator() + filename, ""); if (saveAs == "") { sendAck(false); return; } _file = new QFile(saveAs); _file->open(QIODevice::WriteOnly); // gui filenameLabel->setText(saveAs); progressBar->setValue(0); progressBar->setMaximum(_bytesToRead/div); labelNick->setText(nick); labelB->setText(formatSize(_bytesToRead)); connect(cancelButton, SIGNAL(clicked()), this, SLOT(close())); sendAck(true); show(); } void ClientFileReceiveDialog::sendAck(bool b) { disconnect(_socket, SIGNAL(readyRead()), this, SLOT(receiveHeader())); if (b) { QString ack = QString("ok\n"); _socket->write(ack.toUtf8()); qDebug("[%s] Sending ack...", metaObject()->className()); connect(_socket, SIGNAL(readyRead()), this, SLOT(receiveFile())); } else { QString ack = QString("no\n"); _socket->write(ack.toUtf8()); qDebug("[%s] Sending nack!!!", metaObject()->className()); close(); } } void ClientFileReceiveDialog::receiveFile() { qint64 bytesRead = _file->write(_socket->readAll()); _bytesToRead -= bytesRead; progressBar->setValue(progressBar->value() + bytesRead/div); labelA->setText(formatSize(progressBar->value()*div)); } void ClientFileReceiveDialog::close() { if (_file && _file->isOpen()) { _file->flush(); _file->close(); qDebug("[%s] File closed.", metaObject()->className()); } if (_socket && _socket->isOpen()) { disconnect(_socket, SIGNAL(readyRead()), this, SLOT(receiveHeader())); disconnect(_socket, SIGNAL(readyRead()), this, SLOT(receiveFile())); disconnect(_socket, SIGNAL(disconnected()), this, SLOT(close())); disconnect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError))); _socket->disconnectFromHost(); qDebug("[%s] Connection closed.", metaObject()->className()); } disconnect(cancelButton, SIGNAL(clicked()), this, SLOT(close())); if (_bytesToRead == 0) { accept(); QMessageBox::information(0, tr("PVS - File Transfer"), tr("File Transfer complete.")); } else { reject(); QMessageBox::warning(0, tr("PVS - File Transfer"), tr("File Transfer canceled!")); } } void ClientFileReceiveDialog::error(QAbstractSocket::SocketError error) { if (error == QAbstractSocket::RemoteHostClosedError) qDebug("[%s] Socket closed by remote host.", metaObject()->className()); else qDebug("[%s] Socket error: %i", metaObject()->className(), error); close(); } void ClientFileReceiveDialog::mcastTransferStarted(qulonglong transferID) { if(transferID != _transferID) return; } void ClientFileReceiveDialog::mcastTransferProgress(qulonglong transferID, qulonglong bytes, qulonglong of) { if(transferID != _transferID) return; progressBar->setRange(0, of); progressBar->setValue(bytes); labelA->setText(formatSize(bytes)); labelB->setText(formatSize(of)); } void ClientFileReceiveDialog::mcastTransferFinished(qulonglong transferID) { if(transferID != _transferID) return; QString filename = QFileDialog::getSaveFileName(this, tr("Where should I save %1?").arg(_filename), _filename); QFile* file = new QFile(_filename); if(filename.isNull() || filename.isEmpty()) { file->remove(); } else { if(!file->rename(filename)) { QMessageBox::warning(this, tr("Could not rename file"), tr("Failed to rename %1 to %2").arg(_filename).arg(filename)); } } accept(); deleteLater(); } void ClientFileReceiveDialog::mcastTransferFailed(qulonglong transferID, QString reason) { if(transferID != _transferID) return; QMessageBox::warning(this, tr("File transfer failed"), tr("File transfer failed for the following reason:\n%1").arg(reason)); reject(); deleteLater(); } void ClientFileReceiveDialog::cancelTransfer() { _ifaceDBus->cancelIncomingMulticastTransfer(_transferID); } QString ClientFileReceiveDialog::formatSize(qint64 size) { if (size >= 1000000000) // GB return QString("%1GB").arg((qreal)size / 1000000000, 0, 'f',1); else if (size >= 1000000) // MB return QString("%1MB").arg((qreal)size / 1000000, 0, 'f',1); else if (size >= 1000) // KB return QString("%1KB").arg((qreal)size / 1000, 0, 'f',1); else // B return QString("%1B").arg((qreal)size, 0, 'f',1); }