Skip to content
Permalink
Browse files
[FEATURE] Allow copying features from QGIS in GeoJSON format
The previous setting for include WKT when copying features has been
replaced with a choice of copying features as "Plain text, attributes
only", "Plain text, WKT geometry" and a new "GeoJSON" option.

When set to "GeoJSON", copying features in QGIS will place a GeoJSON
text representation of the features on the clipboard for easy
pasting into other applications/javascript code.

Sponsored by North Road
  • Loading branch information
nyalldawson committed May 9, 2016
1 parent 718c5fd commit c3d6c79
Show file tree
Hide file tree
Showing 5 changed files with 457 additions and 104 deletions.
@@ -34,6 +34,7 @@
#include "qgslogger.h"
#include "qgsvectorlayer.h"
#include "qgsogrutils.h"
#include "qgsjsonutils.h"

QgsClipboard::QgsClipboard()
: QObject()
@@ -76,56 +77,81 @@ void QgsClipboard::replaceWithCopyOf( QgsFeatureStore & featureStore )
emit changed();
}

void QgsClipboard::setSystemClipboard()
QString QgsClipboard::generateClipboardText() const
{
// Replace the system clipboard.
QSettings settings;
bool copyWKT = settings.value( "qgis/copyGeometryAsWKT", true ).toBool();

QStringList textLines;
QStringList textFields;

// first do the field names
if ( copyWKT )
CopyFormat format = AttributesWithWKT;
if ( settings.contains( "/qgis/copyFeatureFormat" ) )
format = static_cast< CopyFormat >( settings.value( "/qgis/copyFeatureFormat", true ).toInt() );
else
{
textFields += "wkt_geom";
//old format setting
format = settings.value( "/qgis/copyGeometryAsWKT", true ).toBool() ? AttributesWithWKT : AttributesOnly;
}

Q_FOREACH ( const QgsField& field, mFeatureFields )
switch ( format )
{
textFields += field.name();
}
textLines += textFields.join( "\t" );
textFields.clear();
case AttributesOnly:
case AttributesWithWKT:
{
QStringList textLines;
QStringList textFields;

// then the field contents
for ( QgsFeatureList::const_iterator it = mFeatureClipboard.constBegin(); it != mFeatureClipboard.constEnd(); ++it )
{
QgsAttributes attributes = it->attributes();
// first do the field names
if ( format == AttributesWithWKT )
{
textFields += "wkt_geom";
}

// TODO: Set up Paste Transformations to specify the order in which fields are added.
if ( copyWKT )
{
if ( it->constGeometry() )
textFields += it->constGeometry()->exportToWkt();
else
Q_FOREACH ( const QgsField& field, mFeatureFields )
{
textFields += settings.value( "qgis/nullValue", "NULL" ).toString();
textFields += field.name();
}
}
textLines += textFields.join( "\t" );
textFields.clear();

// QgsDebugMsg("about to traverse fields.");
for ( int idx = 0; idx < attributes.count(); ++idx )
// then the field contents
for ( QgsFeatureList::const_iterator it = mFeatureClipboard.constBegin(); it != mFeatureClipboard.constEnd(); ++it )
{
QgsAttributes attributes = it->attributes();

// TODO: Set up Paste Transformations to specify the order in which fields are added.
if ( format == AttributesWithWKT )
{
if ( it->constGeometry() )
textFields += it->constGeometry()->exportToWkt();
else
{
textFields += settings.value( "qgis/nullValue", "NULL" ).toString();
}
}

// QgsDebugMsg("about to traverse fields.");
for ( int idx = 0; idx < attributes.count(); ++idx )
{
// QgsDebugMsg(QString("inspecting field '%1'.").arg(it2->toString()));
textFields += attributes.at( idx ).toString();
}

textLines += textFields.join( "\t" );
textFields.clear();
}

return textLines.join( "\n" );
}
case GeoJSON:
{
// QgsDebugMsg(QString("inspecting field '%1'.").arg(it2->toString()));
textFields += attributes.at( idx ).toString();
QgsJSONExporter exporter;
exporter.setSourceCrs( mCRS );
return exporter.exportFeatures( mFeatureClipboard );
}

textLines += textFields.join( "\t" );
textFields.clear();
}
return QString();
}

QString textCopy = textLines.join( "\n" );
void QgsClipboard::setSystemClipboard()
{
QString textCopy = generateClipboardText();

QClipboard *cb = QApplication::clipboard();

@@ -53,6 +53,15 @@ class APP_EXPORT QgsClipboard : public QObject
{
Q_OBJECT
public:

//! Available formats for copying features as text
enum CopyFormat
{
AttributesOnly, /*!< Tab delimited text, attributes only */
AttributesWithWKT, /*!< Tab delimited text, with geometry in WKT format */
GeoJSON, /*!< GeoJSON FeatureCollection format */
};

/**
* Constructor for the clipboard.
*/
@@ -146,6 +155,11 @@ class APP_EXPORT QgsClipboard : public QObject
*/
void setSystemClipboard();

/** Creates a text representation of the clipboard features.
* @returns clipboard text, respecting user export format
*/
QString generateClipboardText() const;

/** Attempts to convert a string to a list of features, by parsing the string as WKT and GeoJSON
* @param string string to convert
* @param fields fields for resultant features
@@ -169,6 +183,9 @@ class APP_EXPORT QgsClipboard : public QObject

/** True when the data from the system clipboard should be read */
bool mUseSystemClipboard;

friend class TestQgisAppClipboard;

};

#endif
@@ -42,6 +42,7 @@
#include "qgscolordialog.h"
#include "qgsexpressioncontext.h"
#include "qgsunittypes.h"
#include "qgsclipboard.h"

#include <QInputDialog>
#include <QFileDialog>
@@ -604,7 +605,15 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WindowFlags fl )
cbxEvaluateDefaultValues->setChecked( mSettings->value( "/qgis/evaluateDefaultValues", false ).toBool() );
cbxCompileExpressions->setChecked( mSettings->value( "/qgis/compileExpressions", true ).toBool() );
cbxCreateRasterLegendIcons->setChecked( mSettings->value( "/qgis/createRasterLegendIcons", false ).toBool() );
cbxCopyWKTGeomFromTable->setChecked( mSettings->value( "/qgis/copyGeometryAsWKT", true ).toBool() );

mComboCopyFeatureFormat->addItem( tr( "Plain text, no geometry" ), QgsClipboard::AttributesOnly );
mComboCopyFeatureFormat->addItem( tr( "Plain text, WKT geometry" ), QgsClipboard::AttributesWithWKT );
mComboCopyFeatureFormat->addItem( tr( "GeoJSON" ), QgsClipboard::GeoJSON );
if ( mSettings->contains( "/qgis/copyFeatureFormat" ) )
mComboCopyFeatureFormat->setCurrentIndex( mComboCopyFeatureFormat->findData( mSettings->value( "/qgis/copyFeatureFormat", true ).toInt() ) );
else
mComboCopyFeatureFormat->setCurrentIndex( mComboCopyFeatureFormat->findData( mSettings->value( "/qgis/copyGeometryAsWKT", true ).toBool() ?
QgsClipboard::AttributesWithWKT : QgsClipboard::AttributesOnly ) );
leNullValue->setText( mSettings->value( "qgis/nullValue", "NULL" ).toString() );
cbxIgnoreShapeEncoding->setChecked( mSettings->value( "/qgis/ignoreShapeEncoding", true ).toBool() );
cbxCanvasRotation->setChecked( QgsMapCanvas::rotationEnabled() );
@@ -1157,7 +1166,8 @@ void QgsOptions::saveOptions()
mSettings->setValue( "/qgis/defaultLegendGraphicResolution", mLegendGraphicResolutionSpinBox->value() );
bool createRasterLegendIcons = mSettings->value( "/qgis/createRasterLegendIcons", false ).toBool();
mSettings->setValue( "/qgis/createRasterLegendIcons", cbxCreateRasterLegendIcons->isChecked() );
mSettings->setValue( "/qgis/copyGeometryAsWKT", cbxCopyWKTGeomFromTable->isChecked() );
mSettings->setValue( "/qgis/copyFeatureFormat", mComboCopyFeatureFormat->itemData( mComboCopyFeatureFormat->currentIndex() ).toInt() );

mSettings->setValue( "/qgis/new_layers_visible", chkAddedVisibility->isChecked() );
mSettings->setValue( "/qgis/enable_anti_aliasing", chkAntiAliasing->isChecked() );
mSettings->setValue( "/qgis/enable_render_caching", chkUseRenderCaching->isChecked() );

0 comments on commit c3d6c79

Please sign in to comment.