Mercurial > octave
changeset 23404:314ac710f2ae
highlight error messages in gui and provide links to open files (bug #35619)
* QTerminal.cc (handleCustomContextMenuReques): use method via selecting the
message only in windows
* Filter.cpp (Filter::HotSpot::type(), Filter::HotSpot::setType): make Type
a type in Filter, not in HotSpot;
(RegExpFilter::RegExpFilter) create a filter with the corresponding type
instead of different filters for different types;
(RegExpFilter::HotSpot::HotSpot): A found hot spot is created with the types
of the filter that found that hot spot;
(RegExpFilter::process): remove some old debug message, which were already
commented out, call newHotSpot with type as new parameter;
(RegExpFilter::newHotSpot, UrlFilter::newHotSpot): new parameter type;
(UrlFilter::process): derive this method for UrlFilter, too, allowing
to connect signals for opening files later on;
(UrlFilter::HotSpot::HotSpot): no extra action here, get type from filter;
(UrlFilter::HotSpot::urlType): add new url type;
(UrlFilter::HotSpot::activate): depending on link type, open link as before
or call method for opening the file mentioned in the link;
(UrlFilter::ErrorLinkRegExp): const defined reg. expression for error link;
(UrlFilter::UrlFilter): set reg. expression depending on type;
(UrlFilter::HotSpot::actions): in a case of a file link, only prepare
an open, but no copy action for the context menu;
(UrlFilter::request_open_file): method emitting the signal to the main window
for opening the desired file at desired line;
* Filter.h: make Filter class inherit from QObject for using singals, move
enum Type from HotSpot to Filter and add the types Error and ErrorLink,
Filter and Filter::HotSpot ctors with type parameter, add file opening
signal to RegExpFilter and FilterObject, add Q_OBJECT directives, add
method to FilterObject returning the instance variable _urlObject, add
new urlType ErrorLink, add own process method and open file slot to
UrlFilter, FilterObject: open file slot only emitting open file singal
* QUnixTerminalImpl.cpp (ctor): initialize instance variable _parent;
(initialize): add new filters for errors and for links to related files,
connect latters signal to the appropriate main windows slot;
* QUnixTerminalImpl.h: add instance variable _parent for signal connections
* TerminalView.cpp (paintFilters): underline Link and ErrorLink, draw
rectangle with transparency for Error and LinkError;
(mousePressEvent, mouseMoveEvent): treat Link and ErrorLink the same way
author | Torsten <mttl@mailbox.org> |
---|---|
date | Mon, 17 Apr 2017 21:28:55 +0200 |
parents | fee531225679 |
children | 32ec90068be5 |
files | libgui/qterminal/libqterminal/QTerminal.cc libgui/qterminal/libqterminal/unix/Filter.cpp libgui/qterminal/libqterminal/unix/Filter.h libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.cpp libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.h libgui/qterminal/libqterminal/unix/TerminalView.cpp |
diffstat | 6 files changed, 213 insertions(+), 57 deletions(-) [+] |
line wrap: on
line diff
--- a/libgui/qterminal/libqterminal/QTerminal.cc Mon Apr 17 20:08:24 2017 +0200 +++ b/libgui/qterminal/libqterminal/QTerminal.cc Mon Apr 17 21:28:55 2017 +0200 @@ -99,6 +99,9 @@ _edit_action->setVisible (false); +#if defined (Q_OS_WIN32) + // include this when in windows because there is no filter for + // detecting links and error messages yet if (has_selected_text) { QRegExp file ("(?:[ \\t]+)(\\S+) at line (\\d+) column (?:\\d+)"); @@ -119,6 +122,7 @@ _edit_action->setData (data); } } +#endif _paste_action->setEnabled (cb->text().length() > 0); _copy_action->setEnabled (has_selected_text);
--- a/libgui/qterminal/libqterminal/unix/Filter.cpp Mon Apr 17 20:08:24 2017 +0200 +++ b/libgui/qterminal/libqterminal/unix/Filter.cpp Mon Apr 17 21:28:55 2017 +0200 @@ -2,6 +2,7 @@ Copyright (C) 2007, 2013 by Robert Knight <robertknight@gmail.com> Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008 + Adoption to octave by Torsten <mttl@mailbox.org>, Copyright (c) 2017 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -317,23 +318,25 @@ { return _endColumn; } -Filter::HotSpot::Type Filter::HotSpot::type() const +Filter::Type Filter::HotSpot::type() const { return _type; } -void Filter::HotSpot::setType(Type type) +void Filter::HotSpot::setType(Filter::Type type) { _type = type; } -RegExpFilter::RegExpFilter() +RegExpFilter::RegExpFilter(Type t) + : _type (t) { } -RegExpFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endColumn) +RegExpFilter::HotSpot::HotSpot(int startLine,int startColumn, + int endLine,int endColumn, Filter::Type t) : Filter::HotSpot(startLine,startColumn,endLine,endColumn) { - setType(Marker); + setType(t); } void RegExpFilter::HotSpot::activate(QObject*) @@ -392,11 +395,8 @@ getLineColumn(pos,startLine,startColumn); getLineColumn(pos + _searchText.matchedLength(),endLine,endColumn); - //kDebug() << "start " << startLine << " / " << startColumn; - //kDebug() << "end " << endLine << " / " << endColumn; - RegExpFilter::HotSpot* spot = newHotSpot(startLine,startColumn, - endLine,endColumn); + endLine,endColumn,_type); spot->setCapturedTexts(_searchText.capturedTexts()); addHotSpot( spot ); @@ -409,23 +409,76 @@ } RegExpFilter::HotSpot* RegExpFilter::newHotSpot(int startLine,int startColumn, - int endLine,int endColumn) + int endLine,int endColumn, + Filter::Type t) { return new RegExpFilter::HotSpot(startLine,startColumn, - endLine,endColumn); + endLine,endColumn, t); } -RegExpFilter::HotSpot* UrlFilter::newHotSpot(int startLine,int startColumn,int endLine, - int endColumn) +UrlFilter::HotSpot* UrlFilter::newHotSpot(int startLine,int startColumn,int endLine, + int endColumn, Filter::Type t) { return new UrlFilter::HotSpot(startLine,startColumn, - endLine,endColumn); + endLine,endColumn,t); } -UrlFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endColumn) -: RegExpFilter::HotSpot(startLine,startColumn,endLine,endColumn) + +void UrlFilter::process() +{ + int pos = 0; + const QString* text = buffer(); + + Q_ASSERT( text ); + + // ignore any regular expressions which match an empty string. + // otherwise the while loop below will run indefinitely + static const QString emptyString(""); + if ( _searchText.exactMatch(emptyString) ) + return; + + while(pos >= 0) + { + pos = _searchText.indexIn(*text,pos); + + if ( pos >= 0 ) + { + + int startLine = 0; + int endLine = 0; + int startColumn = 0; + int endColumn = 0; + + + //kDebug() << "pos from " << pos << " to " << pos + _searchText.matchedLength(); + + getLineColumn(pos,startLine,startColumn); + getLineColumn(pos + _searchText.matchedLength(),endLine,endColumn); + + UrlFilter::HotSpot* spot = newHotSpot(startLine,startColumn, + endLine,endColumn,_type); + spot->setCapturedTexts(_searchText.capturedTexts()); + + // Connect the signal of the urlobject to the slot of the filter; + // the filter is then signaling to the main window + connect (spot->get_urlObject (), + SIGNAL (request_open_file_signal (const QString&, int)), + this, SLOT (request_open_file (const QString&, int))); + + addHotSpot( spot ); + pos += _searchText.matchedLength(); + + // if matchedLength == 0, the program will get stuck in an infinite loop + Q_ASSERT( _searchText.matchedLength() > 0 ); + } + } +} + +UrlFilter::HotSpot::HotSpot(int startLine,int startColumn, + int endLine,int endColumn,Type t) +: RegExpFilter::HotSpot(startLine,startColumn,endLine,endColumn,t) , _urlObject(new FilterObject(this)) { - setType(Link); } + QString UrlFilter::HotSpot::tooltip() const { QString url = capturedTexts().first(); @@ -447,6 +500,8 @@ return StandardUrl; else if ( EmailAddressRegExp.exactMatch(url) ) return Email; + else if ( ErrorLinkRegExp.exactMatch(url) ) + return ErrorLink; else return Unknown; } @@ -483,7 +538,23 @@ url.prepend("mailto:"); } - QDesktopServices::openUrl (QUrl (url)); + if (kind == ErrorLink) + { + int pos = ErrorLinkRegExp.indexIn (url); + if (pos > -1) + { + QString file_name = ErrorLinkRegExp.cap (1); + QString line = ErrorLinkRegExp.cap (2); + + // call the urlobject's method for opening a file; this + // method then signals to the filter + _urlObject->request_open_file (file_name, line.toInt ()); + } + } + else + { + QDesktopServices::openUrl (QUrl (url)); + } } } @@ -499,14 +570,19 @@ // email address: // [word chars, dots or dashes]@[word chars, dots or dashes].[word chars] const QRegExp UrlFilter::EmailAddressRegExp("\\b(\\w|\\.|-)+@(\\w|\\.|-)+\\.\\w+\\b"); - // matches full url or email address const QRegExp UrlFilter::CompleteUrlRegExp('('+FullUrlRegExp.pattern()+'|'+ EmailAddressRegExp.pattern()+')'); +// error link +const QRegExp UrlFilter::ErrorLinkRegExp("(\\S+) at line (\\d+) column (?:\\d+)"); -UrlFilter::UrlFilter() +UrlFilter::UrlFilter (Type t) + : RegExpFilter (t) { - setRegExp( CompleteUrlRegExp ); + if (_type == ErrorLink) + setRegExp (ErrorLinkRegExp); + else + setRegExp (CompleteUrlRegExp); } UrlFilter::HotSpot::~HotSpot() { @@ -525,17 +601,29 @@ QAction* openAction = new QAction(_urlObject); QAction* copyAction = new QAction(_urlObject);; - Q_ASSERT( kind == StandardUrl || kind == Email ); + Q_ASSERT (kind == StandardUrl || kind == Email || kind == ErrorLink); if ( kind == StandardUrl ) { - openAction->setText(("Open Link")); - copyAction->setText(("Copy Link Address")); + openAction->setText(tr ("Open Link")); + copyAction->setText(tr ("Copy Link Address")); } else if ( kind == Email ) { - openAction->setText(("Send Email To...")); - copyAction->setText(("Copy Email Address")); + openAction->setText(tr ("Send Email To...")); + copyAction->setText(tr ("Copy Email Address")); + } + else if ( kind == ErrorLink ) + { + QString url = capturedTexts().first(); + int pos = ErrorLinkRegExp.indexIn (url); + if (pos >= 0) + { + QString file_name = ErrorLinkRegExp.cap (1); + QString line = ErrorLinkRegExp.cap (2); + openAction->setText(tr ("Edit %1 at line %2") + .arg (file_name).arg (line)); + } } // object names are set here so that the hotspot performs the @@ -545,12 +633,21 @@ copyAction->setObjectName("copy-action"); QObject::connect( openAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) ); - QObject::connect( copyAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) ); + list << openAction; - list << openAction; - list << copyAction; - + if (kind != ErrorLink) + { + QObject::connect ( copyAction , SIGNAL(triggered()) , + _urlObject , SLOT(activated()) ); + list << copyAction; + } return list; } +void +UrlFilter::request_open_file (const QString& file, int line) +{ + emit request_open_file_signal (file, line); +} + //#include "moc_Filter.cpp"
--- a/libgui/qterminal/libqterminal/unix/Filter.h Mon Apr 17 20:08:24 2017 +0200 +++ b/libgui/qterminal/libqterminal/unix/Filter.h Mon Apr 17 21:28:55 2017 +0200 @@ -2,6 +2,7 @@ Copyright (C) 2007, 2013 by Robert Knight <robertknight@gmail.com> Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008 + Adoption to octave by Torsten <mttl@mailbox.org>, Copyright (c) 2017 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -51,8 +52,11 @@ * When processing the text they should create instances of Filter::HotSpot subclasses for sections of interest * and add them to the filter's list of hotspots using addHotSpot() */ -class Filter +class Filter : public QObject { + + Q_OBJECT + public: /** * Represents an area of text which matched the pattern a particular filter has been looking for. @@ -66,8 +70,22 @@ * Hotspots may have more than one action, in which case the list of actions can be obtained using the * actions() method. These actions may then be displayed in a popup menu or toolbar for example. */ - class HotSpot + + enum Type { + // the type of the hotspot is not specified + NotSpecified, + // this hotspot represents a clickable link + Link, + // this hotspot represents a marker + Marker, + Error, + ErrorLink + }; + + class HotSpot : public QObject + { + public: /** * Constructs a new hotspot which covers the area from (@p startLine,@p startColumn) to (@p endLine,@p endColumn) @@ -76,16 +94,6 @@ HotSpot(int startLine , int startColumn , int endLine , int endColumn); virtual ~HotSpot(); - enum Type - { - // the type of the hotspot is not specified - NotSpecified, - // this hotspot represents a clickable link - Link, - // this hotspot represents a marker - Marker - }; - /** Returns the line when the hotspot area starts */ int startLine() const; /** Returns the line where the hotspot area ends */ @@ -190,6 +198,9 @@ */ class RegExpFilter : public Filter { + + Q_OBJECT + public: /** * Type of hotspot created by RegExpFilter. The capturedTexts() method can be used to find the text @@ -198,19 +209,20 @@ class HotSpot : public Filter::HotSpot { public: - HotSpot(int startLine, int startColumn, int endLine , int endColumn); + HotSpot(int startLine, int startColumn, + int endLine , int endColumn, Filter::Type); virtual void activate(QObject* object = 0); /** Sets the captured texts associated with this hotspot */ void setCapturedTexts(const QStringList& texts); /** Returns the texts found by the filter when matching the filter's regular expression */ QStringList capturedTexts() const; - private: + private: QStringList _capturedTexts; }; /** Constructs a new regular expression filter */ - RegExpFilter(); + RegExpFilter (Type); /** * Sets the regular expression which the filter searches for in blocks of text. @@ -230,15 +242,19 @@ */ virtual void process(); +signals: + + void request_open_file_signal (const QString&, int); + protected: /** * Called when a match for the regular expression is encountered. Subclasses should reimplement this * to return custom hotspot types */ virtual RegExpFilter::HotSpot* newHotSpot(int startLine,int startColumn, - int endLine,int endColumn); + int endLine,int endColumn, Type); + Type _type; -private: QRegExp _searchText; }; @@ -247,6 +263,9 @@ /** A filter which matches URLs in blocks of text */ class UrlFilter : public RegExpFilter { + + Q_OBJECT + public: /** * Hotspot type created by UrlFilter instances. The activate() method opens a web browser @@ -255,7 +274,7 @@ class HotSpot : public RegExpFilter::HotSpot { public: - HotSpot(int startLine,int startColumn,int endLine,int endColumn); + HotSpot(int startLine,int startColumn,int endLine,int endColumn,Type t); virtual ~HotSpot(); virtual QList<QAction*> actions(); @@ -267,11 +286,15 @@ virtual void activate(QObject* object = 0); virtual QString tooltip() const; + + FilterObject* get_urlObject () { return _urlObject; } + private: enum UrlType { StandardUrl, Email, + ErrorLink, Unknown }; UrlType urlType() const; @@ -279,15 +302,21 @@ FilterObject* _urlObject; }; - UrlFilter(); + UrlFilter (Type t = Link); + + virtual void process(); + +public slots: + void request_open_file (const QString&, int); protected: - virtual RegExpFilter::HotSpot* newHotSpot(int,int,int,int); + virtual HotSpot* newHotSpot(int,int,int,int,Type); private: static const QRegExp FullUrlRegExp; static const QRegExp EmailAddressRegExp; + static const QRegExp ErrorLinkRegExp; // combined OR of FullUrlRegExp and EmailAddressRegExp static const QRegExp CompleteUrlRegExp; @@ -298,6 +327,10 @@ Q_OBJECT public: FilterObject(Filter::HotSpot* filter) : _filter(filter) {} + void request_open_file (const QString& file, int line) + { emit request_open_file_signal (file, line); } +signals: + void request_open_file_signal (const QString&, int); private slots: void activated(); private:
--- a/libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.cpp Mon Apr 17 20:08:24 2017 +0200 +++ b/libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.cpp Mon Apr 17 21:28:55 2017 +0200 @@ -24,8 +24,10 @@ #include <termios.h> -QUnixTerminalImpl::QUnixTerminalImpl(QWidget *parent) - : QTerminal(parent) { +QUnixTerminalImpl::QUnixTerminalImpl(QWidget *p) + : QTerminal(p), + _parent (p) +{ setMinimumSize(300, 200); initialize(); } @@ -46,6 +48,16 @@ UrlFilter *url_filter = new UrlFilter(); m_terminalView->filterChain ()->addFilter (url_filter); + RegExpFilter *error_filter = new RegExpFilter (Filter::Type::Error); + error_filter->setRegExp (QRegExp ("error:")); + m_terminalView->filterChain ()->addFilter (error_filter); + + UrlFilter *file_filter = new UrlFilter (Filter::Type::ErrorLink); + m_terminalView->filterChain ()->addFilter (file_filter); + + connect (file_filter, SIGNAL (request_open_file_signal (const QString&, int)), + _parent, SLOT (edit_mfile (const QString&, int))); + connect(m_terminalView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(handleCustomContextMenuRequested(QPoint)));
--- a/libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.h Mon Apr 17 20:08:24 2017 +0200 +++ b/libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.h Mon Apr 17 21:28:55 2017 +0200 @@ -69,6 +69,7 @@ TerminalModel *m_terminalModel; KPty *m_kpty; bool _extra_interrupt; + QWidget *_parent; }; #endif // Q_UNIXTERMINALIMPL
--- a/libgui/qterminal/libqterminal/unix/TerminalView.cpp Mon Apr 17 20:08:24 2017 +0200 +++ b/libgui/qterminal/libqterminal/unix/TerminalView.cpp Mon Apr 17 21:28:55 2017 +0200 @@ -1194,7 +1194,8 @@ endColumn*_fontWidth - 1, (line+1)*_fontHeight - 1 ); // Underline link hotspots - if ( spot->type() == Filter::HotSpot::Link ) + if ( spot->type() == Filter::Link || + spot->type() == Filter::ErrorLink) { QFontMetrics metrics(font()); @@ -1210,10 +1211,16 @@ } // Marker hotspots simply have a transparent rectanglular shape // drawn on top of them - else if ( spot->type() == Filter::HotSpot::Marker ) + else if ( spot->type() == Filter::Error ) { //TODO - Do not use a hardcoded colour for this - painter.fillRect(r,QBrush(QColor(255,0,0,120))); + painter.fillRect(r,QBrush(QColor(255,0,0,96))); + } + + if ( spot->type() == Filter::ErrorLink ) + { + //TODO - Do not use a hardcoded colour for this + painter.fillRect(r,QBrush(QColor(255,0,0,96))); } } } @@ -1564,7 +1571,8 @@ { Filter::HotSpot* spot = _filterChain->hotSpotAt(charLine,charColumn); - if ( spot && spot->type() == Filter::HotSpot::Link) + if ( spot && + (spot->type() == Filter::Link || spot->type() == Filter::ErrorLink)) { QList<QAction*> actions = spot->actions (); if (actions.length ()) @@ -1656,7 +1664,8 @@ // handle filters // change link hot-spot appearance on mouse-over Filter::HotSpot* spot = _filterChain->hotSpotAt(charLine,charColumn); - if ( spot && spot->type() == Filter::HotSpot::Link) + if ( spot && + (spot->type() == Filter::Link || spot->type() == Filter::ErrorLink)) { // change mouse cursor when mouse is over links if (! _mouseOverHotspotArea.isValid())