• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Konsole

Filter.cpp

Go to the documentation of this file.
00001 /*
00002     Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
00003 
00004     This program is free software; you can redistribute it and/or modify
00005     it under the terms of the GNU General Public License as published by
00006     the Free Software Foundation; either version 2 of the License, or
00007     (at your option) any later version.
00008 
00009     This program is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012     GNU General Public License for more details.
00013 
00014     You should have received a copy of the GNU General Public License
00015     along with this program; if not, write to the Free Software
00016     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017     02110-1301  USA.
00018 */
00019 
00020 // Own
00021 #include "Filter.h"
00022 
00023 // System
00024 #include <iostream>
00025 
00026 // Qt
00027 #include <QtGui/QAction>
00028 #include <QtGui/QApplication>
00029 #include <QtGui/QClipboard>
00030 #include <QtCore/QString>
00031 #include <KDebug>
00032 #include <QtCore/QSharedData>
00033 #include <QtCore/QFile>
00034 
00035 // KDE
00036 #include <KLocale>
00037 #include <KRun>
00038 
00039 // Konsole
00040 #include "TerminalCharacterDecoder.h"
00041 
00042 using namespace Konsole;
00043 
00044 FilterChain::~FilterChain()
00045 {
00046     QMutableListIterator<Filter*> iter(*this);
00047     
00048     while ( iter.hasNext() )
00049     {
00050         Filter* filter = iter.next();
00051         iter.remove();
00052         delete filter;
00053     }
00054 }
00055 
00056 void FilterChain::addFilter(Filter* filter)
00057 {
00058     append(filter);
00059 }
00060 void FilterChain::removeFilter(Filter* filter)
00061 {
00062     removeAll(filter);
00063 }
00064 bool FilterChain::containsFilter(Filter* filter)
00065 {
00066     return contains(filter);
00067 }
00068 void FilterChain::reset()
00069 {
00070     QListIterator<Filter*> iter(*this);
00071     while (iter.hasNext())
00072         iter.next()->reset();
00073 }
00074 void FilterChain::setBuffer(const QString* buffer , const QList<int>* linePositions)
00075 {
00076     QListIterator<Filter*> iter(*this);
00077     while (iter.hasNext())
00078         iter.next()->setBuffer(buffer,linePositions);
00079 }
00080 void FilterChain::process()
00081 {
00082     QListIterator<Filter*> iter(*this);
00083     while (iter.hasNext())
00084         iter.next()->process();
00085 }
00086 void FilterChain::clear()
00087 {
00088     QList<Filter*>::clear();
00089 }
00090 Filter::HotSpot* FilterChain::hotSpotAt(int line , int column) const
00091 {
00092     QListIterator<Filter*> iter(*this);
00093     while (iter.hasNext())
00094     {
00095         Filter* filter = iter.next();
00096         Filter::HotSpot* spot = filter->hotSpotAt(line,column);
00097         if ( spot != 0 )
00098         {
00099             return spot;
00100         }
00101     }
00102 
00103     return 0;
00104 }
00105 
00106 QList<Filter::HotSpot*> FilterChain::hotSpots() const
00107 {
00108     QList<Filter::HotSpot*> list;
00109     QListIterator<Filter*> iter(*this);
00110     while (iter.hasNext())
00111     {
00112         Filter* filter = iter.next();
00113         list << filter->hotSpots();
00114     }
00115     return list;
00116 }
00117 //QList<Filter::HotSpot*> FilterChain::hotSpotsAtLine(int line) const;
00118 
00119 TerminalImageFilterChain::TerminalImageFilterChain()
00120 : _buffer(0)
00121 , _linePositions(0)
00122 {
00123 }
00124 
00125 TerminalImageFilterChain::~TerminalImageFilterChain()
00126 {
00127     delete _buffer;
00128     delete _linePositions;
00129 }
00130 
00131 void TerminalImageFilterChain::setImage(const Character* const image , int lines , int columns, const QVector<LineProperty>& lineProperties)
00132 {
00133     if (empty())
00134         return;
00135 
00136     // reset all filters and hotspots
00137     reset();
00138 
00139     PlainTextDecoder decoder;
00140     decoder.setTrailingWhitespace(false);
00141     
00142     // setup new shared buffers for the filters to process on
00143     QString* newBuffer = new QString();
00144     QList<int>* newLinePositions = new QList<int>();
00145     setBuffer( newBuffer , newLinePositions );
00146 
00147     // free the old buffers
00148     delete _buffer;
00149     delete _linePositions;
00150 
00151     _buffer = newBuffer;
00152     _linePositions = newLinePositions;
00153 
00154     QTextStream lineStream(_buffer);
00155     decoder.begin(&lineStream);
00156 
00157     for (int i=0 ; i < lines ; i++)
00158     {
00159         _linePositions->append(_buffer->length());
00160         decoder.decodeLine(image + i*columns,columns,LINE_DEFAULT);
00161 
00162         // pretend that each line ends with a newline character.
00163         // this prevents a link that occurs at the end of one line
00164         // being treated as part of a link that occurs at the start of the next line
00165         //
00166         // the downside is that links which are spread over more than one line are not
00167         // highlighted.  
00168         //
00169         // TODO - Use the "line wrapped" attribute associated with lines in a
00170         // terminal image to avoid adding this imaginary character for wrapped
00171         // lines
00172         if ( !(lineProperties.value(i,LINE_DEFAULT) & LINE_WRAPPED) )
00173             lineStream << QChar('\n');
00174     }
00175     decoder.end();
00176 }
00177 
00178 Filter::Filter() :
00179 _linePositions(0),
00180 _buffer(0)
00181 {
00182 }
00183 
00184 Filter::~Filter()
00185 {
00186     QListIterator<HotSpot*> iter(_hotspotList);
00187     while (iter.hasNext())
00188     {
00189         delete iter.next();
00190     }
00191 }
00192 void Filter::reset()
00193 {
00194     _hotspots.clear();
00195     _hotspotList.clear();
00196 }
00197 
00198 void Filter::setBuffer(const QString* buffer , const QList<int>* linePositions)
00199 {
00200     _buffer = buffer;
00201     _linePositions = linePositions;
00202 }
00203 
00204 void Filter::getLineColumn(int position , int& startLine , int& startColumn)
00205 {
00206     Q_ASSERT( _linePositions );
00207     Q_ASSERT( _buffer );
00208 
00209 
00210     for (int i = 0 ; i < _linePositions->count() ; i++)
00211     {
00212         int nextLine = 0;
00213 
00214         if ( i == _linePositions->count()-1 )
00215             nextLine = _buffer->length() + 1;
00216         else
00217             nextLine = _linePositions->value(i+1);
00218 
00219         if ( _linePositions->value(i) <= position && position < nextLine ) 
00220         {
00221             startLine = i;
00222             startColumn = position - _linePositions->value(i);
00223             return;
00224         }
00225     }
00226 }
00227     
00228 
00229 /*void Filter::addLine(const QString& text)
00230 {
00231     _linePositions << _buffer.length();
00232     _buffer.append(text);
00233 }*/
00234 
00235 const QString* Filter::buffer()
00236 {
00237     return _buffer;
00238 }
00239 Filter::HotSpot::~HotSpot()
00240 {
00241 }
00242 void Filter::addHotSpot(HotSpot* spot)
00243 {
00244     _hotspotList << spot;
00245 
00246     for (int line = spot->startLine() ; line <= spot->endLine() ; line++)
00247     {
00248         _hotspots.insert(line,spot);
00249     }    
00250 }
00251 QList<Filter::HotSpot*> Filter::hotSpots() const
00252 {
00253     return _hotspotList;
00254 }
00255 QList<Filter::HotSpot*> Filter::hotSpotsAtLine(int line) const
00256 {
00257     return _hotspots.values(line);
00258 }
00259 
00260 Filter::HotSpot* Filter::hotSpotAt(int line , int column) const
00261 {
00262     QListIterator<HotSpot*> spotIter(_hotspots.values(line));
00263 
00264     while (spotIter.hasNext())
00265     {
00266         HotSpot* spot = spotIter.next();
00267         
00268         if ( spot->startLine() == line && spot->startColumn() > column )
00269             continue;
00270         if ( spot->endLine() == line && spot->endColumn() < column )
00271             continue;
00272        
00273         return spot;
00274     }
00275 
00276     return 0;
00277 }
00278 
00279 Filter::HotSpot::HotSpot(int startLine , int startColumn , int endLine , int endColumn)
00280     : _startLine(startLine)
00281     , _startColumn(startColumn)
00282     , _endLine(endLine)
00283     , _endColumn(endColumn)
00284     , _type(NotSpecified)
00285 {
00286 }
00287 QString Filter::HotSpot::tooltip() const
00288 {
00289     return QString();
00290 }
00291 QList<QAction*> Filter::HotSpot::actions()
00292 {
00293     return QList<QAction*>();
00294 }
00295 int Filter::HotSpot::startLine() const
00296 {
00297     return _startLine;
00298 }
00299 int Filter::HotSpot::endLine() const
00300 {
00301     return _endLine;
00302 }
00303 int Filter::HotSpot::startColumn() const
00304 {
00305     return _startColumn;
00306 }
00307 int Filter::HotSpot::endColumn() const
00308 {
00309     return _endColumn;
00310 }
00311 Filter::HotSpot::Type Filter::HotSpot::type() const
00312 {
00313     return _type;
00314 }
00315 void Filter::HotSpot::setType(Type type)
00316 {
00317     _type = type;
00318 }
00319 
00320 RegExpFilter::RegExpFilter()
00321 {
00322 }
00323 
00324 RegExpFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endColumn)
00325     : Filter::HotSpot(startLine,startColumn,endLine,endColumn)
00326 {
00327     setType(Marker);
00328 }
00329 
00330 void RegExpFilter::HotSpot::activate(QObject*)
00331 {
00332 }
00333 
00334 void RegExpFilter::HotSpot::setCapturedTexts(const QStringList& texts)
00335 {
00336     _capturedTexts = texts;
00337 }
00338 QStringList RegExpFilter::HotSpot::capturedTexts() const
00339 {
00340     return _capturedTexts;
00341 }
00342 
00343 void RegExpFilter::setRegExp(const QRegExp& regExp) 
00344 {
00345     _searchText = regExp;
00346 }
00347 QRegExp RegExpFilter::regExp() const
00348 {
00349     return _searchText;
00350 }
00351 /*void RegExpFilter::reset(int)
00352 {
00353     _buffer = QString();
00354 }*/
00355 void RegExpFilter::process()
00356 {
00357     int pos = 0;
00358     const QString* text = buffer();
00359 
00360     Q_ASSERT( text );
00361 
00362     // ignore any regular expressions which match an empty string.
00363     // otherwise the while loop below will run indefinitely
00364     static const QString emptyString("");
00365     if ( _searchText.exactMatch(emptyString) )
00366         return;
00367 
00368     while(pos >= 0)
00369     {
00370         pos = _searchText.indexIn(*text,pos);
00371 
00372         if ( pos >= 0 )
00373         {
00374 
00375             int startLine = 0;
00376             int endLine = 0;
00377             int startColumn = 0;
00378             int endColumn = 0;
00379 
00380             getLineColumn(pos,startLine,startColumn);
00381             getLineColumn(pos + _searchText.matchedLength(),endLine,endColumn);
00382 
00383             RegExpFilter::HotSpot* spot = newHotSpot(startLine,startColumn,
00384                                            endLine,endColumn);
00385             spot->setCapturedTexts(_searchText.capturedTexts());
00386 
00387             addHotSpot( spot );  
00388             pos += _searchText.matchedLength();
00389 
00390             // if matchedLength == 0, the program will get stuck in an infinite loop
00391             Q_ASSERT( _searchText.matchedLength() > 0 );
00392         }
00393     }    
00394 }
00395 
00396 RegExpFilter::HotSpot* RegExpFilter::newHotSpot(int startLine,int startColumn,
00397                                                 int endLine,int endColumn)
00398 {
00399     return new RegExpFilter::HotSpot(startLine,startColumn,
00400                                                   endLine,endColumn);
00401 }
00402 RegExpFilter::HotSpot* UrlFilter::newHotSpot(int startLine,int startColumn,int endLine,
00403                                                     int endColumn)
00404 {
00405     return new UrlFilter::HotSpot(startLine,startColumn,
00406                                                endLine,endColumn);
00407 }
00408 UrlFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endColumn)
00409 : RegExpFilter::HotSpot(startLine,startColumn,endLine,endColumn)
00410 , _urlObject(new FilterObject(this))
00411 {
00412     setType(Link);
00413 }
00414 QString UrlFilter::HotSpot::tooltip() const
00415 {
00416     QString url = capturedTexts().first();
00417 
00418     const UrlType kind = urlType();
00419 
00420     if ( kind == StandardUrl )
00421         return QString(); 
00422     else if ( kind == Email )
00423         return QString(); 
00424     else
00425         return QString();
00426 }
00427 UrlFilter::HotSpot::UrlType UrlFilter::HotSpot::urlType() const
00428 {
00429     QString url = capturedTexts().first();
00430     
00431     if ( FullUrlRegExp.exactMatch(url) )
00432         return StandardUrl;
00433     else if ( EmailAddressRegExp.exactMatch(url) )
00434         return Email;
00435     else
00436         return Unknown;
00437 }
00438 
00439 void UrlFilter::HotSpot::activate(QObject* object)
00440 {
00441     QString url = capturedTexts().first();
00442 
00443     const UrlType kind = urlType();
00444 
00445     const QString& actionName = object ? object->objectName() : QString();
00446 
00447     if ( actionName == "copy-action" )
00448     {
00449         QApplication::clipboard()->setText(url);
00450         return;
00451     }
00452 
00453     if ( !object || actionName == "open-action" )
00454     {
00455         if ( kind == StandardUrl )
00456         {
00457             // if the URL path does not include the protocol ( eg. "www.kde.org" ) then
00458             // prepend http:// ( eg. "www.kde.org" --> "http://www.kde.org" )
00459             if (!url.contains("://"))
00460             {
00461                 url.prepend("http://");
00462             }
00463         } 
00464         else if ( kind == Email )
00465         {
00466             url.prepend("mailto:");
00467         }
00468     
00469         new KRun(url,QApplication::activeWindow());
00470     }
00471 }
00472 
00473 // Note:  Altering these regular expressions can have a major effect on the performance of the filters 
00474 // used for finding URLs in the text, especially if they are very general and could match very long
00475 // pieces of text.
00476 // Please be careful when altering them.
00477 
00478 //regexp matches:
00479 // full url:  
00480 // protocolname:// or www. followed by anything other than whitespaces, <, >, ' or ", and ends before whitespaces, <, >, ', ", ], !, comma and dot
00481 const QRegExp UrlFilter::FullUrlRegExp("(www\\.(?!\\.)|[a-z][a-z0-9+.-]*://)[^\\s<>'\"]+[^!,\\.\\s<>'\"\\]]");
00482 // email address:
00483 // [word chars, dots or dashes]@[word chars, dots or dashes].[word chars]
00484 const QRegExp UrlFilter::EmailAddressRegExp("\\b(\\w|\\.|-)+@(\\w|\\.|-)+\\.\\w+\\b");
00485 
00486 // matches full url or email address
00487 const QRegExp UrlFilter::CompleteUrlRegExp('('+FullUrlRegExp.pattern()+'|'+
00488                                             EmailAddressRegExp.pattern()+')');
00489 
00490 UrlFilter::UrlFilter()
00491 {
00492     setRegExp( CompleteUrlRegExp );
00493 }
00494 UrlFilter::HotSpot::~HotSpot()
00495 {
00496     delete _urlObject;
00497 }
00498 void FilterObject::activated()
00499 {
00500     _filter->activate(sender());
00501 }
00502 QList<QAction*> UrlFilter::HotSpot::actions()
00503 {
00504     QList<QAction*> list;
00505 
00506     const UrlType kind = urlType();
00507 
00508     QAction* openAction = new QAction(_urlObject);
00509     QAction* copyAction = new QAction(_urlObject);;
00510 
00511     Q_ASSERT( kind == StandardUrl || kind == Email );
00512 
00513     if ( kind == StandardUrl )
00514     {
00515         openAction->setText(i18n("Open Link"));
00516         copyAction->setText(i18n("Copy Link Address"));
00517     }
00518     else if ( kind == Email )
00519     {
00520         openAction->setText(i18n("Send Email To..."));
00521         copyAction->setText(i18n("Copy Email Address"));
00522     }
00523 
00524     // object names are set here so that the hotspot performs the
00525     // correct action when activated() is called with the triggered
00526     // action passed as a parameter.
00527     openAction->setObjectName("open-action");
00528     copyAction->setObjectName("copy-action");
00529 
00530     QObject::connect( openAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
00531     QObject::connect( copyAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
00532 
00533     list << openAction;
00534     list << copyAction;
00535 
00536     return list; 
00537 }
00538 
00539 #include "Filter.moc"

Konsole

Skip menu "Konsole"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • Konsole
  • Libraries
  •   libkonq
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal