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