mirror of
https://github.com/qgis/QGIS.git
synced 2025-11-22 00:14:55 -05:00
parent
5ea353ba22
commit
303a6f261c
@ -206,48 +206,95 @@ QgsFeatureList QgsClipboard::stringToFeatureList( const QString &string, const Q
|
||||
return features;
|
||||
|
||||
// otherwise try to read in as WKT
|
||||
const QStringList values = string.split( '\n' );
|
||||
if ( values.isEmpty() || string.isEmpty() )
|
||||
if ( string.isEmpty() || string.split( '\n' ).count() == 0 )
|
||||
return features;
|
||||
|
||||
const QgsFields sourceFields = retrieveFields();
|
||||
// Poor man's csv parser
|
||||
bool isInsideQuotes {false};
|
||||
QgsAttributes attrs;
|
||||
QgsGeometry geom;
|
||||
QString attrVal;
|
||||
bool isFirstLine {string.startsWith( QStringLiteral( "wkt_geom" ) )};
|
||||
// it seems there is no other way to check for header
|
||||
const bool hasHeader{string.startsWith( QStringLiteral( "wkt_geom" ) )};
|
||||
QgsGeometry geometry;
|
||||
bool setFields {fields.isEmpty()};
|
||||
QgsFields fieldsFromClipboard;
|
||||
|
||||
const auto constValues = values;
|
||||
for ( const QString &row : constValues )
|
||||
auto parseFunc = [ & ]( const QChar & c )
|
||||
{
|
||||
// Assume that it's just WKT for now. because GeoJSON is managed by
|
||||
// previous QgsOgrUtils::stringToFeatureList call
|
||||
// Get the first value of a \t separated list. WKT clipboard pasted
|
||||
// feature has first element the WKT geom.
|
||||
// This split is to fix the following issue: https://github.com/qgis/QGIS/issues/24769
|
||||
// Value separators are set in generateClipboardText
|
||||
QStringList fieldValues = row.split( '\t' );
|
||||
if ( fieldValues.isEmpty() )
|
||||
continue;
|
||||
|
||||
QgsFeature feature;
|
||||
feature.setFields( sourceFields );
|
||||
feature.initAttributes( fieldValues.size() - 1 );
|
||||
|
||||
//skip header line
|
||||
if ( fieldValues.at( 0 ) == QLatin1String( "wkt_geom" ) )
|
||||
// parse geom only if it wasn't successfully set before
|
||||
if ( geometry.isNull() )
|
||||
{
|
||||
continue;
|
||||
geometry = QgsGeometry::fromWkt( attrVal );
|
||||
}
|
||||
|
||||
for ( int i = 1; i < fieldValues.size(); ++i )
|
||||
if ( isFirstLine ) // ... name
|
||||
{
|
||||
feature.setAttribute( i - 1, fieldValues.at( i ) );
|
||||
if ( attrVal != QStringLiteral( "wkt_geom" ) ) // ignore this one
|
||||
{
|
||||
fieldsFromClipboard.append( QgsField{attrVal, QVariant::String } );
|
||||
}
|
||||
}
|
||||
else // ... or value
|
||||
{
|
||||
attrs.append( attrVal );
|
||||
}
|
||||
|
||||
const QgsGeometry geometry = QgsGeometry::fromWkt( fieldValues[0] );
|
||||
if ( !geometry.isNull() )
|
||||
// end of record, create a new feature if it's not the header
|
||||
if ( c == QChar( '\n' ) )
|
||||
{
|
||||
feature.setGeometry( geometry );
|
||||
if ( isFirstLine )
|
||||
{
|
||||
isFirstLine = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsFeature feature{setFields ? fieldsFromClipboard : fields};
|
||||
feature.setGeometry( geometry );
|
||||
if ( hasHeader || !geometry.isNull() )
|
||||
{
|
||||
attrs.pop_front();
|
||||
}
|
||||
feature.setAttributes( attrs );
|
||||
features.append( feature );
|
||||
geometry = QgsGeometry();
|
||||
attrs.clear();
|
||||
}
|
||||
}
|
||||
attrVal.clear();
|
||||
};
|
||||
|
||||
features.append( feature );
|
||||
for ( auto c = string.constBegin(); c < string.constEnd(); ++c )
|
||||
{
|
||||
if ( *c == QChar( '\n' ) || *c == QChar( '\t' ) )
|
||||
{
|
||||
if ( isInsideQuotes )
|
||||
{
|
||||
attrVal.append( *c );
|
||||
}
|
||||
else
|
||||
{
|
||||
parseFunc( *c );
|
||||
}
|
||||
}
|
||||
else if ( *c == QChar( '\"' ) )
|
||||
{
|
||||
isInsideQuotes = !isInsideQuotes;
|
||||
}
|
||||
else
|
||||
{
|
||||
attrVal.append( *c );
|
||||
}
|
||||
}
|
||||
|
||||
// handle missing newline
|
||||
if ( !string.endsWith( QChar( '\n' ) ) )
|
||||
{
|
||||
parseFunc( QChar( '\n' ) );
|
||||
}
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
|
||||
@ -121,6 +121,7 @@ void TestQgisAppClipboard::copyPaste()
|
||||
|
||||
void TestQgisAppClipboard::copyToText()
|
||||
{
|
||||
|
||||
//set clipboard to some QgsFeatures
|
||||
QgsFields fields;
|
||||
fields.append( QgsField( QStringLiteral( "int_field" ), QVariant::Int ) );
|
||||
@ -221,13 +222,28 @@ void TestQgisAppClipboard::copyToText()
|
||||
settings.setEnumValue( QStringLiteral( "/qgis/copyFeatureFormat" ), QgsClipboard::AttributesWithWKT );
|
||||
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\"" ) );
|
||||
|
||||
}
|
||||
|
||||
void TestQgisAppClipboard::pasteWkt()
|
||||
{
|
||||
|
||||
// test issue GH #44989
|
||||
QgsFeatureList features = mQgisApp->clipboard()->stringToFeatureList( QStringLiteral( "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\"" ), QgsFields() );
|
||||
QCOMPARE( features.length(), 3 );
|
||||
QVERIFY( features.at( 0 ).hasGeometry() && !features.at( 0 ).geometry().isNull() );
|
||||
QVERIFY( features.at( 1 ).hasGeometry() && !features.at( 1 ).geometry().isNull() );
|
||||
QVERIFY( features.at( 2 ).hasGeometry() && !features.at( 2 ).geometry().isNull() );
|
||||
QCOMPARE( features.at( 0 ).fields().count(), 2 );
|
||||
QCOMPARE( features.at( 0 ).attributeCount(), 2 );
|
||||
QCOMPARE( features.at( 1 ).fields().count(), 2 );
|
||||
QCOMPARE( features.at( 1 ).attributeCount(), 2 );
|
||||
QCOMPARE( features.at( 2 ).fields().count(), 2 );
|
||||
QCOMPARE( features.at( 2 ).attributeCount(), 2 );
|
||||
|
||||
mQgisApp->clipboard()->setText( QStringLiteral( "POINT (125 10)\nPOINT (111 30)" ) );
|
||||
|
||||
QgsFeatureList features = mQgisApp->clipboard()->copyOf();
|
||||
features = mQgisApp->clipboard()->copyOf();
|
||||
QCOMPARE( features.length(), 2 );
|
||||
QVERIFY( features.at( 0 ).hasGeometry() && !features.at( 0 ).geometry().isNull() );
|
||||
QCOMPARE( features.at( 0 ).geometry().constGet()->wkbType(), QgsWkbTypes::Point );
|
||||
@ -248,7 +264,8 @@ void TestQgisAppClipboard::pasteWkt()
|
||||
features = mQgisApp->clipboard()->copyOf();
|
||||
QCOMPARE( features.length(), 2 );
|
||||
|
||||
QVERIFY( features.at( 0 ).hasGeometry() && !features.at( 0 ).geometry().isNull() );
|
||||
QVERIFY( features.at( 0 ).hasGeometry() );
|
||||
QVERIFY( !features.at( 0 ).geometry().isNull() );
|
||||
QCOMPARE( features.at( 0 ).geometry().constGet()->wkbType(), QgsWkbTypes::Point );
|
||||
featureGeom = features.at( 0 ).geometry();
|
||||
point = dynamic_cast< const QgsPoint * >( featureGeom.constGet() );
|
||||
@ -262,7 +279,7 @@ void TestQgisAppClipboard::pasteWkt()
|
||||
QCOMPARE( point->y(), 10.0 );
|
||||
|
||||
//clipboard should support features without geometry
|
||||
mQgisApp->clipboard()->setText( QStringLiteral( "\tMNL\t11\t282\tkm\t\t\t\n\tMNL\t11\t347.80000000000001\tkm\t\t\t" ) );
|
||||
mQgisApp->clipboard()->setText( QStringLiteral( "MNL\t11\t282\tkm\t\t\t\nMNL\t11\t347.80000000000001\tkm\t\t\t" ) );
|
||||
features = mQgisApp->clipboard()->copyOf();
|
||||
QCOMPARE( features.length(), 2 );
|
||||
QVERIFY( !features.at( 0 ).hasGeometry() );
|
||||
@ -375,6 +392,7 @@ void TestQgisAppClipboard::pasteGeoJson()
|
||||
mQgisApp->clipboard()->setText( QStringLiteral( "{\n\"type\": \"Feature\",\"geometry\": {\"type\": \"Point\",\"coordinates\": [125, 10]},\"properties\": {\"name\": \"Dinagat Islands\"}}" ) );
|
||||
|
||||
const QgsFeatureList features = mQgisApp->clipboard()->copyOf( fields );
|
||||
|
||||
QCOMPARE( features.length(), 1 );
|
||||
QVERIFY( features.at( 0 ).hasGeometry() && !features.at( 0 ).geometry().isNull() );
|
||||
QCOMPARE( features.at( 0 ).geometry().constGet()->wkbType(), QgsWkbTypes::Point );
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user