source: ogBrowser-Git/qtermwidget/src/Filter.cpp

qndtest
Last change on this file was 8ab4781, checked in by adelcastillo <adelcastillo@…>, 15 years ago

Cambiando a qmake de nuevo.

git-svn-id: https://opengnsys.es/svn/trunk@518 a21b9725-9963-47de-94b9-378ad31fedc9

  • Property mode set to 100644
File size: 14.2 KB
Line 
1/*
2    Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
3
4    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (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, write to the Free Software
18    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19    02110-1301  USA.
20*/
21
22// Own
23#include "Filter.h"
24
25
26// System
27#include <iostream>
28
29// Qt
30#include <QtGui/QAction>
31#include <QtGui/QApplication>
32#include <QtGui/QClipboard>
33#include <QtCore/QString>
34
35#include <QtCore/QSharedData>
36#include <QtCore>
37
38// KDE
39//#include <KLocale>
40//#include <KRun>
41
42// Konsole
43#include "TerminalCharacterDecoder.h"
44
45using namespace Konsole;
46
47FilterChain::~FilterChain()
48{
49    QMutableListIterator<Filter*> iter(*this);
50   
51    while ( iter.hasNext() )
52    {
53        Filter* filter = iter.next();
54        iter.remove();
55        delete filter;
56    }
57}
58
59void FilterChain::addFilter(Filter* filter)
60{
61    append(filter);
62}
63void FilterChain::removeFilter(Filter* filter)
64{
65    removeAll(filter);
66}
67bool FilterChain::containsFilter(Filter* filter)
68{
69    return contains(filter);
70}
71void FilterChain::reset()
72{
73    QListIterator<Filter*> iter(*this);
74    while (iter.hasNext())
75        iter.next()->reset();
76}
77void FilterChain::setBuffer(const QString* buffer , const QList<int>* linePositions)
78{
79    QListIterator<Filter*> iter(*this);
80    while (iter.hasNext())
81        iter.next()->setBuffer(buffer,linePositions);
82}
83void FilterChain::process()
84{
85    QListIterator<Filter*> iter(*this);
86    while (iter.hasNext())
87        iter.next()->process();
88}
89void FilterChain::clear()
90{
91    QList<Filter*>::clear();
92}
93Filter::HotSpot* FilterChain::hotSpotAt(int line , int column) const
94{
95    QListIterator<Filter*> iter(*this);
96    while (iter.hasNext())
97    {
98        Filter* filter = iter.next();
99        Filter::HotSpot* spot = filter->hotSpotAt(line,column);
100        if ( spot != 0 )
101        {
102            return spot;
103        }
104    }
105
106    return 0;
107}
108
109QList<Filter::HotSpot*> FilterChain::hotSpots() const
110{
111    QList<Filter::HotSpot*> list;
112    QListIterator<Filter*> iter(*this);
113    while (iter.hasNext())
114    {
115        Filter* filter = iter.next();
116        list << filter->hotSpots();
117    }
118    return list;
119}
120//QList<Filter::HotSpot*> FilterChain::hotSpotsAtLine(int line) const;
121
122TerminalImageFilterChain::TerminalImageFilterChain()
123: _buffer(0)
124, _linePositions(0)
125{
126}
127
128TerminalImageFilterChain::~TerminalImageFilterChain()
129{
130    delete _buffer;
131    delete _linePositions;
132}
133
134void TerminalImageFilterChain::setImage(const Character* const image , int lines , int columns, const QVector<LineProperty>& lineProperties)
135{
136//qDebug("%s %d", __FILE__, __LINE__);
137    if (empty())
138        return;
139//qDebug("%s %d", __FILE__, __LINE__);
140
141    // reset all filters and hotspots
142    reset();
143//qDebug("%s %d", __FILE__, __LINE__);
144
145    PlainTextDecoder decoder;
146    decoder.setTrailingWhitespace(false);
147   
148//qDebug("%s %d", __FILE__, __LINE__);
149    // setup new shared buffers for the filters to process on
150    QString* newBuffer = new QString();
151    QList<int>* newLinePositions = new QList<int>();
152    setBuffer( newBuffer , newLinePositions );
153
154    // free the old buffers
155    delete _buffer;
156    delete _linePositions;
157
158    _buffer = newBuffer;
159    _linePositions = newLinePositions;
160
161    QTextStream lineStream(_buffer);
162    decoder.begin(&lineStream);
163
164    for (int i=0 ; i < lines ; i++)
165    {
166        _linePositions->append(_buffer->length());
167        decoder.decodeLine(image + i*columns,columns,LINE_DEFAULT);
168
169        // pretend that each line ends with a newline character.
170        // this prevents a link that occurs at the end of one line
171        // being treated as part of a link that occurs at the start of the next line
172        //
173        // the downside is that links which are spread over more than one line are not
174        // highlighted. 
175        //
176        // TODO - Use the "line wrapped" attribute associated with lines in a
177        // terminal image to avoid adding this imaginary character for wrapped
178        // lines
179        if ( !(lineProperties.value(i,LINE_DEFAULT) & LINE_WRAPPED) )
180                lineStream << QChar('\n');
181    }
182    decoder.end();
183//    qDebug("%s %d", __FILE__, __LINE__);
184}
185
186Filter::Filter() :
187_linePositions(0),
188_buffer(0)
189{
190}
191
192Filter::~Filter()
193{
194    QListIterator<HotSpot*> iter(_hotspotList);
195    while (iter.hasNext())
196    {
197        delete iter.next();
198    }
199}
200void Filter::reset()
201{
202    _hotspots.clear();
203    _hotspotList.clear();
204}
205
206void Filter::setBuffer(const QString* buffer , const QList<int>* linePositions)
207{
208    _buffer = buffer;
209    _linePositions = linePositions;
210}
211
212void Filter::getLineColumn(int position , int& startLine , int& startColumn)
213{
214    Q_ASSERT( _linePositions );
215    Q_ASSERT( _buffer );
216
217
218    for (int i = 0 ; i < _linePositions->count() ; i++)
219    {
220        //kDebug() << "line position at " << i << " = " << _linePositions[i];
221        int nextLine = 0;
222
223        if ( i == _linePositions->count()-1 )
224        {
225            nextLine = _buffer->length() + 1;
226        }
227        else
228        {
229            nextLine = _linePositions->value(i+1);
230        }
231
232       // kDebug() << "pos - " << position << " line pos(" << i<< ") " << _linePositions->value(i) <<
233       //     " next = " << nextLine << " buffer len = " << _buffer->length();
234
235        if ( _linePositions->value(i) <= position && position < nextLine ) 
236        {
237            startLine = i;
238            startColumn = position - _linePositions->value(i);
239            return;
240        }
241    }
242}
243   
244
245/*void Filter::addLine(const QString& text)
246{
247    _linePositions << _buffer.length();
248    _buffer.append(text);
249}*/
250
251const QString* Filter::buffer()
252{
253    return _buffer;
254}
255Filter::HotSpot::~HotSpot()
256{
257}
258void Filter::addHotSpot(HotSpot* spot)
259{
260    _hotspotList << spot;
261
262    for (int line = spot->startLine() ; line <= spot->endLine() ; line++)
263    {
264        _hotspots.insert(line,spot);
265    }   
266}
267QList<Filter::HotSpot*> Filter::hotSpots() const
268{
269    return _hotspotList;
270}
271QList<Filter::HotSpot*> Filter::hotSpotsAtLine(int line) const
272{
273    return _hotspots.values(line);
274}
275
276Filter::HotSpot* Filter::hotSpotAt(int line , int column) const
277{
278    QListIterator<HotSpot*> spotIter(_hotspots.values(line));
279
280    while (spotIter.hasNext())
281    {
282        HotSpot* spot = spotIter.next();
283       
284        if ( spot->startLine() == line && spot->startColumn() > column )
285            continue;
286        if ( spot->endLine() == line && spot->endColumn() < column )
287            continue;
288       
289        return spot;
290    }
291
292    return 0;
293}
294
295Filter::HotSpot::HotSpot(int startLine , int startColumn , int endLine , int endColumn)
296    : _startLine(startLine)
297    , _startColumn(startColumn)
298    , _endLine(endLine)
299    , _endColumn(endColumn)
300    , _type(NotSpecified)
301{
302}
303QString Filter::HotSpot::tooltip() const
304{
305    return QString();
306}
307QList<QAction*> Filter::HotSpot::actions()
308{
309    return QList<QAction*>();
310}
311int Filter::HotSpot::startLine() const
312{
313    return _startLine;
314}
315int Filter::HotSpot::endLine() const
316{
317    return _endLine;
318}
319int Filter::HotSpot::startColumn() const
320{
321    return _startColumn;
322}
323int Filter::HotSpot::endColumn() const
324{
325    return _endColumn;
326}
327Filter::HotSpot::Type Filter::HotSpot::type() const
328{
329    return _type;
330}
331void Filter::HotSpot::setType(Type type)
332{
333    _type = type;
334}
335
336RegExpFilter::RegExpFilter()
337{
338}
339
340RegExpFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endColumn)
341    : Filter::HotSpot(startLine,startColumn,endLine,endColumn)
342{
343    setType(Marker);
344}
345
346void RegExpFilter::HotSpot::activate(QObject*)
347{
348}
349
350void RegExpFilter::HotSpot::setCapturedTexts(const QStringList& texts)
351{
352    _capturedTexts = texts;
353}
354QStringList RegExpFilter::HotSpot::capturedTexts() const
355{
356    return _capturedTexts;
357}
358
359void RegExpFilter::setRegExp(const QRegExp& regExp) 
360{
361    _searchText = regExp;
362}
363QRegExp RegExpFilter::regExp() const
364{
365    return _searchText;
366}
367/*void RegExpFilter::reset(int)
368{
369    _buffer = QString();
370}*/
371void RegExpFilter::process()
372{
373    int pos = 0;
374    const QString* text = buffer();
375
376    Q_ASSERT( text );
377
378    // ignore any regular expressions which match an empty string.
379    // otherwise the while loop below will run indefinitely
380    static const QString emptyString("");
381    if ( _searchText.exactMatch(emptyString) )
382        return;
383
384    while(pos >= 0)
385    {
386        pos = _searchText.indexIn(*text,pos);
387
388        if ( pos >= 0 )
389        {
390
391            int startLine = 0;
392            int endLine = 0;
393            int startColumn = 0;
394            int endColumn = 0;
395
396           
397            //kDebug() << "pos from " << pos << " to " << pos + _searchText.matchedLength();
398           
399            getLineColumn(pos,startLine,startColumn);
400            getLineColumn(pos + _searchText.matchedLength(),endLine,endColumn);
401
402            //kDebug() << "start " << startLine << " / " << startColumn;
403            //kDebug() << "end " << endLine << " / " << endColumn;
404
405            RegExpFilter::HotSpot* spot = newHotSpot(startLine,startColumn,
406                                           endLine,endColumn);
407            spot->setCapturedTexts(_searchText.capturedTexts());
408
409            addHotSpot( spot ); 
410            pos += _searchText.matchedLength();
411
412            // if matchedLength == 0, the program will get stuck in an infinite loop
413            Q_ASSERT( _searchText.matchedLength() > 0 );
414        }
415    }   
416}
417
418RegExpFilter::HotSpot* RegExpFilter::newHotSpot(int startLine,int startColumn,
419                                                int endLine,int endColumn)
420{
421    return new RegExpFilter::HotSpot(startLine,startColumn,
422                                                  endLine,endColumn);
423}
424RegExpFilter::HotSpot* UrlFilter::newHotSpot(int startLine,int startColumn,int endLine,
425                                                    int endColumn)
426{
427    return new UrlFilter::HotSpot(startLine,startColumn,
428                                               endLine,endColumn);
429}
430UrlFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endColumn)
431: RegExpFilter::HotSpot(startLine,startColumn,endLine,endColumn)
432, _urlObject(new FilterObject(this))
433{
434    setType(Link);
435}
436QString UrlFilter::HotSpot::tooltip() const
437{
438    QString url = capturedTexts().first();
439
440    const UrlType kind = urlType();
441
442    if ( kind == StandardUrl )
443        return QString(); 
444    else if ( kind == Email )
445        return QString(); 
446    else
447        return QString();
448}
449UrlFilter::HotSpot::UrlType UrlFilter::HotSpot::urlType() const
450{
451    QString url = capturedTexts().first();
452   
453    if ( FullUrlRegExp.exactMatch(url) )
454        return StandardUrl;
455    else if ( EmailAddressRegExp.exactMatch(url) )
456        return Email;
457    else
458        return Unknown;
459}
460
461void UrlFilter::HotSpot::activate(QObject* object)
462{
463    QString url = capturedTexts().first();
464
465    const UrlType kind = urlType();
466
467    const QString& actionName = object ? object->objectName() : QString();
468
469    if ( actionName == "copy-action" )
470    {
471        //kDebug() << "Copying url to clipboard:" << url;
472
473        QApplication::clipboard()->setText(url);
474        return;
475    }
476
477    if ( !object || actionName == "open-action" )
478    {
479        if ( kind == StandardUrl )
480        {
481            // if the URL path does not include the protocol ( eg. "www.kde.org" ) then
482            // prepend http:// ( eg. "www.kde.org" --> "http://www.kde.org" )
483            if (!url.contains("://"))
484            {
485                url.prepend("http://");
486            }
487        } 
488        else if ( kind == Email )
489        {
490            url.prepend("mailto:");
491        }
492   
493//        new KRun(url,QApplication::activeWindow());
494    }
495}
496
497// Note:  Altering these regular expressions can have a major effect on the performance of the filters
498// used for finding URLs in the text, especially if they are very general and could match very long
499// pieces of text.
500// Please be careful when altering them.
501
502//regexp matches:
503// full url: 
504// protocolname:// or www. followed by anything other than whitespaces, <, >, ' or ", and ends before whitespaces, <, >, ', ", ], !, comma and dot
505const QRegExp UrlFilter::FullUrlRegExp("(www\\.(?!\\.)|[a-z][a-z0-9+.-]*://)[^\\s<>'\"]+[^!,\\.\\s<>'\"\\]]");
506// email address:
507// [word chars, dots or dashes]@[word chars, dots or dashes].[word chars]
508const QRegExp UrlFilter::EmailAddressRegExp("\\b(\\w|\\.|-)+@(\\w|\\.|-)+\\.\\w+\\b");
509
510// matches full url or email address
511const QRegExp UrlFilter::CompleteUrlRegExp('('+FullUrlRegExp.pattern()+'|'+
512                                            EmailAddressRegExp.pattern()+')');
513
514UrlFilter::UrlFilter()
515{
516    setRegExp( CompleteUrlRegExp );
517}
518UrlFilter::HotSpot::~HotSpot()
519{
520    delete _urlObject;
521}
522void FilterObject::activated()
523{
524    _filter->activate(sender());
525}
526QList<QAction*> UrlFilter::HotSpot::actions()
527{
528    QList<QAction*> list;
529
530    const UrlType kind = urlType();
531
532    QAction* openAction = new QAction(_urlObject);
533    QAction* copyAction = new QAction(_urlObject);;
534
535    Q_ASSERT( kind == StandardUrl || kind == Email );
536
537    if ( kind == StandardUrl )
538    {
539        openAction->setText(("Open Link"));
540        copyAction->setText(("Copy Link Address"));
541    }
542    else if ( kind == Email )
543    {
544        openAction->setText(("Send Email To..."));
545        copyAction->setText(("Copy Email Address"));
546    }
547
548    // object names are set here so that the hotspot performs the
549    // correct action when activated() is called with the triggered
550    // action passed as a parameter.
551    openAction->setObjectName("open-action");
552    copyAction->setObjectName("copy-action");
553
554    QObject::connect( openAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
555    QObject::connect( copyAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
556
557    list << openAction;
558    list << copyAction;
559
560    return list; 
561}
562
563//#include "moc_Filter.cpp"
Note: See TracBrowser for help on using the repository browser.