mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Merge pull request #3303 from nyalldawson/identify_url
Make links in identify results clickable
This commit is contained in:
commit
258c8999ef
@ -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 );
|
||||
};
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgswebview.h"
|
||||
#include "qgswebframe.h"
|
||||
#include "qgsstringutils.h"
|
||||
|
||||
#include <QCloseEvent>
|
||||
#include <QLabel>
|
||||
@ -53,6 +54,7 @@
|
||||
#include <QDesktopServices>
|
||||
#include <QMessageBox>
|
||||
#include <QComboBox>
|
||||
#include <QTextDocument>
|
||||
|
||||
//graph
|
||||
#include <qwt_plot.h>
|
||||
@ -61,7 +63,6 @@
|
||||
#include <qwt_legend.h>
|
||||
#include "qgsvectorcolorrampv2.h" // for random colors
|
||||
|
||||
|
||||
QgsIdentifyResultsWebView::QgsIdentifyResultsWebView( QWidget *parent ) : QgsWebView( parent )
|
||||
{
|
||||
setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Minimum );
|
||||
@ -471,12 +472,18 @@ void QgsIdentifyResultsDialog::addFeature( QgsVectorLayer *vlayer, const QgsFeat
|
||||
if ( i >= fields.count() )
|
||||
continue;
|
||||
|
||||
if ( vlayer->editFormConfig()->widgetType( i ) == "Hidden" )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
QString defVal;
|
||||
if ( fields.fieldOrigin( i ) == QgsFields::OriginProvider && vlayer->dataProvider() )
|
||||
defVal = vlayer->dataProvider()->defaultValue( fields.fieldOriginIndex( i ) ).toString();
|
||||
|
||||
QString value = defVal == attrs.at( i ) ? defVal : fields.at( i ).displayString( attrs.at( i ) );
|
||||
QTreeWidgetItem *attrItem = new QTreeWidgetItem( QStringList() << QString::number( i ) << value );
|
||||
featItem->addChild( attrItem );
|
||||
|
||||
attrItem->setData( 0, Qt::DisplayRole, vlayer->attributeDisplayName( i ) );
|
||||
attrItem->setData( 0, Qt::UserRole, fields[i].name() );
|
||||
@ -484,15 +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.at( i ) );
|
||||
|
||||
attrItem->setData( 1, Qt::DisplayRole, value );
|
||||
|
||||
if ( fields[i].name() == vlayer->displayField() )
|
||||
{
|
||||
@ -500,8 +513,6 @@ void QgsIdentifyResultsDialog::addFeature( QgsVectorLayer *vlayer, const QgsFeat
|
||||
featItem->setText( 1, attrItem->text( 1 ) );
|
||||
featureLabeled = true;
|
||||
}
|
||||
|
||||
featItem->addChild( attrItem );
|
||||
}
|
||||
|
||||
if ( !featureLabeled )
|
||||
@ -1480,7 +1491,21 @@ void QgsIdentifyResultsDialog::attributeValueChanged( QgsFeatureId fid, int idx,
|
||||
if ( item->data( 0, Qt::UserRole + 1 ).toInt() == idx )
|
||||
{
|
||||
value = representValue( vlayer, fld.name(), val );
|
||||
item->setData( 1, Qt::DisplayRole, value );
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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 )
|
||||
{
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -33,6 +33,7 @@ class TestQgsStringUtils : public QObject
|
||||
void longestCommonSubstring();
|
||||
void hammingDistance();
|
||||
void soundex();
|
||||
void insertLinks();
|
||||
|
||||
};
|
||||
|
||||
@ -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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user