~ubuntu-branches/ubuntu/lucid/konversation/lucid-updates

« back to all changes in this revision

Viewing changes to src/common.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Thomas
  • Date: 2010-02-11 14:52:14 UTC
  • mto: This revision was merged to the branch mainline in revision 43.
  • Revision ID: james.westby@ubuntu.com-20100211145214-xsbd3hmrnu5fmb8f
Tags: upstream-1.2.2
ImportĀ upstreamĀ versionĀ 1.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
 
26
26
namespace Konversation
27
27
{
28
 
    void initChanModesHash()
 
28
 
 
29
    static QRegExp colorRegExp("((\003([0-9]|0[0-9]|1[0-5])(,([0-9]|0[0-9]|1[0-5])|)|\017)|\x02|\x09|\x13|\x16|\x1f)");
 
30
    static QRegExp urlPattern("((www\\.(?!\\.)|(fish|irc|amarok|(f|sf|ht)tp(|s))://)(\\.?[\\d\\w/,\\':~\\?=;#@\\-\\+\\%\\*\\{\\}\\!\\(\\)\\[\\]]|&)+)|"
 
31
        "([-.\\d\\w]+@[-.\\d\\w]{2,}\\.[\\w]{2,})");
 
32
    static QRegExp tdlPattern("(.*)\\.(\\w+),$");
 
33
 
 
34
    QHash<QChar,QString> initChanModesHash()
29
35
    {
30
36
        QHash<QChar,QString> myHash;
31
37
 
41
47
        myHash.insert('c', i18n("no colors allowed"));
42
48
        myHash.insert('l', i18n("user throttling"));
43
49
 
44
 
        m_modesHash = myHash;
 
50
        return myHash;
45
51
    }
46
52
 
 
53
    const QHash<QChar,QString> ChanModes::m_hash = initChanModesHash();
 
54
 
47
55
    QHash<QChar,QString> getChannelModesHash()
48
56
    {
49
 
        if(m_modesHash.isEmpty())
50
 
            initChanModesHash();
51
 
 
52
 
        return m_modesHash;
 
57
        return ChanModes::m_hash;
53
58
    }
54
59
 
55
60
    QString removeIrcMarkup(const QString& text)
56
61
    {
57
 
        QString escaped(text);
 
62
        QString escaped = text;
58
63
        // Escape text decoration
59
64
        escaped.remove(colorRegExp);
60
65
 
 
66
        // Remove Mirc's 0x03 characters too, they show up as rectangles
 
67
        escaped.remove(QChar(0x03));
 
68
 
61
69
        return escaped;
62
70
    }
63
71
 
111
119
        line.replace("%B","\x02");       // replace %B with bold char
112
120
        line.replace("%C","\x03");       // replace %C with color char
113
121
        line.replace("%G","\x07");       // replace %G with ASCII BEL 0x07
114
 
        line.replace("%I","\x1d");       // replace %I with italics char
 
122
        line.replace("%I","\x09");       // replace %I with italics char
115
123
        line.replace("%O","\x0f");       // replace %O with reset to default char
116
124
        line.replace("%S","\x13");       // replace %S with strikethru char
117
125
        // line.replace(QRegExp("%?"),"\x15");
122
130
        return line;
123
131
    }
124
132
 
125
 
    QString replaceIRCMarkups(const QString& text)
 
133
    QString tagUrls(const QString& text, const QString& fromNick, bool useCustomColor)
126
134
    {
127
 
        QString line(text);
128
 
 
129
 
        line.replace('\x02', "%B");      // replace bold char with %B
130
 
        line.replace('\x03', "%C");       // replace color char with %C
131
 
        line.replace('\x07', "%G");       // replace ASCII BEL 0x07 with %G
132
 
        line.replace('\x1d', "%I");       // replace italics char with %I
133
 
        line.replace('\x0f', "%O");       // replace reset to default char with %O
134
 
        line.replace('\x13', "%S");       // replace strikethru char with %S
135
 
        line.replace('\x16', "%R");       // replace reverse char with %R
136
 
        // underline char send by kvirc
137
 
        line.replace('\x1f', "%U");       // replace underline char with %U
138
 
        // underline char send by mirc
139
 
        line.replace('\x15', "%U");       // replace underline char with %U
140
 
 
141
 
        return line;
 
135
        TextUrlData data = extractUrlData(text, fromNick, false, true, useCustomColor);
 
136
 
 
137
        return data.htmlText;
142
138
    }
143
139
 
144
140
    QList<QPair<int, int> > getUrlRanges(const QString& text)
145
141
    {
146
 
        TextUrlData data = extractUrlData(text, false);
 
142
        TextUrlData data = extractUrlData(text, QString(), true, false, false);
147
143
 
148
144
        return data.urlRanges;
149
145
    }
150
146
 
151
 
    QList< QPair< int, int > > getChannelRanges(const QString& text)
152
 
    {
153
 
        TextChannelData data = extractChannelData(text, false);
154
 
 
155
 
        return data.channelRanges;
156
 
    }
157
 
 
158
 
    TextUrlData extractUrlData(const QString& text, bool doUrlFixup)
159
 
    {
 
147
    TextUrlData extractUrlData(const QString& text, const QString& fromNick, bool doUrlRanges,
 
148
        bool doHyperlinks, bool useCustomHyperlinkColor)
 
149
    {
 
150
        // QTime timer;
 
151
        // timer.start();
 
152
 
160
153
        TextUrlData data;
161
 
        QString htmlText(text);
162
 
        urlPattern.setCaseSensitivity(Qt::CaseInsensitive);
 
154
        data.htmlText = text;
163
155
 
164
156
        int pos = 0;
165
157
        int urlLen = 0;
166
158
 
 
159
        QString link;
 
160
        QString insertText;
167
161
        QString protocol;
168
162
        QString href;
169
 
 
170
 
        while ((pos = urlPattern.indexIn(htmlText, pos)) >= 0)
 
163
        QString append;
 
164
 
 
165
        urlPattern.setCaseSensitivity(Qt::CaseInsensitive);
 
166
 
 
167
        if (doHyperlinks)
 
168
        {
 
169
            QString linkColor = Preferences::self()->color(Preferences::Hyperlink).name();
 
170
 
 
171
            if (useCustomHyperlinkColor)
 
172
                link = "<a href=\"#%1\" style=\"color:" + linkColor + "\">%2</a>";
 
173
            else
 
174
                link = "<a href=\"#%1\">%2</a>";
 
175
 
 
176
            if (data.htmlText.contains("#"))
 
177
            {
 
178
                QRegExp chanExp("(^|\\s|^\"|\\s\"|,|'|\\(|\\:|!|@|%|\\+)(#[^,\\s;\\)\\:\\/\\(\\<\\>]*[^.,\\s;\\)\\:\\/\\(\"\''\\<\\>])");
 
179
 
 
180
                while ((pos = chanExp.indexIn(data.htmlText, pos)) >= 0)
 
181
                {
 
182
                    href = chanExp.cap(2);
 
183
                    urlLen = href.length();
 
184
                    pos += chanExp.cap(1).length();
 
185
 
 
186
                    insertText = link.arg(href, href);
 
187
                    data.htmlText.replace(pos, urlLen, insertText);
 
188
                    pos += insertText.length();
 
189
                }
 
190
            }
 
191
 
 
192
            if (useCustomHyperlinkColor)
 
193
                link = "<a href=\"%1%2\" style=\"color:" + linkColor + "\">%3</a>";
 
194
            else
 
195
                link = "<a href=\"%1%2\">%3</a>";
 
196
 
 
197
            pos = 0;
 
198
            urlLen = 0;
 
199
        }
 
200
 
 
201
        while ((pos = urlPattern.indexIn(data.htmlText, pos)) >= 0)
171
202
        {
172
203
            urlLen = urlPattern.matchedLength();
173
 
            href = htmlText.mid(pos, urlLen);
174
 
 
175
 
            data.urlRanges << QPair<int, int>(pos, href.length());
176
 
            pos += href.length();
177
 
 
178
 
            if (doUrlFixup)
179
 
            {
180
 
                protocol.clear();
181
 
                if (urlPattern.cap(2).isEmpty())
 
204
 
 
205
            // check if the matched text is already replaced as a channel
 
206
            if (doHyperlinks && data.htmlText.lastIndexOf("<a", pos ) > data.htmlText.lastIndexOf("</a>", pos))
 
207
            {
 
208
                ++pos;
 
209
                continue;
 
210
            }
 
211
 
 
212
            protocol.clear();
 
213
            href = data.htmlText.mid(pos, urlLen);
 
214
            append.clear();
 
215
 
 
216
            // Don't consider trailing comma part of link.
 
217
            if (href.right(1) == ",")
 
218
            {
 
219
                href.truncate(href.length()-1);
 
220
                append = ',';
 
221
            }
 
222
 
 
223
            // Don't consider trailing semicolon part of link.
 
224
            if (href.right(1) == ";")
 
225
            {
 
226
                href.truncate(href.length()-1);
 
227
                append = ';';
 
228
            }
 
229
 
 
230
            // Don't consider trailing closing parenthesis part of link when
 
231
            // there's an opening parenthesis preceding the beginning of the
 
232
            // URL or there is no opening parenthesis in the URL at all.
 
233
            if (href.right(1) == ")" && (data.htmlText.mid(pos-1, 1) == "(" || !href.contains("(")))
 
234
            {
 
235
                href.truncate(href.length()-1);
 
236
                append.prepend(")");
 
237
            }
 
238
 
 
239
            if (doHyperlinks)
 
240
            {
 
241
                // Qt doesn't support (?<=pattern) so we do it here
 
242
                if ((pos > 0) && data.htmlText[pos-1].isLetterOrNumber())
182
243
                {
183
 
                    QString urlPatternCap1(urlPattern.cap(1));
184
 
                    if (urlPatternCap1.contains('@'))
185
 
                        protocol = "mailto:";
186
 
                    else if (urlPatternCap1.startsWith(QLatin1String("ftp."), Qt::CaseInsensitive))
187
 
                        protocol = "ftp://";
188
 
                    else
189
 
                        protocol = "http://";
 
244
                    pos++;
 
245
                    continue;
190
246
                }
191
247
 
192
 
                href = protocol + removeIrcMarkup(href);
193
 
                data.fixedUrls.append(href);
 
248
                if (urlPattern.cap(1).startsWith(QLatin1String("www."), Qt::CaseInsensitive))
 
249
                    protocol = "http://";
 
250
                else if (urlPattern.cap(1).isEmpty())
 
251
                    protocol = "mailto:";
 
252
 
 
253
                // Use \x0b as a placeholder for & so we can read them after changing all & in the normal text to &amp;
 
254
                insertText = link.arg(protocol, QString(href).replace('&', "\x0b"), href) + append;
 
255
 
 
256
                data.htmlText.replace(pos, urlLen, insertText);
 
257
 
 
258
                Application::instance()->storeUrl(fromNick, href, QDateTime::currentDateTime());
194
259
            }
 
260
            else
 
261
                insertText = href + append;
 
262
 
 
263
            if (doUrlRanges)
 
264
                data.urlRanges << QPair<int, int>(pos, href.length());
 
265
 
 
266
            pos += insertText.length();
195
267
        }
196
 
        return data;
197
 
    }
198
 
 
199
 
    TextChannelData extractChannelData(const QString& text, bool doChannelFixup)
200
 
    {
201
 
        TextChannelData data;
202
 
        QString ircText(text);
203
 
 
204
 
        int pos = 0;
205
 
        int chanLen = 0;
206
 
        QString channel;
207
 
 
208
 
        while ((pos = chanExp.indexIn(ircText, pos)) >= 0)
 
268
 
 
269
        if (doHyperlinks)
209
270
        {
210
 
            channel = chanExp.cap(2);
211
 
            chanLen = channel.length();
212
 
 
213
 
            // we want the pos where #channel starts
214
 
            // indexIn gives us the first match and the first match may be
215
 
            // "#test", " #test" or " \"test", so the first Index is off by some chars
216
 
            pos = chanExp.pos(2);
217
 
 
218
 
            data.channelRanges << QPair<int, int>(pos, chanLen);
219
 
            pos += chanLen;
220
 
 
221
 
            if (doChannelFixup)
222
 
            {
223
 
                channel = removeIrcMarkup(channel);
224
 
                data.fixedChannels.append(channel);
225
 
            }
 
271
            // Change & to &amp; to prevent html entities to do strange things to the text
 
272
            data.htmlText.replace('&', "&amp;");
 
273
            data.htmlText.replace("\x0b", "&");
226
274
        }
 
275
 
 
276
        // kDebug() << "Took (msecs) : " << timer.elapsed() << " for " << data.htmlText;
 
277
 
227
278
        return data;
228
279
    }
229
280
 
232
283
        return urlPattern.exactMatch(text);
233
284
    }
234
285
 
235
 
    QString extractColorCodes(const QString& _text)
236
 
    {
237
 
        QString text(_text);
238
 
        int pos = 0;
239
 
        QString ret;
240
 
        QString match;
241
 
        while ((pos = colorRegExp.indexIn(text, pos)) >= 0)
242
 
        {
243
 
            match = colorRegExp.cap(0);
244
 
            ret += match;
245
 
            text.remove(pos, match.length());
246
 
        }
247
 
        return ret;
248
 
    }
249
 
 
250
286
    QPixmap overlayPixmaps( const QPixmap &under, const QPixmap &over )
251
287
    {
252
288
        if (over.isNull() && under.isNull())
293
329
        for (int i = 0; i < s.length(); ++i)
294
330
        {
295
331
            QChar c(s.at(i));
296
 
            if ((c.category() == QChar::Other_NotAssigned) //perhaps Qt will use QChar::Other_NotAssigned some day
 
332
            if (c.category() == QChar::Other_Surrogate)
 
333
            {
 
334
                if (!c.isHighSurrogate() || (!(i+1 < s.length()) && !s.at(i+1).isLowSurrogate()))
 
335
                    Q_ASSERT("something let a bad surrogate pair through! send the backtrace, tell us how it happened");
 
336
 
 
337
                QChar next = s.at(i+1);
 
338
                if ((next.unicode()&0x3FE) == 0x3FE && (c.unicode()&0x3F) == 0x3F)
 
339
                    s.replace(i, 2, QChar(0xFFFD)); //its one of the last two of the plane, replace it
 
340
 
 
341
                ++i; // skip the high surrogate now, the loop takes care of the low
 
342
            }
 
343
            else if ((c.category() == QChar::Other_NotAssigned) //perhaps Qt will use QChar::Other_NotAssigned some day
297
344
                || (c.unicode() >= 0xFDD0 && c.unicode() <= 0xFDEF) //Unicode class Cn on BMP only
298
345
                || (c.unicode() == 0xFFFE || (c.unicode() == 0xFFFF)) //Unicode class Cn on all planes
299
 
                || (c.category() == QChar::Other_Surrogate)
300
346
                )
301
347
            {
302
348
                s.replace(i, 1, QChar(0xFFFD));