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
00213 int nextLine = 0;
00214
00215 if ( i == _linePositions->count()-1 )
00216 {
00217 nextLine = _buffer->length() + 1;
00218 }
00219 else
00220 {
00221 nextLine = _linePositions->value(i+1);
00222 }
00223
00224
00225
00226
00227 if ( _linePositions->value(i) <= position && position < nextLine )
00228 {
00229 startLine = i;
00230 startColumn = position - _linePositions->value(i);
00231 return;
00232 }
00233 }
00234 }
00235
00236
00237
00238
00239
00240
00241
00242
00243 const QString* Filter::buffer()
00244 {
00245 return _buffer;
00246 }
00247 Filter::HotSpot::~HotSpot()
00248 {
00249 }
00250 void Filter::addHotSpot(HotSpot* spot)
00251 {
00252 _hotspotList << spot;
00253
00254 for (int line = spot->startLine() ; line <= spot->endLine() ; line++)
00255 {
00256 _hotspots.insert(line,spot);
00257 }
00258 }
00259 QList<Filter::HotSpot*> Filter::hotSpots() const
00260 {
00261 return _hotspotList;
00262 }
00263 QList<Filter::HotSpot*> Filter::hotSpotsAtLine(int line) const
00264 {
00265 return _hotspots.values(line);
00266 }
00267
00268 Filter::HotSpot* Filter::hotSpotAt(int line , int column) const
00269 {
00270 QListIterator<HotSpot*> spotIter(_hotspots.values(line));
00271
00272 while (spotIter.hasNext())
00273 {
00274 HotSpot* spot = spotIter.next();
00275
00276 if ( spot->startLine() == line && spot->startColumn() > column )
00277 continue;
00278 if ( spot->endLine() == line && spot->endColumn() < column )
00279 continue;
00280
00281 return spot;
00282 }
00283
00284 return 0;
00285 }
00286
00287 Filter::HotSpot::HotSpot(int startLine , int startColumn , int endLine , int endColumn)
00288 : _startLine(startLine)
00289 , _startColumn(startColumn)
00290 , _endLine(endLine)
00291 , _endColumn(endColumn)
00292 , _type(NotSpecified)
00293 {
00294 }
00295 QString Filter::HotSpot::tooltip() const
00296 {
00297 return QString();
00298 }
00299 QList<QAction*> Filter::HotSpot::actions()
00300 {
00301 return QList<QAction*>();
00302 }
00303 int Filter::HotSpot::startLine() const
00304 {
00305 return _startLine;
00306 }
00307 int Filter::HotSpot::endLine() const
00308 {
00309 return _endLine;
00310 }
00311 int Filter::HotSpot::startColumn() const
00312 {
00313 return _startColumn;
00314 }
00315 int Filter::HotSpot::endColumn() const
00316 {
00317 return _endColumn;
00318 }
00319 Filter::HotSpot::Type Filter::HotSpot::type() const
00320 {
00321 return _type;
00322 }
00323 void Filter::HotSpot::setType(Type type)
00324 {
00325 _type = type;
00326 }
00327
00328 RegExpFilter::RegExpFilter()
00329 {
00330 }
00331
00332 RegExpFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endColumn)
00333 : Filter::HotSpot(startLine,startColumn,endLine,endColumn)
00334 {
00335 setType(Marker);
00336 }
00337
00338 void RegExpFilter::HotSpot::activate(QObject*)
00339 {
00340 }
00341
00342 void RegExpFilter::HotSpot::setCapturedTexts(const QStringList& texts)
00343 {
00344 _capturedTexts = texts;
00345 }
00346 QStringList RegExpFilter::HotSpot::capturedTexts() const
00347 {
00348 return _capturedTexts;
00349 }
00350
00351 void RegExpFilter::setRegExp(const QRegExp& regExp)
00352 {
00353 _searchText = regExp;
00354 }
00355 QRegExp RegExpFilter::regExp() const
00356 {
00357 return _searchText;
00358 }
00359
00360
00361
00362
00363 void RegExpFilter::process()
00364 {
00365 int pos = 0;
00366 const QString* text = buffer();
00367
00368 Q_ASSERT( text );
00369
00370
00371
00372 static const QString emptyString("");
00373 if ( _searchText.exactMatch(emptyString) )
00374 return;
00375
00376 while(pos >= 0)
00377 {
00378 pos = _searchText.indexIn(*text,pos);
00379
00380 if ( pos >= 0 )
00381 {
00382
00383 int startLine = 0;
00384 int endLine = 0;
00385 int startColumn = 0;
00386 int endColumn = 0;
00387
00388
00389
00390
00391 getLineColumn(pos,startLine,startColumn);
00392 getLineColumn(pos + _searchText.matchedLength(),endLine,endColumn);
00393
00394
00395
00396
00397 RegExpFilter::HotSpot* spot = newHotSpot(startLine,startColumn,
00398 endLine,endColumn);
00399 spot->setCapturedTexts(_searchText.capturedTexts());
00400
00401 addHotSpot( spot );
00402 pos += _searchText.matchedLength();
00403
00404
00405 Q_ASSERT( _searchText.matchedLength() > 0 );
00406 }
00407 }
00408 }
00409
00410 RegExpFilter::HotSpot* RegExpFilter::newHotSpot(int startLine,int startColumn,
00411 int endLine,int endColumn)
00412 {
00413 return new RegExpFilter::HotSpot(startLine,startColumn,
00414 endLine,endColumn);
00415 }
00416 RegExpFilter::HotSpot* UrlFilter::newHotSpot(int startLine,int startColumn,int endLine,
00417 int endColumn)
00418 {
00419 return new UrlFilter::HotSpot(startLine,startColumn,
00420 endLine,endColumn);
00421 }
00422 UrlFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endColumn)
00423 : RegExpFilter::HotSpot(startLine,startColumn,endLine,endColumn)
00424 , _urlObject(new FilterObject(this))
00425 {
00426 setType(Link);
00427 }
00428 QString UrlFilter::HotSpot::tooltip() const
00429 {
00430 QString url = capturedTexts().first();
00431
00432 const UrlType kind = urlType();
00433
00434 if ( kind == StandardUrl )
00435 return QString();
00436 else if ( kind == Email )
00437 return QString();
00438 else
00439 return QString();
00440 }
00441 UrlFilter::HotSpot::UrlType UrlFilter::HotSpot::urlType() const
00442 {
00443 QString url = capturedTexts().first();
00444
00445 if ( FullUrlRegExp.exactMatch(url) )
00446 return StandardUrl;
00447 else if ( EmailAddressRegExp.exactMatch(url) )
00448 return Email;
00449 else
00450 return Unknown;
00451 }
00452
00453 void UrlFilter::HotSpot::activate(QObject* object)
00454 {
00455 QString url = capturedTexts().first();
00456
00457 const UrlType kind = urlType();
00458
00459 const QString& actionName = object ? object->objectName() : QString();
00460
00461 if ( actionName == "copy-action" )
00462 {
00463
00464
00465 QApplication::clipboard()->setText(url);
00466 return;
00467 }
00468
00469 if ( !object || actionName == "open-action" )
00470 {
00471 if ( kind == StandardUrl )
00472 {
00473
00474
00475 if (!url.contains("://"))
00476 {
00477 url.prepend("http://");
00478 }
00479 }
00480 else if ( kind == Email )
00481 {
00482 url.prepend("mailto:");
00483 }
00484
00485 new KRun(url,QApplication::activeWindow());
00486 }
00487 }
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497 const QRegExp UrlFilter::FullUrlRegExp("(www\\.(?!\\.)|[a-z][a-z0-9+.-]*://)[^\\s<>'\"]+[^!,\\.\\s<>'\"\\]]");
00498
00499
00500 const QRegExp UrlFilter::EmailAddressRegExp("\\b(\\w|\\.|-)+@(\\w|\\.|-)+\\.\\w+\\b");
00501
00502
00503 const QRegExp UrlFilter::CompleteUrlRegExp('('+FullUrlRegExp.pattern()+'|'+
00504 EmailAddressRegExp.pattern()+')');
00505
00506 UrlFilter::UrlFilter()
00507 {
00508 setRegExp( CompleteUrlRegExp );
00509 }
00510 UrlFilter::HotSpot::~HotSpot()
00511 {
00512 delete _urlObject;
00513 }
00514 void FilterObject::activated()
00515 {
00516 _filter->activate(sender());
00517 }
00518 QList<QAction*> UrlFilter::HotSpot::actions()
00519 {
00520 QList<QAction*> list;
00521
00522 const UrlType kind = urlType();
00523
00524 QAction* openAction = new QAction(_urlObject);
00525 QAction* copyAction = new QAction(_urlObject);;
00526
00527 Q_ASSERT( kind == StandardUrl || kind == Email );
00528
00529 if ( kind == StandardUrl )
00530 {
00531 openAction->setText(i18n("Open Link"));
00532 copyAction->setText(i18n("Copy Link Address"));
00533 }
00534 else if ( kind == Email )
00535 {
00536 openAction->setText(i18n("Send Email To..."));
00537 copyAction->setText(i18n("Copy Email Address"));
00538 }
00539
00540
00541
00542
00543 openAction->setObjectName("open-action");
00544 copyAction->setObjectName("copy-action");
00545
00546 QObject::connect( openAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
00547 QObject::connect( copyAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
00548
00549 list << openAction;
00550 list << copyAction;
00551
00552 return list;
00553 }
00554
00555 #include "Filter.moc"