mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-05-23 00:01:21 -04:00
Fixes two problems in the current group chat:
- the parser fails to embed two links in the same sentence - the parser can potentially put smileys in the middle of <a> tags Solution: Since the message is in HTML, it is parsed into a DOM tree, then that DOM tree is traversed and only the text nodes are parsed (see HandleRichText.cpp for details). Bonus fixes: - missing std:: for endl (which was falling back to its Qt counterpart) - commenting useless code in PeersDialog::smileyWidgetgroupchat() - replacing int by size_t - RetroShare.pro now queries gpgme-config for its include path git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@2888 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
parent
6b3f51c626
commit
988c6c31f5
5 changed files with 281 additions and 40 deletions
124
retroshare-gui/src/gui/chat/HandleRichText.cpp
Normal file
124
retroshare-gui/src/gui/chat/HandleRichText.cpp
Normal file
|
@ -0,0 +1,124 @@
|
|||
/****************************************************************
|
||||
* This file is distributed under the following license:
|
||||
*
|
||||
* Copyright (c) 2010, Thomas Kister
|
||||
*
|
||||
* 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 2
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
****************************************************************/
|
||||
|
||||
#include "HandleRichText.h"
|
||||
|
||||
|
||||
namespace RsChat {
|
||||
|
||||
|
||||
void EmbedInHtmlImg::InitFromAwkwardHash(const QHash< QString, QString >& hash)
|
||||
{
|
||||
QString newRE;
|
||||
for(QHash<QString,QString>::const_iterator it = hash.begin(); it != hash.end(); ++it)
|
||||
foreach(QString smile, it.key().split("|")) {
|
||||
smileys.insert(smile, it.value());
|
||||
newRE += "(" + QRegExp::escape(smile) + ")|";
|
||||
}
|
||||
newRE.chop(1); // remove last |
|
||||
myRE.setPattern(newRE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses a DOM tree and replaces text by HTML tags.
|
||||
* The tree is traversed depth-first, but only through children of Element type
|
||||
* nodes. Any other kind of node is terminal.
|
||||
*
|
||||
* If the node is of type Text, its data is checked against the user-provided
|
||||
* regular expression. If there is a match, the text is cut in three parts: the
|
||||
* preceding part that will be inserted before, the part to be replaced, and the
|
||||
* following part which will be itself checked against the regular expression.
|
||||
*
|
||||
* The part to be replaced is sent to a user-provided functor that will create
|
||||
* the necessary embedding and return a new Element node to be inserted.
|
||||
*
|
||||
* @param[in] doc The whole DOM tree, necessary to create new nodes
|
||||
* @param[in,out] currentElement The current node (which is of type Element)
|
||||
* @param[in] embedInfos The regular expression and the type of embedding to use
|
||||
*/
|
||||
void embedHtml(QDomDocument& doc, QDomElement& currentElement, const EmbedInHtml& embedInfos)
|
||||
{
|
||||
if(embedInfos.myRE.pattern().length() == 0) // we'll get stuck with an empty regexp
|
||||
return;
|
||||
|
||||
QDomNodeList children = currentElement.childNodes();
|
||||
for(uint index = 0; index < children.length(); index++) {
|
||||
QDomNode tempNode = children.item(index);
|
||||
if(tempNode.isElement()) {
|
||||
// child is an element, we skip it if it's an <a> tag
|
||||
QDomElement tempElement = tempNode.toElement();
|
||||
if(tempElement.tagName().toLower() != "head" && tempElement.tagName().toLower() != "a")
|
||||
embedHtml(doc, tempElement, embedInfos);
|
||||
}
|
||||
else if(tempNode.isText()) {
|
||||
// child is a text, we parse it
|
||||
QString tempText = tempNode.toText().data();
|
||||
if(embedInfos.myRE.indexIn(tempText) == -1)
|
||||
continue;
|
||||
|
||||
// there is at least one link inside, we start replacing
|
||||
int currentPos = 0;
|
||||
int nextPos = 0;
|
||||
while((nextPos = embedInfos.myRE.indexIn(tempText, currentPos)) != -1) {
|
||||
// if nextPos == 0 it means the text begins by a link
|
||||
if(nextPos > 0) {
|
||||
QDomText textPart = doc.createTextNode(tempText.mid(currentPos, nextPos - currentPos));
|
||||
currentElement.insertBefore(textPart, tempNode);
|
||||
index++;
|
||||
}
|
||||
|
||||
// inserted tag
|
||||
QDomElement insertedTag;
|
||||
switch(embedInfos.myType) {
|
||||
case Ahref: insertedTag = doc.createElement("a");
|
||||
insertedTag.setAttribute("href", embedInfos.myRE.cap(0));
|
||||
insertedTag.appendChild(doc.createTextNode(embedInfos.myRE.cap(0)));
|
||||
break;
|
||||
case Img: insertedTag = doc.createElement("img");
|
||||
{
|
||||
const EmbedInHtmlImg& embedImg = static_cast<const EmbedInHtmlImg&>(embedInfos);
|
||||
insertedTag.setAttribute("src", embedImg.smileys[embedInfos.myRE.cap(0)]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
currentElement.insertBefore(insertedTag, tempNode);
|
||||
|
||||
currentPos = nextPos + embedInfos.myRE.matchedLength();
|
||||
index++;
|
||||
}
|
||||
|
||||
// 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 tempNode
|
||||
if(currentPos < tempText.length()) {
|
||||
QDomText textPart = doc.createTextNode(tempText.mid(currentPos));
|
||||
currentElement.insertBefore(textPart, tempNode);
|
||||
}
|
||||
else
|
||||
index--;
|
||||
|
||||
currentElement.removeChild(tempNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace RsChat
|
Loading…
Add table
Add a link
Reference in a new issue