mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Simple file transfer widget
This commit is contained in:
parent
8aacd21405
commit
ec69308efc
35
chatform.cpp
35
chatform.cpp
|
@ -2,6 +2,7 @@
|
||||||
#include "friend.h"
|
#include "friend.h"
|
||||||
#include "friendwidget.h"
|
#include "friendwidget.h"
|
||||||
#include "widget.h"
|
#include "widget.h"
|
||||||
|
#include "filetransfertwidget.h"
|
||||||
#include <QFont>
|
#include <QFont>
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
|
@ -67,6 +68,7 @@ ChatForm::ChatForm(Friend* chatFriend)
|
||||||
|
|
||||||
chatArea->setWidget(chatAreaWidget);
|
chatArea->setWidget(chatAreaWidget);
|
||||||
|
|
||||||
|
connect(Widget::getInstance()->getCore(), &Core::fileSendStarted, this, &ChatForm::startFileSend);
|
||||||
connect(sendButton, SIGNAL(clicked()), this, SLOT(onSendTriggered()));
|
connect(sendButton, SIGNAL(clicked()), this, SLOT(onSendTriggered()));
|
||||||
connect(fileButton, SIGNAL(clicked()), this, SLOT(onAttachClicked()));
|
connect(fileButton, SIGNAL(clicked()), this, SLOT(onAttachClicked()));
|
||||||
connect(msgEdit, SIGNAL(enterPressed()), this, SLOT(onSendTriggered()));
|
connect(msgEdit, SIGNAL(enterPressed()), this, SLOT(onSendTriggered()));
|
||||||
|
@ -166,8 +168,6 @@ void ChatForm::onAttachClicked()
|
||||||
file.close();
|
file.close();
|
||||||
QFileInfo fi(path);
|
QFileInfo fi(path);
|
||||||
|
|
||||||
// TODO: Show file send widget
|
|
||||||
|
|
||||||
emit sendFile(f->friendId, fi.fileName(), fileData);
|
emit sendFile(f->friendId, fi.fileName(), fileData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,3 +177,34 @@ void ChatForm::onSliderRangeChanged()
|
||||||
if (lockSliderToBottom)
|
if (lockSliderToBottom)
|
||||||
scroll->setValue(scroll->maximum());
|
scroll->setValue(scroll->maximum());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChatForm::startFileSend(ToxFile *file)
|
||||||
|
{
|
||||||
|
QLabel *author = new QLabel(Widget::getInstance()->getUsername()), *date = new QLabel();
|
||||||
|
QScrollBar* scroll = chatArea->verticalScrollBar();
|
||||||
|
lockSliderToBottom = scroll && scroll->value() == scroll->maximum();
|
||||||
|
author->setAlignment(Qt::AlignTop | Qt::AlignRight);
|
||||||
|
date->setAlignment(Qt::AlignTop);
|
||||||
|
QPalette pal;
|
||||||
|
pal.setColor(QPalette::WindowText, Qt::gray);
|
||||||
|
author->setPalette(pal);
|
||||||
|
if (previousName.isEmpty() || previousName != author->text())
|
||||||
|
{
|
||||||
|
if (curRow)
|
||||||
|
{
|
||||||
|
mainChatLayout->setRowStretch(curRow, 0);
|
||||||
|
mainChatLayout->addItem(new QSpacerItem(0,AUTHOR_CHANGE_SPACING),curRow,0,1,3);
|
||||||
|
curRow++;
|
||||||
|
}
|
||||||
|
mainChatLayout->addWidget(author, curRow, 0);
|
||||||
|
}
|
||||||
|
FileTransfertWidget* fileTrans = new FileTransfertWidget(file);
|
||||||
|
previousName = author->text();
|
||||||
|
mainChatLayout->addWidget(fileTrans, curRow, 1);
|
||||||
|
mainChatLayout->addWidget(date, curRow, 3);
|
||||||
|
mainChatLayout->setRowStretch(curRow+1, 1);
|
||||||
|
mainChatLayout->setRowStretch(curRow, 0);
|
||||||
|
curRow++;
|
||||||
|
|
||||||
|
connect(Widget::getInstance()->getCore(), &Core::fileTransferInfo, fileTrans, &FileTransfertWidget::onFileTransferInfo);
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "chattextedit.h"
|
#include "chattextedit.h"
|
||||||
#include "ui_widget.h"
|
#include "ui_widget.h"
|
||||||
|
#include "core.h"
|
||||||
|
|
||||||
// Spacing in px inserted when the author of the last message changes
|
// Spacing in px inserted when the author of the last message changes
|
||||||
#define AUTHOR_CHANGE_SPACING 5
|
#define AUTHOR_CHANGE_SPACING 5
|
||||||
|
@ -35,6 +36,9 @@ signals:
|
||||||
void sendMessage(int, QString);
|
void sendMessage(int, QString);
|
||||||
void sendFile(int32_t, QString, QByteArray);
|
void sendFile(int32_t, QString, QByteArray);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void startFileSend(ToxFile* file);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onSendTriggered();
|
void onSendTriggered();
|
||||||
void onAttachClicked();
|
void onAttachClicked();
|
||||||
|
|
45
core.cpp
45
core.cpp
|
@ -136,10 +136,26 @@ void Core::onFileSendRequestCallback(Tox* tox, int32_t friendnumber, uint8_t fil
|
||||||
qDebug() << "Core: File send request callback";
|
qDebug() << "Core: File send request callback";
|
||||||
}
|
}
|
||||||
void Core::onFileControlCallback(Tox* tox, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber,
|
void Core::onFileControlCallback(Tox* tox, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber,
|
||||||
uint8_t control_type, uint8_t *data, uint16_t length, void *userdata)
|
uint8_t control_type, uint8_t *data, uint16_t length, void *core)
|
||||||
{
|
{
|
||||||
|
ToxFile* file{nullptr};
|
||||||
|
for (ToxFile& f : fileSendQueue)
|
||||||
|
{
|
||||||
|
if (f.fileNum == filenumber)
|
||||||
|
{
|
||||||
|
file = &f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!file)
|
||||||
|
{
|
||||||
|
qWarning("Core::onFileControlCallback: No such file in queue");
|
||||||
|
// TODO: Warn the Friend* that we're aborting (emit)
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (control_type == TOX_FILECONTROL_ACCEPT && receive_send == 1)
|
if (control_type == TOX_FILECONTROL_ACCEPT && receive_send == 1)
|
||||||
{
|
{
|
||||||
|
emit static_cast<Core*>(core)->fileTransferAccepted(file);
|
||||||
qDebug() << "Core: File control callback, file accepted";
|
qDebug() << "Core: File control callback, file accepted";
|
||||||
int chunkSize = tox_file_data_size(tox, friendnumber);
|
int chunkSize = tox_file_data_size(tox, friendnumber);
|
||||||
if (chunkSize == -1)
|
if (chunkSize == -1)
|
||||||
|
@ -148,21 +164,6 @@ void Core::onFileControlCallback(Tox* tox, int32_t friendnumber, uint8_t receive
|
||||||
// TODO: Warn the Friend* that we're aborting (emit)
|
// TODO: Warn the Friend* that we're aborting (emit)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ToxFile* file{nullptr};
|
|
||||||
for (ToxFile& f : fileSendQueue)
|
|
||||||
{
|
|
||||||
if (f.fileNum == filenumber)
|
|
||||||
{
|
|
||||||
file = &f;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!file)
|
|
||||||
{
|
|
||||||
qWarning("Core::onFileControlCallback: No such file in queue");
|
|
||||||
// TODO: Warn the Friend* that we're aborting (emit)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
chunkSize = std::min(chunkSize, file->fileData.size());
|
chunkSize = std::min(chunkSize, file->fileData.size());
|
||||||
QByteArray toSend = file->fileData.mid(file->bytesSent, chunkSize);
|
QByteArray toSend = file->fileData.mid(file->bytesSent, chunkSize);
|
||||||
if (tox_file_send_data(tox, friendnumber, filenumber, (uint8_t*)toSend.data(), toSend.size()) == -1)
|
if (tox_file_send_data(tox, friendnumber, filenumber, (uint8_t*)toSend.data(), toSend.size()) == -1)
|
||||||
|
@ -178,7 +179,7 @@ void Core::onFileControlCallback(Tox* tox, int32_t friendnumber, uint8_t receive
|
||||||
{
|
{
|
||||||
qWarning("Core::onFileControlCallback: Transfer finished");
|
qWarning("Core::onFileControlCallback: Transfer finished");
|
||||||
tox_file_send_control(tox, friendnumber, 0, filenumber, TOX_FILECONTROL_FINISHED, nullptr, 0);
|
tox_file_send_control(tox, friendnumber, 0, filenumber, TOX_FILECONTROL_FINISHED, nullptr, 0);
|
||||||
// TODO: Notify the Friend* that we're done sending (emit)
|
emit static_cast<Core*>(core)->fileTransferFinished(file);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -186,6 +187,11 @@ void Core::onFileControlCallback(Tox* tox, int32_t friendnumber, uint8_t receive
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (receive_send == 1 && control_type == TOX_FILECONTROL_KILL)
|
||||||
|
{
|
||||||
|
file->status = ToxFile::STOPPED;
|
||||||
|
emit static_cast<Core*>(core)->fileTransferCancelled(file);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qDebug() << QString("Core: File control callback, receive_send=%1, control_type=%2")
|
qDebug() << QString("Core: File control callback, receive_send=%1, control_type=%2")
|
||||||
|
@ -262,7 +268,9 @@ void Core::sendFile(int32_t friendId, QString Filename, QByteArray data)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fileSendQueue.append(ToxFile(fileNum, friendId, data, fileName));
|
fileSendQueue.append(ToxFile(fileNum, friendId, data, fileName, ToxFile::SENDING));
|
||||||
|
|
||||||
|
emit fileSendStarted(&fileSendQueue.last());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::removeFriend(int friendId)
|
void Core::removeFriend(int friendId)
|
||||||
|
@ -355,6 +363,7 @@ void Core::fileHeartbeat()
|
||||||
{
|
{
|
||||||
if (file.status == ToxFile::TRANSMITTING)
|
if (file.status == ToxFile::TRANSMITTING)
|
||||||
{
|
{
|
||||||
|
emit fileTransferInfo(&file);
|
||||||
int chunkSize = tox_file_data_size(tox, file.friendId);
|
int chunkSize = tox_file_data_size(tox, file.friendId);
|
||||||
if (chunkSize == -1)
|
if (chunkSize == -1)
|
||||||
{
|
{
|
||||||
|
|
19
core.h
19
core.h
|
@ -50,9 +50,15 @@ struct ToxFile
|
||||||
TRANSMITTING
|
TRANSMITTING
|
||||||
};
|
};
|
||||||
|
|
||||||
ToxFile(int FileNum, int FriendId, QByteArray FileData, QByteArray FileName)
|
enum FileDirection : bool
|
||||||
|
{
|
||||||
|
SENDING,
|
||||||
|
RECEIVING
|
||||||
|
};
|
||||||
|
|
||||||
|
ToxFile(int FileNum, int FriendId, QByteArray FileData, QByteArray FileName, FileDirection Direction)
|
||||||
: fileNum(FileNum), friendId(FriendId), fileData{FileData},
|
: fileNum(FileNum), friendId(FriendId), fileData{FileData},
|
||||||
fileName{FileName}, bytesSent{0}, status{STOPPED} {}
|
fileName{FileName}, bytesSent{0}, status{STOPPED}, direction{Direction} {}
|
||||||
|
|
||||||
int fileNum;
|
int fileNum;
|
||||||
int friendId;
|
int friendId;
|
||||||
|
@ -60,6 +66,7 @@ struct ToxFile
|
||||||
QByteArray fileName;
|
QByteArray fileName;
|
||||||
long long bytesSent;
|
long long bytesSent;
|
||||||
FileStatus status;
|
FileStatus status;
|
||||||
|
FileDirection direction;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Core : public QObject
|
class Core : public QObject
|
||||||
|
@ -84,7 +91,7 @@ private:
|
||||||
static void onFileSendRequestCallback(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint64_t filesize,
|
static void onFileSendRequestCallback(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint64_t filesize,
|
||||||
uint8_t *filename, uint16_t filename_length, void *userdata);
|
uint8_t *filename, uint16_t filename_length, void *userdata);
|
||||||
static void onFileControlCallback(Tox *tox, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber,
|
static void onFileControlCallback(Tox *tox, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber,
|
||||||
uint8_t control_type, uint8_t *data, uint16_t length, void *userdata);
|
uint8_t control_type, uint8_t *data, uint16_t length, void *core);
|
||||||
static void onFileDataCallback(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata);
|
static void onFileDataCallback(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata);
|
||||||
|
|
||||||
void checkConnection();
|
void checkConnection();
|
||||||
|
@ -243,6 +250,12 @@ signals:
|
||||||
|
|
||||||
void failedToStart();
|
void failedToStart();
|
||||||
|
|
||||||
|
void fileSendStarted(ToxFile* file);
|
||||||
|
void fileTransferAccepted(ToxFile* file);
|
||||||
|
void fileTransferCancelled(ToxFile* file);
|
||||||
|
void fileTransferFinished(ToxFile* file);
|
||||||
|
void fileTransferPaused(ToxFile* file);
|
||||||
|
void fileTransferInfo(ToxFile* file);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CORE_HPP
|
#endif // CORE_HPP
|
||||||
|
|
95
filetransfertwidget.cpp
Normal file
95
filetransfertwidget.cpp
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
#include "filetransfertwidget.h"
|
||||||
|
|
||||||
|
FileTransfertWidget::FileTransfertWidget(ToxFile *File)
|
||||||
|
: file{File}, lastUpdate{QDateTime::currentDateTime()}, lastBytesSent{0}
|
||||||
|
{
|
||||||
|
pic=new QLabel(), filename=new QLabel(), size=new QLabel(), speed=new QLabel(), eta=new QLabel();
|
||||||
|
topright = new QPushButton(), bottomright = new QPushButton();
|
||||||
|
progress = new QProgressBar();
|
||||||
|
mainLayout = new QHBoxLayout(), textLayout = new QHBoxLayout();
|
||||||
|
infoLayout = new QVBoxLayout(), buttonLayout = new QVBoxLayout();
|
||||||
|
QFont prettysmall;
|
||||||
|
prettysmall.setPixelSize(10);
|
||||||
|
QPalette greybg;
|
||||||
|
greybg.setColor(QPalette::Window, Qt::gray);
|
||||||
|
setPalette(greybg);
|
||||||
|
setAutoFillBackground(true);
|
||||||
|
|
||||||
|
setFixedSize(250,50);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
filename->setText(file->fileName);
|
||||||
|
filename->setFont(prettysmall);
|
||||||
|
size->setText(getHumanReadableSize(file->fileData.size()));
|
||||||
|
size->setFont(prettysmall);
|
||||||
|
speed->setText("0B/s");
|
||||||
|
speed->setFont(prettysmall);
|
||||||
|
eta->setText("00:00");
|
||||||
|
eta->setFont(prettysmall);
|
||||||
|
progress->setValue(0);
|
||||||
|
|
||||||
|
topright->setIcon(QIcon("img/button icons/no_2x.png"));
|
||||||
|
if (file->direction == ToxFile::SENDING)
|
||||||
|
bottomright->setIcon(QIcon("img/button icons/pause_2x.png"));
|
||||||
|
else
|
||||||
|
bottomright->setIcon(QIcon("img/button icons/yes_2x.png"));
|
||||||
|
|
||||||
|
topright->setIconSize(QSize(25,25));
|
||||||
|
bottomright->setIconSize(QSize(25,25));
|
||||||
|
|
||||||
|
mainLayout->addWidget(pic);
|
||||||
|
mainLayout->addLayout(infoLayout);
|
||||||
|
mainLayout->addLayout(buttonLayout);
|
||||||
|
|
||||||
|
infoLayout->addWidget(filename);
|
||||||
|
infoLayout->addLayout(textLayout);
|
||||||
|
infoLayout->addWidget(progress);
|
||||||
|
|
||||||
|
textLayout->addWidget(size);
|
||||||
|
textLayout->addWidget(speed);
|
||||||
|
textLayout->addWidget(eta);
|
||||||
|
textLayout->setMargin(0);
|
||||||
|
textLayout->setSpacing(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FileTransfertWidget::getHumanReadableSize(int size)
|
||||||
|
{
|
||||||
|
static const char* suffix[] = {"B","kB","MB","GB","TB"};
|
||||||
|
int exp = 0;
|
||||||
|
if (size)
|
||||||
|
exp = std::min( (int) (log(size) / log(1000)), (int) (sizeof(suffix) / sizeof(suffix[0]) - 1));
|
||||||
|
return QString().setNum(size / pow(1000, exp),'g',3).append(suffix[exp]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileTransfertWidget::onFileTransferInfo(ToxFile* File)
|
||||||
|
{
|
||||||
|
if (File != file)
|
||||||
|
return;
|
||||||
|
QDateTime newtime = QDateTime::currentDateTime();
|
||||||
|
int timediff = lastUpdate.secsTo(newtime);
|
||||||
|
if (!timediff)
|
||||||
|
return;
|
||||||
|
int diff = File->bytesSent - lastBytesSent;
|
||||||
|
int rawspeed = diff / timediff;
|
||||||
|
speed->setText(getHumanReadableSize(rawspeed)+"/s");
|
||||||
|
size->setText(getHumanReadableSize(File->fileData.size()));
|
||||||
|
if (!rawspeed)
|
||||||
|
return;
|
||||||
|
int etaSecs = (File->fileData.size() - File->bytesSent) / rawspeed;
|
||||||
|
QTime etaTime(0,0);
|
||||||
|
etaTime = etaTime.addSecs(etaSecs);
|
||||||
|
eta->setText(etaTime.toString("mm:ss"));
|
||||||
|
progress->setValue(File->bytesSent*100/File->fileData.size());
|
||||||
|
lastUpdate = newtime;
|
||||||
|
lastBytesSent = File->bytesSent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileTransfertWidget::onFileTransferCancelled(ToxFile* File)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileTransfertWidget::onFileTransferFinished(ToxFile* File)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
41
filetransfertwidget.h
Normal file
41
filetransfertwidget.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#ifndef FILETRANSFERTWIDGET_H
|
||||||
|
#define FILETRANSFERTWIDGET_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QProgressBar>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
#include "core.h"
|
||||||
|
|
||||||
|
class ToxFile;
|
||||||
|
|
||||||
|
class FileTransfertWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
FileTransfertWidget(ToxFile* File);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onFileTransferInfo(ToxFile* File);
|
||||||
|
void onFileTransferCancelled(ToxFile* File);
|
||||||
|
void onFileTransferFinished(ToxFile* File);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString getHumanReadableSize(int size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLabel *pic, *filename, *size, *speed, *eta;
|
||||||
|
QPushButton *topright, *bottomright;
|
||||||
|
QProgressBar *progress;
|
||||||
|
ToxFile* file;
|
||||||
|
QHBoxLayout *mainLayout, *textLayout;
|
||||||
|
QVBoxLayout *infoLayout, *buttonLayout;
|
||||||
|
QDateTime lastUpdate;
|
||||||
|
long long lastBytesSent;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FILETRANSFERTWIDGET_H
|
|
@ -32,7 +32,8 @@ SOURCES += main.cpp\
|
||||||
groupwidget.cpp \
|
groupwidget.cpp \
|
||||||
group.cpp \
|
group.cpp \
|
||||||
grouplist.cpp \
|
grouplist.cpp \
|
||||||
groupchatform.cpp
|
groupchatform.cpp \
|
||||||
|
filetransfertwidget.cpp
|
||||||
|
|
||||||
HEADERS += widget.h \
|
HEADERS += widget.h \
|
||||||
core.h \
|
core.h \
|
||||||
|
@ -43,7 +44,6 @@ HEADERS += widget.h \
|
||||||
editablelabelwidget.h \
|
editablelabelwidget.h \
|
||||||
elidelabel.h \
|
elidelabel.h \
|
||||||
copyableelidelabel.h \
|
copyableelidelabel.h \
|
||||||
elidelabel.h \
|
|
||||||
esclineedit.h \
|
esclineedit.h \
|
||||||
friendlist.h \
|
friendlist.h \
|
||||||
friend.h \
|
friend.h \
|
||||||
|
@ -54,7 +54,8 @@ HEADERS += widget.h \
|
||||||
groupwidget.h \
|
groupwidget.h \
|
||||||
group.h \
|
group.h \
|
||||||
grouplist.h \
|
grouplist.h \
|
||||||
groupchatform.h
|
groupchatform.h \
|
||||||
|
filetransfertwidget.h
|
||||||
|
|
||||||
FORMS += widget.ui
|
FORMS += widget.ui
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user