basic error download/upload files handling, need more testing
This commit is contained in:
parent
bd07c49755
commit
4307262f6e
8 changed files with 206 additions and 77 deletions
|
@ -45,6 +45,8 @@ Models::MessageFeed::MessageFeed(const Element* ri, QObject* parent):
|
|||
syncState(incomplete),
|
||||
uploads(),
|
||||
downloads(),
|
||||
failedDownloads(),
|
||||
failedUploads(),
|
||||
unreadMessages(new std::set<QString>()),
|
||||
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;
|
||||
for (MessageRoles role : changeRoles) {
|
||||
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 att;
|
||||
QString id = msg.getId();
|
||||
|
||||
att.localPath = msg.getAttachPath();
|
||||
att.remotePath = msg.getOutOfBandUrl();
|
||||
|
@ -429,22 +444,34 @@ Models::Attachment Models::MessageFeed::fillAttach(const Shared::Message& msg) c
|
|||
if (att.localPath.size() == 0) {
|
||||
att.state = none;
|
||||
} else {
|
||||
Progress::const_iterator itr = uploads.find(msg.getId());
|
||||
if (itr == uploads.end()) {
|
||||
att.state = local;
|
||||
Err::const_iterator eitr = failedUploads.find(id);
|
||||
if (eitr != failedUploads.end()) {
|
||||
att.state = errorUpload;
|
||||
att.error = eitr->second;
|
||||
} else {
|
||||
att.state = uploading;
|
||||
att.progress = itr->second;
|
||||
Progress::const_iterator itr = uploads.find(id);
|
||||
if (itr == uploads.end()) {
|
||||
att.state = local;
|
||||
} else {
|
||||
att.state = uploading;
|
||||
att.progress = itr->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (att.localPath.size() == 0) {
|
||||
Progress::const_iterator itr = downloads.find(msg.getId());
|
||||
if (itr == downloads.end()) {
|
||||
att.state = remote;
|
||||
Err::const_iterator eitr = failedDownloads.find(id);
|
||||
if (eitr != failedDownloads.end()) {
|
||||
att.state = errorDownload;
|
||||
att.error = eitr->second;
|
||||
} else {
|
||||
att.state = downloading;
|
||||
att.progress = itr->second;
|
||||
Progress::const_iterator itr = downloads.find(id);
|
||||
if (itr == downloads.end()) {
|
||||
att.state = remote;
|
||||
} else {
|
||||
att.state = downloading;
|
||||
att.progress = itr->second;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
att.state = ready;
|
||||
|
@ -456,12 +483,19 @@ Models::Attachment Models::MessageFeed::fillAttach(const Shared::Message& msg) c
|
|||
|
||||
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);
|
||||
if (ind.isValid()) {
|
||||
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
|
||||
Shared::Message* msg = static_cast<Shared::Message*>(ind.internalPointer());
|
||||
emit dataChanged(ind, ind, {MessageRoles::Attach});
|
||||
notify = true;
|
||||
emit fileDownloadRequest(msg->getOutOfBandUrl());
|
||||
} else {
|
||||
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 {
|
||||
qDebug() << "An attempt to download an attachment for the message that doesn't exist. ID:" << messageId;
|
||||
}
|
||||
}
|
||||
|
||||
void Models::MessageFeed::uploadAttachment(const QString& messageId)
|
||||
{
|
||||
qDebug() << "request to upload attachment of the message" << messageId;
|
||||
|
||||
if (notify) {
|
||||
emit dataChanged(ind, ind, {MessageRoles::Attach});
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Progress* pr = 0;
|
||||
Err* err = 0;
|
||||
if (up) {
|
||||
pr = &uploads;
|
||||
err = &failedUploads;
|
||||
} else {
|
||||
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);
|
||||
if (itr != pr->end()) {
|
||||
itr->second = value;
|
||||
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)
|
||||
{
|
||||
//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()
|
||||
|
@ -533,19 +612,18 @@ QModelIndex Models::MessageFeed::modelIndexById(const QString& id) const
|
|||
QModelIndex Models::MessageFeed::modelIndexByTime(const QString& id, const QDateTime& time) const
|
||||
{
|
||||
if (indexByTime.size() > 0) {
|
||||
StorageByTime::const_iterator tItr = indexByTime.upper_bound(time);
|
||||
StorageByTime::const_iterator tBeg = indexByTime.begin();
|
||||
StorageByTime::const_iterator tEnd = indexByTime.end();
|
||||
StorageByTime::const_iterator tItr = indexByTime.lower_bound(time);
|
||||
StorageByTime::const_iterator tEnd = indexByTime.upper_bound(time);
|
||||
bool found = false;
|
||||
while (tItr != tBeg) {
|
||||
if (tItr != tEnd && id == (*tItr)->getId()) {
|
||||
while (tItr != tEnd) {
|
||||
if (id == (*tItr)->getId()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
--tItr;
|
||||
++tItr;
|
||||
}
|
||||
|
||||
if (found && tItr != tEnd && id == (*tItr)->getId()) {
|
||||
if (found) {
|
||||
int position = indexByTime.rank(tItr);
|
||||
return createIndex(position, 0, *tItr);
|
||||
}
|
||||
|
@ -566,7 +644,7 @@ void Models::MessageFeed::reportLocalPathInvalid(const QString& messageId)
|
|||
|
||||
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());
|
||||
msg->setAttachPath("");
|
||||
|
||||
|
|
|
@ -65,7 +65,6 @@ public:
|
|||
|
||||
void responseArchive(const std::list<Shared::Message> list, bool last);
|
||||
void downloadAttachment(const QString& messageId);
|
||||
void uploadAttachment(const QString& messageId);
|
||||
bool registerUpload(const QString& messageId);
|
||||
void reportLocalPathInvalid(const QString& messageId);
|
||||
|
||||
|
@ -148,12 +147,16 @@ private:
|
|||
SyncState syncState;
|
||||
|
||||
typedef std::map<QString, qreal> Progress;
|
||||
typedef std::map<QString, QString> Err;
|
||||
Progress uploads;
|
||||
Progress downloads;
|
||||
Err failedDownloads;
|
||||
Err failedUploads;
|
||||
|
||||
std::set<QString>* unreadMessages;
|
||||
uint16_t observersAmount;
|
||||
|
||||
|
||||
static const QHash<int, QByteArray> roles;
|
||||
};
|
||||
|
||||
|
@ -173,6 +176,7 @@ struct Attachment {
|
|||
qreal progress;
|
||||
QString localPath;
|
||||
QString remotePath;
|
||||
QString error;
|
||||
};
|
||||
|
||||
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) {
|
||||
Models::MessageFeed* feed = static_cast<Models::MessageFeed*>(model());
|
||||
|
||||
if (download) {
|
||||
feed->downloadAttachment(messageId);
|
||||
} else {
|
||||
feed->uploadAttachment(messageId);
|
||||
}
|
||||
feed->downloadAttachment(messageId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ protected slots:
|
|||
void rowsInserted(const QModelIndex & parent, int start, int end) override;
|
||||
void verticalScrollbarValueChanged(int value) 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 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
|
||||
break; //but it's a possible performance problem
|
||||
case Models::uploading:
|
||||
paintPreview(data, painter, opt);
|
||||
case Models::downloading:
|
||||
paintBar(getBar(data), painter, data.sentByMe, opt);
|
||||
break;
|
||||
case Models::remote:
|
||||
case Models::local:
|
||||
paintButton(getButton(data), painter, data.sentByMe, opt);
|
||||
break;
|
||||
case Models::ready:
|
||||
case Models::local:
|
||||
clearHelperWidget(data);
|
||||
paintPreview(data, painter, opt);
|
||||
break;
|
||||
case Models::errorDownload:
|
||||
case Models::errorUpload:
|
||||
case Models::errorDownload: {
|
||||
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;
|
||||
}
|
||||
painter->restore();
|
||||
|
@ -212,18 +232,24 @@ QSize MessageDelegate::sizeHint(const QStyleOptionViewItem& option, const QModel
|
|||
case Models::none:
|
||||
break;
|
||||
case Models::uploading:
|
||||
messageSize.rheight() += calculateAttachSize(attach.localPath, messageRect).height() + textMargin;
|
||||
case Models::downloading:
|
||||
messageSize.rheight() += barHeight + textMargin;
|
||||
break;
|
||||
case Models::remote:
|
||||
case Models::local:
|
||||
messageSize.rheight() += buttonHeight + textMargin;
|
||||
break;
|
||||
case Models::ready:
|
||||
case Models::local:
|
||||
messageSize.rheight() += calculateAttachSize(attach.localPath, messageRect).height() + textMargin;
|
||||
break;
|
||||
case Models::errorDownload:
|
||||
messageSize.rheight() += buttonHeight + textMargin;
|
||||
messageSize.rheight() += dateMetrics.boundingRect(messageRect, Qt::TextWordWrap, attach.error).size().height() + textMargin;
|
||||
break;
|
||||
case Models::errorUpload:
|
||||
messageSize.rheight() += calculateAttachSize(attach.localPath, messageRect).height() + textMargin;
|
||||
messageSize.rheight() += dateMetrics.boundingRect(messageRect, Qt::TextWordWrap, attach.error).size().height() + textMargin;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -356,15 +382,7 @@ QPushButton * MessageDelegate::getButton(const Models::FeedItem& data) const
|
|||
std::map<QString, FeedButton*>::const_iterator itr = buttons->find(data.id);
|
||||
FeedButton* result = 0;
|
||||
if (itr != buttons->end()) {
|
||||
if (
|
||||
(data.attach.state == Models::remote && itr->second->download) ||
|
||||
(data.attach.state == Models::local && !itr->second->download)
|
||||
) {
|
||||
result = itr->second;
|
||||
} else {
|
||||
delete itr->second;
|
||||
buttons->erase(itr);
|
||||
}
|
||||
result = itr->second;
|
||||
} else {
|
||||
std::map<QString, QProgressBar*>::const_iterator barItr = bars->find(data.id);
|
||||
if (barItr != bars->end()) {
|
||||
|
@ -376,13 +394,7 @@ QPushButton * MessageDelegate::getButton(const Models::FeedItem& data) const
|
|||
if (result == 0) {
|
||||
result = new FeedButton();
|
||||
result->messageId = data.id;
|
||||
if (data.attach.state == Models::remote) {
|
||||
result->setText(QCoreApplication::translate("MessageLine", "Download"));
|
||||
result->download = true;
|
||||
} else {
|
||||
result->setText(QCoreApplication::translate("MessageLine", "Upload"));
|
||||
result->download = false;
|
||||
}
|
||||
result->setText(QCoreApplication::translate("MessageLine", "Download"));
|
||||
buttons->insert(std::make_pair(data.id, result));
|
||||
connect(result, &QPushButton::clicked, this, &MessageDelegate::onButtonPushed);
|
||||
}
|
||||
|
@ -529,7 +541,7 @@ void MessageDelegate::endClearWidgets()
|
|||
void MessageDelegate::onButtonPushed() const
|
||||
{
|
||||
FeedButton* btn = static_cast<FeedButton*>(sender());
|
||||
emit buttonPushed(btn->messageId, btn->download);
|
||||
emit buttonPushed(btn->messageId);
|
||||
}
|
||||
|
||||
void MessageDelegate::clearHelperWidget(const Models::FeedItem& data) const
|
||||
|
|
|
@ -55,7 +55,7 @@ public:
|
|||
void beginClearWidgets();
|
||||
|
||||
signals:
|
||||
void buttonPushed(const QString& messageId, bool download) const;
|
||||
void buttonPushed(const QString& messageId) const;
|
||||
void invalidPath(const QString& messageId) const;
|
||||
|
||||
protected:
|
||||
|
@ -77,7 +77,6 @@ private:
|
|||
class FeedButton : public QPushButton {
|
||||
public:
|
||||
QString messageId;
|
||||
bool download;
|
||||
};
|
||||
|
||||
QFont bodyFont;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue