p) { return username == p->getUsername(); });
if (it != participants.end()) {
auto foundParticipant = participants.at(std::distance(participants.begin(), it));
auto address = foundParticipant->getSipAddress();
auto isFriend = ToolModel::findFriendByAddress(address);
if (isFriend)
part = "@" + Utils::coreStringToAppString(isFriend->getAddress()->getDisplayName());
QString participantLink = "" + part + "";
finalMentions.append(participantLink);
} else {
finalMentions.append(part);
}
} else {
finalMentions.append(part);
}
}
formattedText.push_back(finalMentions.join(" "));
} else {
formattedText.push_back(mentionsParsed[i].second);
}
}
}
return "" + formattedText.join("");
});
data->requestValue();
return data;
}
QString Utils::encodeEmojiToQmlRichFormat(const QString &body) {
QString fmtBody = "";
QVector utf32_string = body.toUcs4();
bool insideFontBlock = false;
for (auto &code : utf32_string) {
if (Utils::codepointIsEmoji(code)) {
if (!insideFontBlock) {
auto font = App::getInstance()->getSettings()->getEmojiFont().family();
fmtBody += QString("");
insideFontBlock = true;
}
} else {
if (insideFontBlock) {
fmtBody += "";
insideFontBlock = false;
}
}
fmtBody += QString::fromUcs4(reinterpret_cast(&code), 1);
}
if (insideFontBlock) {
fmtBody += "";
}
return fmtBody;
}
static bool codepointIsVisible(uint code) {
return code > 0x00020;
}
bool Utils::isOnlyEmojis(const QString &text) {
if (text.isEmpty()) return false;
QVector utf32_string = text.toUcs4();
for (auto &code : utf32_string)
if (codepointIsVisible(code) && !Utils::codepointIsEmoji(code)) return false;
return true;
}
void Utils::openContactAtAddress(const QString &address) {
App::postModelAsync([address] {
auto isFriend = ToolModel::findFriendByAddress(address);
if (isFriend) {
App::postCoreAsync([address] {
auto window = getMainWindow();
QMetaObject::invokeMethod(window, "displayContactPage", Q_ARG(QVariant, address));
});
} else {
App::postCoreAsync([address] {
auto window = getMainWindow();
QMetaObject::invokeMethod(window, "displayCreateContactPage", Q_ARG(QVariant, ""),
Q_ARG(QVariant, address));
});
}
});
}
QString Utils::getFilename(QUrl url) {
return url.fileName();
}
bool Utils::codepointIsEmoji(uint code) {
return ((code >= 0x1F600 && code <= 0x1F64F) || // Emoticons
(code >= 0x1F300 && code <= 0x1F5FF) || // Misc Symbols and Pictographs
(code >= 0x1F680 && code <= 0x1F6FF) || // Transport & Map
(code >= 0x1F700 && code <= 0x1F77F) || // Alchemical Symbols
(code >= 0x1F900 && code <= 0x1F9FF) || // Supplemental Symbols & Pictographs
(code >= 0x1FA70 && code <= 0x1FAFF) || // Symbols and Pictographs Extended-A
(code >= 0x2600 && code <= 0x26FF) || // Miscellaneous Symbols
(code >= 0x2700 && code <= 0x27BF) // Dingbats
);
}
QString Utils::toDateTimeString(QDateTime date, const QString &format) {
if (date.date() == QDate::currentDate()) return toTimeString(date);
else {
return getOffsettedUTC(date).toString(format);
}
}
QDateTime Utils::getOffsettedUTC(const QDateTime &date) {
QDateTime utc = date.toUTC();
auto timezone = date.timeZone();
int offset = timezone.offsetFromUtc(date);
utc = utc.addSecs(offset);
utc.setTimeZone(QTimeZone(offset));
return utc;
}
QString Utils::toTimeString(QDateTime date, const QString &format) {
// Issue : date.toString() will not print the good time in timezones. Get it from date and add ourself the offset.
return getOffsettedUTC(date).toString(format);
}
QString Utils::getSafeFilePath(const QString &filePath, bool *soFarSoGood) {
if (soFarSoGood) *soFarSoGood = true;
QFileInfo info(filePath);
if (!info.exists()) return filePath;
const QString prefix = QStringLiteral("%1/%2").arg(info.absolutePath()).arg(info.baseName());
const QString ext = info.completeSuffix();
for (int i = 1; i < SafeFilePathLimit; ++i) {
QString safePath = QStringLiteral("%1 (%3).%4").arg(prefix).arg(i).arg(ext);
if (!QFileInfo::exists(safePath)) return safePath;
}
if (soFarSoGood) *soFarSoGood = false;
return QString("");
}
void Utils::forwardMessageTo(ChatMessageGui *message, ChatGui *chatGui) {
auto chatModel = chatGui && chatGui->mCore ? chatGui->mCore->getModel() : nullptr;
auto chatMessageModel = message && message->mCore ? message->mCore->getModel() : nullptr;
if (!chatModel || !chatMessageModel) {
//: Cannot forward an invalid message
QString error = !chatMessageModel ? tr("chat_message_forward_error")
//: Error creating or opening the chat
: tr("chat_error");
//: Error
showInformationPopup(tr("info_popup_error_title"),
//: Could not forward message : %1
tr("info_popup_forward_message_error").arg(error));
return;
}
App::postModelAsync([chatModel, chatMessageModel] {
mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO));
auto chat = chatModel->getMonitor();
auto messageToForward = chatMessageModel->getMonitor();
auto linMessage = chatModel->createForwardMessage(messageToForward);
if (linMessage) {
linMessage->send();
} else {
App::postCoreAsync([] {
//: Error
showInformationPopup(tr("info_popup_error_title"),
//: Failed to create forward message
tr("info_popup_send_forward_message_error_message"));
});
}
});
}
void Utils::sendReplyMessage(ChatMessageGui *message, ChatGui *chatGui, QString text, QVariantList files) {
auto chatModel = chatGui && chatGui->mCore ? chatGui->mCore->getModel() : nullptr;
auto chatMessageModel = message && message->mCore ? message->mCore->getModel() : nullptr;
if (!chatModel || !chatMessageModel) {
//: Cannot reply to invalid message
QString error = !chatMessageModel ? tr("chat_message_reply_error")
//: Error in the chat
: tr("chat_error");
//: Error
showInformationPopup(tr("info_popup_error_title"),
//: Could not send reply message : %1
tr("info_popup_reply_message_error").arg(error));
return;
}
QList> filesContent;
for (auto &file : files) {
auto contentGui = qvariant_cast(file);
if (contentGui) {
auto contentCore = contentGui->mCore;
filesContent.append(contentCore->getContentModel());
}
}
App::postModelAsync([chatModel, chatMessageModel, text, filesContent] {
mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO));
auto chat = chatModel->getMonitor();
auto messageToReplyTo = chatMessageModel->getMonitor();
auto linMessage = chatModel->createReplyMessage(messageToReplyTo);
if (linMessage) {
linMessage->addUtf8TextContent(Utils::appStringToCoreString(text));
for (auto &content : filesContent) {
linMessage->addFileContent(content->getContent());
}
linMessage->send();
} else {
App::postCoreAsync([] {
//: Error
showInformationPopup(tr("info_popup_error_title"),
//: Failed to create reply message
tr("info_popup_send_reply_message_error_message"));
});
}
});
}
VariantObject *Utils::createVoiceRecordingMessage(RecorderGui *recorderGui, ChatGui *chatGui) {
VariantObject *data = new VariantObject("createVoiceRecordingMessage");
if (!data) return nullptr;
data->makeRequest([recorderCore = recorderGui ? recorderGui->getCore() : nullptr,
chatCore = chatGui ? chatGui->getCore() : nullptr]() {
if (!recorderCore || !chatCore) return QVariant();
auto model = recorderCore->getModel();
auto chatModel = chatCore->getModel();
if (!model || !chatModel) return QVariant();
auto recorder = model->getRecorder();
auto linMessage = chatModel->createVoiceRecordingMessage(recorder);
if (linMessage) {
auto messageCore = ChatMessageCore::create(linMessage);
return QVariant::fromValue(new ChatMessageGui(messageCore));
}
return QVariant();
});
data->requestValue();
return data;
}
void Utils::sendVoiceRecordingMessage(RecorderGui *recorderGui, ChatGui *chatGui) {
auto chatModel = chatGui && chatGui->mCore ? chatGui->mCore->getModel() : nullptr;
auto recorderModel = recorderGui && recorderGui->mCore ? recorderGui->mCore->getModel() : nullptr;
if (!chatModel || !recorderModel) {
//: Error with the recorder
QString error = !recorderModel ? tr("recorder_error")
//: Error in the chat
: tr("chat_error");
//: Error
showInformationPopup(tr("info_popup_error_title"),
//: Could not send voice message : %1
tr("info_popup_send_voice_message_error_message").arg(error));
return;
}
App::postModelAsync([chatModel, recorderModel] {
mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO));
auto chat = chatModel->getMonitor();
auto recorder = recorderModel->getRecorder();
auto linMessage = chatModel->createVoiceRecordingMessage(recorder);
if (linMessage) {
linMessage->send();
} else
//: Error
showInformationPopup(tr("info_popup_error_title"),
//: Failed to create message from record
tr("info_popup_send_voice_message_sending_error_message"));
});
}
bool Utils::isVideo(const QString &path) {
if (path.isEmpty()) return false;
return QMimeDatabase().mimeTypeForFile(path).name().contains("video/");
}
bool Utils::isPdf(const QString &path) {
if (path.isEmpty()) return false;
return QMimeDatabase().mimeTypeForFile(path).name().contains("application/pdf");
}
bool Utils::isText(const QString &path) {
if (path.isEmpty()) return false;
return QMimeDatabase().mimeTypeForFile(path).name().contains("text");
}
bool Utils::isImage(const QString &path) {
if (path.isEmpty()) return false;
QFileInfo info(path);
if (!info.exists() || SettingsModel::getInstance()->getVfsEncrypted()) {
return QMimeDatabase().mimeTypeForFile(path).name().contains("image/");
} else {
if (!QMimeDatabase().mimeTypeForFile(info).name().contains("image/")) return false;
QImageReader reader(path);
return reader.canRead() && reader.imageCount() == 1;
}
}
bool Utils::isAnimatedImage(const QString &path) {
if (path.isEmpty()) return false;
QFileInfo info(path);
if (!info.exists() || !QMimeDatabase().mimeTypeForFile(info).name().contains("image/")) return false;
QImageReader reader(path);
return reader.canRead() && reader.supportsAnimation() && reader.imageCount() > 1;
}
bool Utils::fileExists(const QString &path) {
return QFileInfo::exists(path);
}
bool Utils::canHaveThumbnail(const QString &path) {
if (path.isEmpty()) return false;
return isImage(path) || isAnimatedImage(path) /*|| isPdf(path)*/ || isVideo(path);
}
QImage Utils::getImage(const QString &pUri) {
QImage image(pUri);
QImageReader reader(pUri);
reader.setAutoTransform(true);
if (image.isNull()) { // Try to determine format from headers instead of using suffix
reader.setDecideFormatFromContent(true);
}
return reader.read();
}
void Utils::setGlobalCursor(Qt::CursorShape cursor) {
if (!App::getInstance()->overrideCursor() || App::getInstance()->overrideCursor()->shape() != cursor) {
App::getInstance()->setOverrideCursor(QCursor(cursor));
}
}
void Utils::restoreGlobalCursor() {
App::getInstance()->restoreOverrideCursor();
}
QString Utils::getEphemeralFormatedTime(int selectedTime) {
if (selectedTime == 60) return tr("nMinute", "", 1).arg(1);
else if (selectedTime == 3600) return tr("nHour", "", 1).arg(1);
else if (selectedTime == 86400) return tr("nDay", "", 1).arg(1);
else if (selectedTime == 259200) return tr("nDay", "", 3).arg(3);
else if (selectedTime == 604800) return tr("nWeek", "", 1).arg(1);
else return tr("nSeconds", "", selectedTime).arg(selectedTime);
}
bool Utils::stringMatchFormat(QString toMatch, QRegularExpression regExp) {
if (!regExp.isValid()) return false;
auto match = regExp.match(toMatch);
return match.hasMatch();
}
void Utils::forceCrash() {
raise(SIGSEGV);
}