forked from blue/squawk
basic error download/upload files handling, need more testing
This commit is contained in:
parent
bd07c49755
commit
4307262f6e
@ -70,6 +70,9 @@ void Core::NetworkAccess::start()
|
|||||||
{
|
{
|
||||||
if (!running) {
|
if (!running) {
|
||||||
manager = new QNetworkAccessManager();
|
manager = new QNetworkAccessManager();
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||||
|
manager->setTransferTimeout();
|
||||||
|
#endif
|
||||||
storage.open();
|
storage.open();
|
||||||
running = true;
|
running = true;
|
||||||
}
|
}
|
||||||
@ -99,31 +102,56 @@ void Core::NetworkAccess::onDownloadProgress(qint64 bytesReceived, qint64 bytesT
|
|||||||
qDebug() << "an error downloading" << url << ": the request had some progress but seems like no one is waiting for it, skipping";
|
qDebug() << "an error downloading" << url << ": the request had some progress but seems like no one is waiting for it, skipping";
|
||||||
} else {
|
} else {
|
||||||
Transfer* dwn = itr->second;
|
Transfer* dwn = itr->second;
|
||||||
|
if (dwn->success) {
|
||||||
qreal received = bytesReceived;
|
qreal received = bytesReceived;
|
||||||
qreal total = bytesTotal;
|
qreal total = bytesTotal;
|
||||||
qreal progress = received/total;
|
qreal progress = received/total;
|
||||||
dwn->progress = progress;
|
dwn->progress = progress;
|
||||||
emit loadFileProgress(dwn->messages, progress, false);
|
emit loadFileProgress(dwn->messages, progress, false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::NetworkAccess::onDownloadError(QNetworkReply::NetworkError code)
|
void Core::NetworkAccess::onDownloadError(QNetworkReply::NetworkError code)
|
||||||
{
|
{
|
||||||
|
qDebug() << "DEBUG: DOWNLOAD ERROR";
|
||||||
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
||||||
|
qDebug() << rpl->errorString();
|
||||||
QString url = rpl->url().toString();
|
QString url = rpl->url().toString();
|
||||||
std::map<QString, Transfer*>::const_iterator itr = downloads.find(url);
|
std::map<QString, Transfer*>::const_iterator itr = downloads.find(url);
|
||||||
if (itr == downloads.end()) {
|
if (itr == downloads.end()) {
|
||||||
qDebug() << "an error downloading" << url << ": the request is reporting an error but seems like no one is waiting for it, skipping";
|
qDebug() << "an error downloading" << url << ": the request is reporting an error but seems like no one is waiting for it, skipping";
|
||||||
} else {
|
} else {
|
||||||
QString errorText = getErrorText(code);
|
QString errorText = getErrorText(code);
|
||||||
if (errorText.size() > 0) {
|
//if (errorText.size() > 0) {
|
||||||
itr->second->success = false;
|
itr->second->success = false;
|
||||||
Transfer* dwn = itr->second;
|
Transfer* dwn = itr->second;
|
||||||
emit loadFileError(dwn->messages, errorText, false);
|
emit loadFileError(dwn->messages, errorText, false);
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Core::NetworkAccess::onDownloadSSLError(const QList<QSslError>& errors)
|
||||||
|
{
|
||||||
|
qDebug() << "DEBUG: DOWNLOAD SSL ERRORS";
|
||||||
|
for (const QSslError& err : errors) {
|
||||||
|
qDebug() << err.errorString();
|
||||||
|
}
|
||||||
|
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
||||||
|
QString url = rpl->url().toString();
|
||||||
|
std::map<QString, Transfer*>::const_iterator itr = downloads.find(url);
|
||||||
|
if (itr == downloads.end()) {
|
||||||
|
qDebug() << "an SSL error downloading" << url << ": the request is reporting an error but seems like no one is waiting for it, skipping";
|
||||||
|
} else {
|
||||||
|
//if (errorText.size() > 0) {
|
||||||
|
itr->second->success = false;
|
||||||
|
Transfer* dwn = itr->second;
|
||||||
|
emit loadFileError(dwn->messages, "SSL errors occured", false);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QString Core::NetworkAccess::getErrorText(QNetworkReply::NetworkError code)
|
QString Core::NetworkAccess::getErrorText(QNetworkReply::NetworkError code)
|
||||||
{
|
{
|
||||||
QString errorText("");
|
QString errorText("");
|
||||||
@ -146,7 +174,11 @@ QString Core::NetworkAccess::getErrorText(QNetworkReply::NetworkError code)
|
|||||||
errorText = "Connection was closed because it timed out";
|
errorText = "Connection was closed because it timed out";
|
||||||
break;
|
break;
|
||||||
case QNetworkReply::OperationCanceledError:
|
case QNetworkReply::OperationCanceledError:
|
||||||
//this means I closed it myself by abort() or close(), don't think I need to notify here
|
//this means I closed it myself by abort() or close()
|
||||||
|
//I don't call them directory, but this is the error code
|
||||||
|
//Qt returns when it can not resume donwload after the network failure
|
||||||
|
//or when the download is canceled by the timout;
|
||||||
|
errorText = "Connection lost";
|
||||||
break;
|
break;
|
||||||
case QNetworkReply::SslHandshakeFailedError:
|
case QNetworkReply::SslHandshakeFailedError:
|
||||||
errorText = "Security error"; //TODO need to handle sslErrors signal to get a better description here
|
errorText = "Security error"; //TODO need to handle sslErrors signal to get a better description here
|
||||||
@ -247,6 +279,7 @@ QString Core::NetworkAccess::getErrorText(QNetworkReply::NetworkError code)
|
|||||||
|
|
||||||
void Core::NetworkAccess::onDownloadFinished()
|
void Core::NetworkAccess::onDownloadFinished()
|
||||||
{
|
{
|
||||||
|
qDebug() << "DEBUG: DOWNLOAD FINISHED";
|
||||||
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
||||||
QString url = rpl->url().toString();
|
QString url = rpl->url().toString();
|
||||||
std::map<QString, Transfer*>::const_iterator itr = downloads.find(url);
|
std::map<QString, Transfer*>::const_iterator itr = downloads.find(url);
|
||||||
@ -256,11 +289,14 @@ void Core::NetworkAccess::onDownloadFinished()
|
|||||||
Transfer* dwn = itr->second;
|
Transfer* dwn = itr->second;
|
||||||
if (dwn->success) {
|
if (dwn->success) {
|
||||||
qDebug() << "download success for" << url;
|
qDebug() << "download success for" << url;
|
||||||
|
QString err;
|
||||||
QStringList hops = url.split("/");
|
QStringList hops = url.split("/");
|
||||||
QString fileName = hops.back();
|
QString fileName = hops.back();
|
||||||
QString jid;
|
QString jid;
|
||||||
if (dwn->messages.size() > 0) {
|
if (dwn->messages.size() > 0) {
|
||||||
jid = dwn->messages.front().jid;
|
jid = dwn->messages.front().jid;
|
||||||
|
} else {
|
||||||
|
qDebug() << "An attempt to save the file but it doesn't seem to belong to any message, download is definately going to be broken";
|
||||||
}
|
}
|
||||||
QString path = prepareDirectory(jid);
|
QString path = prepareDirectory(jid);
|
||||||
if (path.size() > 0) {
|
if (path.size() > 0) {
|
||||||
@ -274,15 +310,16 @@ void Core::NetworkAccess::onDownloadFinished()
|
|||||||
qDebug() << "file" << path << "was successfully downloaded";
|
qDebug() << "file" << path << "was successfully downloaded";
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "couldn't save file" << path;
|
qDebug() << "couldn't save file" << path;
|
||||||
path = QString();
|
err = "Error opening file to write:" + file.errorString();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
err = "Couldn't prepare a directory for file";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path.size() > 0) {
|
if (path.size() > 0) {
|
||||||
emit downloadFileComplete(dwn->messages, path);
|
emit downloadFileComplete(dwn->messages, path);
|
||||||
} else {
|
} else {
|
||||||
//TODO do I need to handle the failure here or it's already being handled in error?
|
emit loadFileError(dwn->messages, "Error saving file " + url + "; " + err, false);
|
||||||
//emit loadFileError(dwn->messages, path, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,6 +335,7 @@ void Core::NetworkAccess::startDownload(const std::list<Shared::MessageInfo>& ms
|
|||||||
QNetworkRequest req(url);
|
QNetworkRequest req(url);
|
||||||
dwn->reply = manager->get(req);
|
dwn->reply = manager->get(req);
|
||||||
connect(dwn->reply, &QNetworkReply::downloadProgress, this, &NetworkAccess::onDownloadProgress);
|
connect(dwn->reply, &QNetworkReply::downloadProgress, this, &NetworkAccess::onDownloadProgress);
|
||||||
|
connect(dwn->reply, &QNetworkReply::sslErrors, this, &NetworkAccess::onDownloadSSLError);
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||||
connect(dwn->reply, qOverload<QNetworkReply::NetworkError>(&QNetworkReply::errorOccurred), this, &NetworkAccess::onDownloadError);
|
connect(dwn->reply, qOverload<QNetworkReply::NetworkError>(&QNetworkReply::errorOccurred), this, &NetworkAccess::onDownloadError);
|
||||||
#else
|
#else
|
||||||
@ -317,11 +355,11 @@ void Core::NetworkAccess::onUploadError(QNetworkReply::NetworkError code)
|
|||||||
qDebug() << "an error uploading" << url << ": the request is reporting an error but there is no record of it being uploading, ignoring";
|
qDebug() << "an error uploading" << url << ": the request is reporting an error but there is no record of it being uploading, ignoring";
|
||||||
} else {
|
} else {
|
||||||
QString errorText = getErrorText(code);
|
QString errorText = getErrorText(code);
|
||||||
if (errorText.size() > 0) {
|
//if (errorText.size() > 0) {
|
||||||
itr->second->success = false;
|
itr->second->success = false;
|
||||||
Transfer* upl = itr->second;
|
Transfer* upl = itr->second;
|
||||||
emit loadFileError(upl->messages, errorText, true);
|
emit loadFileError(upl->messages, errorText, true);
|
||||||
}
|
//}
|
||||||
|
|
||||||
//TODO deletion?
|
//TODO deletion?
|
||||||
}
|
}
|
||||||
@ -360,12 +398,14 @@ void Core::NetworkAccess::onUploadProgress(qint64 bytesReceived, qint64 bytesTot
|
|||||||
qDebug() << "an error downloading" << url << ": the request had some progress but seems like no one is waiting for it, skipping";
|
qDebug() << "an error downloading" << url << ": the request had some progress but seems like no one is waiting for it, skipping";
|
||||||
} else {
|
} else {
|
||||||
Transfer* upl = itr->second;
|
Transfer* upl = itr->second;
|
||||||
|
if (upl->success) {
|
||||||
qreal received = bytesReceived;
|
qreal received = bytesReceived;
|
||||||
qreal total = bytesTotal;
|
qreal total = bytesTotal;
|
||||||
qreal progress = received/total;
|
qreal progress = received/total;
|
||||||
upl->progress = progress;
|
upl->progress = progress;
|
||||||
emit loadFileProgress(upl->messages, progress, true);
|
emit loadFileProgress(upl->messages, progress, true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Core::NetworkAccess::getFileRemoteUrl(const QString& path)
|
QString Core::NetworkAccess::getFileRemoteUrl(const QString& path)
|
||||||
|
@ -75,6 +75,7 @@ private:
|
|||||||
private slots:
|
private slots:
|
||||||
void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
|
void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
|
||||||
void onDownloadError(QNetworkReply::NetworkError code);
|
void onDownloadError(QNetworkReply::NetworkError code);
|
||||||
|
void onDownloadSSLError(const QList<QSslError> &errors);
|
||||||
void onDownloadFinished();
|
void onDownloadFinished();
|
||||||
void onUploadProgress(qint64 bytesReceived, qint64 bytesTotal);
|
void onUploadProgress(qint64 bytesReceived, qint64 bytesTotal);
|
||||||
void onUploadError(QNetworkReply::NetworkError code);
|
void onUploadError(QNetworkReply::NetworkError code);
|
||||||
|
@ -45,6 +45,8 @@ Models::MessageFeed::MessageFeed(const Element* ri, QObject* parent):
|
|||||||
syncState(incomplete),
|
syncState(incomplete),
|
||||||
uploads(),
|
uploads(),
|
||||||
downloads(),
|
downloads(),
|
||||||
|
failedDownloads(),
|
||||||
|
failedUploads(),
|
||||||
unreadMessages(new std::set<QString>()),
|
unreadMessages(new std::set<QString>()),
|
||||||
observersAmount(0)
|
observersAmount(0)
|
||||||
{
|
{
|
||||||
@ -142,6 +144,18 @@ void Models::MessageFeed::changeMessage(const QString& id, const QMap<QString, Q
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Err::const_iterator eitr = failedDownloads.find(id);
|
||||||
|
if (eitr != failedDownloads.end()) {
|
||||||
|
failedDownloads.erase(eitr);
|
||||||
|
changeRoles.insert(MessageRoles::Attach);
|
||||||
|
} else {
|
||||||
|
eitr = failedUploads.find(id);
|
||||||
|
if (eitr != failedUploads.end()) {
|
||||||
|
failedUploads.erase(eitr);
|
||||||
|
changeRoles.insert(MessageRoles::Attach);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QVector<int> cr;
|
QVector<int> cr;
|
||||||
for (MessageRoles role : changeRoles) {
|
for (MessageRoles role : changeRoles) {
|
||||||
cr.push_back(role);
|
cr.push_back(role);
|
||||||
@ -421,6 +435,7 @@ bool Models::MessageFeed::sentByMe(const Shared::Message& msg) const
|
|||||||
Models::Attachment Models::MessageFeed::fillAttach(const Shared::Message& msg) const
|
Models::Attachment Models::MessageFeed::fillAttach(const Shared::Message& msg) const
|
||||||
{
|
{
|
||||||
::Models::Attachment att;
|
::Models::Attachment att;
|
||||||
|
QString id = msg.getId();
|
||||||
|
|
||||||
att.localPath = msg.getAttachPath();
|
att.localPath = msg.getAttachPath();
|
||||||
att.remotePath = msg.getOutOfBandUrl();
|
att.remotePath = msg.getOutOfBandUrl();
|
||||||
@ -429,7 +444,12 @@ Models::Attachment Models::MessageFeed::fillAttach(const Shared::Message& msg) c
|
|||||||
if (att.localPath.size() == 0) {
|
if (att.localPath.size() == 0) {
|
||||||
att.state = none;
|
att.state = none;
|
||||||
} else {
|
} else {
|
||||||
Progress::const_iterator itr = uploads.find(msg.getId());
|
Err::const_iterator eitr = failedUploads.find(id);
|
||||||
|
if (eitr != failedUploads.end()) {
|
||||||
|
att.state = errorUpload;
|
||||||
|
att.error = eitr->second;
|
||||||
|
} else {
|
||||||
|
Progress::const_iterator itr = uploads.find(id);
|
||||||
if (itr == uploads.end()) {
|
if (itr == uploads.end()) {
|
||||||
att.state = local;
|
att.state = local;
|
||||||
} else {
|
} else {
|
||||||
@ -437,15 +457,22 @@ Models::Attachment Models::MessageFeed::fillAttach(const Shared::Message& msg) c
|
|||||||
att.progress = itr->second;
|
att.progress = itr->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (att.localPath.size() == 0) {
|
if (att.localPath.size() == 0) {
|
||||||
Progress::const_iterator itr = downloads.find(msg.getId());
|
Err::const_iterator eitr = failedDownloads.find(id);
|
||||||
|
if (eitr != failedDownloads.end()) {
|
||||||
|
att.state = errorDownload;
|
||||||
|
att.error = eitr->second;
|
||||||
|
} else {
|
||||||
|
Progress::const_iterator itr = downloads.find(id);
|
||||||
if (itr == downloads.end()) {
|
if (itr == downloads.end()) {
|
||||||
att.state = remote;
|
att.state = remote;
|
||||||
} else {
|
} else {
|
||||||
att.state = downloading;
|
att.state = downloading;
|
||||||
att.progress = itr->second;
|
att.progress = itr->second;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
att.state = ready;
|
att.state = ready;
|
||||||
}
|
}
|
||||||
@ -456,12 +483,19 @@ Models::Attachment Models::MessageFeed::fillAttach(const Shared::Message& msg) c
|
|||||||
|
|
||||||
void Models::MessageFeed::downloadAttachment(const QString& messageId)
|
void Models::MessageFeed::downloadAttachment(const QString& messageId)
|
||||||
{
|
{
|
||||||
|
bool notify = false;
|
||||||
|
Err::const_iterator eitr = failedDownloads.find(messageId);
|
||||||
|
if (eitr != failedDownloads.end()) {
|
||||||
|
failedDownloads.erase(eitr);
|
||||||
|
notify = true;
|
||||||
|
}
|
||||||
|
|
||||||
QModelIndex ind = modelIndexById(messageId);
|
QModelIndex ind = modelIndexById(messageId);
|
||||||
if (ind.isValid()) {
|
if (ind.isValid()) {
|
||||||
std::pair<Progress::iterator, bool> progressPair = downloads.insert(std::make_pair(messageId, 0));
|
std::pair<Progress::iterator, bool> progressPair = downloads.insert(std::make_pair(messageId, 0));
|
||||||
if (progressPair.second) { //Only to take action if we weren't already downloading it
|
if (progressPair.second) { //Only to take action if we weren't already downloading it
|
||||||
Shared::Message* msg = static_cast<Shared::Message*>(ind.internalPointer());
|
Shared::Message* msg = static_cast<Shared::Message*>(ind.internalPointer());
|
||||||
emit dataChanged(ind, ind, {MessageRoles::Attach});
|
notify = true;
|
||||||
emit fileDownloadRequest(msg->getOutOfBandUrl());
|
emit fileDownloadRequest(msg->getOutOfBandUrl());
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Attachment download for message with id" << messageId << "is already in progress, skipping";
|
qDebug() << "Attachment download for message with id" << messageId << "is already in progress, skipping";
|
||||||
@ -469,32 +503,55 @@ void Models::MessageFeed::downloadAttachment(const QString& messageId)
|
|||||||
} else {
|
} else {
|
||||||
qDebug() << "An attempt to download an attachment for the message that doesn't exist. ID:" << messageId;
|
qDebug() << "An attempt to download an attachment for the message that doesn't exist. ID:" << messageId;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void Models::MessageFeed::uploadAttachment(const QString& messageId)
|
if (notify) {
|
||||||
{
|
emit dataChanged(ind, ind, {MessageRoles::Attach});
|
||||||
qDebug() << "request to upload attachment of the message" << messageId;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Models::MessageFeed::registerUpload(const QString& messageId)
|
bool Models::MessageFeed::registerUpload(const QString& messageId)
|
||||||
{
|
{
|
||||||
return uploads.insert(std::make_pair(messageId, 0)).second;
|
bool success = uploads.insert(std::make_pair(messageId, 0)).second;
|
||||||
|
|
||||||
|
QVector<int> roles({});
|
||||||
|
Err::const_iterator eitr = failedUploads.find(messageId);
|
||||||
|
if (eitr != failedUploads.end()) {
|
||||||
|
failedUploads.erase(eitr);
|
||||||
|
roles.push_back(MessageRoles::Attach);
|
||||||
|
} else if (success) {
|
||||||
|
roles.push_back(MessageRoles::Attach);
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex ind = modelIndexById(messageId);
|
||||||
|
emit dataChanged(ind, ind, roles);
|
||||||
|
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Models::MessageFeed::fileProgress(const QString& messageId, qreal value, bool up)
|
void Models::MessageFeed::fileProgress(const QString& messageId, qreal value, bool up)
|
||||||
{
|
{
|
||||||
Progress* pr = 0;
|
Progress* pr = 0;
|
||||||
|
Err* err = 0;
|
||||||
if (up) {
|
if (up) {
|
||||||
pr = &uploads;
|
pr = &uploads;
|
||||||
|
err = &failedUploads;
|
||||||
} else {
|
} else {
|
||||||
pr = &downloads;
|
pr = &downloads;
|
||||||
|
err = &failedDownloads;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<int> roles({});
|
||||||
|
Err::const_iterator eitr = err->find(messageId);
|
||||||
|
if (eitr != err->end() && value != 1) { //like I want to clear this state when the download is started anew
|
||||||
|
err->erase(eitr);
|
||||||
|
roles.push_back(MessageRoles::Attach);
|
||||||
}
|
}
|
||||||
|
|
||||||
Progress::iterator itr = pr->find(messageId);
|
Progress::iterator itr = pr->find(messageId);
|
||||||
if (itr != pr->end()) {
|
if (itr != pr->end()) {
|
||||||
itr->second = value;
|
itr->second = value;
|
||||||
QModelIndex ind = modelIndexById(messageId);
|
QModelIndex ind = modelIndexById(messageId);
|
||||||
emit dataChanged(ind, ind); //the type of the attach didn't change, so, there is no need to relayout, there is no role in event
|
emit dataChanged(ind, ind, roles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,7 +562,29 @@ void Models::MessageFeed::fileComplete(const QString& messageId, bool up)
|
|||||||
|
|
||||||
void Models::MessageFeed::fileError(const QString& messageId, const QString& error, bool up)
|
void Models::MessageFeed::fileError(const QString& messageId, const QString& error, bool up)
|
||||||
{
|
{
|
||||||
//TODO
|
Err* failed;
|
||||||
|
Progress* loads;
|
||||||
|
if (up) {
|
||||||
|
failed = &failedUploads;
|
||||||
|
loads = &uploads;
|
||||||
|
} else {
|
||||||
|
failed = &failedDownloads;
|
||||||
|
loads = &downloads;
|
||||||
|
}
|
||||||
|
|
||||||
|
Progress::iterator pitr = loads->find(messageId);
|
||||||
|
if (pitr != loads->end()) {
|
||||||
|
loads->erase(pitr);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<Err::iterator, bool> pair = failed->insert(std::make_pair(messageId, error));
|
||||||
|
if (!pair.second) {
|
||||||
|
pair.first->second = error;
|
||||||
|
}
|
||||||
|
QModelIndex ind = modelIndexById(messageId);
|
||||||
|
if (ind.isValid()) {
|
||||||
|
emit dataChanged(ind, ind, {MessageRoles::Attach});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Models::MessageFeed::incrementObservers()
|
void Models::MessageFeed::incrementObservers()
|
||||||
@ -533,19 +612,18 @@ QModelIndex Models::MessageFeed::modelIndexById(const QString& id) const
|
|||||||
QModelIndex Models::MessageFeed::modelIndexByTime(const QString& id, const QDateTime& time) const
|
QModelIndex Models::MessageFeed::modelIndexByTime(const QString& id, const QDateTime& time) const
|
||||||
{
|
{
|
||||||
if (indexByTime.size() > 0) {
|
if (indexByTime.size() > 0) {
|
||||||
StorageByTime::const_iterator tItr = indexByTime.upper_bound(time);
|
StorageByTime::const_iterator tItr = indexByTime.lower_bound(time);
|
||||||
StorageByTime::const_iterator tBeg = indexByTime.begin();
|
StorageByTime::const_iterator tEnd = indexByTime.upper_bound(time);
|
||||||
StorageByTime::const_iterator tEnd = indexByTime.end();
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
while (tItr != tBeg) {
|
while (tItr != tEnd) {
|
||||||
if (tItr != tEnd && id == (*tItr)->getId()) {
|
if (id == (*tItr)->getId()) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
--tItr;
|
++tItr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found && tItr != tEnd && id == (*tItr)->getId()) {
|
if (found) {
|
||||||
int position = indexByTime.rank(tItr);
|
int position = indexByTime.rank(tItr);
|
||||||
return createIndex(position, 0, *tItr);
|
return createIndex(position, 0, *tItr);
|
||||||
}
|
}
|
||||||
@ -566,7 +644,7 @@ void Models::MessageFeed::reportLocalPathInvalid(const QString& messageId)
|
|||||||
|
|
||||||
emit localPathInvalid(msg->getAttachPath());
|
emit localPathInvalid(msg->getAttachPath());
|
||||||
|
|
||||||
//gonna change the message in current model right away, to prevent spam on each attemt to draw element
|
//gonna change the message in current model right away, to prevent spam on each attempt to draw element
|
||||||
QModelIndex index = modelIndexByTime(messageId, msg->getTime());
|
QModelIndex index = modelIndexByTime(messageId, msg->getTime());
|
||||||
msg->setAttachPath("");
|
msg->setAttachPath("");
|
||||||
|
|
||||||
|
@ -65,7 +65,6 @@ public:
|
|||||||
|
|
||||||
void responseArchive(const std::list<Shared::Message> list, bool last);
|
void responseArchive(const std::list<Shared::Message> list, bool last);
|
||||||
void downloadAttachment(const QString& messageId);
|
void downloadAttachment(const QString& messageId);
|
||||||
void uploadAttachment(const QString& messageId);
|
|
||||||
bool registerUpload(const QString& messageId);
|
bool registerUpload(const QString& messageId);
|
||||||
void reportLocalPathInvalid(const QString& messageId);
|
void reportLocalPathInvalid(const QString& messageId);
|
||||||
|
|
||||||
@ -148,12 +147,16 @@ private:
|
|||||||
SyncState syncState;
|
SyncState syncState;
|
||||||
|
|
||||||
typedef std::map<QString, qreal> Progress;
|
typedef std::map<QString, qreal> Progress;
|
||||||
|
typedef std::map<QString, QString> Err;
|
||||||
Progress uploads;
|
Progress uploads;
|
||||||
Progress downloads;
|
Progress downloads;
|
||||||
|
Err failedDownloads;
|
||||||
|
Err failedUploads;
|
||||||
|
|
||||||
std::set<QString>* unreadMessages;
|
std::set<QString>* unreadMessages;
|
||||||
uint16_t observersAmount;
|
uint16_t observersAmount;
|
||||||
|
|
||||||
|
|
||||||
static const QHash<int, QByteArray> roles;
|
static const QHash<int, QByteArray> roles;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -173,6 +176,7 @@ struct Attachment {
|
|||||||
qreal progress;
|
qreal progress;
|
||||||
QString localPath;
|
QString localPath;
|
||||||
QString remotePath;
|
QString remotePath;
|
||||||
|
QString error;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FeedItem {
|
struct FeedItem {
|
||||||
|
@ -394,16 +394,11 @@ void FeedView::setModel(QAbstractItemModel* p_model)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FeedView::onMessageButtonPushed(const QString& messageId, bool download)
|
void FeedView::onMessageButtonPushed(const QString& messageId)
|
||||||
{
|
{
|
||||||
if (specialModel) {
|
if (specialModel) {
|
||||||
Models::MessageFeed* feed = static_cast<Models::MessageFeed*>(model());
|
Models::MessageFeed* feed = static_cast<Models::MessageFeed*>(model());
|
||||||
|
|
||||||
if (download) {
|
|
||||||
feed->downloadAttachment(messageId);
|
feed->downloadAttachment(messageId);
|
||||||
} else {
|
|
||||||
feed->uploadAttachment(messageId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ protected slots:
|
|||||||
void rowsInserted(const QModelIndex & parent, int start, int end) override;
|
void rowsInserted(const QModelIndex & parent, int start, int end) override;
|
||||||
void verticalScrollbarValueChanged(int value) override;
|
void verticalScrollbarValueChanged(int value) override;
|
||||||
void dataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight, const QVector<int> & roles) override;
|
void dataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight, const QVector<int> & roles) override;
|
||||||
void onMessageButtonPushed(const QString& messageId, bool download);
|
void onMessageButtonPushed(const QString& messageId);
|
||||||
void onMessageInvalidPath(const QString& messageId);
|
void onMessageInvalidPath(const QString& messageId);
|
||||||
void onModelSyncStateChange(Models::MessageFeed::SyncState state);
|
void onModelSyncStateChange(Models::MessageFeed::SyncState state);
|
||||||
|
|
||||||
|
@ -137,19 +137,39 @@ void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio
|
|||||||
clearHelperWidget(data); //i can't imagine the situation where it's gonna be needed
|
clearHelperWidget(data); //i can't imagine the situation where it's gonna be needed
|
||||||
break; //but it's a possible performance problem
|
break; //but it's a possible performance problem
|
||||||
case Models::uploading:
|
case Models::uploading:
|
||||||
|
paintPreview(data, painter, opt);
|
||||||
case Models::downloading:
|
case Models::downloading:
|
||||||
paintBar(getBar(data), painter, data.sentByMe, opt);
|
paintBar(getBar(data), painter, data.sentByMe, opt);
|
||||||
break;
|
break;
|
||||||
case Models::remote:
|
case Models::remote:
|
||||||
case Models::local:
|
|
||||||
paintButton(getButton(data), painter, data.sentByMe, opt);
|
paintButton(getButton(data), painter, data.sentByMe, opt);
|
||||||
break;
|
break;
|
||||||
case Models::ready:
|
case Models::ready:
|
||||||
|
case Models::local:
|
||||||
clearHelperWidget(data);
|
clearHelperWidget(data);
|
||||||
paintPreview(data, painter, opt);
|
paintPreview(data, painter, opt);
|
||||||
break;
|
break;
|
||||||
case Models::errorDownload:
|
case Models::errorDownload: {
|
||||||
case Models::errorUpload:
|
paintButton(getButton(data), painter, data.sentByMe, opt);
|
||||||
|
painter->setFont(dateFont);
|
||||||
|
QColor q = painter->pen().color();
|
||||||
|
q.setAlpha(180);
|
||||||
|
painter->setPen(q);
|
||||||
|
painter->drawText(opt.rect, opt.displayAlignment, data.attach.error, &rect);
|
||||||
|
opt.rect.adjust(0, rect.height() + textMargin, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Models::errorUpload:{
|
||||||
|
clearHelperWidget(data);
|
||||||
|
paintPreview(data, painter, opt);
|
||||||
|
painter->setFont(dateFont);
|
||||||
|
QColor q = painter->pen().color();
|
||||||
|
q.setAlpha(180);
|
||||||
|
painter->setPen(q);
|
||||||
|
painter->drawText(opt.rect, opt.displayAlignment, data.attach.error, &rect);
|
||||||
|
opt.rect.adjust(0, rect.height() + textMargin, 0, 0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
painter->restore();
|
painter->restore();
|
||||||
@ -212,18 +232,24 @@ QSize MessageDelegate::sizeHint(const QStyleOptionViewItem& option, const QModel
|
|||||||
case Models::none:
|
case Models::none:
|
||||||
break;
|
break;
|
||||||
case Models::uploading:
|
case Models::uploading:
|
||||||
|
messageSize.rheight() += calculateAttachSize(attach.localPath, messageRect).height() + textMargin;
|
||||||
case Models::downloading:
|
case Models::downloading:
|
||||||
messageSize.rheight() += barHeight + textMargin;
|
messageSize.rheight() += barHeight + textMargin;
|
||||||
break;
|
break;
|
||||||
case Models::remote:
|
case Models::remote:
|
||||||
case Models::local:
|
|
||||||
messageSize.rheight() += buttonHeight + textMargin;
|
messageSize.rheight() += buttonHeight + textMargin;
|
||||||
break;
|
break;
|
||||||
case Models::ready:
|
case Models::ready:
|
||||||
|
case Models::local:
|
||||||
messageSize.rheight() += calculateAttachSize(attach.localPath, messageRect).height() + textMargin;
|
messageSize.rheight() += calculateAttachSize(attach.localPath, messageRect).height() + textMargin;
|
||||||
break;
|
break;
|
||||||
case Models::errorDownload:
|
case Models::errorDownload:
|
||||||
|
messageSize.rheight() += buttonHeight + textMargin;
|
||||||
|
messageSize.rheight() += dateMetrics.boundingRect(messageRect, Qt::TextWordWrap, attach.error).size().height() + textMargin;
|
||||||
|
break;
|
||||||
case Models::errorUpload:
|
case Models::errorUpload:
|
||||||
|
messageSize.rheight() += calculateAttachSize(attach.localPath, messageRect).height() + textMargin;
|
||||||
|
messageSize.rheight() += dateMetrics.boundingRect(messageRect, Qt::TextWordWrap, attach.error).size().height() + textMargin;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,15 +382,7 @@ QPushButton * MessageDelegate::getButton(const Models::FeedItem& data) const
|
|||||||
std::map<QString, FeedButton*>::const_iterator itr = buttons->find(data.id);
|
std::map<QString, FeedButton*>::const_iterator itr = buttons->find(data.id);
|
||||||
FeedButton* result = 0;
|
FeedButton* result = 0;
|
||||||
if (itr != buttons->end()) {
|
if (itr != buttons->end()) {
|
||||||
if (
|
|
||||||
(data.attach.state == Models::remote && itr->second->download) ||
|
|
||||||
(data.attach.state == Models::local && !itr->second->download)
|
|
||||||
) {
|
|
||||||
result = itr->second;
|
result = itr->second;
|
||||||
} else {
|
|
||||||
delete itr->second;
|
|
||||||
buttons->erase(itr);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
std::map<QString, QProgressBar*>::const_iterator barItr = bars->find(data.id);
|
std::map<QString, QProgressBar*>::const_iterator barItr = bars->find(data.id);
|
||||||
if (barItr != bars->end()) {
|
if (barItr != bars->end()) {
|
||||||
@ -376,13 +394,7 @@ QPushButton * MessageDelegate::getButton(const Models::FeedItem& data) const
|
|||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
result = new FeedButton();
|
result = new FeedButton();
|
||||||
result->messageId = data.id;
|
result->messageId = data.id;
|
||||||
if (data.attach.state == Models::remote) {
|
|
||||||
result->setText(QCoreApplication::translate("MessageLine", "Download"));
|
result->setText(QCoreApplication::translate("MessageLine", "Download"));
|
||||||
result->download = true;
|
|
||||||
} else {
|
|
||||||
result->setText(QCoreApplication::translate("MessageLine", "Upload"));
|
|
||||||
result->download = false;
|
|
||||||
}
|
|
||||||
buttons->insert(std::make_pair(data.id, result));
|
buttons->insert(std::make_pair(data.id, result));
|
||||||
connect(result, &QPushButton::clicked, this, &MessageDelegate::onButtonPushed);
|
connect(result, &QPushButton::clicked, this, &MessageDelegate::onButtonPushed);
|
||||||
}
|
}
|
||||||
@ -529,7 +541,7 @@ void MessageDelegate::endClearWidgets()
|
|||||||
void MessageDelegate::onButtonPushed() const
|
void MessageDelegate::onButtonPushed() const
|
||||||
{
|
{
|
||||||
FeedButton* btn = static_cast<FeedButton*>(sender());
|
FeedButton* btn = static_cast<FeedButton*>(sender());
|
||||||
emit buttonPushed(btn->messageId, btn->download);
|
emit buttonPushed(btn->messageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageDelegate::clearHelperWidget(const Models::FeedItem& data) const
|
void MessageDelegate::clearHelperWidget(const Models::FeedItem& data) const
|
||||||
|
@ -55,7 +55,7 @@ public:
|
|||||||
void beginClearWidgets();
|
void beginClearWidgets();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void buttonPushed(const QString& messageId, bool download) const;
|
void buttonPushed(const QString& messageId) const;
|
||||||
void invalidPath(const QString& messageId) const;
|
void invalidPath(const QString& messageId) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -77,7 +77,6 @@ private:
|
|||||||
class FeedButton : public QPushButton {
|
class FeedButton : public QPushButton {
|
||||||
public:
|
public:
|
||||||
QString messageId;
|
QString messageId;
|
||||||
bool download;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QFont bodyFont;
|
QFont bodyFont;
|
||||||
|
Loading…
Reference in New Issue
Block a user