[QGIS Commit] r14781 - in trunk/qgis: resources/context_help
src/plugins/delimited_text src/providers/delimitedtext
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Sun Nov 28 20:47:52 EST 2010
Author: gsherman
Date: 2010-11-28 17:47:52 -0800 (Sun, 28 Nov 2010)
New Revision: 14781
Modified:
trunk/qgis/resources/context_help/QgsDelimitedTextPluginGui-en_US
trunk/qgis/src/plugins/delimited_text/qgsdelimitedtextplugin.cpp
trunk/qgis/src/plugins/delimited_text/qgsdelimitedtextplugingui.cpp
trunk/qgis/src/plugins/delimited_text/qgsdelimitedtextplugingui.h
trunk/qgis/src/plugins/delimited_text/qgsdelimitedtextpluginguibase.ui
trunk/qgis/src/providers/delimitedtext/qgsdelimitedtextprovider.cpp
trunk/qgis/src/providers/delimitedtext/qgsdelimitedtextprovider.h
Log:
Squashed commit of the following:
Application of patch from ticket #3259 - support WKT field in delimited
text plugin.
commit 0dc370a39c7349d85859fac462e91e346bf8fb83
Modified context help to reflect addition of WKT capability to the
delimited text plugin.
Tightened up the delimited text dialog a bit.
commit 25484867621d6b4760952a8f00a07d253273ecfd
Added *.wkt to file open filter
commit 9f16a276b6b2ecbea2eebede50e3275a1df0389b
Patch for providing wkt support in delimited text plugin
Modified: trunk/qgis/resources/context_help/QgsDelimitedTextPluginGui-en_US
===================================================================
--- trunk/qgis/resources/context_help/QgsDelimitedTextPluginGui-en_US 2010-11-28 20:48:26 UTC (rev 14780)
+++ trunk/qgis/resources/context_help/QgsDelimitedTextPluginGui-en_US 2010-11-29 01:47:52 UTC (rev 14781)
@@ -4,6 +4,7 @@
<p>
<a href="#re">Requirements</a><br/>
<a href="#example">Example of a valid text file</a><br/>
+<a href="#wkt_example">Example of a valid text file with a WKT field</a><br/>
<a href="#notes">Notes</a><br/>
<a name="re">
@@ -12,24 +13,47 @@
To view a delimited text file as layer, the text file must contain:
<ol>
<li>A delimited header row of field names. This must be the first line in the text file.</li>
-<li>The header row must contain an X and Y field. These fields can have any name.</li>
+<li>The header row must contain an X and Y field <em>or</em> a Well Known Text (WKT) field. These fields can have any name.</li>
<li>The <B>x</B> and <B>y</B> coordinates must be specified as a number. The coordinate system is not important.</li>
+<li>A WKT field must be in the standard format.
</ol>
<a name="example">
-<h4>Example of a valid text file</h4>
+<h4>Example of a valid text file with x and y fields</h4>
</a>
-X;Y;ELEV<br/>
--300120;7689960;13<br/>
--654360;7562040;52<br/>
-1640;7512840;3<br/>
-[...]<br/>
+<tt>
+ X;Y;ELEV<br/>
+ -300120;7689960;13<br/>
+ -654360;7562040;52<br/>
+ 1640;7512840;3<br/>
+ [...]<br/>
+</tt>
+<a name="wkt_example">
+<h4>Example of a valid text file with a WKT field</h4>
+</a>
+<tt>
+id|wkt<br/>
+1|POINT(172.0702250 -43.6031036)<br/>
+2|POINT(172.0702250 -43.6031036)<br/>
+3|POINT(172.1543206 -43.5731302)<br/>
+4|POINT(171.9282585 -43.5493308)<br/>
+5|POINT(171.8827359 -43.5875983)<br/>
+</tt>
<a name="notes">
<h4>Notes</h4>
</a>
<ol>
-<li>The example text file uses <b>;</b> as delimiter. Any character can be used to delimit the fields.</li>
+ <li>The example text file:</li>
+<ul>
+<li> Uses <b>;</b> as delimiter. Any character can be used to delimit the fields.</li>
<li>The first row is the header row. It contains the fields X, Y and ELEV.</li>
<li>No quotes (") are used to delimit text fields.</li>
<li>The x coordinates are contained in the X field.</li>
<li>The y coordinates are contained in the Y field.</li>
-</ol>
\ No newline at end of file
+</ul>
+<li>The example text file with WKT:</li>
+<ul>
+ <li>Has two fields defined in the header row: id and wkt.
+ <li>Uses <b>|</b> as a delimiter.</li>
+ <li>Specifies each point using the WKT notation
+</ul>
+</ol>
Modified: trunk/qgis/src/plugins/delimited_text/qgsdelimitedtextplugin.cpp
===================================================================
--- trunk/qgis/src/plugins/delimited_text/qgsdelimitedtextplugin.cpp 2010-11-28 20:48:26 UTC (rev 14780)
+++ trunk/qgis/src/plugins/delimited_text/qgsdelimitedtextplugin.cpp 2010-11-29 01:47:52 UTC (rev 14781)
@@ -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
Modified: trunk/qgis/src/plugins/delimited_text/qgsdelimitedtextplugingui.cpp
===================================================================
--- trunk/qgis/src/plugins/delimited_text/qgsdelimitedtextplugingui.cpp 2010-11-28 20:48:26 UTC (rev 14780)
+++ trunk/qgis/src/plugins/delimited_text/qgsdelimitedtextplugingui.cpp 2010-11-29 01:47:52 UTC (rev 14781)
@@ -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();
@@ -318,41 +406,36 @@
this,
tr( "Choose a delimited text file to open" ),
settings.value( "/Plugin-DelimitedText/text_path", "./" ).toString(),
- "Text files (*.txt *.csv);; All files (* *.*)" );
+ "Text files (*.txt *.csv);; Well Known Text files (*.wkt);; All files (* *.*)" );
// set path
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 );
Modified: trunk/qgis/src/plugins/delimited_text/qgsdelimitedtextplugingui.h
===================================================================
--- trunk/qgis/src/plugins/delimited_text/qgsdelimitedtextplugingui.h 2010-11-28 20:48:26 UTC (rev 14780)
+++ trunk/qgis/src/plugins/delimited_text/qgsdelimitedtextplugingui.h 2010-11-29 01:47:52 UTC (rev 14781)
@@ -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:
Modified: trunk/qgis/src/plugins/delimited_text/qgsdelimitedtextpluginguibase.ui
===================================================================
--- trunk/qgis/src/plugins/delimited_text/qgsdelimitedtextpluginguibase.ui 2010-11-28 20:48:26 UTC (rev 14780)
+++ trunk/qgis/src/plugins/delimited_text/qgsdelimitedtextpluginguibase.ui 2010-11-29 01:47:52 UTC (rev 14781)
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>532</width>
- <height>513</height>
+ <width>492</width>
+ <height>528</height>
</rect>
</property>
<property name="windowTitle">
@@ -18,8 +18,8 @@
<normaloff/>
</iconset>
</property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="0" column="0">
<widget class="QWidget" name="widget_3" native="true">
<property name="acceptDrops">
<bool>true</bool>
@@ -105,12 +105,12 @@
</layout>
</widget>
</item>
- <item>
+ <item row="1" column="0">
<widget class="QFrame" name="frame_select_delimiters">
<property name="enabled">
<bool>true</bool>
</property>
- <layout class="QGridLayout" name="gridLayout_5">
+ <layout class="QGridLayout" name="gridLayout_5" columnstretch="1,2">
<item row="0" column="0">
<widget class="QRadioButton" name="delimiterSelection">
<property name="text">
@@ -121,70 +121,7 @@
</property>
</widget>
</item>
- <item row="2" column="1">
- <widget class="QCheckBox" name="cbxDelimSemicolon">
- <property name="text">
- <string>Semicolon</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QCheckBox" name="cbxDelimTab">
- <property name="text">
- <string>Tab</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QCheckBox" name="cbxDelimSpace">
- <property name="text">
- <string>Space</string>
- </property>
- <property name="checked">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QCheckBox" name="cbxDelimComma">
- <property name="text">
- <string>Comma</string>
- </property>
- </widget>
- </item>
- <item row="4" column="1">
- <widget class="QCheckBox" name="cbxDelimColon">
- <property name="text">
- <string>Colon</string>
- </property>
- </widget>
- </item>
- <item row="4" column="0">
- <widget class="QLineEdit" name="txtDelimiter">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="maximumSize">
- <size>
- <width>32767</width>
- <height>32767</height>
- </size>
- </property>
- <property name="toolTip">
- <string>Delimiter to use when splitting fields in the text file. The delimiter can be more than one character.</string>
- </property>
- <property name="whatsThis">
- <string>Delimiter to use when splitting fields in the delimited text file. The delimiter can be 1 or more characters in length.</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
+ <item row="5" column="0">
<widget class="QRadioButton" name="delimiterRegexp">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
@@ -222,10 +159,77 @@
</property>
</widget>
</item>
+ <item row="0" column="1">
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QCheckBox" name="cbxDelimTab">
+ <property name="text">
+ <string>Tab</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QCheckBox" name="cbxDelimSpace">
+ <property name="text">
+ <string>Space</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QCheckBox" name="cbxDelimComma">
+ <property name="text">
+ <string>Comma</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QCheckBox" name="cbxDelimSemicolon">
+ <property name="text">
+ <string>Semicolon</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QCheckBox" name="cbxDelimColon">
+ <property name="text">
+ <string>Colon</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="txtDelimiter">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Delimiter to use when splitting fields in the text file. The delimiter can be more than one character.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Delimiter to use when splitting fields in the delimited text file. The delimiter can be 1 or more characters in length.</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
- <item>
+ <item row="2" column="0">
<widget class="QWidget" name="widget_5" native="true">
<property name="enabled">
<bool>true</bool>
@@ -236,7 +240,7 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
- <layout class="QGridLayout" name="gridLayout_6">
+ <layout class="QGridLayout" name="gridLayout_6" columnstretch="1,2">
<item row="1" column="1">
<widget class="QSpinBox" name="rowCounter">
<property name="minimumSize">
@@ -275,50 +279,117 @@
</layout>
</widget>
</item>
- <item>
- <widget class="QWidget" name="widget_2" native="true">
+ <item row="3" column="0">
+ <widget class="QFrame" name="gridFrame_2">
<layout class="QGridLayout" name="gridLayout_2">
- <item row="0" column="2">
- <widget class="QLabel" name="textLabelx">
- <property name="text">
- <string><p align="right">X field</p></string>
- </property>
- </widget>
+ <item row="0" column="0" colspan="3">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QRadioButton" name="geomTypeXY">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="whatsThis">
+ <string>The file contains X and Y coordinate columns</string>
+ </property>
+ <property name="text">
+ <string>X Y fields</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="textLabelx">
+ <property name="text">
+ <string><p align="right">X field</p></string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="cmbXField">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>120</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Name of the field containing x values</string>
+ </property>
+ <property name="whatsThis">
+ <string>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.</string>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="textLabely">
+ <property name="text">
+ <string><p align="right">Y field</p></string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="cmbYField">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>120</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Name of the field containing y values</string>
+ </property>
+ <property name="whatsThis">
+ <string>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.</string>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
</item>
- <item row="0" column="3">
- <widget class="QComboBox" name="cmbXField">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
+ <item row="1" column="0">
+ <widget class="QRadioButton" name="geomTypeWKT">
+ <property name="enabled">
+ <bool>false</bool>
</property>
- <property name="minimumSize">
- <size>
- <width>120</width>
- <height>0</height>
- </size>
- </property>
- <property name="toolTip">
- <string>Name of the field containing x values</string>
- </property>
<property name="whatsThis">
- <string>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.</string>
+ <string>The file contains a well known text geometry field</string>
</property>
- <property name="editable">
- <bool>true</bool>
+ <property name="text">
+ <string>WKT field</string>
</property>
</widget>
</item>
- <item row="0" column="5">
- <widget class="QLabel" name="textLabely">
- <property name="text">
- <string><p align="right">Y field</p></string>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="cmbWktField">
+ <property name="enabled">
+ <bool>false</bool>
</property>
- </widget>
- </item>
- <item row="0" column="6">
- <widget class="QComboBox" name="cmbYField">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
@@ -342,20 +413,33 @@
</property>
</widget>
</item>
+ <item row="1" column="2">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>177</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
</layout>
</widget>
</item>
- <item>
+ <item row="4" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Sample text</string>
</property>
</widget>
</item>
- <item>
+ <item row="5" column="0">
<widget class="QTableWidget" name="tblSample"/>
</item>
- <item>
+ <item row="6" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -376,8 +460,25 @@
</customwidget>
</customwidgets>
<tabstops>
+ <tabstop>txtFilePath</tabstop>
+ <tabstop>btnBrowseForFile</tabstop>
+ <tabstop>txtLayerName</tabstop>
+ <tabstop>delimiterSelection</tabstop>
+ <tabstop>cbxDelimTab</tabstop>
+ <tabstop>cbxDelimSpace</tabstop>
+ <tabstop>cbxDelimComma</tabstop>
+ <tabstop>cbxDelimSemicolon</tabstop>
+ <tabstop>cbxDelimColon</tabstop>
+ <tabstop>delimiterPlain</tabstop>
+ <tabstop>delimiterRegexp</tabstop>
+ <tabstop>txtDelimiter</tabstop>
+ <tabstop>rowCounter</tabstop>
+ <tabstop>geomTypeXY</tabstop>
<tabstop>cmbXField</tabstop>
<tabstop>cmbYField</tabstop>
+ <tabstop>geomTypeWKT</tabstop>
+ <tabstop>cmbWktField</tabstop>
+ <tabstop>tblSample</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources>
@@ -395,8 +496,8 @@
<y>121</y>
</hint>
<hint type="destinationlabel">
- <x>282</x>
- <y>115</y>
+ <x>445</x>
+ <y>113</y>
</hint>
</hints>
</connection>
@@ -411,8 +512,8 @@
<y>110</y>
</hint>
<hint type="destinationlabel">
- <x>277</x>
- <y>149</y>
+ <x>286</x>
+ <y>113</y>
</hint>
</hints>
</connection>
@@ -427,8 +528,8 @@
<y>109</y>
</hint>
<hint type="destinationlabel">
- <x>281</x>
- <y>175</y>
+ <x>445</x>
+ <y>138</y>
</hint>
</hints>
</connection>
@@ -443,8 +544,8 @@
<y>114</y>
</hint>
<hint type="destinationlabel">
- <x>293</x>
- <y>203</y>
+ <x>286</x>
+ <y>138</y>
</hint>
</hints>
</connection>
@@ -459,8 +560,8 @@
<y>114</y>
</hint>
<hint type="destinationlabel">
- <x>118</x>
- <y>218</y>
+ <x>397</x>
+ <y>165</y>
</hint>
</hints>
</connection>
@@ -475,8 +576,8 @@
<y>113</y>
</hint>
<hint type="destinationlabel">
- <x>301</x>
- <y>225</y>
+ <x>531</x>
+ <y>138</y>
</hint>
</hints>
</connection>
Modified: trunk/qgis/src/providers/delimitedtext/qgsdelimitedtextprovider.cpp
===================================================================
--- trunk/qgis/src/providers/delimitedtext/qgsdelimitedtextprovider.cpp 2010-11-28 20:48:26 UTC (rev 14780)
+++ trunk/qgis/src/providers/delimitedtext/qgsdelimitedtextprovider.cpp 2010-11-29 01:47:52 UTC (rev 14781)
@@ -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::OpenMode>( 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;
Modified: trunk/qgis/src/providers/delimitedtext/qgsdelimitedtextprovider.h
===================================================================
--- trunk/qgis/src/providers/delimitedtext/qgsdelimitedtextprovider.h 2010-11-28 20:48:26 UTC (rev 14780)
+++ trunk/qgis/src/providers/delimitedtext/qgsdelimitedtextprovider.h 2010-11-29 01:47:52 UTC (rev 14781)
@@ -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<int> 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 );
More information about the QGIS-commit
mailing list