Merge pull request #659 from hunbernd/fix/slow-emoticons

Fix slow emoticon loading
This commit is contained in:
csoler 2017-02-06 23:56:43 +01:00 committed by GitHub
commit 266affeabd
4 changed files with 70 additions and 28 deletions

View File

@ -400,7 +400,13 @@ void CreateGxsForumMsg::smileyWidgetForums()
void CreateGxsForumMsg::addSmileys()
{
ui.forumMessage->textCursor().insertText(qobject_cast<QPushButton*>(sender())->toolTip().split("|").first());
QString smiley = qobject_cast<QPushButton*>(sender())->toolTip().split("|").first();
// add trailing space
smiley += QString(" ");
// add preceding space when needed (not at start of text or preceding space already exists)
if(!ui.forumMessage->textCursor().atStart() && ui.forumMessage->toPlainText()[ui.forumMessage->textCursor().position() - 1] != QChar(' '))
smiley = QString(" ") + smiley;
ui.forumMessage->textCursor().insertText(smiley);
}
void CreateGxsForumMsg::addFile()

View File

@ -2200,7 +2200,13 @@ void MessageComposer::smileyWidget()
void MessageComposer::addSmileys()
{
ui.msgText->textCursor().insertText(qobject_cast<QPushButton*>(sender())->toolTip().split("|").first());
QString smiley = qobject_cast<QPushButton*>(sender())->toolTip().split("|").first();
// add trailing space
smiley += QString(" ");
// add preceding space when needed (not at start of text or preceding space already exists)
if(!ui.msgText->textCursor().atStart() && ui.msgText->toPlainText()[ui.msgText->textCursor().position() - 1] != QChar(' '))
smiley = QString(" ") + smiley;
ui.msgText->textCursor().insertText(smiley);
}
void MessageComposer::currentCharFormatChanged(const QTextCharFormat &format)

View File

@ -168,6 +168,13 @@ RsHtml::RsHtml()
void RsHtml::initEmoticons(const QHash<QString, QPair<QVector<QString>, QHash<QString, QString> > >& hash)
{
//add rules for standard emoticons
QString genericpattern;
genericpattern += "(?:^|\\s)(:\\w{1,40}:)(?:$|\\s)|"; //generic rule for :emoji_name:
genericpattern += "(?:^|\\s)(\\(\\w{1,40}\\))(?:$|\\s)"; //generic rule for (emoji_name)
QRegExp genericrx(genericpattern);
genericrx.setMinimal(true);
QString newRE;
for(QHash<QString, QPair<QVector<QString>, QHash<QString, QString> > >::const_iterator groupit = hash.begin(); groupit != hash.end(); ++groupit) {
QHash<QString,QString> group = groupit.value().second;
@ -177,38 +184,42 @@ void RsHtml::initEmoticons(const QHash<QString, QPair<QVector<QString>, QHash<QS
continue;
}
defEmbedImg.smileys.insert(smile, it.value());
// add space around smileys
newRE += "(?:^|\\s)(" + QRegExp::escape(smile) + ")(?:$|\\s)|";
// explanations:
// (?:^|\s)(*smiley*)(?:$|\s)
//
// (?:^|\s) Non-capturing group
// 1st Alternative: ^
// ^ assert position at start of the string
// 2nd Alternative: \s
// \s match any white space character [\r\n\t\f ]
//
// 1st Capturing group (*smiley*)
// *smiley* matches the characters *smiley* literally (case sensitive)
//
// (?:$|\s) Non-capturing group
// 1st Alternative: $
// $ assert position at end of the string
// 2nd Alternative: \s
// \s match any white space character [\r\n\t\f ]
//check if smiley is using standard format :new-format: or (old-format) and don't make a new regexp for it
if(!genericrx.exactMatch(smile)) {
// add space around smileys
newRE += "(?:^|\\s)(" + QRegExp::escape(smile) + ")(?:$|\\s)|";
// explanations:
// (?:^|\s)(*smiley*)(?:$|\s)
//
// (?:^|\s) Non-capturing group
// 1st Alternative: ^
// ^ assert position at start of the string
// 2nd Alternative: \s
// \s match any white space character [\r\n\t\f ]
//
// 1st Capturing group (*smiley*)
// *smiley* matches the characters *smiley* literally (case sensitive)
//
// (?:$|\s) Non-capturing group
// 1st Alternative: $
// $ assert position at end of the string
// 2nd Alternative: \s
// \s match any white space character [\r\n\t\f ]
/*
/*
* TODO
* a better version is:
* (?<=^|\s)(*smile*)(?=$|\s) using the lookbehind/lookahead operator instead of non-capturing groups.
* This solves the problem that spaces are matched, too (see workaround in RsHtml::embedHtml)
* This is not supported by Qt4!
*/
}
}
}
newRE.chop(1); // remove last |
defEmbedImg.myREs.append(QRegExp(newRE));
QRegExp emojimatcher(newRE + genericpattern);
emojimatcher.setMinimal(true);
defEmbedImg.myREs.append(emojimatcher);
}
bool RsHtml::canReplaceAnchor(QDomDocument &/*doc*/, QDomElement &/*element*/, const RetroShareLink &link)
@ -311,6 +322,22 @@ void RsHtml::replaceAnchorWithImg(QDomDocument &doc, QDomElement &element, QText
element.appendChild(img);
}
int RsHtml::indexInWithValidation(QRegExp &rx, const QString &text, EmbedInHtml &embedInfos, int pos)
{
int index = rx.indexIn(text, pos);
if(index == -1 || embedInfos.myType != Img) return index;
const EmbedInHtmlImg& embedImg = static_cast<const EmbedInHtmlImg&>(embedInfos);
while((index = rx.indexIn(text, pos)) != -1) {
if(embedImg.smileys.contains(rx.cap(0).trimmed()))
return index;
else
++pos;
}
return -1;
}
/**
* Parses a DOM tree and replaces text by HTML tags.
* The tree is traversed depth-first, but only through children of Element type
@ -376,13 +403,13 @@ void RsHtml::embedHtml(QTextDocument *textDocument, QDomDocument& doc, QDomEleme
if(myRE.pattern().length() == 0) // we'll get stuck with an empty regexp
return;
if(myRE.indexIn(tempText) == -1)
int nextPos = 0;
if((nextPos = indexInWithValidation(myRE, tempText, embedInfos)) == -1)
continue;
// there is at least one link inside, we start replacing
int currentPos = 0;
int nextPos = 0;
while((nextPos = myRE.indexIn(tempText, currentPos)) != -1) {
do {
// if nextPos == 0 it means the text begins by a link
if(nextPos > 0) {
QDomText textPart = doc.createTextNode(tempText.mid(currentPos, nextPos - currentPos));
@ -439,7 +466,7 @@ void RsHtml::embedHtml(QTextDocument *textDocument, QDomDocument& doc, QDomEleme
index++;
currentPos = nextPos + myRE.matchedLength();
}
} while((nextPos = indexInWithValidation(myRE, tempText, embedInfos, currentPos)) != -1);
// text after the last link, only if there's one, don't touch the index
// otherwise decrement the index because we're going to remove node

View File

@ -86,6 +86,9 @@ protected:
virtual bool canReplaceAnchor(QDomDocument &doc, QDomElement &element, const RetroShareLink &link);
virtual void anchorTextForImg(QDomDocument &doc, QDomElement &element, const RetroShareLink &link, QString &text);
virtual void anchorStylesheetForImg(QDomDocument &doc, QDomElement &element, const RetroShareLink &link, QString &styleSheet);
private:
int indexInWithValidation(QRegExp &rx, const QString &text, EmbedInHtml &embedInfos, int pos = 0);
};
#endif // HANDLE_RICH_TEXT_H_