Skip to content

Commit 8e25124

Browse files
author
homann
committed
Automatically adds projections previously unknown to QGIS (but still valid) as a Custom CRS. This can later be edited for name etc. No user interaction required, one new text to translate. Fixes #418.
git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@11366 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent 061a839 commit 8e25124

File tree

2 files changed

+172
-8
lines changed

2 files changed

+172
-8
lines changed

src/core/qgscoordinatereferencesystem.cpp

Lines changed: 163 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "qgsmessageoutput.h"
3232
#include "qgis.h" //const vals declared here
3333

34+
#include <cassert>
3435
#include <sqlite3.h>
3536

3637
//gdal and ogr includes (needed for == operator)
@@ -349,18 +350,20 @@ bool QgsCoordinateReferenceSystem::createFromProj4( const QString theProj4String
349350
* have been set if this method has been delegated to from createFromWkt.
350351
* Normally we wouldnt expect this to work, but its worth trying first
351352
* as its quicker than methods below..
352-
*/
353+
*/
353354
long mySrsId = 0;
354355
QgsCoordinateReferenceSystem::RecordMap myRecord;
355-
if ( !mDescription.trimmed().isEmpty() )
356-
{
357-
myRecord = getRecord( "select * from tbl_srs where description='" + mDescription.trimmed() + "'" );
358-
}
356+
357+
// *** Matching on descriptions feels iffy. Different projs can have same description. Homann ***
358+
// if ( !mDescription.trimmed().isEmpty() )
359+
//{
360+
// myRecord = getRecord( "select * from tbl_srs where description='" + mDescription.trimmed() + "'" );
361+
//}
359362

360363
/*
361364
* - if the above does not match perform a whole text search on proj4 string (if not null)
362365
*/
363-
QgsDebugMsg( "wholetext match on name failed, trying proj4string match" );
366+
// QgsDebugMsg( "wholetext match on name failed, trying proj4string match" );
364367
myRecord = getRecord( "select * from tbl_srs where parameters='" + theProj4String.trimmed() + "'" );
365368
if ( !myRecord.empty() )
366369
{
@@ -434,7 +437,34 @@ bool QgsCoordinateReferenceSystem::createFromProj4( const QString theProj4String
434437
// if we failed to look up the projection in database, don't worry. we can still use it :)
435438
if ( !mIsValidFlag )
436439
{
440+
QgsDebugMsg( "Projection is not found in databases." );
437441
setProj4String( theProj4String );
442+
// Is the SRS is valid now, we know it's a decent +proj string that can be entered into the srs.db
443+
if ( mIsValidFlag )
444+
{
445+
// Try to save. If not possible, set to invalid. Problems on read only systems?
446+
QgsDebugMsg( "Projection appears to be valid. Save to database!" );
447+
mIsValidFlag = saveAsUserCRS();
448+
// The srsid is not set, we should do that now.
449+
if ( mIsValidFlag )
450+
{
451+
myRecord = getRecord( "select * from tbl_srs where parameters='" + theProj4String.trimmed() + "'" );
452+
if ( !myRecord.empty() )
453+
{
454+
mySrsId = myRecord["srs_id"].toLong();
455+
QgsDebugMsg( "proj4string match search for srsid returned srsid: " + QString::number( mySrsId ) );
456+
if ( mySrsId > 0 )
457+
{
458+
createFromSrsId( mySrsId );
459+
}
460+
else
461+
{
462+
QgsDebugMsg( "Couldn't find newly added proj string?" );
463+
mIsValidFlag = false;
464+
}
465+
}
466+
}
467+
}
438468
}
439469

440470

@@ -610,7 +640,8 @@ QString QgsCoordinateReferenceSystem::toProj4() const
610640
toProj4 = proj4src;
611641
CPLFree( proj4src );
612642

613-
return toProj4;
643+
// Stray spaces at the end?
644+
return toProj4.trimmed();
614645
}
615646

616647
bool QgsCoordinateReferenceSystem::geographicFlag() const
@@ -740,7 +771,7 @@ long QgsCoordinateReferenceSystem::findMatchingProj()
740771
QgsDebugMsg( "entered." );
741772
if ( mEllipsoidAcronym.isNull() || mProjectionAcronym.isNull() || !mIsValidFlag )
742773
{
743-
QgsLogger::warning( "QgsCoordinateReferenceSystem::findMatchingProj will only work if prj acr ellipsoid acr and proj4string are set!..." );
774+
QgsDebugMsg( "QgsCoordinateReferenceSystem::findMatchingProj will only work if prj acr ellipsoid acr and proj4string are set!..." );
744775
return 0;
745776
}
746777

@@ -1122,3 +1153,127 @@ QString QgsCoordinateReferenceSystem::validationHint()
11221153
{
11231154
return mValidationHint;
11241155
}
1156+
1157+
/// Copied from QgsCustomProjectionDialog ///
1158+
/// Please refactor into SQL handler !!! ///
1159+
1160+
bool QgsCoordinateReferenceSystem::saveAsUserCRS()
1161+
{
1162+
1163+
if ( ! mIsValidFlag )
1164+
{
1165+
QgsDebugMsg( "Can't save an invalid CRS!" );
1166+
return false;
1167+
}
1168+
1169+
QString mySql;
1170+
QString myName = QString( " * %1 (%2)" )
1171+
.arg( QObject::tr( "Generated CRS", "A CRS automatically generated from layer info get this prefix for description" ))
1172+
.arg( toProj4() );
1173+
1174+
//if this is the first record we need to ensure that its srs_id is 10000. For
1175+
//any rec after that sqlite3 will take care of the autonumering
1176+
//this was done to support sqlite 3.0 as it does not yet support
1177+
//the autoinc related system tables.
1178+
if ( getRecordCount() == 0 )
1179+
{
1180+
mySql = QString( "insert into tbl_srs (srs_id,description,projection_acronym,ellipsoid_acronym,parameters,is_geo) " )
1181+
+ " values (" + QString::number( USER_CRS_START_ID ) + ",'"
1182+
+ sqlSafeString( myName ) + "','" + projectionAcronym()
1183+
+ "','" + ellipsoidAcronym() + "','" + sqlSafeString( toProj4() )
1184+
+ "',0)"; // <-- is_geo shamelessly hard coded for now
1185+
}
1186+
else
1187+
{
1188+
mySql = "insert into tbl_srs (description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values ('"
1189+
+ sqlSafeString( myName ) + "','" + projectionAcronym()
1190+
+ "','" + ellipsoidAcronym() + "','" + sqlSafeString( toProj4() )
1191+
+ "',0)"; // <-- is_geo shamelessly hard coded for now
1192+
}
1193+
sqlite3 *myDatabase;
1194+
const char *myTail;
1195+
sqlite3_stmt *myPreparedStatement;
1196+
int myResult;
1197+
//check the db is available
1198+
myResult = sqlite3_open( QgsApplication::qgisUserDbFilePath().toUtf8().data(), &myDatabase );
1199+
if ( myResult != SQLITE_OK )
1200+
{
1201+
QgsDebugMsg( QString( "Can't open database: %1 \n please notify QGIS developers of this error \n %2 (file name) " ).arg( sqlite3_errmsg( myDatabase ) ).arg( QgsApplication::qgisUserDbFilePath() ) );
1202+
// XXX This will likely never happen since on open, sqlite creates the
1203+
// database if it does not exist.
1204+
assert( myResult == SQLITE_OK );
1205+
}
1206+
QgsDebugMsg( QString( "Update or insert sql \n%1" ).arg( mySql ) );
1207+
myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.length(), &myPreparedStatement, &myTail );
1208+
sqlite3_step( myPreparedStatement );
1209+
// XXX Need to free memory from the error msg if one is set
1210+
return myResult == SQLITE_OK;
1211+
1212+
}
1213+
1214+
long QgsCoordinateReferenceSystem::getRecordCount()
1215+
{
1216+
sqlite3 *myDatabase;
1217+
const char *myTail;
1218+
sqlite3_stmt *myPreparedStatement;
1219+
int myResult;
1220+
long myRecordCount = 0;
1221+
//check the db is available
1222+
myResult = sqlite3_open( QgsApplication::qgisUserDbFilePath().toUtf8().data(), &myDatabase );
1223+
if ( myResult != SQLITE_OK )
1224+
{
1225+
QgsDebugMsg( QString( "Can't open database: %1" ).arg( sqlite3_errmsg( myDatabase ) ) );
1226+
// XXX This will likely never happen since on open, sqlite creates the
1227+
// database if it does not exist.
1228+
assert( myResult == SQLITE_OK );
1229+
}
1230+
// Set up the query to retrieve the projection information needed to populate the ELLIPSOID list
1231+
QString mySql = "select count(*) from tbl_srs";
1232+
myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.length(), &myPreparedStatement, &myTail );
1233+
// XXX Need to free memory from the error msg if one is set
1234+
if ( myResult == SQLITE_OK )
1235+
{
1236+
if ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
1237+
{
1238+
QString myRecordCountString = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) );
1239+
myRecordCount = myRecordCountString.toLong();
1240+
}
1241+
}
1242+
// close the sqlite3 statement
1243+
sqlite3_finalize( myPreparedStatement );
1244+
sqlite3_close( myDatabase );
1245+
return myRecordCount;
1246+
1247+
}
1248+
1249+
const QString QgsCoordinateReferenceSystem::sqlSafeString( const QString theSQL )
1250+
{
1251+
1252+
QString myRetval;
1253+
QChar *it = ( QChar * )theSQL.unicode();
1254+
for ( int i = 0; i < theSQL.length(); i++ )
1255+
{
1256+
if ( *it == '\"' )
1257+
{
1258+
myRetval += "\\\"";
1259+
}
1260+
else if ( *it == '\'' )
1261+
{
1262+
myRetval += "\\'";
1263+
}
1264+
else if ( *it == '\\' )
1265+
{
1266+
myRetval += "\\\\";
1267+
}
1268+
else if ( *it == '%' )
1269+
{
1270+
myRetval += "\\%";
1271+
}
1272+
else
1273+
{
1274+
myRetval += *it;
1275+
}
1276+
it++;
1277+
}
1278+
return myRetval;
1279+
}

src/core/qgscoordinatereferencesystem.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,15 @@ class CORE_EXPORT QgsCoordinateReferenceSystem
387387
//! Work out the projection units and set the appropriate local variable
388388
void setMapUnits();
389389

390+
//! Save the proj4-string as a custom CRS
391+
bool saveAsUserCRS();
392+
393+
//! Helper for getting number of user CRS already in db
394+
long getRecordCount();
395+
396+
//! Helper for sql-safin strings
397+
const QString sqlSafeString( const QString theSQL );
398+
390399
void *mCRS;
391400

392401
bool loadFromDb( QString db, QString field, long id );

0 commit comments

Comments
 (0)