Support CTRL+Click for opening links in attribute table

This commit is contained in:
Sandro Mani 2021-08-01 17:19:02 +02:00
parent 1bd8f5cb0f
commit 2a2899a87c
6 changed files with 81 additions and 3 deletions

View File

@ -279,6 +279,17 @@ links.
:return: string with inserted links
.. versionadded:: 3.0
%End
static bool isUrl( const QString &string );
%Docstring
Returns whether the string is a URL (http,https,ftp,file)
:param string: the string to check
:return: whether the string is an URL
.. versionadded:: 3.22
%End
static QString wordWrap( const QString &string, int length, bool useMaxLineLength = true, const QString &customDelimiter = QString() );

View File

@ -563,6 +563,12 @@ QString QgsStringUtils::insertLinks( const QString &string, bool *foundLinks )
return converted;
}
bool QgsStringUtils::isUrl( const QString &string )
{
const thread_local QRegularExpression rxUrl( "^(http|https|ftp|file)://\\S+$" );
return rxUrl.match( string ).hasMatch();
}
QString QgsStringUtils::htmlToMarkdown( const QString &html )
{
// Any changes in this function must be copied to qgscrashreport.cpp too

View File

@ -277,6 +277,14 @@ class CORE_EXPORT QgsStringUtils
*/
static QString insertLinks( const QString &string, bool *foundLinks = nullptr );
/**
* Returns whether the string is a URL (http,https,ftp,file)
* \param string the string to check
* \returns whether the string is an URL
* \since QGIS 3.22
*/
static bool isUrl( const QString &string );
/**
* Automatically wraps a \a string by inserting new line characters at appropriate locations in the string.
*

View File

@ -40,6 +40,7 @@
#include "qgsfieldmodel.h"
#include "qgstexteditwidgetfactory.h"
#include "qgsexpressioncontextutils.h"
#include "qgsstringutils.h"
#include "qgsvectorlayerutils.h"
#include "qgsvectorlayercache.h"
@ -702,13 +703,24 @@ QVariant QgsAttributeTableModel::data( const QModelIndex &index, int role ) cons
switch ( role )
{
case Qt::DisplayRole:
case Qt::ToolTipRole:
return mFieldFormatters.at( index.column() )->representValue( mLayer,
fieldId,
mWidgetConfigs.at( index.column() ),
mAttributeWidgetCaches.at( index.column() ),
val );
case Qt::ToolTipRole:
{
QString tooltip = mFieldFormatters.at( index.column() )->representValue( mLayer,
fieldId,
mWidgetConfigs.at( index.column() ),
mAttributeWidgetCaches.at( index.column() ),
val );
if ( val.type() == QVariant::String && QgsStringUtils::isUrl( val.toString() ) )
{
tooltip = tr( "%1 (Ctrl+click to open)" ).arg( tooltip );
}
return tooltip;
}
case Qt::EditRole:
return val;
@ -746,7 +758,7 @@ QVariant QgsAttributeTableModel::data( const QModelIndex &index, int role ) cons
#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
if ( role == Qt::TextColorRole && style.validTextColor() )
#else
if ( role == Qt::ForegroundRole && style.validTextColor() )
if ( role == Qt::ForegroundRole )
#endif
return style.textColor();
if ( role == Qt::DecorationRole )
@ -754,6 +766,19 @@ QVariant QgsAttributeTableModel::data( const QModelIndex &index, int role ) cons
if ( role == Qt::FontRole )
return style.font();
}
else if ( val.type() == QVariant::String && QgsStringUtils::isUrl( val.toString() ) )
{
if ( role == Qt::ForegroundRole )
{
return QColor( Qt::blue );
}
else if ( role == Qt::FontRole )
{
QFont font;
font.setUnderline( true );
return font;
}
}
return QVariant();
}

View File

@ -13,6 +13,7 @@
* *
***************************************************************************/
#include <QDesktopServices>
#include <QKeyEvent>
#include <QHeaderView>
#include <QMenu>
@ -34,6 +35,7 @@
#include "qgsfeatureselectionmodel.h"
#include "qgsmaplayeractionregistry.h"
#include "qgsfeatureiterator.h"
#include "qgsstringutils.h"
#include "qgsgui.h"
QgsAttributeTableView::QgsAttributeTableView( QWidget *parent )
@ -304,6 +306,19 @@ void QgsAttributeTableView::mouseReleaseEvent( QMouseEvent *event )
setSelectionMode( QAbstractItemView::NoSelection );
QTableView::mouseReleaseEvent( event );
setSelectionMode( QAbstractItemView::ExtendedSelection );
if ( event->modifiers() == Qt::ControlModifier )
{
QModelIndex index = indexAt( event->pos() );
QVariant data = model()->data( index, Qt::DisplayRole );
if ( data.type() == QVariant::String )
{
QString textVal = data.toString();
if ( QgsStringUtils::isUrl( textVal ) )
{
QDesktopServices::openUrl( QUrl( textVal ) );
}
}
}
}
void QgsAttributeTableView::mouseMoveEvent( QMouseEvent *event )

View File

@ -42,6 +42,7 @@ class TestQgsStringUtils : public QObject
void htmlToMarkdown();
void wordWrap_data();
void wordWrap();
void testIsUrl();
};
@ -258,6 +259,18 @@ void TestQgsStringUtils::wordWrap()
QCOMPARE( QgsStringUtils::wordWrap( input, length, isMax, delimiter ), expected );
}
void TestQgsStringUtils::testIsUrl()
{
QVERIFY( QgsStringUtils::isUrl( QStringLiteral( "http://example.com" ) ) );
QVERIFY( QgsStringUtils::isUrl( QStringLiteral( "https://example.com" ) ) );
QVERIFY( QgsStringUtils::isUrl( QStringLiteral( "ftp://example.com" ) ) );
QVERIFY( QgsStringUtils::isUrl( QStringLiteral( "file:///path/to/file" ) ) );
QVERIFY( QgsStringUtils::isUrl( QStringLiteral( "file://C:\\path\\to\\file" ) ) );
QVERIFY( !QgsStringUtils::isUrl( QStringLiteral( "" ) ) );
QVERIFY( !QgsStringUtils::isUrl( QStringLiteral( "some:random/string" ) ) );
QVERIFY( !QgsStringUtils::isUrl( QStringLiteral( "bla" ) ) );
}
QGSTEST_MAIN( TestQgsStringUtils )
#include "testqgsstringutils.moc"