00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "Filter.h"
00022
00023
00024 #include <iostream>
00025
00026
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
00036 #include <KLocale>
00037 #include <KRun>
00038
00039
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
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
00137 reset();
00138
00139 PlainTextDecoder decoder;
00140 decoder.setTrailingWhitespace(false);
00141
00142
00143 QString* newBuffer = new QString();
00144 QList<int>* newLinePositions = new QList<int>();
00145 setBuffer( newBuffer , newLinePositions );
00146
00147
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
00163
00164
00165
00166
00167
00168
00169
00170
00171
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
00230
00231
00232
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
00352
00353
00354
00355 void RegExpFilter::process()
00356 {
00357 int pos = 0;
00358 const QString* text = buffer();
00359
00360 Q_ASSERT( text );
00361
00362
00363
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
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
00458
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
00474
00475
00476
00477
00478
00479
00480
00481 const QRegExp UrlFilter::FullUrlRegExp("(www\\.(?!\\.)|[a-z][a-z0-9+.-]*://)[^\\s<>'\"]+[^!,\\.\\s<>'\"\\]]");
00482
00483
00484 const QRegExp UrlFilter::EmailAddressRegExp("\\b(\\w|\\.|-)+@(\\w|\\.|-)+\\.\\w+\\b");
00485
00486
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
00525
00526
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"