Skip to content

Commit

Permalink
Followups and fixes to identify results linking
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jul 13, 2016
1 parent 0075a4b commit 05ced67
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 36 deletions.
9 changes: 9 additions & 0 deletions python/core/qgsstringutils.sip
Expand Up @@ -46,4 +46,13 @@ class QgsStringUtils
* @returns 4 letter Soundex code
*/
static QString soundex( const QString &string );

/** Returns a string with any URL (eg http(s)/ftp) and mailto: text converted to valid HTML <a ...>
* links.
* @param string string to insert links into
* @param foundLinks if specified, will be set to true if any links were inserted into the string
* @returns string with inserted links
* @note added in QGIS 3.0
*/
static QString insertLinks( const QString& string, bool* foundLinks = nullptr );
};
68 changes: 32 additions & 36 deletions src/app/qgsidentifyresultsdialog.cpp
Expand Up @@ -37,6 +37,7 @@
#include "qgsvectordataprovider.h"
#include "qgswebview.h"
#include "qgswebframe.h"
#include "qgsstringutils.h"

#include <QCloseEvent>
#include <QLabel>
Expand All @@ -62,28 +63,6 @@
#include <qwt_legend.h>
#include "qgsvectorcolorrampv2.h" // for random colors

static QString& insertLinkAnchors( QString& value )
{
// http://alanstorm.com/url_regex_explained
static QRegExp urlRegEx( "(\\b(([\\w-]+://?|www[.])[^\\s()<>]+(?:\\([\\w\\d]+\\)|([^!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_`{|}~\\s]|/))))" );
static QRegExp protoRegEx( "^(?:f|ht)tps?://" );

int offset = 0;
while ( urlRegEx.indexIn( value, offset ) != -1 )
{
QString url = urlRegEx.cap( 1 );
QString protoUrl = url;
if ( protoRegEx.indexIn( protoUrl ) == -1 )
{
protoUrl.prepend( "http://" );
}
QString anchor = QString( "<a href=\"%1\">%2</a>" ).arg( Qt::escape( protoUrl ) ).arg( Qt::escape( url ) );
value.replace( urlRegEx.pos( 1 ), url.length(), anchor );
offset = urlRegEx.pos( 1 ) + anchor.length();
}
return value;
}

QgsIdentifyResultsWebView::QgsIdentifyResultsWebView( QWidget *parent ) : QgsWebView( parent )
{
setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Minimum );
Expand Down Expand Up @@ -493,8 +472,10 @@ void QgsIdentifyResultsDialog::addFeature( QgsVectorLayer *vlayer, const QgsFeat
if ( i >= fields.count() )
continue;

if ( vlayer->editorWidgetV2( i ) == "Hidden" )
if ( vlayer->editFormConfig()->widgetType( i ) == "Hidden" )
{
continue;
}

QString defVal;
if ( fields.fieldOrigin( i ) == QgsFields::OriginProvider && vlayer->dataProvider() )
Expand All @@ -510,18 +491,21 @@ void QgsIdentifyResultsDialog::addFeature( QgsVectorLayer *vlayer, const QgsFeat

attrItem->setData( 1, Qt::UserRole, value );

if ( vlayer->editFormConfig()->widgetType( i ) == "Hidden" )
value = representValue( vlayer, fields.at( i ).name(), attrs.at( i ) );
bool foundLinks = false;
QString links = QgsStringUtils::insertLinks( value, &foundLinks );
if ( foundLinks )
{
delete attrItem;
continue;
QLabel* valueLabel = new QLabel( links );
valueLabel->setOpenExternalLinks( true );
attrItem->treeWidget()->setItemWidget( attrItem, 1, valueLabel );
attrItem->setData( 1, Qt::DisplayRole, QString() );
}
else
{
attrItem->setData( 1, Qt::DisplayRole, value );
attrItem->treeWidget()->setItemWidget( attrItem, 1, nullptr );
}

value = representValue( vlayer, fields[i].name(), attrs[i] );
QLabel* valueLabel = new QLabel( insertLinkAnchors( value ) );
valueLabel->setOpenExternalLinks( true );
attrItem->treeWidget()->setItemWidget( attrItem, 1, valueLabel );

attrItem->setData( 1, Qt::DisplayRole, QString() );

if ( fields[i].name() == vlayer->displayField() )
{
Expand Down Expand Up @@ -1507,9 +1491,21 @@ void QgsIdentifyResultsDialog::attributeValueChanged( QgsFeatureId fid, int idx,
if ( item->data( 0, Qt::UserRole + 1 ).toInt() == idx )
{
value = representValue( vlayer, fld.name(), val );
QLabel* valueLabel = new QLabel( insertLinkAnchors( value ) );
valueLabel->setOpenExternalLinks( true );
item->treeWidget()->setItemWidget( item, 1, valueLabel );

bool foundLinks = false;
QString links = QgsStringUtils::insertLinks( value, &foundLinks );
if ( foundLinks )
{
QLabel* valueLabel = new QLabel( links );
valueLabel->setOpenExternalLinks( true );
item->treeWidget()->setItemWidget( item, 1, valueLabel );
item->setData( 1, Qt::DisplayRole, QString() );
}
else
{
item->treeWidget()->setItemWidget( item, 1, nullptr );
item->setData( 1, Qt::DisplayRole, value );
}
return;
}
}
Expand Down
43 changes: 43 additions & 0 deletions src/core/qgsstringutils.cpp
Expand Up @@ -15,6 +15,8 @@

#include "qgsstringutils.h"
#include <QVector>
#include <QRegExp>
#include <QTextDocument> // for Qt::escape

int QgsStringUtils::levenshteinDistance( const QString& string1, const QString& string2, bool caseSensitive )
{
Expand Down Expand Up @@ -294,3 +296,44 @@ QString QgsStringUtils::soundex( const QString& string )

return tmp;
}

QString QgsStringUtils::insertLinks( const QString& string, bool *foundLinks )
{
QString converted = string;

// http://alanstorm.com/url_regex_explained
// note - there's more robust implementations available, but we need one which works within the limitation of QRegExp
static QRegExp urlRegEx( "(\\b(([\\w-]+://?|www[.])[^\\s()<>]+(?:\\([\\w\\d]+\\)|([^!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_`{|}~\\s]|/))))" );
static QRegExp protoRegEx( "^(?:f|ht)tps?://" );
static QRegExp emailRegEx( "([\\w._%+-]+@[\\w.-]+\\.[A-Za-z]+)" );

int offset = 0;
bool found = false;
while ( urlRegEx.indexIn( converted, offset ) != -1 )
{
found = true;
QString url = urlRegEx.cap( 1 );
QString protoUrl = url;
if ( protoRegEx.indexIn( protoUrl ) == -1 )
{
protoUrl.prepend( "http://" );
}
QString anchor = QString( "<a href=\"%1\">%2</a>" ).arg( Qt::escape( protoUrl ) ).arg( Qt::escape( url ) );
converted.replace( urlRegEx.pos( 1 ), url.length(), anchor );
offset = urlRegEx.pos( 1 ) + anchor.length();
}
offset = 0;
while ( emailRegEx.indexIn( converted, offset ) != -1 )
{
found = true;
QString email = emailRegEx.cap( 1 );
QString anchor = QString( "<a href=\"mailto:%1\">%1</a>" ).arg( Qt::escape( email ) ).arg( Qt::escape( email ) );
converted.replace( emailRegEx.pos( 1 ), email.length(), anchor );
offset = emailRegEx.pos( 1 ) + anchor.length();
}

if ( foundLinks )
*foundLinks = found;

return converted;
}
9 changes: 9 additions & 0 deletions src/core/qgsstringutils.h
Expand Up @@ -64,6 +64,15 @@ class CORE_EXPORT QgsStringUtils
* @returns 4 letter Soundex code
*/
static QString soundex( const QString &string );

/** Returns a string with any URL (eg http(s)/ftp) and mailto: text converted to valid HTML <a ...>
* links.
* @param string string to insert links into
* @param foundLinks if specified, will be set to true if any links were inserted into the string
* @returns string with inserted links
* @note added in QGIS 3.0
*/
static QString insertLinks( const QString& string, bool* foundLinks = nullptr );
};

#endif //QGSSTRINGUTILS_H
36 changes: 36 additions & 0 deletions tests/src/core/testqgsstringutils.cpp
Expand Up @@ -33,6 +33,7 @@ class TestQgsStringUtils : public QObject
void longestCommonSubstring();
void hammingDistance();
void soundex();
void insertLinks();

};

Expand Down Expand Up @@ -118,6 +119,41 @@ void TestQgsStringUtils::soundex()
QCOMPARE( QgsStringUtils::soundex( "ashcroft" ), QString( "A261" ) );
}

void TestQgsStringUtils::insertLinks()
{
QCOMPARE( QgsStringUtils::insertLinks( QString() ), QString() );
QCOMPARE( QgsStringUtils::insertLinks( QString( "not a link!" ) ), QString( "not a link!" ) );
bool found = true;
QCOMPARE( QgsStringUtils::insertLinks( QString( "not a link!" ), &found ), QString( "not a link!" ) );
QVERIFY( !found );
QCOMPARE( QgsStringUtils::insertLinks( QString( "this www.north-road.com is a link" ), &found ), QString( "this <a href=\"http://www.north-road.com\">www.north-road.com</a> is a link" ) );
QVERIFY( found );
QCOMPARE( QgsStringUtils::insertLinks( QString( "this www.north-road.com.au is a link" ), &found ), QString( "this <a href=\"http://www.north-road.com.au\">www.north-road.com.au</a> is a link" ) );
QVERIFY( found );
QCOMPARE( QgsStringUtils::insertLinks( QString( "this www.north-road.sucks is not a good link" ), &found ), QString( "this <a href=\"http://www.north-road.sucks\">www.north-road.sucks</a> is not a good link" ) );
QVERIFY( found );
QCOMPARE( QgsStringUtils::insertLinks( QString( "this http://www.north-road.com is a link" ), &found ), QString( "this <a href=\"http://www.north-road.com\">http://www.north-road.com</a> is a link" ) );
QVERIFY( found );
QCOMPARE( QgsStringUtils::insertLinks( QString( "this http://north-road.com is a link" ), &found ), QString( "this <a href=\"http://north-road.com\">http://north-road.com</a> is a link" ) );
QVERIFY( found );
QCOMPARE( QgsStringUtils::insertLinks( QString( "this http://north-road.com is a link, so is http://qgis.org, ok?" ), &found ), QString( "this <a href=\"http://north-road.com\">http://north-road.com</a> is a link, so is <a href=\"http://qgis.org\">http://qgis.org</a>, ok?" ) );
QVERIFY( found );
QCOMPARE( QgsStringUtils::insertLinks( QString( "this north-road.com might not be a link" ), &found ), QString( "this north-road.com might not be a link" ) );
QVERIFY( !found );
QCOMPARE( QgsStringUtils::insertLinks( QString( "please ftp to ftp://droopbox.ru and submit stuff" ), &found ), QString( "please ftp to <a href=\"ftp://droopbox.ru\">ftp://droopbox.ru</a> and submit stuff" ) );
QVERIFY( found );
QCOMPARE( QgsStringUtils::insertLinks( QString( "please visit https://fsociety.org" ), &found ), QString( "please visit <a href=\"https://fsociety.org\">https://fsociety.org</a>" ) );
QVERIFY( found );
QCOMPARE( QgsStringUtils::insertLinks( QString( "send your credit card number to qgis@qgis.org today!" ), &found ), QString( "send your credit card number to <a href=\"mailto:qgis@qgis.org\">qgis@qgis.org</a> today!" ) );
QVERIFY( found );
QCOMPARE( QgsStringUtils::insertLinks( QString( "send your credit card number to qgis@qgis.org.nz today!" ), &found ), QString( "send your credit card number to <a href=\"mailto:qgis@qgis.org.nz\">qgis@qgis.org.nz</a> today!" ) );
QVERIFY( found );
QCOMPARE( QgsStringUtils::insertLinks( QString( "visit http://qgis.org or email qgis@qgis.org" ), &found ), QString( "visit <a href=\"http://qgis.org\">http://qgis.org</a> or email <a href=\"mailto:qgis@qgis.org\">qgis@qgis.org</a>" ) );
QVERIFY( found );
QCOMPARE( QgsStringUtils::insertLinks( QString( "is a@a an email?" ), &found ), QString( "is a@a an email?" ) );
QVERIFY( !found );
}


QTEST_MAIN( TestQgsStringUtils )
#include "testqgsstringutils.moc"

0 comments on commit 05ced67

Please sign in to comment.