1 /*
2  * %kadu copyright begin%
3  * Copyright 2012 Rafał Przemysław Malinowski (rafal.przemyslaw.malinowski@gmail.com)
4  * %kadu copyright end%
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <QtXml/QDomText>
21 
22 #include "walker/emoticon-walker.h"
23 #include "emoticon.h"
24 
25 #include "emoticon-expander.h"
26 
EmoticonExpander(EmoticonPrefixTree * tree,std::unique_ptr<EmoticonPathProvider> pathProvider)27 EmoticonExpander::EmoticonExpander(EmoticonPrefixTree *tree, std::unique_ptr<EmoticonPathProvider> pathProvider) :
28 		m_tree{tree},
29 		m_pathProvider{std::move(pathProvider)}
30 {
31 	Q_ASSERT(m_tree);
32 	Q_ASSERT(m_pathProvider);
33 }
34 
~EmoticonExpander()35 EmoticonExpander::~EmoticonExpander()
36 {
37 }
38 
insertEmoticon(QDomText textNode,const Emoticon & emoticon,int index) const39 QDomText EmoticonExpander::insertEmoticon(QDomText textNode, const Emoticon &emoticon, int index) const
40 {
41 	int emoticonLength = emoticon.triggerText().length();
42 
43 	QDomText afterEmoticon = textNode.splitText(index + emoticonLength);
44 	textNode.setNodeValue(textNode.nodeValue().mid(0, index));
45 
46 	QDomElement emoticonElement = textNode.ownerDocument().createElement("img");
47 	emoticonElement.setAttribute("emoticon", emoticon.triggerText());
48 	emoticonElement.setAttribute("title", emoticon.triggerText());
49 	emoticonElement.setAttribute("alt", emoticon.triggerText());
50 	emoticonElement.setAttribute("src", "file:///" + m_pathProvider->emoticonPath(emoticon));
51 	textNode.parentNode().insertBefore(emoticonElement, afterEmoticon);
52 
53 	return afterEmoticon;
54 }
55 
expandFirstEmoticon(QDomText textNode) const56 QDomText EmoticonExpander::expandFirstEmoticon(QDomText textNode) const
57 {
58 	QString text = textNode.nodeValue().toLower();
59 	int textLength = text.length();
60 
61 	if (0 == textLength)
62 		return QDomText();
63 
64 	int currentEmoticonStart = -1;
65 	Emoticon currentEmoticon;
66 
67 	EmoticonWalker walker(m_tree);
68 
69 	for (int i = 0; i < textLength; i++)
70 	{
71 		Emoticon emoticon = walker.matchEmoticon(text.at(i), (i < textLength - 1) && text.at(i + 1).isLetter());
72 		if (emoticon.isNull())
73 			continue;
74 
75 		// TODO: remove this dependency
76 		int emoticonStart = i - emoticon.triggerText().length() + 1;
77 		if (currentEmoticon.isNull() || currentEmoticonStart >= emoticonStart)
78 		{
79 			currentEmoticon = emoticon;
80 			currentEmoticonStart = emoticonStart;
81 			continue;
82 		}
83 
84 		return insertEmoticon(textNode, currentEmoticon, currentEmoticonStart);
85 	}
86 
87 	if (!currentEmoticon.isNull())
88 		insertEmoticon(textNode, currentEmoticon, currentEmoticonStart);
89 
90 	return QDomText();
91 }
92 
visit(QDomText textNode) const93 QDomNode EmoticonExpander::visit(QDomText textNode) const
94 {
95 	QDomText result = textNode;
96 	while (!textNode.isNull())
97 	{
98 		result = textNode;
99 		textNode = expandFirstEmoticon(textNode);
100 	}
101 
102 	return result; // last real node
103 }
104 
beginVisit(QDomElement elementNode) const105 QDomNode EmoticonExpander::beginVisit(QDomElement elementNode) const
106 {
107 	return elementNode;
108 }
109 
endVisit(QDomElement elementNode) const110 QDomNode EmoticonExpander::endVisit(QDomElement elementNode) const
111 {
112 	return elementNode.nextSibling();
113 }
114