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 if ( _searchText.matchedLength() == 0 )
00392 pos = -1;
00393 }
00394 }
00395 }
00396
00397 RegExpFilter::HotSpot* RegExpFilter::newHotSpot(int startLine,int startColumn,
00398 int endLine,int endColumn)
00399 {
00400 return new RegExpFilter::HotSpot(startLine,startColumn,
00401 endLine,endColumn);
00402 }
00403 RegExpFilter::HotSpot* UrlFilter::newHotSpot(int startLine,int startColumn,int endLine,
00404 int endColumn)
00405 {
00406 return new UrlFilter::HotSpot(startLine,startColumn,
00407 endLine,endColumn);
00408 }
00409 UrlFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endColumn)
00410 : RegExpFilter::HotSpot(startLine,startColumn,endLine,endColumn)
00411 , _urlObject(new FilterObject(this))
00412 {
00413 setType(Link);
00414 }
00415 QString UrlFilter::HotSpot::tooltip() const
00416 {
00417 QString url = capturedTexts().first();
00418
00419 const UrlType kind = urlType();
00420
00421 if ( kind == StandardUrl )
00422 return QString();
00423 else if ( kind == Email )
00424 return QString();
00425 else
00426 return QString();
00427 }
00428 UrlFilter::HotSpot::UrlType UrlFilter::HotSpot::urlType() const
00429 {
00430 QString url = capturedTexts().first();
00431
00432 if ( FullUrlRegExp.exactMatch(url) )
00433 return StandardUrl;
00434 else if ( EmailAddressRegExp.exactMatch(url) )
00435 return Email;
00436 else
00437 return Unknown;
00438 }
00439
00440 void UrlFilter::HotSpot::activate(QObject* object)
00441 {
00442 QString url = capturedTexts().first();
00443
00444 const UrlType kind = urlType();
00445
00446 const QString& actionName = object ? object->objectName() : QString();
00447
00448 if ( actionName == "copy-action" )
00449 {
00450 QApplication::clipboard()->setText(url);
00451 return;
00452 }
00453
00454 if ( !object || actionName == "open-action" )
00455 {
00456 if ( kind == StandardUrl )
00457 {
00458
00459
00460 if (!url.contains("://"))
00461 {
00462 url.prepend("http://");
00463 }
00464 }
00465 else if ( kind == Email )
00466 {
00467 url.prepend("mailto:");
00468 }
00469
00470 new KRun(url,QApplication::activeWindow());
00471 }
00472 }
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482 const QRegExp UrlFilter::FullUrlRegExp("(www\\.(?!\\.)|[a-z][a-z0-9+.-]*://)[^\\s<>'\"]+[^!,\\.\\s<>'\"\\]]");
00483
00484
00485 const QRegExp UrlFilter::EmailAddressRegExp("\\b(\\w|\\.|-)+@(\\w|\\.|-)+\\.\\w+\\b");
00486
00487
00488 const QRegExp UrlFilter::CompleteUrlRegExp('('+FullUrlRegExp.pattern()+'|'+
00489 EmailAddressRegExp.pattern()+')');
00490
00491 UrlFilter::UrlFilter()
00492 {
00493 setRegExp( CompleteUrlRegExp );
00494 }
00495 UrlFilter::HotSpot::~HotSpot()
00496 {
00497 delete _urlObject;
00498 }
00499 void FilterObject::activated()
00500 {
00501 _filter->activate(sender());
00502 }
00503 QList<QAction*> UrlFilter::HotSpot::actions()
00504 {
00505 QList<QAction*> list;
00506
00507 const UrlType kind = urlType();
00508
00509 QAction* openAction = new QAction(_urlObject);
00510 QAction* copyAction = new QAction(_urlObject);;
00511
00512 Q_ASSERT( kind == StandardUrl || kind == Email );
00513
00514 if ( kind == StandardUrl )
00515 {
00516 openAction->setText(i18n("Open Link"));
00517 copyAction->setText(i18n("Copy Link Address"));
00518 }
00519 else if ( kind == Email )
00520 {
00521 openAction->setText(i18n("Send Email To..."));
00522 copyAction->setText(i18n("Copy Email Address"));
00523 }
00524
00525
00526
00527
00528 openAction->setObjectName("open-action");
00529 copyAction->setObjectName("copy-action");
00530
00531 QObject::connect( openAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
00532 QObject::connect( copyAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
00533
00534 list << openAction;
00535 list << copyAction;
00536
00537 return list;
00538 }
00539
00540 #include "Filter.moc"