fileUpload #30
@ -14,6 +14,15 @@ include_directories(.)
|
||||
find_package(Qt5Widgets CONFIG REQUIRED)
|
||||
find_package(Qt5LinguistTools)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-g -Wall -Wextra")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
|
||||
message("Build type: ${CMAKE_BUILD_TYPE}")
|
||||
|
||||
|
||||
set(squawk_SRC
|
||||
main.cpp
|
||||
global.cpp
|
||||
|
46
README.md
46
README.md
@ -8,22 +8,52 @@ A compact XMPP desktop messenger
|
||||
- uuid _(usually included in some other package, for example it's ***libutil-linux*** in archlinux)_
|
||||
- lmdb
|
||||
- CMake 3.0 or higher
|
||||
- qxmpp 1.1.0 or higher
|
||||
|
||||
### Getting
|
||||
|
||||
The easiest way to get the Squawk is to install it from AUR (if you use Archlinux like distribution)
|
||||
|
||||
Here is the [link](https://aur.archlinux.org/packages/squawk/) for the AUR package
|
||||
|
||||
You can also install it from console if you use some AUR wrapper. Here what it's going to look like with *pacaur*
|
||||
|
||||
```
|
||||
$ pacaur -S squawk
|
||||
```
|
||||
|
||||
### Building
|
||||
|
||||
You can also clone the repo and build it from source
|
||||
|
||||
Squawk requires Qt with SSL enabled. It uses CMake as build system.
|
||||
|
||||
Squawk uses upstream version of QXmpp library so first we need to pull it
|
||||
There are two ways to build, it depends whether you have qxmpp installed in your system
|
||||
|
||||
#### Building with system qxmpp
|
||||
|
||||
Here is what you do
|
||||
|
||||
```
|
||||
git submodule update --init --recursive
|
||||
$ git clone https://git.macaw.me/blue/squawk
|
||||
$ cd squawk
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ cmake ..
|
||||
$ cmake --build .
|
||||
```
|
||||
Then create a folder for the build, go there and build the project using CMake
|
||||
|
||||
|
||||
#### Building with bundled qxmpp
|
||||
|
||||
Here is what you do
|
||||
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
cmake --build .
|
||||
$ git clone --recurse-submodules https://git.macaw.me/blue/squawk
|
||||
$ cd squawk
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ cmake .. -D SYSTEM_QXMPP=False
|
||||
$ cmake --build .
|
||||
```
|
||||
|
||||
## License
|
||||
|
132
core/account.cpp
132
core/account.cpp
@ -23,7 +23,7 @@
|
||||
|
||||
using namespace Core;
|
||||
|
||||
Account::Account(const QString& p_login, const QString& p_server, const QString& p_password, const QString& p_name, QObject* parent):
|
||||
Account::Account(const QString& p_login, const QString& p_server, const QString& p_password, const QString& p_name, NetworkAccess* p_net, QObject* parent):
|
||||
QObject(parent),
|
||||
name(p_name),
|
||||
achiveQueries(),
|
||||
@ -38,15 +38,20 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
|
||||
bm(new QXmppBookmarkManager()),
|
||||
rm(client.findExtension<QXmppRosterManager>()),
|
||||
vm(client.findExtension<QXmppVCardManager>()),
|
||||
um(new QXmppUploadRequestManager()),
|
||||
dm(client.findExtension<QXmppDiscoveryManager>()),
|
||||
contacts(),
|
||||
conferences(),
|
||||
maxReconnectTimes(0),
|
||||
reconnectTimes(0),
|
||||
queuedContacts(),
|
||||
outOfRosterContacts(),
|
||||
pendingMessages(),
|
||||
uploadingSlotsQueue(),
|
||||
avatarHash(),
|
||||
avatarType(),
|
||||
ownVCardRequestInProgress(false)
|
||||
ownVCardRequestInProgress(false),
|
||||
network(p_net)
|
||||
{
|
||||
config.setUser(p_login);
|
||||
config.setDomain(p_server);
|
||||
@ -85,6 +90,16 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
|
||||
QObject::connect(vm, &QXmppVCardManager::vCardReceived, this, &Account::onVCardReceived);
|
||||
//QObject::connect(&vm, &QXmppVCardManager::clientVCardReceived, this, &Account::onOwnVCardReceived); //for some reason it doesn't work, launching from common handler
|
||||
|
||||
client.addExtension(um);
|
||||
QObject::connect(um, &QXmppUploadRequestManager::slotReceived, this, &Account::onUploadSlotReceived);
|
||||
QObject::connect(um, &QXmppUploadRequestManager::requestFailed, this, &Account::onUploadSlotRequestFailed);
|
||||
|
||||
QObject::connect(dm, &QXmppDiscoveryManager::itemsReceived, this, &Account::onDiscoveryItemsReceived);
|
||||
QObject::connect(dm, &QXmppDiscoveryManager::infoReceived, this, &Account::onDiscoveryInfoReceived);
|
||||
|
||||
QObject::connect(network, &NetworkAccess::uploadFileComplete, this, &Account::onFileUploaded);
|
||||
QObject::connect(network, &NetworkAccess::uploadFileError, this, &Account::onFileUploadError);
|
||||
|
||||
QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
|
||||
path += "/" + name;
|
||||
QDir dir(path);
|
||||
@ -133,6 +148,9 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
|
||||
|
||||
Account::~Account()
|
||||
{
|
||||
QObject::disconnect(network, &NetworkAccess::uploadFileComplete, this, &Account::onFileUploaded);
|
||||
QObject::disconnect(network, &NetworkAccess::uploadFileError, this, &Account::onFileUploadError);
|
||||
|
||||
for (std::map<QString, Contact*>::const_iterator itr = contacts.begin(), end = contacts.end(); itr != end; ++itr) {
|
||||
delete itr->second;
|
||||
}
|
||||
@ -141,6 +159,7 @@ Account::~Account()
|
||||
delete itr->second;
|
||||
}
|
||||
|
||||
delete um;
|
||||
delete bm;
|
||||
delete mm;
|
||||
delete am;
|
||||
@ -181,6 +200,7 @@ void Core::Account::onClientConnected()
|
||||
reconnectTimes = maxReconnectTimes;
|
||||
state = Shared::connected;
|
||||
cm->setCarbonsEnabled(true);
|
||||
dm->requestItems(getServer());
|
||||
emit connectionStateChanged(state);
|
||||
} else {
|
||||
qDebug() << "Something weird had happened - xmpp client reported about successful connection but account wasn't in" << state << "state";
|
||||
@ -598,6 +618,7 @@ void Core::Account::sendMessage(const Shared::Message& data)
|
||||
QXmppMessage msg(data.getFrom(), data.getTo(), data.getBody(), data.getThread());
|
||||
msg.setId(data.getId());
|
||||
msg.setType(static_cast<QXmppMessage::Type>(data.getType())); //it is safe here, my type is compatible
|
||||
msg.setOutOfBandUrl(data.getOutOfBandUrl());
|
||||
|
||||
RosterItem* ri = 0;
|
||||
std::map<QString, Contact*>::const_iterator itr = contacts.find(data.getPenPalJid());
|
||||
@ -623,6 +644,50 @@ void Core::Account::sendMessage(const Shared::Message& data)
|
||||
}
|
||||
}
|
||||
|
||||
void Core::Account::sendMessage(const Shared::Message& data, const QString& path)
|
||||
{
|
||||
if (state == Shared::connected) {
|
||||
QString url = network->getFileRemoteUrl(path);
|
||||
if (url.size() != 0) {
|
||||
sendMessageWithLocalUploadedFile(data, url);
|
||||
} else {
|
||||
if (network->isUploading(path, data.getId())) {
|
||||
pendingMessages.emplace(data.getId(), data);
|
||||
} else {
|
||||
if (um->serviceFound()) {
|
||||
QFileInfo file(path);
|
||||
if (file.exists() && file.isReadable()) {
|
||||
uploadingSlotsQueue.emplace_back(path, data);
|
||||
if (uploadingSlotsQueue.size() == 1) {
|
||||
um->requestUploadSlot(file);
|
||||
}
|
||||
} else {
|
||||
emit onFileUploadError(data.getId(), "Uploading file dissapeared or your system user has no permission to read it");
|
||||
qDebug() << "Requested upload slot in account" << name << "for file" << path << "but the file doesn't exist or is not readable";
|
||||
}
|
||||
} else {
|
||||
emit onFileUploadError(data.getId(), "Your server doesn't support file upload service, or it's prohibited for your account");
|
||||
qDebug() << "Requested upload slot in account" << name << "for file" << path << "but upload manager didn't discover any upload services";
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
emit onFileUploadError(data.getId(), "Account is offline or reconnecting");
|
||||
qDebug() << "An attempt to send message with not connected account " << name << ", skipping";
|
||||
}
|
||||
}
|
||||
|
||||
void Core::Account::sendMessageWithLocalUploadedFile(Shared::Message msg, const QString& url)
|
||||
{
|
||||
msg.setOutOfBandUrl(url);
|
||||
if (msg.getBody().size() == 0) {
|
||||
msg.setBody(url);
|
||||
}
|
||||
sendMessage(msg);
|
||||
//TODO removal/progress update
|
||||
}
|
||||
|
||||
|
||||
void Core::Account::onCarbonMessageReceived(const QXmppMessage& msg)
|
||||
{
|
||||
handleChatMessage(msg, false, true);
|
||||
@ -1551,3 +1616,66 @@ void Core::Account::uploadVCard(const Shared::VCard& card)
|
||||
vm->setClientVCard(iq);
|
||||
onOwnVCardReceived(iq);
|
||||
}
|
||||
|
||||
void Core::Account::onUploadSlotReceived(const QXmppHttpUploadSlotIq& slot)
|
||||
{
|
||||
if (uploadingSlotsQueue.size() == 0) {
|
||||
qDebug() << "HTTP Upload manager of account" << name << "reports about success requesting upload slot, but none was requested";
|
||||
} else {
|
||||
const std::pair<QString, Shared::Message>& pair = uploadingSlotsQueue.front();
|
||||
const QString& mId = pair.second.getId();
|
||||
network->uploadFile(mId, pair.first, slot.putUrl(), slot.getUrl(), slot.putHeaders());
|
||||
pendingMessages.emplace(mId, pair.second);
|
||||
uploadingSlotsQueue.pop_front();
|
||||
|
||||
if (uploadingSlotsQueue.size() > 0) {
|
||||
um->requestUploadSlot(uploadingSlotsQueue.front().first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Core::Account::onUploadSlotRequestFailed(const QXmppHttpUploadRequestIq& request)
|
||||
{
|
||||
if (uploadingSlotsQueue.size() == 0) {
|
||||
qDebug() << "HTTP Upload manager of account" << name << "reports about an error requesting upload slot, but none was requested";
|
||||
qDebug() << request.error().text();
|
||||
} else {
|
||||
const std::pair<QString, Shared::Message>& pair = uploadingSlotsQueue.front();
|
||||
qDebug() << "Error requesting upload slot for file" << pair.first << "in account" << name << ":" << request.error().text();
|
||||
emit uploadFileError(pair.second.getId(), "Error requesting slot to upload file: " + request.error().text());
|
||||
|
||||
if (uploadingSlotsQueue.size() > 0) {
|
||||
um->requestUploadSlot(uploadingSlotsQueue.front().first);
|
||||
}
|
||||
uploadingSlotsQueue.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
void Core::Account::onFileUploaded(const QString& messageId, const QString& url)
|
||||
{
|
||||
std::map<QString, Shared::Message>::const_iterator itr = pendingMessages.find(messageId);
|
||||
if (itr != pendingMessages.end()) {
|
||||
sendMessageWithLocalUploadedFile(itr->second, url);
|
||||
pendingMessages.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
void Core::Account::onFileUploadError(const QString& messageId, const QString& errMsg)
|
||||
{
|
||||
std::map<QString, Shared::Message>::const_iterator itr = pendingMessages.find(messageId);
|
||||
if (itr != pendingMessages.end()) {
|
||||
pendingMessages.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
void Core::Account::onDiscoveryItemsReceived(const QXmppDiscoveryIq& items)
|
||||
{
|
||||
for (QXmppDiscoveryIq::Item item : items.items()) {
|
||||
dm->requestInfo(item.jid());
|
||||
}
|
||||
}
|
||||
|
||||
void Core::Account::onDiscoveryInfoReceived(const QXmppDiscoveryIq& info)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -31,16 +31,20 @@
|
||||
|
||||
#include <QXmppRosterManager.h>
|
||||
#include <QXmppCarbonManager.h>
|
||||
#include <QXmppDiscoveryManager.h>
|
||||
#include <QXmppMamManager.h>
|
||||
#include <QXmppMucManager.h>
|
||||
#include <QXmppClient.h>
|
||||
#include <QXmppBookmarkManager.h>
|
||||
#include <QXmppBookmarkSet.h>
|
||||
#include <QXmppUploadRequestManager.h>
|
||||
#include <QXmppHttpUploadIq.h>
|
||||
#include <QXmppVCardIq.h>
|
||||
#include <QXmppVCardManager.h>
|
||||
#include "../global.h"
|
||||
#include "global.h"
|
||||
#include "contact.h"
|
||||
#include "conference.h"
|
||||
#include "networkaccess.h"
|
||||
|
||||
namespace Core
|
||||
{
|
||||
@ -49,7 +53,7 @@ class Account : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Account(const QString& p_login, const QString& p_server, const QString& p_password, const QString& p_name, QObject* parent = 0);
|
||||
Account(const QString& p_login, const QString& p_server, const QString& p_password, const QString& p_name, NetworkAccess* p_net, QObject* parent = 0);
|
||||
~Account();
|
||||
|
||||
void connect();
|
||||
@ -73,6 +77,7 @@ public:
|
||||
void setAvailability(Shared::Availability avail);
|
||||
QString getFullJid() const;
|
||||
void sendMessage(const Shared::Message& data);
|
||||
void sendMessage(const Shared::Message& data, const QString& path);
|
||||
void requestArchive(const QString& jid, int count, const QString& before);
|
||||
void setReconnectTimes(unsigned int times);
|
||||
void subscribeToContact(const QString& jid, const QString& reason);
|
||||
@ -112,6 +117,8 @@ signals:
|
||||
void changeRoomParticipant(const QString& jid, const QString& nickName, const QMap<QString, QVariant>& data);
|
||||
void removeRoomParticipant(const QString& jid, const QString& nickName);
|
||||
void receivedVCard(const QString& jid, const Shared::VCard& card);
|
||||
void uploadFile(const QFileInfo& file, const QUrl& set, const QUrl& get, QMap<QString, QString> headers);
|
||||
void uploadFileError(const QString& messageId, const QString& error);
|
||||
|
||||
private:
|
||||
QString name;
|
||||
@ -127,6 +134,8 @@ private:
|
||||
QXmppBookmarkManager* bm;
|
||||
QXmppRosterManager* rm;
|
||||
QXmppVCardManager* vm;
|
||||
QXmppUploadRequestManager* um;
|
||||
QXmppDiscoveryManager* dm;
|
||||
std::map<QString, Contact*> contacts;
|
||||
std::map<QString, Conference*> conferences;
|
||||
unsigned int maxReconnectTimes;
|
||||
@ -135,10 +144,13 @@ private:
|
||||
std::map<QString, QString> queuedContacts;
|
||||
std::set<QString> outOfRosterContacts;
|
||||
std::set<QString> pendingVCardRequests;
|
||||
std::map<QString, Shared::Message> pendingMessages;
|
||||
std::deque<std::pair<QString, Shared::Message>> uploadingSlotsQueue;
|
||||
|
||||
QString avatarHash;
|
||||
QString avatarType;
|
||||
bool ownVCardRequestInProgress;
|
||||
NetworkAccess* network;
|
||||
|
||||
private slots:
|
||||
void onClientConnected();
|
||||
@ -183,6 +195,13 @@ private slots:
|
||||
|
||||
void onVCardReceived(const QXmppVCardIq& card);
|
||||
void onOwnVCardReceived(const QXmppVCardIq& card);
|
||||
|
||||
void onUploadSlotReceived(const QXmppHttpUploadSlotIq& slot);
|
||||
void onUploadSlotRequestFailed(const QXmppHttpUploadRequestIq& request);
|
||||
void onFileUploaded(const QString& messageId, const QString& url);
|
||||
void onFileUploadError(const QString& messageId, const QString& errMsg);
|
||||
void onDiscoveryItemsReceived (const QXmppDiscoveryIq& items);
|
||||
void onDiscoveryInfoReceived (const QXmppDiscoveryIq& info);
|
||||
|
||||
private:
|
||||
void addedAccount(const QString &bareJid);
|
||||
@ -199,7 +218,7 @@ private:
|
||||
void logMessage(const QXmppMessage& msg, const QString& reason = "Message wasn't handled: ");
|
||||
void storeConferences();
|
||||
void clearConferences();
|
||||
|
||||
void sendMessageWithLocalUploadedFile(Shared::Message msg, const QString& url);
|
||||
};
|
||||
|
||||
void initializeVCard(Shared::VCard& vCard, const QXmppVCardIq& card);
|
||||
|
@ -23,7 +23,8 @@ Core::NetworkAccess::NetworkAccess(QObject* parent):
|
||||
running(false),
|
||||
manager(0),
|
||||
files("files"),
|
||||
downloads()
|
||||
downloads(),
|
||||
uploads()
|
||||
{
|
||||
}
|
||||
|
||||
@ -34,9 +35,9 @@ Core::NetworkAccess::~NetworkAccess()
|
||||
|
||||
void Core::NetworkAccess::fileLocalPathRequest(const QString& messageId, const QString& url)
|
||||
{
|
||||
std::map<QString, Download*>::iterator itr = downloads.find(url);
|
||||
std::map<QString, Transfer*>::iterator itr = downloads.find(url);
|
||||
if (itr != downloads.end()) {
|
||||
Download* dwn = itr->second;
|
||||
Transfer* dwn = itr->second;
|
||||
std::set<QString>::const_iterator mItr = dwn->messages.find(messageId);
|
||||
if (mItr == dwn->messages.end()) {
|
||||
dwn->messages.insert(messageId);
|
||||
@ -63,9 +64,9 @@ void Core::NetworkAccess::fileLocalPathRequest(const QString& messageId, const Q
|
||||
|
||||
void Core::NetworkAccess::downladFileRequest(const QString& messageId, const QString& url)
|
||||
{
|
||||
std::map<QString, Download*>::iterator itr = downloads.find(url);
|
||||
std::map<QString, Transfer*>::iterator itr = downloads.find(url);
|
||||
if (itr != downloads.end()) {
|
||||
Download* dwn = itr->second;
|
||||
Transfer* dwn = itr->second;
|
||||
std::set<QString>::const_iterator mItr = dwn->messages.find(messageId);
|
||||
if (mItr == dwn->messages.end()) {
|
||||
dwn->messages.insert(messageId);
|
||||
@ -85,7 +86,7 @@ void Core::NetworkAccess::downladFileRequest(const QString& messageId, const QSt
|
||||
startDownload(messageId, url);
|
||||
} catch (Archive::Unknown e) {
|
||||
qDebug() << "Error requesting file path:" << e.what();
|
||||
startDownload(messageId, url);
|
||||
emit downloadFileError(messageId, QString("Database error: ") + e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -107,7 +108,7 @@ void Core::NetworkAccess::stop()
|
||||
manager = 0;
|
||||
running = false;
|
||||
|
||||
for (std::map<QString, Download*>::const_iterator itr = downloads.begin(), end = downloads.end(); itr != end; ++itr) {
|
||||
for (std::map<QString, Transfer*>::const_iterator itr = downloads.begin(), end = downloads.end(); itr != end; ++itr) {
|
||||
itr->second->success = false;
|
||||
itr->second->reply->abort(); //assuming it's gonna call onRequestFinished slot
|
||||
}
|
||||
@ -118,11 +119,11 @@ void Core::NetworkAccess::onDownloadProgress(qint64 bytesReceived, qint64 bytesT
|
||||
{
|
||||
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
||||
QString url = rpl->url().toString();
|
||||
std::map<QString, Download*>::const_iterator itr = downloads.find(url);
|
||||
std::map<QString, Transfer*>::const_iterator itr = downloads.find(url);
|
||||
if (itr == downloads.end()) {
|
||||
qDebug() << "an error downloading" << url << ": the request had some progress but seems like noone 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 {
|
||||
Download* dwn = itr->second;
|
||||
Transfer* dwn = itr->second;
|
||||
qreal received = bytesReceived;
|
||||
qreal total = bytesTotal;
|
||||
qreal progress = received/total;
|
||||
@ -133,132 +134,18 @@ void Core::NetworkAccess::onDownloadProgress(qint64 bytesReceived, qint64 bytesT
|
||||
}
|
||||
}
|
||||
|
||||
void Core::NetworkAccess::onRequestError(QNetworkReply::NetworkError code)
|
||||
void Core::NetworkAccess::onDownloadError(QNetworkReply::NetworkError code)
|
||||
{
|
||||
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
||||
QString url = rpl->url().toString();
|
||||
std::map<QString, Download*>::const_iterator itr = downloads.find(url);
|
||||
std::map<QString, Transfer*>::const_iterator itr = downloads.find(url);
|
||||
if (itr == downloads.end()) {
|
||||
qDebug() << "an error downloading" << url << ": the request is reporting an error but seems like noone 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 {
|
||||
QString errorText;
|
||||
switch (code) {
|
||||
case QNetworkReply::NoError:
|
||||
//this never is supposed to happen
|
||||
break;
|
||||
|
||||
// network layer errors [relating to the destination server] (1-99):
|
||||
case QNetworkReply::ConnectionRefusedError:
|
||||
errorText = "Connection refused";
|
||||
break;
|
||||
case QNetworkReply::RemoteHostClosedError:
|
||||
errorText = "Remote server closed the connection";
|
||||
break;
|
||||
case QNetworkReply::HostNotFoundError:
|
||||
errorText = "Remote host is not found";
|
||||
break;
|
||||
case QNetworkReply::TimeoutError:
|
||||
errorText = "Connection was closed because it timed out";
|
||||
break;
|
||||
case QNetworkReply::OperationCanceledError:
|
||||
//this means I closed it myself by abort() or close(), don't think I need to notify here
|
||||
break;
|
||||
case QNetworkReply::SslHandshakeFailedError:
|
||||
errorText = "Security error"; //TODO need to handle sslErrors signal to get a better description here
|
||||
break;
|
||||
case QNetworkReply::TemporaryNetworkFailureError:
|
||||
//this means the connection is lost by opened route, but it's going to be resumed, not sure I need to notify
|
||||
break;
|
||||
case QNetworkReply::NetworkSessionFailedError:
|
||||
errorText = "Outgoing connection problem";
|
||||
break;
|
||||
case QNetworkReply::BackgroundRequestNotAllowedError:
|
||||
errorText = "Background request is not allowed";
|
||||
break;
|
||||
case QNetworkReply::TooManyRedirectsError:
|
||||
errorText = "The request was redirected too many times";
|
||||
break;
|
||||
case QNetworkReply::InsecureRedirectError:
|
||||
errorText = "The request was redirected to insecure connection";
|
||||
break;
|
||||
case QNetworkReply::UnknownNetworkError:
|
||||
errorText = "Unknown network error";
|
||||
break;
|
||||
|
||||
// proxy errors (101-199):
|
||||
case QNetworkReply::ProxyConnectionRefusedError:
|
||||
errorText = "The connection to the proxy server was refused";
|
||||
break;
|
||||
case QNetworkReply::ProxyConnectionClosedError:
|
||||
errorText = "Proxy server closed the connection";
|
||||
break;
|
||||
case QNetworkReply::ProxyNotFoundError:
|
||||
errorText = "Proxy host was not found";
|
||||
break;
|
||||
case QNetworkReply::ProxyTimeoutError:
|
||||
errorText = "Connection to the proxy server was closed because it timed out";
|
||||
break;
|
||||
case QNetworkReply::ProxyAuthenticationRequiredError:
|
||||
errorText = "Couldn't connect to proxy server, authentication is required";
|
||||
break;
|
||||
case QNetworkReply::UnknownProxyError:
|
||||
errorText = "Unknown proxy error";
|
||||
break;
|
||||
|
||||
// content errors (201-299):
|
||||
case QNetworkReply::ContentAccessDenied:
|
||||
errorText = "The access to file is denied";
|
||||
break;
|
||||
case QNetworkReply::ContentOperationNotPermittedError:
|
||||
errorText = "The operation over requesting file is not permitted";
|
||||
break;
|
||||
case QNetworkReply::ContentNotFoundError:
|
||||
errorText = "The file was not found";
|
||||
break;
|
||||
case QNetworkReply::AuthenticationRequiredError:
|
||||
errorText = "Couldn't access the file, authentication is required";
|
||||
break;
|
||||
case QNetworkReply::ContentReSendError:
|
||||
errorText = "Sending error, one more attempt will probably solve this problem";
|
||||
break;
|
||||
case QNetworkReply::ContentConflictError:
|
||||
errorText = "The request could not be completed due to a conflict with the current state of the resource";
|
||||
break;
|
||||
case QNetworkReply::ContentGoneError:
|
||||
errorText = "The requested resource is no longer available at the server";
|
||||
break;
|
||||
case QNetworkReply::UnknownContentError:
|
||||
errorText = "Unknown content error";
|
||||
break;
|
||||
|
||||
// protocol errors
|
||||
case QNetworkReply::ProtocolUnknownError:
|
||||
errorText = "Unknown protocol error";
|
||||
break;
|
||||
case QNetworkReply::ProtocolInvalidOperationError:
|
||||
errorText = "Requested operation is not permitted in this protocol";
|
||||
break;
|
||||
case QNetworkReply::ProtocolFailure:
|
||||
errorText = "Low level protocol error";
|
||||
break;
|
||||
|
||||
// Server side errors (401-499)
|
||||
case QNetworkReply::InternalServerError:
|
||||
errorText = "Internal server error";
|
||||
break;
|
||||
case QNetworkReply::OperationNotImplementedError:
|
||||
errorText = "Server doesn't support requested operation";
|
||||
break;
|
||||
case QNetworkReply::ServiceUnavailableError:
|
||||
errorText = "The server is not available for this operation right now";
|
||||
break;
|
||||
case QNetworkReply::UnknownServerError:
|
||||
errorText = "Unknown server error";
|
||||
break;
|
||||
}
|
||||
QString errorText = getErrorText(code);
|
||||
if (errorText.size() > 0) {
|
||||
itr->second->success = false;
|
||||
Download* dwn = itr->second;
|
||||
Transfer* dwn = itr->second;
|
||||
for (std::set<QString>::const_iterator mItr = dwn->messages.begin(), end = dwn->messages.end(); mItr != end; ++mItr) {
|
||||
emit downloadFileError(*mItr, errorText);
|
||||
}
|
||||
@ -266,16 +153,137 @@ void Core::NetworkAccess::onRequestError(QNetworkReply::NetworkError code)
|
||||
}
|
||||
}
|
||||
|
||||
void Core::NetworkAccess::onRequestFinished()
|
||||
QString Core::NetworkAccess::getErrorText(QNetworkReply::NetworkError code)
|
||||
{
|
||||
QString errorText("");
|
||||
switch (code) {
|
||||
case QNetworkReply::NoError:
|
||||
//this never is supposed to happen
|
||||
break;
|
||||
|
||||
// network layer errors [relating to the destination server] (1-99):
|
||||
case QNetworkReply::ConnectionRefusedError:
|
||||
errorText = "Connection refused";
|
||||
break;
|
||||
case QNetworkReply::RemoteHostClosedError:
|
||||
errorText = "Remote server closed the connection";
|
||||
break;
|
||||
case QNetworkReply::HostNotFoundError:
|
||||
errorText = "Remote host is not found";
|
||||
break;
|
||||
case QNetworkReply::TimeoutError:
|
||||
errorText = "Connection was closed because it timed out";
|
||||
break;
|
||||
case QNetworkReply::OperationCanceledError:
|
||||
//this means I closed it myself by abort() or close(), don't think I need to notify here
|
||||
break;
|
||||
case QNetworkReply::SslHandshakeFailedError:
|
||||
errorText = "Security error"; //TODO need to handle sslErrors signal to get a better description here
|
||||
break;
|
||||
case QNetworkReply::TemporaryNetworkFailureError:
|
||||
//this means the connection is lost by opened route, but it's going to be resumed, not sure I need to notify
|
||||
break;
|
||||
case QNetworkReply::NetworkSessionFailedError:
|
||||
errorText = "Outgoing connection problem";
|
||||
break;
|
||||
case QNetworkReply::BackgroundRequestNotAllowedError:
|
||||
errorText = "Background request is not allowed";
|
||||
break;
|
||||
case QNetworkReply::TooManyRedirectsError:
|
||||
errorText = "The request was redirected too many times";
|
||||
break;
|
||||
case QNetworkReply::InsecureRedirectError:
|
||||
errorText = "The request was redirected to insecure connection";
|
||||
break;
|
||||
case QNetworkReply::UnknownNetworkError:
|
||||
errorText = "Unknown network error";
|
||||
break;
|
||||
|
||||
// proxy errors (101-199):
|
||||
case QNetworkReply::ProxyConnectionRefusedError:
|
||||
errorText = "The connection to the proxy server was refused";
|
||||
break;
|
||||
case QNetworkReply::ProxyConnectionClosedError:
|
||||
errorText = "Proxy server closed the connection";
|
||||
break;
|
||||
case QNetworkReply::ProxyNotFoundError:
|
||||
errorText = "Proxy host was not found";
|
||||
break;
|
||||
case QNetworkReply::ProxyTimeoutError:
|
||||
errorText = "Connection to the proxy server was closed because it timed out";
|
||||
break;
|
||||
case QNetworkReply::ProxyAuthenticationRequiredError:
|
||||
errorText = "Couldn't connect to proxy server, authentication is required";
|
||||
break;
|
||||
case QNetworkReply::UnknownProxyError:
|
||||
errorText = "Unknown proxy error";
|
||||
break;
|
||||
|
||||
// content errors (201-299):
|
||||
case QNetworkReply::ContentAccessDenied:
|
||||
errorText = "The access to file is denied";
|
||||
break;
|
||||
case QNetworkReply::ContentOperationNotPermittedError:
|
||||
errorText = "The operation over requesting file is not permitted";
|
||||
break;
|
||||
case QNetworkReply::ContentNotFoundError:
|
||||
errorText = "The file was not found";
|
||||
break;
|
||||
case QNetworkReply::AuthenticationRequiredError:
|
||||
errorText = "Couldn't access the file, authentication is required";
|
||||
break;
|
||||
case QNetworkReply::ContentReSendError:
|
||||
errorText = "Sending error, one more attempt will probably solve this problem";
|
||||
break;
|
||||
case QNetworkReply::ContentConflictError:
|
||||
errorText = "The request could not be completed due to a conflict with the current state of the resource";
|
||||
break;
|
||||
case QNetworkReply::ContentGoneError:
|
||||
errorText = "The requested resource is no longer available at the server";
|
||||
break;
|
||||
case QNetworkReply::UnknownContentError:
|
||||
errorText = "Unknown content error";
|
||||
break;
|
||||
|
||||
// protocol errors
|
||||
case QNetworkReply::ProtocolUnknownError:
|
||||
errorText = "Unknown protocol error";
|
||||
break;
|
||||
case QNetworkReply::ProtocolInvalidOperationError:
|
||||
errorText = "Requested operation is not permitted in this protocol";
|
||||
break;
|
||||
case QNetworkReply::ProtocolFailure:
|
||||
errorText = "Low level protocol error";
|
||||
break;
|
||||
|
||||
// Server side errors (401-499)
|
||||
case QNetworkReply::InternalServerError:
|
||||
errorText = "Internal server error";
|
||||
break;
|
||||
case QNetworkReply::OperationNotImplementedError:
|
||||
errorText = "Server doesn't support requested operation";
|
||||
break;
|
||||
case QNetworkReply::ServiceUnavailableError:
|
||||
errorText = "The server is not available for this operation right now";
|
||||
break;
|
||||
case QNetworkReply::UnknownServerError:
|
||||
errorText = "Unknown server error";
|
||||
break;
|
||||
}
|
||||
return errorText;
|
||||
}
|
||||
|
||||
|
||||
void Core::NetworkAccess::onDownloadFinished()
|
||||
{
|
||||
QString path("");
|
||||
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
||||
QString url = rpl->url().toString();
|
||||
std::map<QString, Download*>::const_iterator itr = downloads.find(url);
|
||||
std::map<QString, Transfer*>::const_iterator itr = downloads.find(url);
|
||||
if (itr == downloads.end()) {
|
||||
qDebug() << "an error downloading" << url << ": the request is done but seems like noone is waiting for it, skipping";
|
||||
} else {
|
||||
Download* dwn = itr->second;
|
||||
Transfer* dwn = itr->second;
|
||||
if (dwn->success) {
|
||||
qDebug() << "download success for" << url;
|
||||
QStringList hops = url.split("/");
|
||||
@ -320,13 +328,173 @@ void Core::NetworkAccess::onRequestFinished()
|
||||
|
||||
void Core::NetworkAccess::startDownload(const QString& messageId, const QString& url)
|
||||
{
|
||||
Download* dwn = new Download({{messageId}, 0, 0, true});
|
||||
Transfer* dwn = new Transfer({{messageId}, 0, 0, true, "", url, 0});
|
||||
QNetworkRequest req(url);
|
||||
dwn->reply = manager->get(req);
|
||||
connect(dwn->reply, &QNetworkReply::downloadProgress, this, &NetworkAccess::onDownloadProgress);
|
||||
connect(dwn->reply, qOverload<QNetworkReply::NetworkError>(&QNetworkReply::error), this, &NetworkAccess::onRequestError);
|
||||
connect(dwn->reply, &QNetworkReply::finished, this, &NetworkAccess::onRequestFinished);
|
||||
connect(dwn->reply, qOverload<QNetworkReply::NetworkError>(&QNetworkReply::error), this, &NetworkAccess::onDownloadError);
|
||||
connect(dwn->reply, &QNetworkReply::finished, this, &NetworkAccess::onDownloadFinished);
|
||||
downloads.insert(std::make_pair(url, dwn));
|
||||
emit downloadFileProgress(messageId, 0);
|
||||
}
|
||||
|
||||
void Core::NetworkAccess::onUploadError(QNetworkReply::NetworkError code)
|
||||
{
|
||||
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
||||
QString url = rpl->url().toString();
|
||||
std::map<QString, Transfer*>::const_iterator itr = uploads.find(url);
|
||||
if (itr == uploads.end()) {
|
||||
qDebug() << "an error uploading" << url << ": the request is reporting an error but seems like noone is waiting for it, skipping";
|
||||
} else {
|
||||
QString errorText = getErrorText(code);
|
||||
if (errorText.size() > 0) {
|
||||
itr->second->success = false;
|
||||
Transfer* upl = itr->second;
|
||||
for (std::set<QString>::const_iterator mItr = upl->messages.begin(), end = upl->messages.end(); mItr != end; ++mItr) {
|
||||
emit uploadFileError(*mItr, errorText);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Core::NetworkAccess::onUploadFinished()
|
||||
{
|
||||
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
||||
QString url = rpl->url().toString();
|
||||
std::map<QString, Transfer*>::const_iterator itr = uploads.find(url);
|
||||
if (itr == downloads.end()) {
|
||||
qDebug() << "an error uploading" << url << ": the request is done but seems like no one is waiting for it, skipping";
|
||||
} else {
|
||||
Transfer* upl = itr->second;
|
||||
if (upl->success) {
|
||||
qDebug() << "upload success for" << url;
|
||||
files.addRecord(upl->url, upl->path);
|
||||
|
||||
for (std::set<QString>::const_iterator mItr = upl->messages.begin(), end = upl->messages.end(); mItr != end; ++mItr) {
|
||||
emit fileLocalPathResponse(*mItr, upl->path);
|
||||
emit uploadFileComplete(*mItr, upl->url);
|
||||
}
|
||||
}
|
||||
|
||||
upl->reply->deleteLater();
|
||||
upl->file->close();
|
||||
upl->file->deleteLater();
|
||||
delete upl;
|
||||
uploads.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
void Core::NetworkAccess::onUploadProgress(qint64 bytesReceived, qint64 bytesTotal)
|
||||
{
|
||||
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
||||
QString url = rpl->url().toString();
|
||||
std::map<QString, Transfer*>::const_iterator itr = uploads.find(url);
|
||||
if (itr == uploads.end()) {
|
||||
qDebug() << "an error downloading" << url << ": the request had some progress but seems like no one is waiting for it, skipping";
|
||||
} else {
|
||||
Transfer* upl = itr->second;
|
||||
qreal received = bytesReceived;
|
||||
qreal total = bytesTotal;
|
||||
qreal progress = received/total;
|
||||
upl->progress = progress;
|
||||
for (std::set<QString>::const_iterator mItr = upl->messages.begin(), end = upl->messages.end(); mItr != end; ++mItr) {
|
||||
emit uploadFileProgress(*mItr, progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Core::NetworkAccess::startUpload(const QString& messageId, const QString& url, const QString& path)
|
||||
{
|
||||
Transfer* upl = new Transfer({{messageId}, 0, 0, true, path, url, 0});
|
||||
QNetworkRequest req(url);
|
||||
QFile* file = new QFile(path);
|
||||
if (file->open(QIODevice::ReadOnly)) {
|
||||
upl->reply = manager->put(req, file);
|
||||
|
||||
connect(upl->reply, &QNetworkReply::uploadProgress, this, &NetworkAccess::onUploadProgress);
|
||||
connect(upl->reply, qOverload<QNetworkReply::NetworkError>(&QNetworkReply::error), this, &NetworkAccess::onUploadError);
|
||||
connect(upl->reply, &QNetworkReply::finished, this, &NetworkAccess::onUploadFinished);
|
||||
uploads.insert(std::make_pair(url, upl));
|
||||
emit downloadFileProgress(messageId, 0);
|
||||
} else {
|
||||
qDebug() << "couldn't upload file" << path;
|
||||
emit uploadFileError(messageId, "Error opening file");
|
||||
delete file;
|
||||
}
|
||||
}
|
||||
|
||||
void Core::NetworkAccess::uploadFileRequest(const QString& messageId, const QString& url, const QString& path)
|
||||
{
|
||||
std::map<QString, Transfer*>::iterator itr = uploads.find(url);
|
||||
if (itr != uploads.end()) {
|
||||
Transfer* upl = itr->second;
|
||||
std::set<QString>::const_iterator mItr = upl->messages.find(messageId);
|
||||
if (mItr == upl->messages.end()) {
|
||||
upl->messages.insert(messageId);
|
||||
}
|
||||
emit uploadFileProgress(messageId, upl->progress);
|
||||
} else {
|
||||
try {
|
||||
QString ePath = files.getRecord(url);
|
||||
if (ePath == path) {
|
||||
QFileInfo info(path);
|
||||
if (info.exists() && info.isFile()) {
|
||||
emit fileLocalPathResponse(messageId, path);
|
||||
} else {
|
||||
files.removeRecord(url);
|
||||
startUpload(messageId, url, path);
|
||||
}
|
||||
} else {
|
||||
QFileInfo info(path);
|
||||
if (info.exists() && info.isFile()) {
|
||||
files.changeRecord(url, path);
|
||||
emit fileLocalPathResponse(messageId, path);
|
||||
} else {
|
||||
files.removeRecord(url);
|
||||
startUpload(messageId, url, path);
|
||||
}
|
||||
}
|
||||
} catch (Archive::NotFound e) {
|
||||
startUpload(messageId, url, path);
|
||||
} catch (Archive::Unknown e) {
|
||||
qDebug() << "Error requesting file path on upload:" << e.what();
|
||||
emit uploadFileError(messageId, QString("Database error: ") + e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString Core::NetworkAccess::getFileRemoteUrl(const QString& path)
|
||||
{
|
||||
return ""; //TODO this is a way not to upload some file more then 1 time, here I'm supposed to return that file GET url
|
||||
}
|
||||
|
||||
bool Core::NetworkAccess::isUploading(const QString& path, const QString& messageId)
|
||||
{
|
||||
return false; //TODO this is a way to avoid parallel uploading of the same files by different chats
|
||||
// message is is supposed to be added to the uploading messageids list
|
||||
// the result should be true if there was an uploading file with this path
|
||||
// message id can be empty, then it's just to check and not to add
|
||||
}
|
||||
|
||||
void Core::NetworkAccess::uploadFile(const QString& messageId, const QString& path, const QUrl& put, const QUrl& get, const QMap<QString, QString> headers)
|
||||
{
|
||||
QFile* file = new QFile(path);
|
||||
Transfer* upl = new Transfer({{messageId}, 0, 0, true, path, get.toString(), file});
|
||||
QNetworkRequest req(put);
|
||||
for (QMap<QString, QString>::const_iterator itr = headers.begin(), end = headers.end(); itr != end; itr++) {
|
||||
req.setRawHeader(itr.key().toUtf8(), itr.value().toUtf8());
|
||||
}
|
||||
if (file->open(QIODevice::ReadOnly)) {
|
||||
upl->reply = manager->put(req, file);
|
||||
|
||||
connect(upl->reply, &QNetworkReply::uploadProgress, this, &NetworkAccess::onUploadProgress);
|
||||
connect(upl->reply, qOverload<QNetworkReply::NetworkError>(&QNetworkReply::error), this, &NetworkAccess::onUploadError);
|
||||
connect(upl->reply, &QNetworkReply::finished, this, &NetworkAccess::onUploadFinished);
|
||||
uploads.insert(std::make_pair(put.toString(), upl));
|
||||
emit downloadFileProgress(messageId, 0);
|
||||
} else {
|
||||
qDebug() << "couldn't upload file" << path;
|
||||
emit uploadFileError(messageId, "Error opening file");
|
||||
delete file;
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ namespace Core {
|
||||
class NetworkAccess : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
struct Download;
|
||||
struct Transfer;
|
||||
public:
|
||||
NetworkAccess(QObject* parent = nullptr);
|
||||
virtual ~NetworkAccess();
|
||||
@ -47,34 +47,51 @@ public:
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
QString getFileRemoteUrl(const QString& path);
|
||||
bool isUploading(const QString& path, const QString& messageId = "");
|
||||
void uploadFile(const QString& messageId, const QString& path, const QUrl& put, const QUrl& get, const QMap<QString, QString> headers);
|
||||
|
||||
signals:
|
||||
void fileLocalPathResponse(const QString& messageId, const QString& path);
|
||||
void downloadFileProgress(const QString& messageId, qreal value);
|
||||
void downloadFileError(const QString& messageId, const QString& path);
|
||||
void uploadFileProgress(const QString& messageId, qreal value);
|
||||
void uploadFileError(const QString& messageId, const QString& path);
|
||||
void uploadFileComplete(const QString& messageId, const QString& url);
|
||||
|
||||
public slots:
|
||||
void fileLocalPathRequest(const QString& messageId, const QString& url);
|
||||
void downladFileRequest(const QString& messageId, const QString& url);
|
||||
void uploadFileRequest(const QString& messageId, const QString& url, const QString& path);
|
||||
|
||||
private:
|
||||
void startDownload(const QString& messageId, const QString& url);
|
||||
void startUpload(const QString& messageId, const QString& url, const QString& path);
|
||||
QString getErrorText(QNetworkReply::NetworkError code);
|
||||
|
||||
private slots:
|
||||
void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
|
||||
void onRequestError(QNetworkReply::NetworkError code);
|
||||
void onRequestFinished();
|
||||
void onDownloadError(QNetworkReply::NetworkError code);
|
||||
void onDownloadFinished();
|
||||
void onUploadProgress(qint64 bytesReceived, qint64 bytesTotal);
|
||||
void onUploadError(QNetworkReply::NetworkError code);
|
||||
void onUploadFinished();
|
||||
|
||||
private:
|
||||
bool running;
|
||||
QNetworkAccessManager* manager;
|
||||
Storage files;
|
||||
std::map<QString, Download*> downloads;
|
||||
std::map<QString, Transfer*> downloads;
|
||||
std::map<QString, Transfer*> uploads;
|
||||
|
||||
struct Download {
|
||||
struct Transfer {
|
||||
std::set<QString> messages;
|
||||
qreal progress;
|
||||
QNetworkReply* reply;
|
||||
bool success;
|
||||
QString path;
|
||||
QString url;
|
||||
QFile* file;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -31,6 +31,8 @@ Core::Squawk::Squawk(QObject* parent):
|
||||
connect(&network, &NetworkAccess::fileLocalPathResponse, this, &Squawk::fileLocalPathResponse);
|
||||
connect(&network, &NetworkAccess::downloadFileProgress, this, &Squawk::downloadFileProgress);
|
||||
connect(&network, &NetworkAccess::downloadFileError, this, &Squawk::downloadFileError);
|
||||
connect(&network, &NetworkAccess::uploadFileProgress, this, &Squawk::uploadFileProgress);
|
||||
connect(&network, &NetworkAccess::uploadFileError, this, &Squawk::uploadFileError);
|
||||
}
|
||||
|
||||
Core::Squawk::~Squawk()
|
||||
@ -104,7 +106,7 @@ void Core::Squawk::addAccount(const QString& login, const QString& server, const
|
||||
QSettings settings;
|
||||
unsigned int reconnects = settings.value("reconnects", 2).toUInt();
|
||||
|
||||
Account* acc = new Account(login, server, password, name);
|
||||
Account* acc = new Account(login, server, password, name, &network);
|
||||
acc->setResource(resource);
|
||||
acc->setReconnectTimes(reconnects);
|
||||
accounts.push_back(acc);
|
||||
@ -135,6 +137,8 @@ void Core::Squawk::addAccount(const QString& login, const QString& server, const
|
||||
|
||||
connect(acc, &Account::receivedVCard, this, &Squawk::responseVCard);
|
||||
|
||||
connect(acc, &Account::uploadFileError, this, &Squawk::uploadFileError);
|
||||
|
||||
QMap<QString, QVariant> map = {
|
||||
{"login", login},
|
||||
{"server", server},
|
||||
@ -281,6 +285,17 @@ void Core::Squawk::sendMessage(const QString& account, const Shared::Message& da
|
||||
itr->second->sendMessage(data);
|
||||
}
|
||||
|
||||
void Core::Squawk::sendMessage(const QString& account, const Shared::Message& data, const QString& path)
|
||||
{
|
||||
AccountsMap::const_iterator itr = amap.find(account);
|
||||
if (itr == amap.end()) {
|
||||
qDebug("An attempt to send a message with non existing account, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
itr->second->sendMessage(data, path);
|
||||
}
|
||||
|
||||
void Core::Squawk::requestArchive(const QString& account, const QString& jid, int count, const QString& before)
|
||||
{
|
||||
AccountsMap::const_iterator itr = amap.find(account);
|
||||
@ -373,7 +388,6 @@ void Core::Squawk::removeAccountRequest(const QString& name)
|
||||
acc->deleteLater();
|
||||
}
|
||||
|
||||
|
||||
void Core::Squawk::subscribeContact(const QString& account, const QString& jid, const QString& reason)
|
||||
{
|
||||
AccountsMap::const_iterator itr = amap.find(account);
|
||||
|
@ -66,6 +66,8 @@ signals:
|
||||
void fileLocalPathResponse(const QString& messageId, const QString& path);
|
||||
void downloadFileError(const QString& messageId, const QString& error);
|
||||
void downloadFileProgress(const QString& messageId, qreal value);
|
||||
void uploadFileError(const QString& messageId, const QString& error);
|
||||
void uploadFileProgress(const QString& messageId, qreal value);
|
||||
void responseVCard(const QString& jid, const Shared::VCard& card);
|
||||
|
||||
public slots:
|
||||
@ -78,6 +80,7 @@ public slots:
|
||||
void disconnectAccount(const QString& account);
|
||||
void changeState(int state);
|
||||
void sendMessage(const QString& account, const Shared::Message& data);
|
||||
void sendMessage(const QString& account, const Shared::Message& data, const QString& path);
|
||||
void requestArchive(const QString& account, const QString& jid, int count, const QString& before);
|
||||
void subscribeContact(const QString& account, const QString& jid, const QString& reason);
|
||||
void unsubscribeContact(const QString& account, const QString& jid, const QString& reason);
|
||||
|
@ -73,7 +73,7 @@ void Core::Storage::close()
|
||||
void Core::Storage::addRecord(const QString& key, const QString& value)
|
||||
{
|
||||
if (!opened) {
|
||||
throw Archive::Closed("addElement", name.toStdString());
|
||||
throw Archive::Closed("addRecord", name.toStdString());
|
||||
}
|
||||
const std::string& id = key.toStdString();
|
||||
const std::string& val = value.toStdString();
|
||||
@ -99,6 +99,33 @@ void Core::Storage::addRecord(const QString& key, const QString& value)
|
||||
}
|
||||
}
|
||||
|
||||
void Core::Storage::changeRecord(const QString& key, const QString& value)
|
||||
{
|
||||
if (!opened) {
|
||||
throw Archive::Closed("changeRecord", name.toStdString());
|
||||
}
|
||||
const std::string& id = key.toStdString();
|
||||
const std::string& val = value.toStdString();
|
||||
|
||||
MDB_val lmdbKey, lmdbData;
|
||||
lmdbKey.mv_size = id.size();
|
||||
lmdbKey.mv_data = (char*)id.c_str();
|
||||
lmdbData.mv_size = val.size();
|
||||
lmdbData.mv_data = (char*)val.c_str();
|
||||
MDB_txn *txn;
|
||||
mdb_txn_begin(environment, NULL, 0, &txn);
|
||||
int rc;
|
||||
rc = mdb_put(txn, base, &lmdbKey, &lmdbData, 0);
|
||||
if (rc != 0) {
|
||||
mdb_txn_abort(txn);
|
||||
if (rc) {
|
||||
throw Archive::Unknown(name.toStdString(), mdb_strerror(rc));
|
||||
}
|
||||
} else {
|
||||
mdb_txn_commit(txn);
|
||||
}
|
||||
}
|
||||
|
||||
QString Core::Storage::getRecord(const QString& key) const
|
||||
{
|
||||
if (!opened) {
|
||||
|
@ -39,6 +39,7 @@ public:
|
||||
void close();
|
||||
|
||||
void addRecord(const QString& key, const QString& value);
|
||||
void changeRecord(const QString& key, const QString& value);
|
||||
void removeRecord(const QString& key);
|
||||
QString getRecord(const QString& key) const;
|
||||
|
||||
|
2
external/qxmpp
vendored
2
external/qxmpp
vendored
@ -1 +1 @@
|
||||
Subproject commit b18a57daa33f0fefa5f4c63aa7f448b48d302e0d
|
||||
Subproject commit f8c546c5b701c53d708a38a951fcc734eaee7940
|
16
main.cpp
16
main.cpp
@ -39,7 +39,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
QApplication::setApplicationName("squawk");
|
||||
QApplication::setApplicationDisplayName("Squawk");
|
||||
QApplication::setApplicationVersion("0.0.5");
|
||||
QApplication::setApplicationVersion("0.1.1");
|
||||
|
||||
QTranslator qtTranslator;
|
||||
qtTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
|
||||
@ -90,7 +90,10 @@ int main(int argc, char *argv[])
|
||||
QObject::connect(&w, &Squawk::connectAccount, squawk, &Core::Squawk::connectAccount);
|
||||
QObject::connect(&w, &Squawk::disconnectAccount, squawk, &Core::Squawk::disconnectAccount);
|
||||
QObject::connect(&w, &Squawk::changeState, squawk, &Core::Squawk::changeState);
|
||||
QObject::connect(&w, &Squawk::sendMessage, squawk, &Core::Squawk::sendMessage);
|
||||
QObject::connect(&w, qOverload<const QString&, const Shared::Message&>(&Squawk::sendMessage),
|
||||
squawk, qOverload<const QString&, const Shared::Message&>(&Core::Squawk::sendMessage));
|
||||
QObject::connect(&w, qOverload<const QString&, const Shared::Message&, const QString&>(&Squawk::sendMessage),
|
||||
squawk, qOverload<const QString&, const Shared::Message&, const QString&>(&Core::Squawk::sendMessage));
|
||||
QObject::connect(&w, &Squawk::requestArchive, squawk, &Core::Squawk::requestArchive);
|
||||
QObject::connect(&w, &Squawk::subscribeContact, squawk, &Core::Squawk::subscribeContact);
|
||||
QObject::connect(&w, &Squawk::unsubscribeContact, squawk, &Core::Squawk::unsubscribeContact);
|
||||
@ -131,13 +134,12 @@ int main(int argc, char *argv[])
|
||||
QObject::connect(squawk, &Core::Squawk::changeRoomParticipant, &w, &Squawk::changeRoomParticipant);
|
||||
QObject::connect(squawk, &Core::Squawk::removeRoomParticipant, &w, &Squawk::removeRoomParticipant);
|
||||
QObject::connect(squawk, &Core::Squawk::fileLocalPathResponse, &w, &Squawk::fileLocalPathResponse);
|
||||
QObject::connect(squawk, &Core::Squawk::downloadFileProgress, &w, &Squawk::downloadFileProgress);
|
||||
QObject::connect(squawk, &Core::Squawk::downloadFileError, &w, &Squawk::downloadFileError);
|
||||
QObject::connect(squawk, &Core::Squawk::downloadFileProgress, &w, &Squawk::fileProgress);
|
||||
QObject::connect(squawk, &Core::Squawk::downloadFileError, &w, &Squawk::fileError);
|
||||
QObject::connect(squawk, &Core::Squawk::uploadFileProgress, &w, &Squawk::fileProgress);
|
||||
QObject::connect(squawk, &Core::Squawk::uploadFileError, &w, &Squawk::fileError);
|
||||
QObject::connect(squawk, &Core::Squawk::responseVCard, &w, &Squawk::responseVCard);
|
||||
|
||||
|
||||
//qDebug() << QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
|
||||
|
||||
coreThread->start();
|
||||
|
||||
int result = app.exec();
|
||||
|
@ -1,18 +1,18 @@
|
||||
# Maintainer: Yury Gubich <blue@macaw.me>
|
||||
pkgname=squawk
|
||||
pkgver=0.0.5
|
||||
pkgver=0.1.1
|
||||
pkgrel=1
|
||||
pkgdesc="An XMPP desktop messenger, written on qt"
|
||||
arch=('i686' 'x86_64')
|
||||
url="https://git.macaw.me/blue/squawk"
|
||||
license=('GPL3')
|
||||
depends=('hicolor-icon-theme' 'desktop-file-utils' 'lmdb' 'qxmpp>=1.0.0')
|
||||
depends=('hicolor-icon-theme' 'desktop-file-utils' 'lmdb' 'qxmpp>=1.1.0')
|
||||
makedepends=('cmake>=3.3' 'imagemagick' 'qt5-tools')
|
||||
source=("$pkgname-$pkgver.tar.gz")
|
||||
sha256sums=('12bfc517574387257a82143d8970ec0d8d434ccd32f7ac400355ed5fa18192ab')
|
||||
sha256sums=('d0448f2fdb321e31a40c08b77adc951bafe8d1c271f70d6ffc80fb17cef670cf')
|
||||
build() {
|
||||
cd "$srcdir/squawk"
|
||||
cmake . -D CMAKE_INSTALL_PREFIX=/usr
|
||||
cmake . -D CMAKE_INSTALL_PREFIX=/usr -D CMAKE_BUILD_TYPE=Release
|
||||
cmake --build . -j $nproc
|
||||
}
|
||||
package() {
|
||||
|
@ -5,77 +5,92 @@
|
||||
<name>Account</name>
|
||||
<message>
|
||||
<location filename="../ui/widgets/account.ui" line="14"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_account.h" line="127"/>
|
||||
<source>Account</source>
|
||||
<translatorcomment>Заголовок окна</translatorcomment>
|
||||
<translation>Учетная запись</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/account.ui" line="40"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_account.h" line="129"/>
|
||||
<source>Your account login</source>
|
||||
<translation>Имя пользователя Вашей учетной записи</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/account.ui" line="43"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_account.h" line="131"/>
|
||||
<source>john_smith1987</source>
|
||||
<translation>ivan_ivanov1987</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/account.ui" line="50"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_account.h" line="132"/>
|
||||
<source>Server</source>
|
||||
<translation>Сервер</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/account.ui" line="57"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_account.h" line="134"/>
|
||||
<source>A server address of your account. Like 404.city or macaw.me</source>
|
||||
<translation>Адресс сервера вашей учетной записи (выглядит как 404.city или macaw.me)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/account.ui" line="60"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_account.h" line="136"/>
|
||||
<source>macaw.me</source>
|
||||
<translation>macaw.me</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/account.ui" line="67"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_account.h" line="137"/>
|
||||
<source>Login</source>
|
||||
<translation>Имя учетной записи</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/account.ui" line="74"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_account.h" line="138"/>
|
||||
<source>Password</source>
|
||||
<translation>Пароль</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/account.ui" line="81"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_account.h" line="140"/>
|
||||
<source>Password of your account</source>
|
||||
<translation>Пароль вашей учетной записи</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/account.ui" line="103"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_account.h" line="145"/>
|
||||
<source>Name</source>
|
||||
<translation>Имя</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/account.ui" line="110"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_account.h" line="147"/>
|
||||
<source>Just a name how would you call this account, doesn't affect anything</source>
|
||||
<translation>Просто имя, то как Вы называете свою учетную запись, может быть любым</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/account.ui" line="113"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_account.h" line="149"/>
|
||||
<source>John</source>
|
||||
<translation>Иван</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/account.ui" line="120"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_account.h" line="150"/>
|
||||
<source>Resource</source>
|
||||
<translation>Ресурс</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/account.ui" line="127"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_account.h" line="152"/>
|
||||
<source>A resource name like "Home" or "Work"</source>
|
||||
<translation>Имя этой программы для ваших контактов, может быть "Home" или "Phone"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/account.ui" line="130"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_account.h" line="154"/>
|
||||
<source>QXmpp</source>
|
||||
<translatorcomment>Ресурс по умолчанию</translatorcomment>
|
||||
<translation>QXmpp</translation>
|
||||
@ -85,31 +100,37 @@
|
||||
<name>Accounts</name>
|
||||
<message>
|
||||
<location filename="../ui/widgets/accounts.ui" line="14"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_accounts.h" line="108"/>
|
||||
<source>Accounts</source>
|
||||
<translation>Учетные записи</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/accounts.ui" line="45"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_accounts.h" line="109"/>
|
||||
<source>Delete</source>
|
||||
<translation>Удалить</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/accounts.ui" line="86"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_accounts.h" line="110"/>
|
||||
<source>Add</source>
|
||||
<translation>Добавить</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/accounts.ui" line="96"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_accounts.h" line="111"/>
|
||||
<source>Edit</source>
|
||||
<translation>Редактировать</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/accounts.ui" line="106"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_accounts.h" line="112"/>
|
||||
<source>Change password</source>
|
||||
<translation>Изменить пароль</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/accounts.ui" line="129"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_accounts.h" line="113"/>
|
||||
<location filename="../ui/widgets/accounts.cpp" line="125"/>
|
||||
<location filename="../ui/widgets/accounts.cpp" line="128"/>
|
||||
<source>Connect</source>
|
||||
@ -125,11 +146,12 @@
|
||||
<name>Conversation</name>
|
||||
<message>
|
||||
<location filename="../ui/widgets/conversation.ui" line="449"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_conversation.h" line="324"/>
|
||||
<source>Type your message here...</source>
|
||||
<translation>Введите сообщение...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/conversation.cpp" line="260"/>
|
||||
<location filename="../ui/widgets/conversation.cpp" line="284"/>
|
||||
<source>Chose a file to send</source>
|
||||
<translation>Выберите файл для отправки</translation>
|
||||
</message>
|
||||
@ -281,52 +303,62 @@
|
||||
<name>JoinConference</name>
|
||||
<message>
|
||||
<location filename="../ui/widgets/joinconference.ui" line="14"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_joinconference.h" line="116"/>
|
||||
<source>Join new conference</source>
|
||||
<translatorcomment>Заголовок окна</translatorcomment>
|
||||
<translation>Присоединиться к новой беседе</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/joinconference.ui" line="22"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_joinconference.h" line="117"/>
|
||||
<source>JID</source>
|
||||
<translation>JID</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/joinconference.ui" line="29"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_joinconference.h" line="119"/>
|
||||
<source>Room JID</source>
|
||||
<translation>Jabber-идентификатор беседы</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/joinconference.ui" line="32"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_joinconference.h" line="121"/>
|
||||
<source>identifier@conference.server.org</source>
|
||||
<translation>identifier@conference.server.org</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/joinconference.ui" line="39"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_joinconference.h" line="122"/>
|
||||
<source>Account</source>
|
||||
<translation>Учетная запись</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/joinconference.ui" line="49"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_joinconference.h" line="123"/>
|
||||
<source>Join on login</source>
|
||||
<translation>Автовход</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/joinconference.ui" line="56"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_joinconference.h" line="125"/>
|
||||
<source>If checked Squawk will try to join this conference on login</source>
|
||||
<translation>Если стоит галочка Squawk автоматически присоединится к этой беседе при подключении</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/joinconference.ui" line="66"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_joinconference.h" line="128"/>
|
||||
<source>Nick name</source>
|
||||
<translation>Псевдоним</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/joinconference.ui" line="73"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_joinconference.h" line="130"/>
|
||||
<source>Your nick name for that conference. If you leave this field empty your account name will be used as a nick name</source>
|
||||
<translation>Ваш псевдоним в этой беседе, если оставите это поле пустым - будет использовано имя Вашей учетной записи</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/joinconference.ui" line="76"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_joinconference.h" line="132"/>
|
||||
<source>John</source>
|
||||
<translation>Ivan</translation>
|
||||
</message>
|
||||
@ -334,26 +366,58 @@
|
||||
<context>
|
||||
<name>Message</name>
|
||||
<message>
|
||||
<location filename="../ui/utils/message.cpp" line="119"/>
|
||||
<source>Download</source>
|
||||
<translation>Скачать</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/utils/message.cpp" line="123"/>
|
||||
<location filename="../ui/utils/message.cpp" line="172"/>
|
||||
<source>Open</source>
|
||||
<translation>Открыть</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageLine</name>
|
||||
<message>
|
||||
<location filename="../ui/utils/messageline.cpp" line="146"/>
|
||||
<source>Downloading...</source>
|
||||
<translation>Скачивается...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/utils/messageline.cpp" line="258"/>
|
||||
<location filename="../ui/utils/messageline.cpp" line="324"/>
|
||||
<source>Download</source>
|
||||
<translation>Скачать</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/utils/messageline.cpp" line="259"/>
|
||||
<source>Push the button to daownload the file</source>
|
||||
<translation>Нажмите на кнопку что бы загрузить файл</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/utils/messageline.cpp" line="319"/>
|
||||
<source>Error uploading file: %1
|
||||
You can try again</source>
|
||||
<translation>Ошибка загрузки файла на сервер:
|
||||
%1
|
||||
Для того, что бы попробовать снова нажмите на кнопку</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/utils/messageline.cpp" line="320"/>
|
||||
<source>Upload</source>
|
||||
<translation>Загрузить</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/utils/messageline.cpp" line="325"/>
|
||||
<source>Error downloading file: %1
|
||||
You can try again</source>
|
||||
<translation>Ошибка загрузки файла: %1
|
||||
<translation>Ошибка скачивания файла:
|
||||
%1
|
||||
Вы можете попробовать снова</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/utils/message.cpp" line="125"/>
|
||||
<source>%1 is offering you to download a file</source>
|
||||
<translation>%1 предлагает Вам скачать файл</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/utils/message.cpp" line="190"/>
|
||||
<source>Open</source>
|
||||
<translation>Открыть</translation>
|
||||
<location filename="../ui/utils/messageline.cpp" line="336"/>
|
||||
<source>Uploading...</source>
|
||||
<translation>Загружается...</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -470,48 +534,57 @@ You can try again</source>
|
||||
<name>NewContact</name>
|
||||
<message>
|
||||
<location filename="../ui/widgets/newcontact.ui" line="14"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_newcontact.h" line="103"/>
|
||||
<source>Add new contact</source>
|
||||
<translatorcomment>Заголовок окна</translatorcomment>
|
||||
<translation>Добавление нового контакта</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/newcontact.ui" line="22"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_newcontact.h" line="104"/>
|
||||
<source>Account</source>
|
||||
<translation>Учетная запись</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/newcontact.ui" line="29"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_newcontact.h" line="106"/>
|
||||
<source>An account that is going to have new contact</source>
|
||||
<translation>Учетная запись для которой будет добавлен контакт</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/newcontact.ui" line="36"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_newcontact.h" line="108"/>
|
||||
<source>JID</source>
|
||||
<translation>JID</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/newcontact.ui" line="43"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_newcontact.h" line="110"/>
|
||||
<source>Jabber id of your new contact</source>
|
||||
<translation>Jabber-идентификатор нового контакта</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/newcontact.ui" line="46"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_newcontact.h" line="112"/>
|
||||
<source>name@server.dmn</source>
|
||||
<translatorcomment>Placeholder поля ввода JID</translatorcomment>
|
||||
<translation>name@server.dmn</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/newcontact.ui" line="53"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_newcontact.h" line="113"/>
|
||||
<source>Name</source>
|
||||
<translation>Имя</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/newcontact.ui" line="60"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_newcontact.h" line="115"/>
|
||||
<source>The way this new contact will be labeled in your roster (optional)</source>
|
||||
<translation>То, как будет подписан контакт в вашем списке контактов (не обязательно)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/newcontact.ui" line="63"/>
|
||||
<location filename="../build/ui/widgets/squawkWidgets_autogen/include/ui_newcontact.h" line="117"/>
|
||||
<source>John Smith</source>
|
||||
<translation>Иван Иванов</translation>
|
||||
</message>
|
||||
@ -520,36 +593,43 @@ You can try again</source>
|
||||
<name>Squawk</name>
|
||||
<message>
|
||||
<location filename="../ui/squawk.ui" line="14"/>
|
||||
<location filename="../build/ui/squawkUI_autogen/include/ui_squawk.h" line="137"/>
|
||||
<source>squawk</source>
|
||||
<translation>Squawk</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.ui" line="78"/>
|
||||
<location filename="../build/ui/squawkUI_autogen/include/ui_squawk.h" line="143"/>
|
||||
<source>Settings</source>
|
||||
<translation>Настройки</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.ui" line="84"/>
|
||||
<location filename="../build/ui/squawkUI_autogen/include/ui_squawk.h" line="144"/>
|
||||
<source>Squawk</source>
|
||||
<translation>Squawk</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.ui" line="99"/>
|
||||
<location filename="../build/ui/squawkUI_autogen/include/ui_squawk.h" line="138"/>
|
||||
<source>Accounts</source>
|
||||
<translation>Учетные записи</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.ui" line="108"/>
|
||||
<location filename="../build/ui/squawkUI_autogen/include/ui_squawk.h" line="139"/>
|
||||
<source>Quit</source>
|
||||
<translation>Выйти</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.ui" line="120"/>
|
||||
<location filename="../build/ui/squawkUI_autogen/include/ui_squawk.h" line="140"/>
|
||||
<source>Add contact</source>
|
||||
<translation>Добавить контакт</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.ui" line="132"/>
|
||||
<location filename="../build/ui/squawkUI_autogen/include/ui_squawk.h" line="141"/>
|
||||
<source>Add conference</source>
|
||||
<translation>Присоединиться к беседе</translation>
|
||||
</message>
|
||||
@ -559,52 +639,52 @@ You can try again</source>
|
||||
<translation>Список контактов</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.cpp" line="549"/>
|
||||
<location filename="../ui/squawk.cpp" line="558"/>
|
||||
<source>Disconnect</source>
|
||||
<translation>Отключить</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.cpp" line="555"/>
|
||||
<location filename="../ui/squawk.cpp" line="564"/>
|
||||
<source>Connect</source>
|
||||
<translation>Подключить</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.cpp" line="561"/>
|
||||
<location filename="../ui/squawk.cpp" line="659"/>
|
||||
<location filename="../ui/squawk.cpp" line="570"/>
|
||||
<location filename="../ui/squawk.cpp" line="668"/>
|
||||
<source>VCard</source>
|
||||
<translation>Карточка</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.cpp" line="565"/>
|
||||
<location filename="../ui/squawk.cpp" line="663"/>
|
||||
<location filename="../ui/squawk.cpp" line="703"/>
|
||||
<location filename="../ui/squawk.cpp" line="574"/>
|
||||
<location filename="../ui/squawk.cpp" line="672"/>
|
||||
<location filename="../ui/squawk.cpp" line="712"/>
|
||||
<source>Remove</source>
|
||||
<translation>Удалить</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.cpp" line="577"/>
|
||||
<location filename="../ui/squawk.cpp" line="586"/>
|
||||
<source>Open dialog</source>
|
||||
<translation>Открыть диалог</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.cpp" line="587"/>
|
||||
<location filename="../ui/squawk.cpp" line="684"/>
|
||||
<location filename="../ui/squawk.cpp" line="596"/>
|
||||
<location filename="../ui/squawk.cpp" line="693"/>
|
||||
<source>Unsubscribe</source>
|
||||
<translation>Отписаться</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.cpp" line="597"/>
|
||||
<location filename="../ui/squawk.cpp" line="693"/>
|
||||
<location filename="../ui/squawk.cpp" line="606"/>
|
||||
<location filename="../ui/squawk.cpp" line="702"/>
|
||||
<source>Subscribe</source>
|
||||
<translation>Подписаться</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.cpp" line="608"/>
|
||||
<location filename="../ui/squawk.cpp" line="617"/>
|
||||
<source>Rename</source>
|
||||
<translation>Переименовать</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.cpp" line="621"/>
|
||||
<location filename="../ui/squawk.cpp" line="630"/>
|
||||
<source>Input new name for %1
|
||||
or leave it empty for the contact
|
||||
to be displayed as %1</source>
|
||||
@ -614,47 +694,47 @@ to be displayed as %1</source>
|
||||
%1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.cpp" line="622"/>
|
||||
<location filename="../ui/squawk.cpp" line="631"/>
|
||||
<source>Renaming %1</source>
|
||||
<translation>Назначение имени контакту %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.cpp" line="628"/>
|
||||
<location filename="../ui/squawk.cpp" line="637"/>
|
||||
<source>Groups</source>
|
||||
<translation>Группы</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.cpp" line="643"/>
|
||||
<location filename="../ui/squawk.cpp" line="652"/>
|
||||
<source>New group</source>
|
||||
<translation>Создать новую группу</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.cpp" line="653"/>
|
||||
<location filename="../ui/squawk.cpp" line="662"/>
|
||||
<source>New group name</source>
|
||||
<translation>Имя группы</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.cpp" line="654"/>
|
||||
<location filename="../ui/squawk.cpp" line="663"/>
|
||||
<source>Add %1 to a new group</source>
|
||||
<translation>Добавление %1 в новую группу</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.cpp" line="675"/>
|
||||
<location filename="../ui/squawk.cpp" line="684"/>
|
||||
<source>Open conversation</source>
|
||||
<translation>Открыть окно беседы</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.cpp" line="780"/>
|
||||
<location filename="../ui/squawk.cpp" line="789"/>
|
||||
<source>%1 account card</source>
|
||||
<translation>Карточка учетной записи %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.cpp" line="782"/>
|
||||
<location filename="../ui/squawk.cpp" line="791"/>
|
||||
<source>%1 contact card</source>
|
||||
<translation>Карточка контакта %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/squawk.cpp" line="794"/>
|
||||
<location filename="../ui/squawk.cpp" line="803"/>
|
||||
<source>Downloading vCard</source>
|
||||
<translation>Получение карточки</translation>
|
||||
</message>
|
||||
@ -663,119 +743,145 @@ to be displayed as %1</source>
|
||||
<name>VCard</name>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="65"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="612"/>
|
||||
<source>Received 12.07.2007 at 17.35</source>
|
||||
<translation>Не обновлялось</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="100"/>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="425"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="624"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="627"/>
|
||||
<source>General</source>
|
||||
<translation>Общее</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="130"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="613"/>
|
||||
<source>Organization</source>
|
||||
<translation>Место работы</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="180"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="614"/>
|
||||
<source>Middle name</source>
|
||||
<translation>Среднее имя</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="190"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="615"/>
|
||||
<source>First name</source>
|
||||
<translation>Имя</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="200"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="616"/>
|
||||
<source>Last name</source>
|
||||
<translation>Фамилия</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="226"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="617"/>
|
||||
<source>Nick name</source>
|
||||
<translation>Псевдоним</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="252"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="618"/>
|
||||
<source>Birthday</source>
|
||||
<translation>Дата рождения</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="272"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="619"/>
|
||||
<source>Organization name</source>
|
||||
<translation>Название организации</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="298"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="620"/>
|
||||
<source>Unit / Department</source>
|
||||
<translation>Отдел</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="324"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="621"/>
|
||||
<source>Role / Profession</source>
|
||||
<translation>Профессия</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="350"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="622"/>
|
||||
<source>Job title</source>
|
||||
<translation>Наименование должности</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="390"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="623"/>
|
||||
<source>Full name</source>
|
||||
<translation>Полное имя</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="460"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="625"/>
|
||||
<source>Personal information</source>
|
||||
<translation>Личная информация</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="653"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="629"/>
|
||||
<source>Addresses</source>
|
||||
<translation>Адреса</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="682"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="630"/>
|
||||
<source>E-Mail addresses</source>
|
||||
<translation>Адреса электронной почты</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="767"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="633"/>
|
||||
<source>Phone numbers</source>
|
||||
<translation>Номера телефонов</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="522"/>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="546"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="628"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="634"/>
|
||||
<source>Contact</source>
|
||||
<translation>Контактная информация</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="713"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="631"/>
|
||||
<source>Jabber ID</source>
|
||||
<translation>Jabber ID</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="739"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="632"/>
|
||||
<source>Web site</source>
|
||||
<translation>Веб сайт</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="798"/>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="822"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="635"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="636"/>
|
||||
<source>Description</source>
|
||||
<translation>Описание</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="859"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="610"/>
|
||||
<source>Set avatar</source>
|
||||
<translation>Установить иконку</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/widgets/vcard/vcard.ui" line="868"/>
|
||||
<location filename="../build/ui/widgets/vcard/vCardUI_autogen/include/ui_vcard.h" line="611"/>
|
||||
<source>Clear avatar</source>
|
||||
<translation>Убрать иконку</translation>
|
||||
</message>
|
||||
|
@ -300,7 +300,9 @@ void Squawk::onRosterItemDoubleClicked(const QModelIndex& item)
|
||||
conv->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
connect(conv, &Conversation::destroyed, this, &Squawk::onConversationClosed);
|
||||
connect(conv, &Conversation::sendMessage, this, &Squawk::onConversationMessage);
|
||||
connect(conv, qOverload<const Shared::Message&>(&Conversation::sendMessage), this, qOverload<const Shared::Message&>(&Squawk::onConversationMessage));
|
||||
connect(conv, qOverload<const Shared::Message&, const QString&>(&Conversation::sendMessage),
|
||||
this, qOverload<const Shared::Message&, const QString&>(&Squawk::onConversationMessage));
|
||||
connect(conv, &Conversation::requestArchive, this, &Squawk::onConversationRequestArchive);
|
||||
connect(conv, &Conversation::requestLocalFile, this, &Squawk::onConversationRequestLocalFile);
|
||||
connect(conv, &Conversation::downloadFile, this, &Squawk::onConversationDownloadFile);
|
||||
@ -367,11 +369,11 @@ void Squawk::onConversationDownloadFile(const QString& messageId, const QString&
|
||||
}
|
||||
}
|
||||
|
||||
void Squawk::downloadFileProgress(const QString& messageId, qreal value)
|
||||
void Squawk::fileProgress(const QString& messageId, qreal value)
|
||||
{
|
||||
std::map<QString, std::set<Models::Roster::ElId>>::const_iterator itr = requestedFiles.find(messageId);
|
||||
if (itr == requestedFiles.end()) {
|
||||
qDebug() << "downloadFileProgress in UI Squawk but there is nobody waiting for that id" << messageId << ", skipping";
|
||||
qDebug() << "fileProgress in UI Squawk but there is nobody waiting for that id" << messageId << ", skipping";
|
||||
return;
|
||||
} else {
|
||||
const std::set<Models::Roster::ElId>& convs = itr->second;
|
||||
@ -379,17 +381,17 @@ void Squawk::downloadFileProgress(const QString& messageId, qreal value)
|
||||
const Models::Roster::ElId& id = *cItr;
|
||||
Conversations::const_iterator c = conversations.find(id);
|
||||
if (c != conversations.end()) {
|
||||
c->second->responseDownloadProgress(messageId, value);
|
||||
c->second->responseFileProgress(messageId, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Squawk::downloadFileError(const QString& messageId, const QString& error)
|
||||
void Squawk::fileError(const QString& messageId, const QString& error)
|
||||
{
|
||||
std::map<QString, std::set<Models::Roster::ElId>>::const_iterator itr = requestedFiles.find(messageId);
|
||||
if (itr == requestedFiles.end()) {
|
||||
qDebug() << "downloadFileError in UI Squawk but there is nobody waiting for that id" << messageId << ", skipping";
|
||||
qDebug() << "fileError in UI Squawk but there is nobody waiting for that id" << messageId << ", skipping";
|
||||
return;
|
||||
} else {
|
||||
const std::set<Models::Roster::ElId>& convs = itr->second;
|
||||
@ -397,7 +399,7 @@ void Squawk::downloadFileError(const QString& messageId, const QString& error)
|
||||
const Models::Roster::ElId& id = *cItr;
|
||||
Conversations::const_iterator c = conversations.find(id);
|
||||
if (c != conversations.end()) {
|
||||
c->second->downloadError(messageId, error);
|
||||
c->second->fileError(messageId, error);
|
||||
}
|
||||
}
|
||||
requestedFiles.erase(itr);
|
||||
@ -489,10 +491,18 @@ void Squawk::notify(const QString& account, const Shared::Message& msg)
|
||||
void Squawk::onConversationMessage(const Shared::Message& msg)
|
||||
{
|
||||
Conversation* conv = static_cast<Conversation*>(sender());
|
||||
|
||||
emit sendMessage(conv->getAccount(), msg);
|
||||
}
|
||||
|
||||
void Squawk::onConversationMessage(const Shared::Message& msg, const QString& path)
|
||||
{
|
||||
Conversation* conv = static_cast<Conversation*>(sender());
|
||||
std::map<QString, std::set<Models::Roster::ElId>>::iterator itr = requestedFiles.insert(std::make_pair(msg.getId(), std::set<Models::Roster::ElId>())).first;
|
||||
itr->second.insert(Models::Roster::ElId(conv->getAccount(), conv->getJid()));
|
||||
|
||||
emit sendMessage(conv->getAccount(), msg, path);
|
||||
}
|
||||
|
||||
void Squawk::onConversationRequestArchive(const QString& before)
|
||||
{
|
||||
Conversation* conv = static_cast<Conversation*>(sender());
|
||||
@ -518,7 +528,6 @@ void Squawk::removeAccount(const QString& account)
|
||||
++itr;
|
||||
Conversation* conv = lItr->second;
|
||||
disconnect(conv, &Conversation::destroyed, this, &Squawk::onConversationClosed);
|
||||
disconnect(conv, &Conversation::sendMessage, this, &Squawk::onConversationMessage);
|
||||
disconnect(conv, &Conversation::requestArchive, this, &Squawk::onConversationRequestArchive);
|
||||
disconnect(conv, &Conversation::shown, this, &Squawk::onConversationShown);
|
||||
conv->close();
|
||||
|
@ -58,6 +58,7 @@ signals:
|
||||
void disconnectAccount(const QString&);
|
||||
void changeState(int state);
|
||||
void sendMessage(const QString& account, const Shared::Message& data);
|
||||
void sendMessage(const QString& account, const Shared::Message& data, const QString& path);
|
||||
void requestArchive(const QString& account, const QString& jid, int count, const QString& before);
|
||||
void subscribeContact(const QString& account, const QString& jid, const QString& reason);
|
||||
void unsubscribeContact(const QString& account, const QString& jid, const QString& reason);
|
||||
@ -97,8 +98,8 @@ public slots:
|
||||
void changeRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap<QString, QVariant>& data);
|
||||
void removeRoomParticipant(const QString& account, const QString& jid, const QString& name);
|
||||
void fileLocalPathResponse(const QString& messageId, const QString& path);
|
||||
void downloadFileError(const QString& messageId, const QString& error);
|
||||
void downloadFileProgress(const QString& messageId, qreal value);
|
||||
void fileError(const QString& messageId, const QString& error);
|
||||
void fileProgress(const QString& messageId, qreal value);
|
||||
void responseVCard(const QString& jid, const Shared::VCard& card);
|
||||
|
||||
private:
|
||||
@ -132,6 +133,7 @@ private slots:
|
||||
void onComboboxActivated(int index);
|
||||
void onRosterItemDoubleClicked(const QModelIndex& item);
|
||||
void onConversationMessage(const Shared::Message& msg);
|
||||
void onConversationMessage(const Shared::Message& msg, const QString& path);
|
||||
void onConversationRequestArchive(const QString& before);
|
||||
void onRosterContextMenu(const QPoint& point);
|
||||
void onConversationShown();
|
||||
|
@ -34,16 +34,14 @@ Message::Message(const Shared::Message& source, bool outgoing, const QString& p_
|
||||
sender(new QLabel(p_sender)),
|
||||
text(new QLabel()),
|
||||
shadow(new QGraphicsDropShadowEffect()),
|
||||
downloadButton(0),
|
||||
button(0),
|
||||
file(0),
|
||||
progress(0),
|
||||
fileComment(new QLabel()),
|
||||
errorText(""),
|
||||
hasDownloadButton(false),
|
||||
hasButton(false),
|
||||
hasProgress(false),
|
||||
hasFile(false),
|
||||
commentAdded(false),
|
||||
errorDownloadingFile(false)
|
||||
commentAdded(false)
|
||||
{
|
||||
body->setBackgroundRole(QPalette::AlternateBase);
|
||||
body->setAutoFillBackground(true);
|
||||
@ -79,13 +77,13 @@ Message::Message(const Shared::Message& source, bool outgoing, const QString& p_
|
||||
body->setGraphicsEffect(shadow);
|
||||
|
||||
if (outgoing) {
|
||||
addWidget(body);
|
||||
addStretch();
|
||||
} else {
|
||||
sender->setAlignment(Qt::AlignRight);
|
||||
date->setAlignment(Qt::AlignRight);
|
||||
addStretch();
|
||||
addWidget(body);
|
||||
} else {
|
||||
addWidget(body);
|
||||
addStretch();
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,6 +92,7 @@ Message::~Message()
|
||||
if (!commentAdded) {
|
||||
delete fileComment;
|
||||
}
|
||||
delete body;
|
||||
}
|
||||
|
||||
QString Message::getId() const
|
||||
@ -101,47 +100,38 @@ QString Message::getId() const
|
||||
return msg.getId();
|
||||
}
|
||||
|
||||
QString Message::getFileUrl() const
|
||||
{
|
||||
return msg.getOutOfBandUrl();
|
||||
}
|
||||
|
||||
void Message::setSender(const QString& p_sender)
|
||||
{
|
||||
sender->setText(p_sender);
|
||||
}
|
||||
|
||||
void Message::addDownloadDialog()
|
||||
void Message::addButton(const QIcon& icon, const QString& buttonText, const QString& tooltip)
|
||||
{
|
||||
hideFile();
|
||||
hideProgress();
|
||||
if (!hasDownloadButton) {
|
||||
if (!hasButton) {
|
||||
hideComment();
|
||||
if (msg.getBody() == msg.getOutOfBandUrl()) {
|
||||
text->setText("");
|
||||
text->hide();
|
||||
}
|
||||
downloadButton = new QPushButton(QIcon::fromTheme("download"), tr("Download"));
|
||||
downloadButton->setToolTip("<a href=\"" + msg.getOutOfBandUrl() + "\">" + msg.getOutOfBandUrl() + "</a>");
|
||||
if (errorDownloadingFile) {
|
||||
fileComment->setWordWrap(true);
|
||||
fileComment->setText(tr("Error downloading file: %1\nYou can try again").arg(QCoreApplication::translate("NetworkErrors", errorText.toLatin1())));
|
||||
} else {
|
||||
fileComment->setText(tr("%1 is offering you to download a file").arg(sender->text()));
|
||||
}
|
||||
fileComment->show();
|
||||
connect(downloadButton, &QPushButton::clicked, this, &Message::onDownload);
|
||||
bodyLayout->insertWidget(2, fileComment);
|
||||
bodyLayout->insertWidget(3, downloadButton);
|
||||
hasDownloadButton = true;
|
||||
commentAdded = true;
|
||||
button = new QPushButton(icon, buttonText);
|
||||
button->setToolTip(tooltip);
|
||||
connect(button, &QPushButton::clicked, this, &Message::buttonClicked);
|
||||
bodyLayout->insertWidget(2, button);
|
||||
hasButton = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Message::onDownload()
|
||||
{
|
||||
emit downloadFile(msg.getId(), msg.getOutOfBandUrl());
|
||||
}
|
||||
|
||||
void Message::setProgress(qreal value)
|
||||
{
|
||||
hideFile();
|
||||
hideDownload();
|
||||
hideButton();
|
||||
if (!hasProgress) {
|
||||
hideComment();
|
||||
if (msg.getBody() == msg.getOutOfBandUrl()) {
|
||||
@ -150,19 +140,15 @@ void Message::setProgress(qreal value)
|
||||
}
|
||||
progress = new QProgressBar();
|
||||
progress->setRange(0, 100);
|
||||
fileComment->setText("Downloading...");
|
||||
fileComment->show();
|
||||
bodyLayout->insertWidget(2, progress);
|
||||
bodyLayout->insertWidget(3, fileComment);
|
||||
hasProgress = true;
|
||||
commentAdded = true;
|
||||
}
|
||||
progress->setValue(value * 100);
|
||||
}
|
||||
|
||||
void Message::showFile(const QString& path)
|
||||
{
|
||||
hideDownload();
|
||||
hideButton();
|
||||
hideProgress();
|
||||
if (!hasFile) {
|
||||
hideComment();
|
||||
@ -175,16 +161,13 @@ void Message::showFile(const QString& path)
|
||||
QStringList parts = type.name().split("/");
|
||||
QString big = parts.front();
|
||||
QFileInfo info(path);
|
||||
fileComment = new QLabel();
|
||||
if (big == "image") {
|
||||
file = new Image(path);
|
||||
} else {
|
||||
file = new QLabel();
|
||||
file->setPixmap(QIcon::fromTheme(type.iconName()).pixmap(50));
|
||||
file->setAlignment(Qt::AlignCenter);
|
||||
fileComment->setText(info.fileName());
|
||||
fileComment->setWordWrap(true);
|
||||
fileComment->show();
|
||||
showComment(info.fileName(), true);
|
||||
}
|
||||
file->setContextMenuPolicy(Qt::ActionsContextMenu);
|
||||
QAction* openAction = new QAction(QIcon::fromTheme("document-new-from-template"), tr("Open"), file);
|
||||
@ -193,9 +176,7 @@ void Message::showFile(const QString& path)
|
||||
});
|
||||
file->addAction(openAction);
|
||||
bodyLayout->insertWidget(2, file);
|
||||
bodyLayout->insertWidget(3, fileComment);
|
||||
hasFile = true;
|
||||
commentAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,13 +189,12 @@ void Message::hideComment()
|
||||
}
|
||||
}
|
||||
|
||||
void Message::hideDownload()
|
||||
void Message::hideButton()
|
||||
{
|
||||
if (hasDownloadButton) {
|
||||
downloadButton->deleteLater();
|
||||
downloadButton = 0;
|
||||
hasDownloadButton = false;
|
||||
errorDownloadingFile = false;
|
||||
if (hasButton) {
|
||||
button->deleteLater();
|
||||
button = 0;
|
||||
hasButton = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,10 +215,29 @@ void Message::hideProgress()
|
||||
hasProgress = false;;
|
||||
}
|
||||
}
|
||||
|
||||
void Message::showError(const QString& error)
|
||||
void Message::showComment(const QString& comment, bool wordWrap)
|
||||
{
|
||||
errorDownloadingFile = true;
|
||||
errorText = error;
|
||||
addDownloadDialog();
|
||||
if (!commentAdded) {
|
||||
int index = 2;
|
||||
if (hasFile) {
|
||||
index++;
|
||||
}
|
||||
if (hasButton) {
|
||||
index++;
|
||||
}
|
||||
if (hasProgress) {
|
||||
index++;
|
||||
}
|
||||
bodyLayout->insertWidget(index, fileComment);
|
||||
fileComment->show();
|
||||
commentAdded = true;
|
||||
}
|
||||
fileComment->setWordWrap(wordWrap);
|
||||
fileComment->setText(comment);
|
||||
}
|
||||
|
||||
const Shared::Message & Message::getMessage() const
|
||||
{
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
@ -30,9 +30,9 @@
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
|
||||
#include "../../global.h"
|
||||
#include "../utils/resizer.h"
|
||||
#include "../utils/image.h"
|
||||
#include "global.h"
|
||||
#include "resizer.h"
|
||||
#include "image.h"
|
||||
|
||||
/**
|
||||
* @todo write docs
|
||||
@ -46,14 +46,17 @@ public:
|
||||
|
||||
void setSender(const QString& sender);
|
||||
QString getId() const;
|
||||
QString getFileUrl() const;
|
||||
const Shared::Message& getMessage() const;
|
||||
|
||||
void addDownloadDialog();
|
||||
void addButton(const QIcon& icon, const QString& buttonText, const QString& tooltip = "");
|
||||
void showComment(const QString& comment, bool wordWrap = false);
|
||||
void hideComment();
|
||||
void showFile(const QString& path);
|
||||
void showError(const QString& error);
|
||||
void setProgress(qreal value);
|
||||
|
||||
signals:
|
||||
void downloadFile(const QString& messageId, const QString& url);
|
||||
void buttonClicked();
|
||||
|
||||
private:
|
||||
Shared::Message msg;
|
||||
@ -63,25 +66,19 @@ private:
|
||||
QLabel* sender;
|
||||
QLabel* text;
|
||||
QGraphicsDropShadowEffect* shadow;
|
||||
QPushButton* downloadButton;
|
||||
QPushButton* button;
|
||||
QLabel* file;
|
||||
QProgressBar* progress;
|
||||
QLabel* fileComment;
|
||||
QString errorText;
|
||||
bool hasDownloadButton;
|
||||
bool hasButton;
|
||||
bool hasProgress;
|
||||
bool hasFile;
|
||||
bool commentAdded;
|
||||
bool errorDownloadingFile;
|
||||
|
||||
private slots:
|
||||
void onDownload();
|
||||
|
||||
private:
|
||||
void hideDownload();
|
||||
void hideButton();
|
||||
void hideProgress();
|
||||
void hideFile();
|
||||
void hideComment();
|
||||
};
|
||||
|
||||
#endif // MESSAGE_H
|
||||
|
@ -26,10 +26,12 @@ MessageLine::MessageLine(bool p_room, QWidget* parent):
|
||||
messageOrder(),
|
||||
myMessages(),
|
||||
palMessages(),
|
||||
uploadPaths(),
|
||||
layout(new QVBoxLayout(this)),
|
||||
myName(),
|
||||
palNames(),
|
||||
views(),
|
||||
uploading(),
|
||||
downloading(),
|
||||
room(p_room),
|
||||
busyShown(false),
|
||||
progress()
|
||||
@ -45,7 +47,7 @@ MessageLine::~MessageLine()
|
||||
}
|
||||
}
|
||||
|
||||
MessageLine::Position MessageLine::message(const Shared::Message& msg)
|
||||
MessageLine::Position MessageLine::message(const Shared::Message& msg, bool forceOutgoing)
|
||||
{
|
||||
QString id = msg.getId();
|
||||
Index::iterator itr = messageIndex.find(id);
|
||||
@ -57,27 +59,32 @@ MessageLine::Position MessageLine::message(const Shared::Message& msg)
|
||||
QString sender;
|
||||
bool outgoing;
|
||||
|
||||
if (room) {
|
||||
if (msg.getFromResource() == myName) {
|
||||
sender = myName;
|
||||
outgoing = false;
|
||||
} else {
|
||||
sender = msg.getFromResource();
|
||||
outgoing = true;
|
||||
}
|
||||
if (forceOutgoing) {
|
||||
sender = myName;
|
||||
outgoing = true;
|
||||
} else {
|
||||
if (msg.getOutgoing()) {
|
||||
sender = myName;
|
||||
outgoing = false;
|
||||
} else {
|
||||
QString jid = msg.getFromJid();
|
||||
std::map<QString, QString>::iterator itr = palNames.find(jid);
|
||||
if (itr != palNames.end()) {
|
||||
sender = itr->second;
|
||||
if (room) {
|
||||
if (msg.getFromResource() == myName) {
|
||||
sender = myName;
|
||||
outgoing = true;
|
||||
} else {
|
||||
sender = jid;
|
||||
sender = msg.getFromResource();
|
||||
outgoing = false;
|
||||
}
|
||||
} else {
|
||||
if (msg.getOutgoing()) {
|
||||
sender = myName;
|
||||
outgoing = true;
|
||||
} else {
|
||||
QString jid = msg.getFromJid();
|
||||
std::map<QString, QString>::iterator itr = palNames.find(jid);
|
||||
if (itr != palNames.end()) {
|
||||
sender = itr->second;
|
||||
} else {
|
||||
sender = jid;
|
||||
}
|
||||
outgoing = false;
|
||||
}
|
||||
outgoing = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,6 +97,8 @@ MessageLine::Position MessageLine::message(const Shared::Message& msg)
|
||||
return invalid;
|
||||
}
|
||||
if (outgoing) {
|
||||
myMessages.insert(std::make_pair(id, message));
|
||||
} else {
|
||||
if (room) {
|
||||
|
||||
} else {
|
||||
@ -100,8 +109,6 @@ MessageLine::Position MessageLine::message(const Shared::Message& msg)
|
||||
}
|
||||
pItr->second.insert(std::make_pair(id, message));
|
||||
}
|
||||
} else {
|
||||
myMessages.insert(std::make_pair(id, message));
|
||||
}
|
||||
messageIndex.insert(std::make_pair(id, message));
|
||||
int index = std::distance<Order::const_iterator>(messageOrder.begin(), result.first); //need to make with binary indexed tree
|
||||
@ -125,14 +132,29 @@ MessageLine::Position MessageLine::message(const Shared::Message& msg)
|
||||
layout->insertLayout(index, message);
|
||||
}
|
||||
|
||||
if (msg.hasOutOfBandUrl()) {\
|
||||
if (msg.hasOutOfBandUrl()) {
|
||||
emit requestLocalFile(msg.getId(), msg.getOutOfBandUrl());
|
||||
connect(message, &Message::downloadFile, this, &MessageLine::downloadFile);
|
||||
connect(message, &Message::buttonClicked, this, &MessageLine::onDownload);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void MessageLine::onDownload()
|
||||
{
|
||||
Message* msg = static_cast<Message*>(sender());
|
||||
QString messageId = msg->getId();
|
||||
Index::const_iterator itr = downloading.find(messageId);
|
||||
if (itr == downloading.end()) {
|
||||
downloading.insert(std::make_pair(messageId, msg));
|
||||
msg->setProgress(0);
|
||||
msg->showComment(tr("Downloading..."));
|
||||
emit downloadFile(messageId, msg->getFileUrl());
|
||||
} else {
|
||||
qDebug() << "An attempt to initiate download for already downloading file" << msg->getFileUrl() << ", skipping";
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLine::setMyName(const QString& name)
|
||||
{
|
||||
myName = name;
|
||||
@ -192,11 +214,11 @@ void MessageLine::hideBusyIndicator()
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLine::responseDownloadProgress(const QString& messageId, qreal progress)
|
||||
void MessageLine::fileProgress(const QString& messageId, qreal progress)
|
||||
{
|
||||
Index::const_iterator itr = messageIndex.find(messageId);
|
||||
if (itr == messageIndex.end()) {
|
||||
|
||||
//TODO may be some logging, that's not normal
|
||||
} else {
|
||||
itr->second->setProgress(progress);
|
||||
}
|
||||
@ -208,21 +230,121 @@ void MessageLine::responseLocalFile(const QString& messageId, const QString& pat
|
||||
if (itr == messageIndex.end()) {
|
||||
|
||||
} else {
|
||||
Index::const_iterator uItr = uploading.find(messageId);
|
||||
if (path.size() > 0) {
|
||||
itr->second->showFile(path);
|
||||
Index::const_iterator dItr = downloading.find(messageId);
|
||||
if (dItr != downloading.end()) {
|
||||
downloading.erase(dItr);
|
||||
itr->second->showFile(path);
|
||||
} else {
|
||||
if (uItr != uploading.end()) {
|
||||
uploading.erase(uItr);
|
||||
std::map<QString, QString>::const_iterator muItr = uploadPaths.find(messageId);
|
||||
if (muItr != uploadPaths.end()) {
|
||||
uploadPaths.erase(muItr);
|
||||
}
|
||||
if (room) {
|
||||
removeMessage(messageId);
|
||||
} else {
|
||||
Shared::Message msg = itr->second->getMessage();
|
||||
removeMessage(messageId);
|
||||
msg.setCurrentTime();
|
||||
message(msg);
|
||||
itr = messageIndex.find(messageId);
|
||||
itr->second->showFile(path);
|
||||
}
|
||||
} else {
|
||||
itr->second->showFile(path); //then it is already cached file
|
||||
}
|
||||
}
|
||||
} else {
|
||||
itr->second->addDownloadDialog();
|
||||
if (uItr == uploading.end()) {
|
||||
const Shared::Message& msg = itr->second->getMessage();
|
||||
itr->second->addButton(QIcon::fromTheme("download"), tr("Download"), "<a href=\"" + msg.getOutOfBandUrl() + "\">" + msg.getOutOfBandUrl() + "</a>");
|
||||
itr->second->showComment(tr("Push the button to daownload the file"));
|
||||
} else {
|
||||
qDebug() << "An unhandled state for file uploading - empty path";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLine::downloadError(const QString& messageId, const QString& error)
|
||||
void MessageLine::removeMessage(const QString& messageId)
|
||||
{
|
||||
Index::const_iterator itr = messageIndex.find(messageId);
|
||||
if (itr == messageIndex.end()) {
|
||||
|
||||
if (itr != messageIndex.end()) {
|
||||
Message* ui = itr->second;
|
||||
const Shared::Message& msg = ui->getMessage();
|
||||
messageIndex.erase(itr);
|
||||
Order::const_iterator oItr = messageOrder.find(msg.getTime());
|
||||
if (oItr != messageOrder.end()) {
|
||||
messageOrder.erase(oItr);
|
||||
} else {
|
||||
qDebug() << "An attempt to remove message from messageLine, but it wasn't found in order";
|
||||
}
|
||||
if (msg.getOutgoing()) {
|
||||
Index::const_iterator mItr = myMessages.find(messageId);
|
||||
if (mItr != myMessages.end()) {
|
||||
myMessages.erase(mItr);
|
||||
} else {
|
||||
qDebug() << "Error removing message: it seems to be outgoing yet it wasn't found in outgoing messages";
|
||||
}
|
||||
} else {
|
||||
if (room) {
|
||||
|
||||
} else {
|
||||
QString jid = msg.getFromJid();
|
||||
std::map<QString, Index>::iterator pItr = palMessages.find(jid);
|
||||
if (pItr != palMessages.end()) {
|
||||
Index& pMsgs = pItr->second;
|
||||
Index::const_iterator pmitr = pMsgs.find(messageId);
|
||||
if (pmitr != pMsgs.end()) {
|
||||
pMsgs.erase(pmitr);
|
||||
} else {
|
||||
qDebug() << "Error removing message: it seems to be incoming yet it wasn't found among messages from that penpal";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ui->deleteLater();
|
||||
qDebug() << "message" << messageId << "has been removed";
|
||||
} else {
|
||||
itr->second->showError(error);
|
||||
qDebug() << "An attempt to remove non existing message from messageLine";
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLine::fileError(const QString& messageId, const QString& error)
|
||||
{
|
||||
Index::const_iterator itr = downloading.find(messageId);
|
||||
if (itr == downloading.end()) {
|
||||
Index::const_iterator itr = uploading.find(messageId);
|
||||
if (itr == uploading.end()) {
|
||||
//TODO may be some logging, that's not normal
|
||||
} else {
|
||||
itr->second->showComment(tr("Error uploading file: %1\nYou can try again").arg(QCoreApplication::translate("NetworkErrors", error.toLatin1())), true);
|
||||
itr->second->addButton(QIcon::fromTheme("upload"), tr("Upload"));
|
||||
}
|
||||
} else {
|
||||
const Shared::Message& msg = itr->second->getMessage();
|
||||
itr->second->addButton(QIcon::fromTheme("download"), tr("Download"), "<a href=\"" + msg.getOutOfBandUrl() + "\">" + msg.getOutOfBandUrl() + "</a>");
|
||||
itr->second->showComment(tr("Error downloading file: %1\nYou can try again").arg(QCoreApplication::translate("NetworkErrors", error.toLatin1())), true);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLine::appendMessageWithUpload(const Shared::Message& msg, const QString& path)
|
||||
{
|
||||
message(msg, true);
|
||||
QString id = msg.getId();
|
||||
Message* ui = messageIndex.find(id)->second;
|
||||
connect(ui, &Message::buttonClicked, this, &MessageLine::onUpload); //this is in case of retry;
|
||||
ui->setProgress(0);
|
||||
ui->showComment(tr("Uploading..."));
|
||||
uploading.insert(std::make_pair(id, ui));
|
||||
uploadPaths.insert(std::make_pair(id, path));
|
||||
emit uploadFile(msg, path);
|
||||
}
|
||||
|
||||
void MessageLine::onUpload()
|
||||
{
|
||||
//TODO retry
|
||||
}
|
||||
|
@ -43,24 +43,31 @@ public:
|
||||
MessageLine(bool p_room, QWidget* parent = 0);
|
||||
~MessageLine();
|
||||
|
||||
Position message(const Shared::Message& msg);
|
||||
Position message(const Shared::Message& msg, bool forceOutgoing = false);
|
||||
void setMyName(const QString& name);
|
||||
void setPalName(const QString& jid, const QString& name);
|
||||
QString firstMessageId() const;
|
||||
void showBusyIndicator();
|
||||
void hideBusyIndicator();
|
||||
void responseLocalFile(const QString& messageId, const QString& path);
|
||||
void downloadError(const QString& messageId, const QString& error);
|
||||
void responseDownloadProgress(const QString& messageId, qreal progress);
|
||||
void fileError(const QString& messageId, const QString& error);
|
||||
void fileProgress(const QString& messageId, qreal progress);
|
||||
void appendMessageWithUpload(const Shared::Message& msg, const QString& path);
|
||||
void removeMessage(const QString& messageId);
|
||||
|
||||
signals:
|
||||
void resize(int amount);
|
||||
void downloadFile(const QString& messageId, const QString& url);
|
||||
void uploadFile(const Shared::Message& msg, const QString& path);
|
||||
void requestLocalFile(const QString& messageId, const QString& url);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent * event) override;
|
||||
|
||||
protected:
|
||||
void onDownload();
|
||||
void onUpload();
|
||||
|
||||
private:
|
||||
struct Comparator {
|
||||
bool operator()(const Shared::Message& a, const Shared::Message& b) const {
|
||||
@ -76,11 +83,13 @@ private:
|
||||
Order messageOrder;
|
||||
Index myMessages;
|
||||
std::map<QString, Index> palMessages;
|
||||
std::map<QString, QString> uploadPaths;
|
||||
QVBoxLayout* layout;
|
||||
|
||||
QString myName;
|
||||
std::map<QString, QString> palNames;
|
||||
std::deque<QHBoxLayout*> views;
|
||||
Index uploading;
|
||||
Index downloading;
|
||||
bool room;
|
||||
bool busyShown;
|
||||
Progress progress;
|
||||
|
@ -27,7 +27,8 @@ QObject(parent)
|
||||
bool Resizer::eventFilter(QObject* obj, QEvent* event)
|
||||
{
|
||||
if (event->type() == QEvent::Resize) {
|
||||
emit resized();
|
||||
QResizeEvent* ev = static_cast<QResizeEvent*>(event);
|
||||
emit resized(ev->oldSize(), ev->size());
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QEvent>
|
||||
#include <QResizeEvent>
|
||||
|
||||
/**
|
||||
* @todo write docs
|
||||
@ -35,7 +36,7 @@ protected:
|
||||
bool eventFilter(QObject* obj, QEvent* event) override;
|
||||
|
||||
signals:
|
||||
void resized();
|
||||
void resized(const QSize& oldSize, const QSize& newSize);
|
||||
};
|
||||
|
||||
#endif // RESIZER_H
|
||||
|
@ -36,7 +36,8 @@ Conversation::Conversation(bool muc, const QString& mJid, const QString mRes, co
|
||||
line(new MessageLine(muc)),
|
||||
m_ui(new Ui::Conversation()),
|
||||
ker(),
|
||||
res(),
|
||||
scrollResizeCatcher(),
|
||||
attachResizeCatcher(),
|
||||
vis(),
|
||||
thread(),
|
||||
statusIcon(0),
|
||||
@ -60,14 +61,17 @@ Conversation::Conversation(bool muc, const QString& mJid, const QString mRes, co
|
||||
statusLabel = m_ui->statusLabel;
|
||||
|
||||
connect(&ker, &KeyEnterReceiver::enterPressed, this, &Conversation::onEnterPressed);
|
||||
connect(&res, &Resizer::resized, this, &Conversation::onScrollResize);
|
||||
connect(&scrollResizeCatcher, &Resizer::resized, this, &Conversation::onScrollResize);
|
||||
connect(&attachResizeCatcher, &Resizer::resized, this, &Conversation::onAttachResize);
|
||||
connect(&vis, &VisibilityCatcher::shown, this, &Conversation::onScrollResize);
|
||||
connect(&vis, &VisibilityCatcher::hidden, this, &Conversation::onScrollResize);
|
||||
connect(m_ui->sendButton, &QPushButton::clicked, this, &Conversation::onEnterPressed);
|
||||
connect(line, &MessageLine::resize, this, &Conversation::onMessagesResize);
|
||||
connect(line, &MessageLine::downloadFile, this, &Conversation::downloadFile);
|
||||
connect(line, &MessageLine::uploadFile, this, qOverload<const Shared::Message&, const QString&>(&Conversation::sendMessage));
|
||||
connect(line, &MessageLine::requestLocalFile, this, &Conversation::requestLocalFile);
|
||||
connect(m_ui->attachButton, &QPushButton::clicked, this, &Conversation::onAttach);
|
||||
connect(m_ui->clearButton, &QPushButton::clicked, this, &Conversation::onClearButton);
|
||||
|
||||
m_ui->messageEditor->installEventFilter(&ker);
|
||||
|
||||
@ -77,7 +81,8 @@ Conversation::Conversation(bool muc, const QString& mJid, const QString mRes, co
|
||||
vs->setBackgroundRole(QPalette::Base);
|
||||
vs->setAutoFillBackground(true);
|
||||
connect(vs, &QScrollBar::valueChanged, this, &Conversation::onSliderValueChanged);
|
||||
m_ui->scrollArea->installEventFilter(&res);
|
||||
m_ui->scrollArea->installEventFilter(&scrollResizeCatcher);
|
||||
m_ui->filesPanel->installEventFilter(&attachResizeCatcher);
|
||||
|
||||
applyVisualEffects();
|
||||
}
|
||||
@ -184,6 +189,25 @@ void Conversation::onEnterPressed()
|
||||
m_ui->messageEditor->clear();
|
||||
handleSendMessage(body);
|
||||
}
|
||||
if (filesToAttach.size() > 0) {
|
||||
for (Badge* badge : filesToAttach) {
|
||||
Shared::Message msg;
|
||||
if (isMuc) {
|
||||
msg.setType(Shared::Message::groupChat);
|
||||
} else {
|
||||
msg.setType(Shared::Message::chat);
|
||||
msg.setToResource(activePalResource);
|
||||
}
|
||||
msg.setFromJid(myJid);
|
||||
msg.setFromResource(myResource);
|
||||
msg.setToJid(palJid);
|
||||
msg.setOutgoing(true);
|
||||
msg.generateRandomId();
|
||||
msg.setCurrentTime();
|
||||
line->appendMessageWithUpload(msg, badge->id);
|
||||
}
|
||||
clearAttachedFiles();
|
||||
}
|
||||
}
|
||||
|
||||
void Conversation::onMessagesResize(int amount)
|
||||
@ -294,14 +318,14 @@ void Conversation::onScrollResize()
|
||||
}
|
||||
}
|
||||
|
||||
void Conversation::responseDownloadProgress(const QString& messageId, qreal progress)
|
||||
void Conversation::responseFileProgress(const QString& messageId, qreal progress)
|
||||
{
|
||||
line->responseDownloadProgress(messageId, progress);
|
||||
line->fileProgress(messageId, progress);
|
||||
}
|
||||
|
||||
void Conversation::downloadError(const QString& messageId, const QString& error)
|
||||
void Conversation::fileError(const QString& messageId, const QString& error)
|
||||
{
|
||||
line->downloadError(messageId, error);
|
||||
line->fileError(messageId, error);
|
||||
}
|
||||
|
||||
void Conversation::responseLocalFile(const QString& messageId, const QString& path)
|
||||
@ -352,6 +376,30 @@ void Conversation::clearAttachedFiles()
|
||||
filesLayout->setContentsMargins(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void Conversation::onClearButton()
|
||||
{
|
||||
clearAttachedFiles();
|
||||
m_ui->messageEditor->clear();
|
||||
}
|
||||
|
||||
void Conversation::onAttachResize(const QSize& oldSize, const QSize& newSize)
|
||||
{
|
||||
int oh = oldSize.height();
|
||||
int nh = newSize.height();
|
||||
|
||||
int d = oh - nh;
|
||||
|
||||
if (d != 0) {
|
||||
QList<int> cs = m_ui->splitter->sizes();
|
||||
cs.first() += d;
|
||||
cs.last() -=d;
|
||||
|
||||
m_ui->splitter->setSizes(cs);
|
||||
m_ui->scrollArea->verticalScrollBar()->setValue(m_ui->scrollArea->verticalScrollBar()->maximum());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool VisibilityCatcher::eventFilter(QObject* obj, QEvent* event)
|
||||
{
|
||||
if (event->type() == QEvent::Show) {
|
||||
|
@ -75,11 +75,12 @@ public:
|
||||
void responseArchive(const std::list<Shared::Message> list);
|
||||
void showEvent(QShowEvent * event) override;
|
||||
void responseLocalFile(const QString& messageId, const QString& path);
|
||||
void downloadError(const QString& messageId, const QString& error);
|
||||
void responseDownloadProgress(const QString& messageId, qreal progress);
|
||||
void fileError(const QString& messageId, const QString& error);
|
||||
void responseFileProgress(const QString& messageId, qreal progress);
|
||||
|
||||
signals:
|
||||
void sendMessage(const Shared::Message& message);
|
||||
void sendMessage(const Shared::Message& message, const QString& path);
|
||||
void requestArchive(const QString& before);
|
||||
void shown();
|
||||
void requestLocalFile(const QString& messageId, const QString& url);
|
||||
@ -101,7 +102,9 @@ protected slots:
|
||||
void onAttach();
|
||||
void onFileSelected();
|
||||
void onScrollResize();
|
||||
void onAttachResize(const QSize& oldSize, const QSize& newSize);
|
||||
void onBadgeClose();
|
||||
void onClearButton();
|
||||
|
||||
public:
|
||||
const bool isMuc;
|
||||
@ -120,7 +123,8 @@ protected:
|
||||
MessageLine* line;
|
||||
QScopedPointer<Ui::Conversation> m_ui;
|
||||
KeyEnterReceiver ker;
|
||||
Resizer res;
|
||||
Resizer scrollResizeCatcher;
|
||||
Resizer attachResizeCatcher;
|
||||
VisibilityCatcher vis;
|
||||
QString thread;
|
||||
QLabel* statusIcon;
|
||||
|
Loading…
Reference in New Issue
Block a user