mirror of
https://github.com/qgis/QGIS.git
synced 2025-03-08 00:02:35 -05:00
[clipboard] Fix copying of string attributes containing new lines and tabs characters
This commit is contained in:
parent
0c906bf9d9
commit
692d05ba23
@ -75,31 +75,38 @@ void QgsClipboard::replaceWithCopyOf( QgsFeatureStore &featureStore )
|
||||
emit changed();
|
||||
}
|
||||
|
||||
QString QgsClipboard::generateClipboardText() const
|
||||
void QgsClipboard::generateClipboardText( QString &textContent, QString &htmlContent ) const
|
||||
{
|
||||
CopyFormat format = QgsSettings().enumValue( QStringLiteral( "qgis/copyFeatureFormat" ), AttributesWithWKT );
|
||||
|
||||
textContent.clear();
|
||||
htmlContent.clear();
|
||||
|
||||
switch ( format )
|
||||
{
|
||||
case AttributesOnly:
|
||||
case AttributesWithWKT:
|
||||
{
|
||||
QStringList textLines;
|
||||
QStringList textFields;
|
||||
QStringList textLines, htmlLines;
|
||||
QStringList textFields, htmlFields;
|
||||
|
||||
// first do the field names
|
||||
if ( format == AttributesWithWKT )
|
||||
{
|
||||
textFields += QStringLiteral( "wkt_geom" );
|
||||
htmlFields += QStringLiteral( "<td>wkt_geom</td>" );
|
||||
}
|
||||
|
||||
const auto constMFeatureFields = mFeatureFields;
|
||||
for ( const QgsField &field : constMFeatureFields )
|
||||
{
|
||||
textFields += field.name();
|
||||
htmlFields += QStringLiteral( "<td>%1</td>" ).arg( field.name() );
|
||||
}
|
||||
textLines += textFields.join( QStringLiteral( "\t" ) );
|
||||
htmlLines += htmlFields.join( QString() );
|
||||
textFields.clear();
|
||||
htmlFields.clear();
|
||||
|
||||
// then the field contents
|
||||
for ( QgsFeatureList::const_iterator it = mFeatureClipboard.constBegin(); it != mFeatureClipboard.constEnd(); ++it )
|
||||
@ -110,38 +117,50 @@ QString QgsClipboard::generateClipboardText() const
|
||||
if ( format == AttributesWithWKT )
|
||||
{
|
||||
if ( it->hasGeometry() )
|
||||
textFields += it->geometry().asWkt();
|
||||
{
|
||||
QString wkt = it->geometry().asWkt();
|
||||
textFields += wkt;
|
||||
htmlFields += QStringLiteral( "<td>%1</td>" ).arg( wkt );
|
||||
}
|
||||
else
|
||||
{
|
||||
textFields += QgsApplication::nullRepresentation();
|
||||
htmlFields += QStringLiteral( "<td>%1</td>" ).arg( QgsApplication::nullRepresentation() );
|
||||
}
|
||||
}
|
||||
|
||||
for ( int idx = 0; idx < attributes.count(); ++idx )
|
||||
{
|
||||
// QgsDebugMsg(QString("inspecting field '%1'.").arg(it2->toString()));
|
||||
if ( attributes.at( idx ).toString().contains( QStringLiteral( "\n" ), Qt::CaseInsensitive ) )
|
||||
textFields += QStringLiteral( "\"" ) + attributes.at( idx ).toString() + QStringLiteral( "\"" );
|
||||
QString value = attributes.at( idx ).toString();
|
||||
if ( value.contains( '\n' ) || value.contains( '\t' ) )
|
||||
textFields += '"' + value.replace( '"', QStringLiteral( "\"\"" ) ) + '\"';
|
||||
else
|
||||
{
|
||||
textFields += attributes.at( idx ).toString();
|
||||
textFields += value;
|
||||
}
|
||||
value = attributes.at( idx ).toString();
|
||||
value.replace( '\n', QStringLiteral( "<br>" ) ).replace( '\t', QStringLiteral( " " ) );
|
||||
htmlFields += QStringLiteral( "<td>%1</td>" ).arg( value );
|
||||
}
|
||||
|
||||
textLines += textFields.join( QStringLiteral( "\t" ) );
|
||||
htmlLines += htmlFields.join( QString() );
|
||||
textFields.clear();
|
||||
htmlFields.clear();
|
||||
}
|
||||
|
||||
return textLines.join( QStringLiteral( "\n" ) );
|
||||
textContent = textLines.join( '\n' );
|
||||
htmlContent = QStringLiteral( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"><html><head><meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/></head><body><table border=\"1\"><tr>" ) + htmlLines.join( QStringLiteral( "</tr><tr>" ) ) + QStringLiteral( "</tr></table></body></html>" );
|
||||
break;
|
||||
}
|
||||
case GeoJSON:
|
||||
{
|
||||
QgsJsonExporter exporter;
|
||||
exporter.setSourceCrs( mCRS );
|
||||
return exporter.exportFeatures( mFeatureClipboard );
|
||||
|
||||
textContent = exporter.exportFeatures( mFeatureClipboard );
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
void QgsClipboard::setSystemClipboard()
|
||||
@ -155,31 +174,14 @@ void QgsClipboard::setSystemClipboard()
|
||||
QClipboard *cb = QApplication::clipboard();
|
||||
|
||||
// Copy text into the clipboard
|
||||
QString textCopy = generateClipboardText();
|
||||
QString textCopy, htmlCopy;
|
||||
generateClipboardText( textCopy, htmlCopy );
|
||||
QMimeData *m = new QMimeData();
|
||||
m->setText( textCopy );
|
||||
|
||||
if ( mFeatureClipboard.count() < 1000 )
|
||||
if ( mFeatureClipboard.count() < 1000 && !htmlCopy.isEmpty() )
|
||||
{
|
||||
CopyFormat format = QgsSettings().enumValue( QStringLiteral( "qgis/copyFeatureFormat" ), AttributesWithWKT );
|
||||
|
||||
QString htmlCopy;
|
||||
switch ( format )
|
||||
{
|
||||
case AttributesOnly:
|
||||
case AttributesWithWKT:
|
||||
htmlCopy = textCopy;
|
||||
htmlCopy.replace( '\n', QStringLiteral( "</td></tr><tr><td>" ) );
|
||||
htmlCopy.replace( '\t', QStringLiteral( "</td><td>" ) );
|
||||
htmlCopy = QStringLiteral( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"><html><head><meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/></head><body><table border=\"1\"><tr><td>" ) + htmlCopy + QStringLiteral( "</td></tr></table></body></html>" );
|
||||
break;
|
||||
case GeoJSON:
|
||||
break;
|
||||
}
|
||||
if ( !htmlCopy.isEmpty() )
|
||||
{
|
||||
m->setHtml( htmlCopy );
|
||||
}
|
||||
m->setHtml( htmlCopy );
|
||||
}
|
||||
|
||||
// With qgis running under Linux, but with a Windows based X
|
||||
|
@ -154,7 +154,7 @@ class APP_EXPORT QgsClipboard : public QObject
|
||||
* Creates a text representation of the clipboard features.
|
||||
* \returns clipboard text, respecting user export format
|
||||
*/
|
||||
QString generateClipboardText() const;
|
||||
void generateClipboardText( QString &textContent, QString &htmlContent ) const;
|
||||
|
||||
/**
|
||||
* Attempts to convert a string to a list of features, by parsing the string as WKT and GeoJSON
|
||||
|
@ -141,12 +141,13 @@ void TestQgisAppClipboard::copyToText()
|
||||
// attributes only
|
||||
QgsSettings settings;
|
||||
settings.setEnumValue( QStringLiteral( "/qgis/copyFeatureFormat" ), QgsClipboard::AttributesOnly );
|
||||
QString result = mQgisApp->clipboard()->generateClipboardText();
|
||||
QString result, resultHtml;
|
||||
mQgisApp->clipboard()->generateClipboardText( result, resultHtml );
|
||||
QCOMPARE( result, QString( "int_field\tstring_field\n9\tval\n19\tval2" ) );
|
||||
|
||||
// attributes with WKT
|
||||
settings.setEnumValue( QStringLiteral( "/qgis/copyFeatureFormat" ), QgsClipboard::AttributesWithWKT );
|
||||
result = mQgisApp->clipboard()->generateClipboardText();
|
||||
mQgisApp->clipboard()->generateClipboardText( result, resultHtml );
|
||||
QCOMPARE( result, QString( "wkt_geom\tint_field\tstring_field\nPoint (5 6)\t9\tval\nPoint (7 8)\t19\tval2" ) );
|
||||
|
||||
// HTML test
|
||||
@ -156,7 +157,7 @@ void TestQgisAppClipboard::copyToText()
|
||||
|
||||
// GeoJSON
|
||||
settings.setEnumValue( QStringLiteral( "/qgis/copyFeatureFormat" ), QgsClipboard::GeoJSON );
|
||||
result = mQgisApp->clipboard()->generateClipboardText();
|
||||
mQgisApp->clipboard()->generateClipboardText( result, resultHtml );
|
||||
QString expected = "{\"features\":[{\"geometry\":{\"coordinates\":[5.0,6.0],\"type\":\"Point\"},\"id\":5,"
|
||||
"\"properties\":{\"int_field\":9,\"string_field\":\"val\"},\"type\":\"Feature\"},"
|
||||
"{\"geometry\":{\"coordinates\":[7.0,8.0],\"type\":\"Point\"},\"id\":6,"
|
||||
@ -174,7 +175,7 @@ void TestQgisAppClipboard::copyToText()
|
||||
feats.setFields( fields );
|
||||
mQgisApp->clipboard()->replaceWithCopyOf( feats );
|
||||
|
||||
result = mQgisApp->clipboard()->generateClipboardText();
|
||||
mQgisApp->clipboard()->generateClipboardText( result, resultHtml );
|
||||
|
||||
// just test coordinates as integers - that's enough to verify that reprojection has occurred
|
||||
// and helps avoid rounding issues
|
||||
@ -211,13 +212,13 @@ void TestQgisAppClipboard::copyToText()
|
||||
|
||||
// attributes only
|
||||
settings.setEnumValue( QStringLiteral( "/qgis/copyFeatureFormat" ), QgsClipboard::AttributesOnly );
|
||||
result = mQgisApp->clipboard()->generateClipboardText();
|
||||
mQgisApp->clipboard()->generateClipboardText( result, resultHtml );
|
||||
qDebug() << result;
|
||||
QCOMPARE( result, QString( "int_field\tstring_field\n1\tSingle line text\n2\t\"Unix Multiline \nText\"\n3\t\"Windows Multiline \r\nText\"" ) );
|
||||
|
||||
// attributes with WKT
|
||||
settings.setEnumValue( QStringLiteral( "/qgis/copyFeatureFormat" ), QgsClipboard::AttributesWithWKT );
|
||||
result = mQgisApp->clipboard()->generateClipboardText();
|
||||
mQgisApp->clipboard()->generateClipboardText( result, resultHtml );
|
||||
QCOMPARE( result, QString( "wkt_geom\tint_field\tstring_field\nPoint (5 6)\t1\tSingle line text\nPoint (7 8)\t2\t\"Unix Multiline \nText\"\nPoint (9 10)\t3\t\"Windows Multiline \r\nText\"" ) );
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user