linphone-desktop/linphone-app/src/components/content/ContentModel.cpp
Julien Wadel 9f52ed6a88 Try to download content message if requested, even if the message state is not right.
Fix SIP address selection on search bars (Qt bug on models)
2021-12-20 14:59:53 +01:00

242 lines
No EOL
7.8 KiB
C++

/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ContentModel.hpp"
#include <QQmlApplicationEngine>
#include <QDesktopServices>
#include <QImageReader>
#include <QMessageBox>
#include "app/App.hpp"
#include "app/paths/Paths.hpp"
#include "app/providers/ThumbnailProvider.hpp"
#include "components/chat-events/ChatMessageModel.hpp"
#include "utils/QExifImageHeader.hpp"
#include "utils/Utils.hpp"
#include "utils/Constants.hpp"
#include "components/Components.hpp"
// =============================================================================
ContentModel::ContentModel(ChatMessageModel* chatModel){
App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE
mChatMessageModel = chatModel;
mWasDownloaded = false;
mFileOffset = 0;
}
ContentModel::ContentModel(std::shared_ptr<linphone::Content> content, ChatMessageModel* chatModel){
App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE
mChatMessageModel = chatModel;
mWasDownloaded = false;
mFileOffset = 0;
setContent(content);
}
std::shared_ptr<linphone::Content> ContentModel::getContent()const{
return mContent;
}
ChatMessageModel * ContentModel::getChatMessageModel()const{
return mChatMessageModel;
}
quint64 ContentModel::getFileSize() const{
auto s = mContent->getFileSize();
return (quint64)s;
}
QString ContentModel::getName() const{
return QString::fromStdString(mContent->getName());
}
QString ContentModel::getThumbnail() const{
return mThumbnail;
}
QString ContentModel::getFilePath() const{
return Utils::coreStringToAppString(mContent->getFilePath());
}
QString ContentModel::getUtf8Text() const{
return QString::fromStdString(mContent->getUtf8Text());
}
void ContentModel::setFileOffset(quint64 fileOffset){
if( mFileOffset != fileOffset) {
mFileOffset = fileOffset;
emit fileOffsetChanged();
}
}
void ContentModel::setThumbnail(const QString& data){
if( mThumbnail != data) {
mThumbnail = data;
emit thumbnailChanged();
}
}
void ContentModel::setWasDownloaded(bool wasDownloaded){
if( mWasDownloaded != wasDownloaded) {
mWasDownloaded = wasDownloaded;
emit wasDownloadedChanged();
}
}
void ContentModel::setContent(std::shared_ptr<linphone::Content> content){
mContent = content;
if(isFile() || isFileEncrypted() || isFileTransfer() ){
QString path = Utils::coreStringToAppString(mContent->getFilePath());
if (!path.isEmpty())
createThumbnail();
}
}
bool ContentModel::isFile() const{
return mContent->isFile();
}
bool ContentModel::isFileEncrypted() const{
return mContent->isFileEncrypted();
}
bool ContentModel::isFileTransfer() const{
return mContent->isFileTransfer();
}
bool ContentModel::isIcalendar() const{
return mContent->isIcalendar();
}
bool ContentModel::isMultipart() const{
return mContent->isMultipart();
}
bool ContentModel::isText() const{
return mContent->isText();
}
bool ContentModel::isVoiceRecording()const{
return mContent->isVoiceRecording();
}
// Create a thumbnail from the first content that have a file and store it in Appdata
void ContentModel::createThumbnail () {
if(isFile() || isFileEncrypted() || isFileTransfer()){
QString id;
QString path = getFilePath();
auto appdata = ChatMessageModel::AppDataManager(QString::fromStdString(mChatMessageModel->getChatMessage()->getAppdata()));
if(!appdata.mData.contains(path)
|| !QFileInfo(QString::fromStdString(Paths::getThumbnailsDirPath())+appdata.mData[path]).isFile()){
// File don't exist. Create the thumbnail
QImage image(path);
if( image.isNull()){// Try to determine format from headers
QImageReader reader(path);
reader.setDecideFormatFromContent(true);
QByteArray format = reader.format();
if(!format.isEmpty())
image = QImage(path, format);
}
if (!image.isNull()){
int rotation = 0;
QExifImageHeader exifImageHeader;
if (exifImageHeader.loadFromJpeg(path))
rotation = int(exifImageHeader.value(QExifImageHeader::ImageTag::Orientation).toShort());
QImage thumbnail = image.scaled(
Constants::ThumbnailImageFileWidth, Constants::ThumbnailImageFileHeight,
Qt::KeepAspectRatio, Qt::SmoothTransformation
);
if (rotation != 0) {
QTransform transform;
if (rotation == 3 || rotation == 4)
transform.rotate(180);
else if (rotation == 5 || rotation == 6)
transform.rotate(90);
else if (rotation == 7 || rotation == 8)
transform.rotate(-90);
thumbnail = thumbnail.transformed(transform);
if (rotation == 2 || rotation == 4 || rotation == 5 || rotation == 7)
thumbnail = thumbnail.mirrored(true, false);
}
QString uuid = QUuid::createUuid().toString();
id = QStringLiteral("%1.jpg").arg(uuid.mid(1, uuid.length() - 2));
if (!thumbnail.save(QString::fromStdString(Paths::getThumbnailsDirPath()) + id , "jpg", 100)) {
qWarning() << QStringLiteral("Unable to create thumbnail of: `%1`.").arg(path);
}else{
appdata.mData[path] = id;
mChatMessageModel->getChatMessage()->setAppdata(appdata.toString().toStdString());
}
}
}
if( path != ""){
setWasDownloaded( !path.isEmpty() && QFileInfo(path).isFile());
if(appdata.mData.contains(path) && !appdata.mData[path].isEmpty())
setThumbnail(QStringLiteral("image://%1/%2").arg(ThumbnailProvider::ProviderId).arg(appdata.mData[path]));
}
}
}
void ContentModel::downloadFile(){
switch (mChatMessageModel->getState()) {
case LinphoneEnums::ChatMessageStateDelivered:
case LinphoneEnums::ChatMessageStateDeliveredToUser:
case LinphoneEnums::ChatMessageStateDisplayed:
case LinphoneEnums::ChatMessageStateFileTransferDone:
break;
default:
qWarning() << QStringLiteral("Wrong message state when requesting downloading, state=%1.").arg(mChatMessageModel->getState());
}
bool soFarSoGood;
QString filename = getName();//mFileTransfertContent->getName();
const QString safeFilePath = Utils::getSafeFilePath(
QStringLiteral("%1%2")
.arg(CoreManager::getInstance()->getSettingsModel()->getDownloadFolder())
.arg(filename),
&soFarSoGood
);
if (!soFarSoGood) {
qWarning() << QStringLiteral("Unable to create safe file path for: %1.").arg(filename);
return;
}
mContent->setFilePath(Utils::appStringToCoreString(safeFilePath));
if( !mContent->isFileTransfer()){
QMessageBox::warning(nullptr, "Download File", "This file was already downloaded and is no more on the server. Your peer have to resend it if you want to get it");
}else
{
if (!mChatMessageModel->getChatMessage()->downloadContent(mContent))
qWarning() << QStringLiteral("Unable to download file of entry %1.").arg(filename);
}
}
void ContentModel::openFile (bool showDirectory) {
if (!mWasDownloaded && !mChatMessageModel->isOutgoing()) {
downloadFile();
}else{
QFileInfo info( Utils::coreStringToAppString(mContent->getFilePath()));
QDesktopServices::openUrl(
QUrl(QStringLiteral("file:///%1").arg(showDirectory ? info.absolutePath() : info.absoluteFilePath()))
);
}
}
void ContentModel::updateTransferData(){
}