Index: src/plugins/delimited_text/qgsdelimitedtextplugin.cpp
===================================================================
--- src/plugins/delimited_text/qgsdelimitedtextplugin.cpp (revision 14778)
+++ src/plugins/delimited_text/qgsdelimitedtextplugin.cpp (working copy)
@@ -102,7 +102,7 @@
setCurrentTheme( "" );
myQActionPointer->setWhatsThis( tr( "Add a delimited text file as a map layer. "
"The file must have a header row containing the field names. "
- "X and Y fields are required and must contain coordinates in decimal units." ) );
+ "The file must either contain X and Y fields with coordinates in decimal units or a WKT field." ) );
// Connect the action to the run
connect( myQActionPointer, SIGNAL( triggered() ), this, SLOT( run() ) );
// Add the icon to the toolbar
Index: src/plugins/delimited_text/qgsdelimitedtextplugingui.cpp
===================================================================
--- src/plugins/delimited_text/qgsdelimitedtextplugingui.cpp (revision 14778)
+++ src/plugins/delimited_text/qgsdelimitedtextplugingui.cpp (working copy)
@@ -33,7 +33,7 @@
setupUi( this );
pbnOK = buttonBox->button( QDialogButtonBox::Ok );
- enableAccept();
+ updateFieldsAndEnable();
// at startup, fetch the last used delimiter and directory from
// settings
@@ -58,22 +58,23 @@
cmbXField->setDisabled( true );
cmbYField->setDisabled( true );
+ cmbWktField->setDisabled( true );
- connect( txtFilePath, SIGNAL( textChanged( QString ) ), this, SLOT( enableAccept() ) );
+ connect( txtFilePath, SIGNAL( textChanged( QString ) ), this, SLOT( updateFieldsAndEnable() ) );
- connect( delimiterSelection, SIGNAL( toggled( bool ) ), this, SLOT( enableAccept() ) );
- connect( delimiterPlain, SIGNAL( toggled( bool ) ), this, SLOT( enableAccept() ) );
- connect( delimiterRegexp, SIGNAL( toggled( bool ) ), this, SLOT( enableAccept() ) );
+ connect( delimiterSelection, SIGNAL( toggled( bool ) ), this, SLOT( updateFieldsAndEnable() ) );
+ connect( delimiterPlain, SIGNAL( toggled( bool ) ), this, SLOT( updateFieldsAndEnable() ) );
+ connect( delimiterRegexp, SIGNAL( toggled( bool ) ), this, SLOT( updateFieldsAndEnable() ) );
- connect( cbxDelimSpace, SIGNAL( stateChanged( int ) ), this, SLOT( enableAccept() ) );
- connect( cbxDelimTab, SIGNAL( stateChanged( int ) ), this, SLOT( enableAccept() ) );
- connect( cbxDelimSemicolon, SIGNAL( stateChanged( int ) ), this, SLOT( enableAccept() ) );
- connect( cbxDelimComma, SIGNAL( stateChanged( int ) ), this, SLOT( enableAccept() ) );
- connect( cbxDelimColon, SIGNAL( stateChanged( int ) ), this, SLOT( enableAccept() ) );
+ connect( cbxDelimSpace, SIGNAL( stateChanged( int ) ), this, SLOT( updateFieldsAndEnable() ) );
+ connect( cbxDelimTab, SIGNAL( stateChanged( int ) ), this, SLOT( updateFieldsAndEnable() ) );
+ connect( cbxDelimSemicolon, SIGNAL( stateChanged( int ) ), this, SLOT( updateFieldsAndEnable() ) );
+ connect( cbxDelimComma, SIGNAL( stateChanged( int ) ), this, SLOT( updateFieldsAndEnable() ) );
+ connect( cbxDelimColon, SIGNAL( stateChanged( int ) ), this, SLOT( updateFieldsAndEnable() ) );
- connect( txtDelimiter, SIGNAL( editingFinished() ), this, SLOT( enableAccept() ) );
+ connect( txtDelimiter, SIGNAL( editingFinished() ), this, SLOT( updateFieldsAndEnable() ) );
- connect( rowCounter, SIGNAL( valueChanged( int ) ), this, SLOT( enableAccept() ) );
+ connect( rowCounter, SIGNAL( valueChanged( int ) ), this, SLOT( updateFieldsAndEnable() ) );
}
QgsDelimitedTextPluginGui::~QgsDelimitedTextPluginGui()
@@ -103,12 +104,23 @@
.arg( txtDelimiter->text() )
.arg( delimiterType );
- if ( !cmbXField->currentText().isEmpty() && !cmbYField->currentText().isEmpty() )
- {
- uri += QString( "&xField=%1&yField=%2" )
- .arg( cmbXField->currentText() )
- .arg( cmbYField->currentText() );
- }
+ if( geomTypeXY->isChecked())
+ {
+ if ( !cmbXField->currentText().isEmpty() && !cmbYField->currentText().isEmpty() )
+ {
+ uri += QString( "&xField=%1&yField=%2" )
+ .arg( cmbXField->currentText() )
+ .arg( cmbYField->currentText() );
+ }
+ }
+ else
+ {
+ if( ! cmbWktField->currentText().isEmpty() )
+ {
+ uri += QString( "&wktField=%1" )
+ .arg( cmbWktField->currentText() );
+ }
+ }
int skipLines = rowCounter->value();
if ( skipLines > 0 )
@@ -177,6 +189,31 @@
return fieldList;
}
+bool QgsDelimitedTextPluginGui::haveValidFileAndDelimiters()
+{
+
+ bool valid = true;
+ // If there is no valid file or field delimiters than cannot determine fields
+ if ( txtFilePath->text().isEmpty() || !QFile( txtFilePath->text() ).exists() )
+ {
+ valid = false;
+ }
+ else if ( delimiterSelection->isChecked() )
+ {
+ valid =
+ cbxDelimSpace->isChecked() ||
+ cbxDelimTab->isChecked() ||
+ cbxDelimSemicolon->isChecked() ||
+ cbxDelimComma->isChecked() ||
+ cbxDelimColon->isChecked();
+ }
+ else
+ {
+ valid = !txtDelimiter->text().isEmpty();
+ }
+ return valid;
+}
+
void QgsDelimitedTextPluginGui::updateFieldLists()
{
// Update the x and y field dropdown boxes
@@ -184,17 +221,28 @@
disconnect( cmbXField, SIGNAL( currentIndexChanged( int ) ), this, SLOT( enableAccept() ) );
disconnect( cmbYField, SIGNAL( currentIndexChanged( int ) ), this, SLOT( enableAccept() ) );
+ disconnect( cmbWktField, SIGNAL( currentIndexChanged( int ) ), this, SLOT( enableAccept() ) );
+ disconnect(geomTypeXY, SIGNAL(toggled(bool)), cmbXField, SLOT(setEnabled(bool)));
+ disconnect(geomTypeXY, SIGNAL(toggled(bool)), cmbYField, SLOT(setEnabled(bool)));
+ disconnect(geomTypeXY, SIGNAL(toggled(bool)), cmbWktField, SLOT(setDisabled(bool)));
QString columnX = cmbXField->currentText();
QString columnY = cmbYField->currentText();
+ QString columnWkt = cmbWktField->currentText();
// clear the field lists
cmbXField->clear();
cmbYField->clear();
+ cmbWktField->clear();
+ geomTypeXY->setEnabled( false );
+ geomTypeWKT->setEnabled( false );
cmbXField->setEnabled( false );
cmbYField->setEnabled( false );
+ cmbWktField->setEnabled( false );
+ if( ! haveValidFileAndDelimiters()) return;
+
QFile file( txtFilePath->text() );
if ( !file.open( QIODevice::ReadOnly ) )
return;
@@ -220,6 +268,8 @@
//
// We don't know anything about a text based field other
// than its name. All fields are assumed to be text
+ bool haveFields = false;
+
foreach( QString field, fieldList )
{
if (( field.left( 1 ) == "'" || field.left( 1 ) == "\"" ) &&
@@ -233,10 +283,28 @@
cmbXField->addItem( field );
cmbYField->addItem( field );
+ cmbWktField->addItem( field );
+ haveFields = true;
}
- cmbXField->setEnabled( cmbXField->count() > 0 );
- cmbYField->setEnabled( cmbYField->count() > 0 );
+ int indexWkt = -1;
+ if( ! columnWkt.isEmpty() )
+ {
+ indexWkt = cmbWktField->findText( columnWkt );
+ }
+ if( indexWkt < 0 )
+ {
+ indexWkt = cmbWktField->findText("wkt", Qt::MatchContains );
+ }
+ if( indexWkt < 0 )
+ {
+ indexWkt = cmbWktField->findText("geometry", Qt::MatchContains );
+ }
+ if( indexWkt < 0 )
+ {
+ indexWkt = cmbWktField->findText("shape", Qt::MatchContains );
+ }
+ cmbWktField->setCurrentIndex( indexWkt);
int indexX = -1;
if ( !columnX.isEmpty() )
@@ -274,9 +342,29 @@
cmbYField->setCurrentIndex( indexY );
- connect( cmbXField, SIGNAL( currentIndexChanged( int ) ), this, SLOT( enableAccept() ) );
- connect( cmbYField, SIGNAL( currentIndexChanged( int ) ), this, SLOT( enableAccept() ) );
+ bool isXY = (geomTypeXY->isChecked() && indexX >= 0 && indexY >= 0) || indexWkt < 0;
+
+ geomTypeXY->setChecked( isXY );
+ geomTypeWKT->setChecked( ! isXY );
+
+ if( haveFields )
+ {
+ geomTypeXY->setEnabled(true);
+ geomTypeWKT->setEnabled(true);
+ cmbXField->setEnabled( isXY );
+ cmbYField->setEnabled( isXY );
+ cmbWktField->setEnabled( ! isXY );
+
+
+ connect( cmbXField, SIGNAL( currentIndexChanged( int ) ), this, SLOT( enableAccept() ) );
+ connect( cmbYField, SIGNAL( currentIndexChanged( int ) ), this, SLOT( enableAccept() ) );
+ connect( cmbWktField, SIGNAL( currentIndexChanged( int ) ), this, SLOT( enableAccept() ) );
+ connect(geomTypeXY, SIGNAL(toggled(bool)), cmbXField, SLOT(setEnabled(bool)));
+ connect(geomTypeXY, SIGNAL(toggled(bool)), cmbYField, SLOT(setEnabled(bool)));
+ connect(geomTypeXY, SIGNAL(toggled(bool)), cmbWktField, SLOT(setDisabled(bool)));
+ }
+
// clear the sample text box
tblSample->clear();
@@ -324,35 +412,30 @@
txtFilePath->setText( s );
}
+void QgsDelimitedTextPluginGui::updateFieldsAndEnable()
+{
+ updateFieldLists();
+ enableAccept();
+}
+
void QgsDelimitedTextPluginGui::enableAccept()
{
- bool enabled = false;
- if ( txtFilePath->text().isEmpty() || !QFile( txtFilePath->text() ).exists() )
- {
- enabled = false;
- }
- else if ( delimiterSelection->isChecked() )
- {
- enabled =
- cbxDelimSpace->isChecked() ||
- cbxDelimTab->isChecked() ||
- cbxDelimSemicolon->isChecked() ||
- cbxDelimComma->isChecked() ||
- cbxDelimColon->isChecked();
- }
- else
- {
- enabled = !txtDelimiter->text().isEmpty();
- }
+ // If the geometry type field is enabled then there must be
+ // a valid file, and it must be
+ bool enabled = haveValidFileAndDelimiters();
-
if ( enabled )
{
- updateFieldLists();
- enabled = ( cmbXField->currentText().isEmpty() && cmbYField->currentText().isEmpty() )
- || ( !cmbXField->currentText().isEmpty() && !cmbYField->currentText().isEmpty() && cmbXField->currentText() != cmbYField->currentText() );
+ if( geomTypeXY->isChecked() )
+ {
+ enabled = !( cmbXField->currentText().isEmpty() || cmbYField->currentText().isEmpty() || cmbXField->currentText() == cmbYField->currentText() );
+ }
+ else
+ {
+ enabled = !cmbWktField->currentText().isEmpty();
+ }
}
pbnOK->setEnabled( enabled );
Index: src/plugins/delimited_text/qgsdelimitedtextplugingui.h
===================================================================
--- src/plugins/delimited_text/qgsdelimitedtextplugingui.h (revision 14778)
+++ src/plugins/delimited_text/qgsdelimitedtextplugingui.h (working copy)
@@ -34,6 +34,7 @@
QStringList splitLine( QString line );
private:
+ bool haveValidFileAndDelimiters();
void updateFieldLists();
void getOpenFileName();
@@ -47,6 +48,7 @@
void on_btnBrowseForFile_clicked();
public slots:
+ void updateFieldsAndEnable();
void enableAccept();
signals:
Index: src/plugins/delimited_text/qgsdelimitedtextpluginguibase.ui
===================================================================
--- src/plugins/delimited_text/qgsdelimitedtextpluginguibase.ui (revision 14778)
+++ src/plugins/delimited_text/qgsdelimitedtextpluginguibase.ui (working copy)
@@ -6,8 +6,8 @@
0
0
- 532
- 513
+ 589
+ 522
@@ -110,7 +110,7 @@
true
-
+
-
@@ -121,70 +121,7 @@
- -
-
-
- Semicolon
-
-
-
- -
-
-
- Tab
-
-
-
- -
-
-
- Space
-
-
- true
-
-
-
- -
-
-
- Comma
-
-
-
- -
-
-
- Colon
-
-
-
- -
-
-
- false
-
-
-
- 0
- 0
-
-
-
-
- 32767
- 32767
-
-
-
- Delimiter to use when splitting fields in the text file. The delimiter can be more than one character.
-
-
- Delimiter to use when splitting fields in the delimited text file. The delimiter can be 1 or more characters in length.
-
-
-
- -
+
-
@@ -222,6 +159,73 @@
+ -
+
+
-
+
+
+ Tab
+
+
+
+ -
+
+
+ Space
+
+
+ true
+
+
+
+ -
+
+
+ Comma
+
+
+
+ -
+
+
+ Semicolon
+
+
+
+ -
+
+
+ Colon
+
+
+
+
+
+ -
+
+
+ false
+
+
+
+ 0
+ 0
+
+
+
+
+ 32767
+ 32767
+
+
+
+ Delimiter to use when splitting fields in the text file. The delimiter can be more than one character.
+
+
+ Delimiter to use when splitting fields in the delimited text file. The delimiter can be 1 or more characters in length.
+
+
+
@@ -236,7 +240,7 @@
0
-
+
-
@@ -276,17 +280,84 @@
-
-
-
-
-
+
+
+
+ 9
+
+
-
+
+
+ false
+
+
+ The file contains a well known text geometry field
+
+
+ WKT field
+
+
+
+ -
<p align="right">X field</p>
- -
-
+
-
+
+
-
+
+
+ false
+
+
+
+ 0
+ 0
+
+
+
+
+ 120
+ 0
+
+
+
+ Name of the field containing x values
+
+
+ Name of the field containing x values. Choose a field from the list. The list is generated by parsing the header row of the delimited text file.
+
+
+ true
+
+
+
+
+
+ -
+
+
+ false
+
+
+ The file contains X and Y coordinate columns
+
+
+ X Y fields
+
+
+ true
+
+
+
+ -
+
+
+ false
+
0
@@ -300,25 +371,28 @@
- Name of the field containing x values
+ Name of the field containing y values
- Name of the field containing x values. Choose a field from the list. The list is generated by parsing the header row of the delimited text file.
+ Name of the field containing y values. Choose a field from the list. The list is generated by parsing the header row of the delimited text file.
true
- -
+
-
<p align="right">Y field</p>
- -
-
+
-
+
+
+ false
+
0
@@ -376,8 +450,25 @@
+ txtFilePath
+ btnBrowseForFile
+ txtLayerName
+ delimiterSelection
+ cbxDelimTab
+ cbxDelimSpace
+ cbxDelimComma
+ cbxDelimSemicolon
+ cbxDelimColon
+ delimiterPlain
+ delimiterRegexp
+ txtDelimiter
+ rowCounter
+ geomTypeXY
cmbXField
cmbYField
+ geomTypeWKT
+ cmbWktField
+ tblSample
buttonBox
@@ -395,8 +486,8 @@
121
- 282
- 115
+ 445
+ 113
@@ -411,8 +502,8 @@
110
- 277
- 149
+ 286
+ 113
@@ -427,8 +518,8 @@
109
- 281
- 175
+ 445
+ 138
@@ -443,8 +534,8 @@
114
- 293
- 203
+ 286
+ 138
@@ -459,8 +550,8 @@
114
- 118
- 218
+ 397
+ 165
@@ -475,8 +566,8 @@
113
- 301
- 225
+ 531
+ 138
Index: src/providers/delimitedtext/qgsdelimitedtextprovider.cpp
===================================================================
--- src/providers/delimitedtext/qgsdelimitedtextprovider.cpp (revision 14778)
+++ src/providers/delimitedtext/qgsdelimitedtextprovider.cpp (working copy)
@@ -34,6 +34,7 @@
#include "qgsdataprovider.h"
#include "qgsfeature.h"
#include "qgsfield.h"
+#include "qgsgeometry.h"
#include "qgslogger.h"
#include "qgsmessageoutput.h"
#include "qgsrectangle.h"
@@ -132,8 +133,12 @@
QgsDelimitedTextProvider::QgsDelimitedTextProvider( QString uri )
: QgsVectorDataProvider( uri ),
- mXFieldIndex( -1 ), mYFieldIndex( -1 ),
- mShowInvalidLines( true ), mWkbType( QGis::WKBPoint )
+ mHasWktField( false ), mFieldCount(0),
+ mXFieldIndex( -1 ), mYFieldIndex( -1 ),
+ mWktFieldIndex( -1 ), mWktHasZM( false),
+ mWktZMRegexp("\\s+(?:z|m|zm)(?=\\s*\\()",Qt::CaseInsensitive),
+ mWktCrdRegexp("(\\-?\\d+(?:\\.\\d*)?\\s+\\-?\\d+(?:\\.\\d*)?)\\s[\\s\\d\\.\\-]+"),
+ mShowInvalidLines( true ), mWkbType( QGis::WKBNoGeometry )
{
// Get the file name and mDelimiter out of the uri
mFileName = uri.left( uri.indexOf( "?" ) );
@@ -147,6 +152,8 @@
mDelimiter = temp.size() ? temp[0].mid( temp[0].indexOf( "=" ) + 1 ) : "";
temp = parameters.filter( "delimiterType=" );
mDelimiterType = temp.size() ? temp[0].mid( temp[0].indexOf( "=" ) + 1 ) : "";
+ temp = parameters.filter( "wktField=" );
+ QString wktField = temp.size() ? temp[0].mid( temp[0].indexOf( "=" ) + 1 ) : "";
temp = parameters.filter( "xField=" );
QString xField = temp.size() ? temp[0].mid( temp[0].indexOf( "=" ) + 1 ) : "";
temp = parameters.filter( "yField=" );
@@ -157,8 +164,12 @@
mFileName = QUrl::fromPercentEncoding( mFileName.toUtf8() );
mDelimiter = QUrl::fromPercentEncoding( mDelimiter.toUtf8() );
mDelimiterType = QUrl::fromPercentEncoding( mDelimiterType.toUtf8() );
+ wktField = QUrl::fromPercentEncoding( wktField.toUtf8() );
xField = QUrl::fromPercentEncoding( xField.toUtf8() );
yField = QUrl::fromPercentEncoding( yField.toUtf8() );
+
+ mHasWktField = wktField != "";
+
skipLines = QUrl::fromPercentEncoding( skipLines.toUtf8() );
mSkipLines = skipLines.toInt();
@@ -167,6 +178,7 @@
QgsDebugMsg( "Delimited text file is: " + mFileName );
QgsDebugMsg( "Delimiter is: " + mDelimiter );
QgsDebugMsg( "Delimiter type is: " + mDelimiterType );
+ QgsDebugMsg( "wktField is: " + xField );
QgsDebugMsg( "xField is: " + xField );
QgsDebugMsg( "yField is: " + yField );
QgsDebugMsg( "skipLines is: " + QString::number( mSkipLines ) );
@@ -218,7 +230,6 @@
QString line;
mNumberFeatures = 0;
int lineNumber = 0;
- bool firstPoint = true;
bool hasFields = false;
while ( !mStream->atEnd() )
{
@@ -236,101 +247,153 @@
// fields vector
QStringList fieldList = splitLine( line );
+ mFieldCount = fieldList.count();
+
// We don't know anything about a text based field other
// than its name. All fields are assumed to be text
int fieldPos = 0;
- for ( QStringList::Iterator it = fieldList.begin(); it != fieldList.end(); ++it )
- {
- QString field = *it;
+ for( int column = 0; column < mFieldCount; column++ )
+ {
+ QString field = fieldList[column];
if ( field.length() > 0 )
{
- // for now, let's set field type as text
- attributeFields[fieldPos] = QgsField( *it, QVariant::String, "Text" );
// check to see if this field matches either the x or y field
- if ( xField == *it )
+ if ( wktField == field )
{
- QgsDebugMsg( "Found x field: " + ( *it ) );
- mXFieldIndex = fieldPos;
+ QgsDebugMsg( "Found wkt field: " + ( field ) );
+ mWktFieldIndex = column;
}
- else if ( yField == *it )
+ else if ( xField == field )
{
- QgsDebugMsg( "Found y field: " + ( *it ) );
- mYFieldIndex = fieldPos;
+ QgsDebugMsg( "Found x field: " + ( field ) );
+ mXFieldIndex = column;
}
+ else if ( yField == field )
+ {
+ QgsDebugMsg( "Found y field: " + ( field ) );
+ mYFieldIndex = column;
+ }
- QgsDebugMsg( "Adding field: " + ( *it ) );
+ // WKT geometry field won't be displayed in attribute tables
+ if( column == mWktFieldIndex ) continue;
+
+ QgsDebugMsg( "Adding field: " + ( field ) );
// assume that the field could be integer or double
+ // for now, let's set field type as text
+ attributeColumns.append(column);
+ attributeFields[fieldPos] = QgsField( field, QVariant::String, "Text" );
couldBeInt.insert( fieldPos, true );
couldBeDouble.insert( fieldPos, true );
fieldPos++;
}
}
+ if( mWktFieldIndex >= 0 ) { mXFieldIndex = -1; mYFieldIndex=-1; }
QgsDebugMsg( "Field count for the delimited text file is " + QString::number( attributeFields.size() ) );
hasFields = true;
}
- else //field names already read
+ else // hasFields == true - field names already read
{
- mNumberFeatures++;
// split the line on the delimiter
QStringList parts = splitLine( line );
// Skip malformed lines silently. Report line number with nextFeature()
- if ( attributeFields.size() != parts.size() )
+ if ( parts.size() != mFieldCount )
{
continue;
}
- // Get the x and y values, first checking to make sure they
- // aren't null.
- QString sX, sY;
- if ( mXFieldIndex >= 0 && mYFieldIndex >= 0 )
- {
- sX = parts[mXFieldIndex];
- sY = parts[mYFieldIndex];
- }
+ if( mHasWktField && mWktFieldIndex >= 0 )
+ {
+ // Get the wkt - confirm it is valid, get the type, and
+ // if compatible with the rest of file, add to the extents
- bool xOk = true;
- bool yOk = true;
- double x = sX.toDouble( &xOk );
- double y = sY.toDouble( &yOk );
+ QString sWkt = parts[mWktFieldIndex];
+ QgsGeometry *geom = 0;
+ try
+ {
+ if( ! mWktHasZM && sWkt.indexOf(mWktZMRegexp) >= 0 ) mWktHasZM = true;
+ if( mWktHasZM )
+ {
+ sWkt.remove(mWktZMRegexp).replace(mWktCrdRegexp,"\\1");
+ }
+ geom = QgsGeometry::fromWkt(sWkt);
+ }
+ catch(...)
+ {
+ geom = 0;
+ }
- if ( xOk && yOk )
- {
- if ( !firstPoint )
- {
- mExtent.combineExtentWith( x, y );
- }
- else
- {
- // Extent for the first point is just the first point
- mExtent.set( x, y, x, y );
- firstPoint = false;
- }
- }
+ if( geom )
+ {
+ QGis::WkbType type = geom->wkbType();
+ if( type != QGis::WKBNoGeometry )
+ {
+ if( mNumberFeatures == 0 )
+ {
+ mNumberFeatures++;
+ mWkbType = type;
+ mExtent = geom->boundingBox();
+ }
+ else if( type == mWkbType )
+ {
+ mNumberFeatures++;
+ QgsRectangle bbox( geom->boundingBox());
+ mExtent.combineExtentWith( &bbox );
+ }
+ }
+ delete geom;
+ }
+ }
- int i = 0;
- for ( QStringList::iterator it = parts.begin(); it != parts.end(); ++it, ++i )
- {
+ else if( ! mHasWktField && mXFieldIndex >= 0 && mYFieldIndex >= 0 )
+ {
+
+ // Get the x and y values, first checking to make sure they
+ // aren't null.
+
+ QString sX = parts[mXFieldIndex];
+ QString sY = parts[mYFieldIndex];
+
+ bool xOk = true;
+ bool yOk = true;
+ double x = sX.toDouble( &xOk );
+ double y = sY.toDouble( &yOk );
+
+ if ( xOk && yOk )
+ {
+ if ( mNumberFeatures > 0 )
+ {
+ mExtent.combineExtentWith( x, y );
+ }
+ else
+ {
+ // Extent for the first point is just the first point
+ mExtent.set( x, y, x, y );
+ mWkbType = QGis::WKBPoint;
+ }
+ mNumberFeatures++;
+ }
+ }
+
+ for( int i = 0; i < attributeFields.size(); i++ )
+ {
+ QString &value = parts[attributeColumns[i]];
+ if( value.isEmpty()) continue;
// try to convert attribute values to integer and double
- if ( couldBeInt[i] && !it->isEmpty() )
+ if ( couldBeInt[i] )
{
- it->toInt( &couldBeInt[i] );
+ value.toInt( &couldBeInt[i] );
}
- if ( couldBeDouble[i] && !it->isEmpty() )
+ if ( couldBeDouble[i] )
{
- it->toDouble( &couldBeDouble[i] );
+ value.toDouble( &couldBeDouble[i] );
}
}
}
}
- if ( mXFieldIndex < 0 || mYFieldIndex < 0 )
- {
- mWkbType = QGis::WKBNoGeometry;
- }
-
// now it's time to decide the types for the fields
for ( QgsFieldMap::iterator it = attributeFields.begin(); it != attributeFields.end(); ++it )
{
@@ -379,94 +442,86 @@
// lex the tokens from the current data line
QStringList tokens = splitLine( line );
- bool xOk = false;
- bool yOk = false;
- bool geometryOk = false;
+ QgsGeometry *geom = 0;
- // Skip indexing malformed lines.
- if ( mXFieldIndex < 0 || mYFieldIndex < 0 )
- {
- geometryOk = false;
- }
- else if ( attributeFields.size() == tokens.size() )
- {
- x = tokens[mXFieldIndex].toDouble( &xOk );
- y = tokens[mYFieldIndex].toDouble( &yOk );
- geometryOk = ( xOk && yOk );
- }
+ if( mHasWktField && mWktFieldIndex >= 0 )
+ {
+ try
+ {
+ QString &sWkt = tokens[mWktFieldIndex];
+ if( mWktHasZM )
+ {
+ sWkt.remove(mWktZMRegexp).replace(mWktCrdRegexp,"\\1");
+ }
- // Give every valid line in the file an id, even if it's not
- // in the current extent or bounds.
- ++mFid; // increment to next feature ID
+ geom = QgsGeometry::fromWkt(sWkt);
+ }
+ catch(...)
+ {
+ geom = 0;
+ }
- // skip the feature if it's out of current bounds
- if ( ! boundsCheck( x, y ) )
- continue;
+ if( geom && geom->wkbType() != mWkbType )
+ {
+ delete geom;
+ geom = 0;
+ }
+ mFid++;
+ if( ! boundsCheck(geom))
+ {
+ delete geom;
+ geom = 0;
+ }
+ }
+ else if( ! mHasWktField && mXFieldIndex >= 0 && mYFieldIndex >= 0 )
+ {
+ bool xOk, yOk;
+ double x = tokens[mXFieldIndex].toDouble(&xOk);
+ double y = tokens[mYFieldIndex].toDouble(&yOk);
+ if( xOk && yOk )
+ {
+ mFid++;
+ if( boundsCheck(x,y) )
+ {
+ geom = QgsGeometry::fromPoint(QgsPoint(x,y));
+ }
+ }
+ }
- // at this point, one way or another, the current feature values
- // are valid
- feature.setValid( true );
+ // If no valid geometry skip to the next line
- feature.setFeatureId( mFid );
+ if( ! geom ) continue;
- QByteArray buffer;
- QDataStream s( &buffer, static_cast( QIODevice::WriteOnly ) ); // open on buffers's data
+ // At this point the current feature values are valid
- switch ( QgsApplication::endian() )
- {
- case QgsApplication::NDR :
- // we're on a little-endian platform, so tell the data
- // stream to use that
- s.setByteOrder( QDataStream::LittleEndian );
- s << ( quint8 )1; // 1 is for little-endian
- break;
- case QgsApplication::XDR :
- // don't change byte order since QDataStream is big endian by default
- s << ( quint8 )0; // 0 is for big-endian
- break;
- default :
- QgsDebugMsg( "unknown endian" );
- //delete [] geometry;
- return false;
- }
+ feature.setValid( true );
- s << ( quint32 )QGis::WKBPoint;
- s << x;
- s << y;
+ feature.setFeatureId( mFid );
- unsigned char* geometry = 0;
- if ( geometryOk )
- {
- geometry = new unsigned char[buffer.size()];
- memcpy( geometry, buffer.data(), buffer.size() );
- feature.setGeometryAndOwnership( geometry, sizeof( wkbPoint ) );
- }
- else
- {
- feature.setGeometryAndOwnership( 0, 0 );
- }
+ feature.setGeometry( geom );
for ( QgsAttributeList::const_iterator i = mAttributesToFetch.begin();
i != mAttributesToFetch.end();
++i )
{
+ QString &value = tokens[attributeColumns[*i]];
QVariant val;
switch ( attributeFields[*i].type() )
{
case QVariant::Int:
- if ( !tokens[*i].isEmpty() )
- val = QVariant( tokens[*i].toInt() );
+ if ( !value.isEmpty() )
+ val = QVariant( value );
else
val = QVariant( attributeFields[*i].type() );
break;
case QVariant::Double:
- if ( !tokens[*i].isEmpty() )
- val = QVariant( tokens[*i].toDouble() );
+ if ( !value.isEmpty() )
+ val = QVariant( value.toDouble() );
else
val = QVariant( attributeFields[*i].type() );
break;
default:
- val = QVariant( tokens[*i] );
+ val = QVariant( value );
break;
}
feature.addAttribute( *i, val );
@@ -589,10 +644,20 @@
if ( mSelectionRectangle.isEmpty() || !mFetchGeom )
return true;
- return ( x <= mSelectionRectangle.xMaximum() ) && ( x >= mSelectionRectangle.xMinimum() ) &&
- ( y <= mSelectionRectangle.yMaximum() ) && ( y >= mSelectionRectangle.yMinimum() );
+ return mSelectionRectangle.contains( QgsPoint(x,y) );
}
+/**
+ * Check to see if the geometry is within the selection rectangle
+ */
+bool QgsDelimitedTextProvider::boundsCheck( QgsGeometry *geom )
+{
+ // no selection rectangle or geometry => always in the bounds
+ if ( mSelectionRectangle.isEmpty() || !mFetchGeom )
+ return true;
+ return geom->boundingBox().intersects( mSelectionRectangle );
+}
+
int QgsDelimitedTextProvider::capabilities() const
{
return NoCapabilities;
@@ -606,8 +671,6 @@
}
-
-
QString QgsDelimitedTextProvider::name() const
{
return TEXT_PROVIDER_KEY;
Index: src/providers/delimitedtext/qgsdelimitedtextprovider.h
===================================================================
--- src/providers/delimitedtext/qgsdelimitedtextprovider.h (revision 14778)
+++ src/providers/delimitedtext/qgsdelimitedtextprovider.h (working copy)
@@ -166,12 +166,19 @@
bool boundsCheck( double x, double y );
+ /**
+ * Check to see if a geometry overlaps the selection
+ * rectangle
+ * @param geom geometry to test against bounds
+ * @param y Y value of point
+ * @return True if point is within the rectangle
+ */
+ bool boundsCheck( QgsGeometry *geom );
-
-
private:
//! Fields
+ QList attributeColumns;
QgsFieldMap attributeFields;
QgsAttributeList mAttributesToFetch;
@@ -181,9 +188,21 @@
QRegExp mDelimiterRegexp;
QString mDelimiterType;
+ bool mHasWktField;
+ int mFieldCount; // Note: this includes field count for wkt field
int mXFieldIndex;
int mYFieldIndex;
+ int mWktFieldIndex;
+ // Handling of WKT types with .. Z, .. M, and .. ZM geometries (ie
+ // Z values and/or measures). mWktZMRegexp is used to test for and
+ // remove the Z or M fields, and mWktCrdRegexp is used to remove the
+ // extra coordinate values.
+
+ bool mWktHasZM;
+ QRegExp mWktZMRegexp;
+ QRegExp mWktCrdRegexp;
+
//! Layer extent
QgsRectangle mExtent;
@@ -220,7 +239,7 @@
};
wkbPoint mWKBpt;
- QGis::WkbType mWkbType; //can be WKBPoint or NoGeometry
+ QGis::WkbType mWkbType;
QString readLine( QTextStream *stream );
QStringList splitLine( QString line );