feature: paste image in chat #51

Merged
blue merged 3 commits from shunf4/squawk:feat/paste_img into messageFeed 2021-10-16 15:34:01 +00:00
7 changed files with 86 additions and 7 deletions

View File

@ -378,7 +378,32 @@ void Core::NetworkAccess::onUploadFinished()
qDebug() << "upload success for" << url;
storage.addFile(upl->messages, upl->url, upl->path);
emit uploadFileComplete(upl->messages, upl->url);
emit uploadFileComplete(upl->messages, upl->url, upl->path);
// Copy file to Download folder if it is a temp file. See Conversation::onImagePasted.
if (upl->path.startsWith(QDir::tempPath() + QStringLiteral("/squawk_img_attach_")) && upl->path.endsWith(".png")) {
QString err = "";
QString downloadDirPath = prepareDirectory(upl->messages.front().jid);
if (downloadDirPath.size() > 0) {
QString newPath = downloadDirPath + "/" + upl->path.mid(QDir::tempPath().length() + 1);
// Copy {TEMPDIR}/squawk_img_attach_XXXXXX.png to Download folder
bool copyResult = QFile::copy(upl->path, newPath);
if (copyResult) {
// Change storage
storage.setPath(upl->url, newPath);
} else {
err = "copying to " + newPath + " failed";
}
} else {
err = "Couldn't prepare a directory for file";
}
if (err.size() != 0) {
qDebug() << "failed to copy temporary upload file " << upl->path << " to download folder:" << err;
}
}
}
upl->reply->deleteLater();

View File

@ -58,7 +58,7 @@ public:
signals:
void loadFileProgress(const std::list<Shared::MessageInfo>& msgs, qreal value, bool up);
void loadFileError(const std::list<Shared::MessageInfo>& msgs, const QString& text, bool up);
void uploadFileComplete(const std::list<Shared::MessageInfo>& msgs, const QString& url);
void uploadFileComplete(const std::list<Shared::MessageInfo>& msgs, const QString& url, const QString& path);
void downloadFileComplete(const std::list<Shared::MessageInfo>& msgs, const QString& path);
public slots:

View File

@ -82,7 +82,7 @@ signals:
void fileError(const std::list<Shared::MessageInfo> msgs, const QString& error, bool up);
void fileProgress(const std::list<Shared::MessageInfo> msgs, qreal value, bool up);
void fileDownloadComplete(const std::list<Shared::MessageInfo> msgs, const QString& path);
void fileUploadComplete(const std::list<Shared::MessageInfo> msgs, const QString& path);
void fileUploadComplete(const std::list<Shared::MessageInfo> msgs, const QString& url, const QString& path);
void responseVCard(const QString& jid, const Shared::VCard& card);
void changeMessage(const QString& account, const QString& jid, const QString& id, const QMap<QString, QVariant>& data);

View File

@ -405,7 +405,7 @@ void Squawk::fileError(const std::list<Shared::MessageInfo> msgs, const QString&
rosterModel.fileError(msgs, error, up);
}
void Squawk::fileUploadComplete(const std::list<Shared::MessageInfo> msgs, const QString& path)
void Squawk::fileUploadComplete(const std::list<Shared::MessageInfo> msgs, const QString& url, const QString& path)
{
rosterModel.fileComplete(msgs, true);
}

View File

@ -107,7 +107,7 @@ public slots:
void fileError(const std::list<Shared::MessageInfo> msgs, const QString& error, bool up);
void fileProgress(const std::list<Shared::MessageInfo> msgs, qreal value, bool up);
void fileDownloadComplete(const std::list<Shared::MessageInfo> msgs, const QString& path);
void fileUploadComplete(const std::list<Shared::MessageInfo> msgs, const QString& path);
void fileUploadComplete(const std::list<Shared::MessageInfo> msgs, const QString& url, const QString& path);
void responseVCard(const QString& jid, const Shared::VCard& card);
void changeMessage(const QString& account, const QString& jid, const QString& id, const QMap<QString, QVariant>& data);
void requestPassword(const QString& account);

View File

@ -20,6 +20,7 @@
#include "ui_conversation.h"
#include <QDebug>
#include <QClipboard>
#include <QScrollBar>
#include <QTimer>
#include <QFileDialog>
@ -27,6 +28,9 @@
#include <unistd.h>
#include <QAbstractTextDocumentLayout>
#include <QCoreApplication>
#include <QTemporaryFile>
#include <QDir>
#include <QMenu>
Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el, const QString pJid, const QString pRes, QWidget* parent):
QWidget(parent),
@ -47,6 +51,7 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el,
delegate(new MessageDelegate(this)),
manualSliderChange(false),
tsb(QApplication::style()->styleHint(QStyle::SH_ScrollBar_Transient) == 1),
pasteImageAction(new QAction(tr("Paste Image"), this)),
shadow(10, 1, Qt::black, this),
contextMenu(new QMenu())
{
@ -75,6 +80,7 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el,
statusLabel = m_ui->statusLabel;
connect(&ker, &KeyEnterReceiver::enterPressed, this, &Conversation::onEnterPressed);
connect(&ker, &KeyEnterReceiver::imagePasted, this, &Conversation::onImagePasted);
connect(m_ui->sendButton, &QPushButton::clicked, this, &Conversation::onEnterPressed);
connect(m_ui->attachButton, &QPushButton::clicked, this, &Conversation::onAttach);
connect(m_ui->clearButton, &QPushButton::clicked, this, &Conversation::onClearButton);
@ -82,8 +88,11 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el,
this, &Conversation::onTextEditDocSizeChanged);
m_ui->messageEditor->installEventFilter(&ker);
m_ui->messageEditor->setContextMenuPolicy(Qt::CustomContextMenu);
blue marked this conversation as resolved
Review

Do you mind if we better move it to initialization block? Cuz, since you declare here that variable again as QAction* it might be even considered like another variable rather than that one declared as a property...

Do you mind if we better move it to initialization block? Cuz, since you declare here that variable again as QAction* it might be even considered like another variable rather than that one declared as a property...
Review

How about this change? 52551c1ce0

How about this change? https://git.macaw.me/blue/squawk/commit/52551c1ce0be0a223e388d339389b7a55b159b6c
Review

That's good, thank you!

That's good, thank you!
connect(m_ui->messageEditor, &QTextEdit::customContextMenuRequested, this, &Conversation::onMessageEditorContext);
connect(pasteImageAction, &QAction::triggered, this, &Conversation::onImagePasted);
//line->setAutoFillBackground(false);
//if (testAttribute(Qt::WA_TranslucentBackground)) {
//m_ui->scrollArea->setAutoFillBackground(false);
@ -183,10 +192,20 @@ bool KeyEnterReceiver::eventFilter(QObject* obj, QEvent* event)
}
}
}
if (k == Qt::Key_V && key->modifiers() & Qt::CTRL) {
if (Conversation::checkClipboardImage()) {
emit imagePasted();
return true;
}
}
}
return QObject::eventFilter(obj, event);
}
bool Conversation::checkClipboardImage() {
return !QApplication::clipboard()->image().isNull();
}
QString Conversation::getPalResource() const
{
return activePalResource;
@ -218,6 +237,24 @@ void Conversation::onEnterPressed()
}
}
void Conversation::onImagePasted()
{
QImage image = QApplication::clipboard()->image();
if (image.isNull()) {
return;
}
QTemporaryFile *tempFile = new QTemporaryFile(QDir::tempPath() + QStringLiteral("/squawk_img_attach_XXXXXX.png"), QApplication::instance());
tempFile->open();
image.save(tempFile, "PNG");
tempFile->close();
qDebug() << "image on paste temp file: " << tempFile->fileName();
addAttachedFile(tempFile->fileName());
// The file, if successfully uploaded, will be copied to Download folder.
// On application closing, this temporary file will be automatically removed by Qt.
// See Core::NetworkAccess::onUploadFinished.
}
void Conversation::onAttach()
{
QFileDialog* d = new QFileDialog(this, tr("Chose a file to send"));
@ -443,3 +480,14 @@ void Conversation::onFeedContext(const QPoint& pos)
}
}
}
void Conversation::onMessageEditorContext(const QPoint& pos)
{
pasteImageAction->setEnabled(Conversation::checkClipboardImage());
QMenu *editorMenu = m_ui->messageEditor->createStandardContextMenu();
editorMenu->addSeparator();
editorMenu->addAction(pasteImageAction);
editorMenu->exec(this->m_ui->messageEditor->mapToGlobal(pos));
}

View File

@ -60,6 +60,7 @@ protected:
signals:
void enterPressed();
void imagePasted();
};
class Conversation : public QWidget
@ -77,6 +78,7 @@ public:
void setPalResource(const QString& res);
virtual void setAvatar(const QString& path);
void setFeedFrames(bool top, bool right, bool bottom, bool left);
static bool checkClipboardImage();
signals:
void sendMessage(const Shared::Message& message);
@ -102,6 +104,7 @@ protected:
protected slots:
void onEnterPressed();
void onImagePasted();
void onAttach();
void onFileSelected();
void onBadgeClose();
@ -111,6 +114,7 @@ protected slots:
void onFeedMessage(const Shared::Message& msg);
void positionShadow();
void onFeedContext(const QPoint &pos);
void onMessageEditorContext(const QPoint &pos);
public:
const bool isMuc;
@ -133,6 +137,8 @@ protected:
bool manualSliderChange;
bool tsb; //transient scroll bars
QAction* pasteImageAction;
ShadowOverlay shadow;
QMenu* contextMenu;
};