Merge pull request #343 from homann/qgsexpression_DA

Settings for measurements ellipsoid moved, fix for #3296 and #4252.
This commit is contained in:
Magnus Homann 2012-12-01 04:14:38 -08:00
commit 53790add9b
24 changed files with 420 additions and 289 deletions

View File

@ -61,6 +61,10 @@ class QgsExpression
//! (used by internal functions)
QgsDistanceArea* geomCalculator();
//! Sets the geometry calculator used in evaluation of expressions,
// instead of the default.
void setGeomCalculator( QgsDistanceArea& calc );
/** This function currently replaces each expression between [% and %]
in the string with the result of its evaluation on the feature
passed as argument.

View File

@ -17,6 +17,11 @@ class QgsExpressionBuilderDialog : QDialog
QString expressionText();
/** Sets geometry calculator used in distance/area calculations.
* @note added in version 2.0
*/
void setGeomCalculator( const QgsDistanceArea & da );
protected:
/**
* Handle closing of the window

View File

@ -84,6 +84,11 @@ class QgsExpressionBuilderWidget : QWidget
void loadFieldNames( QMap<int, QgsField> fields );
/** Sets geometry calculator used in distance/area calculations.
* @note added in version 2.0
*/
void setGeomCalculator( const QgsDistanceArea & da );
/** Gets the expression string that has been set in the expression area.
* @returns The expression as a string. */
QString expressionText();

View File

@ -23,6 +23,9 @@ back to QgsVectorLayer.
#include "qgsattributeactiondialog.h"
#include "qgsattributeaction.h"
#include "qgsexpressionbuilderdialog.h"
#include "qgisapp.h"
#include "qgsproject.h"
#include "qgsmapcanvas.h"
#include <QFileDialog>
#include <QHeaderView>
@ -173,6 +176,13 @@ void QgsAttributeActionDialog::insertExpression()
// display the expression builder
QgsExpressionBuilderDialog dlg( mActions->layer(), selText, this );
dlg.setWindowTitle( tr( "Insert expression" ) );
QgsDistanceArea myDa;
myDa.setSourceCrs( mActions->layer()->crs().srsid() );
myDa.setEllipsoidalMode( QgisApp::instance()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled() );
myDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
dlg.setGeomCalculator( myDa );
if ( dlg.exec() == QDialog::Accepted )
{
QString expression = dlg.expressionBuilder()->expressionText();

View File

@ -17,7 +17,8 @@
#include "qgsattributedialog.h"
#include "qgsfield.h"
#include "qgslogger.h"
#include "qgsmapcanvas.h"
#include "qgsproject.h"
#include "qgsvectorlayer.h"
#include "qgsvectordataprovider.h"
#include "qgsuniquevaluerenderer.h"
@ -218,6 +219,13 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
}
else
{
QgsDistanceArea myDa;
myDa.setSourceCrs( vl->crs().srsid() );
myDa.setEllipsoidalMode( QgisApp::instance()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled() );
myDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
for ( QgsFieldMap::const_iterator it = theFieldMap.begin(); it != theFieldMap.end(); ++it )
{
QList<QWidget *> myWidgets = mDialog->findChildren<QWidget*>( it->name() );
@ -258,6 +266,8 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
}
}
exp.setGeomCalculator( myDa );
QVariant value = exp.evaluate( mFeature, vl->pendingFields() );
if ( !exp.hasEvalError() )

View File

@ -32,6 +32,7 @@
#include "qgssearchquerybuilder.h"
#include "qgslogger.h"
#include "qgsmapcanvas.h"
#include "qgsproject.h"
#include "qgsfieldcalculator.h"
#include "qgsfeatureaction.h"
#include "qgsattributeaction.h"
@ -536,6 +537,13 @@ void QgsAttributeTableDialog::updateSelectionFromLayer()
void QgsAttributeTableDialog::doSearch( QString searchString )
{
QgsDistanceArea myDa;
myDa.setSourceCrs( mLayer->crs().srsid() );
myDa.setEllipsoidalMode( QgisApp::instance()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled() );
myDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
// parse search string and build parsed tree
QgsExpression search( searchString );
if ( search.hasParserError() )
@ -556,6 +564,7 @@ void QgsAttributeTableDialog::doSearch( QString searchString )
QApplication::setOverrideCursor( Qt::WaitCursor );
mSelectedFeatures.clear();
search.setGeomCalculator( myDa );
if ( cbxSearchSelectedOnly->isChecked() )
{
QgsFeatureList selectedFeatures = mLayer->selectedFeatures();

View File

@ -13,12 +13,17 @@
* *
***************************************************************************/
#include "qgisapp.h"
#include "qgsfieldcalculator.h"
#include "qgsdistancearea.h"
#include "qgsexpression.h"
#include "qgsmapcanvas.h"
#include "qgsproject.h"
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"
#include <QMessageBox>
#include <QSettings>
QgsFieldCalculator::QgsFieldCalculator( QgsVectorLayer* vl )
: QDialog()
@ -78,6 +83,15 @@ QgsFieldCalculator::~QgsFieldCalculator()
void QgsFieldCalculator::accept()
{
// Set up QgsDistanceArea each time we (re-)calculate
QgsDistanceArea myDa;
myDa.setSourceCrs( mVectorLayer->crs().srsid() );
myDa.setEllipsoidalMode( QgisApp::instance()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled() );
myDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
QString calcString = builder->expressionText();
QgsExpression exp( calcString );
@ -163,6 +177,7 @@ void QgsFieldCalculator::accept()
}
exp.setCurrentRowNumber( rownum );
exp.setGeomCalculator( myDa );
QVariant value = exp.evaluate( &feature );
if ( exp.hasEvalError() )

View File

@ -25,7 +25,8 @@
#include "qgslabelengineconfigdialog.h"
#include "qgsexpressionbuilderdialog.h"
#include "qgsexpression.h"
#include "qgsmapcanvas.h"
#include "qgisapp.h"
#include "qgsproject.h"
#include "qgscharacterselectdialog.h"
#include <QColorDialog>
@ -901,6 +902,13 @@ void QgsLabelingGui::showExpressionDialog()
{
QgsExpressionBuilderDialog dlg( mLayer, cboFieldName->currentText() , this );
dlg.setWindowTitle( tr( "Expression based label" ) );
QgsDistanceArea myDa;
myDa.setSourceCrs( mLayer->crs().srsid() );
myDa.setEllipsoidalMode( QgisApp::instance()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled() );
myDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
dlg.setGeomCalculator( myDa );
if ( dlg.exec() == QDialog::Accepted )
{
QString expression = dlg.expressionText();

View File

@ -214,7 +214,8 @@ bool QgsMapToolIdentify::identifyVectorLayer( QgsVectorLayer *layer, int x, int
// load identify radius from settings
QSettings settings;
double identifyValue = settings.value( "/Map/identifyRadius", QGis::DEFAULT_IDENTIFY_RADIUS ).toDouble();
QString ellipsoid = settings.value( "/qgis/measure/ellipsoid", GEO_NONE ).toString();
QString ellipsoid = QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE );
if ( identifyValue <= 0.0 )
identifyValue = QGis::DEFAULT_IDENTIFY_RADIUS;

View File

@ -19,6 +19,7 @@
#include "qgslogger.h"
#include "qgsmapcanvas.h"
#include "qgsmaptopixel.h"
#include "qgsproject.h"
#include "qgsrubberband.h"
#include <QMouseEvent>
#include <QSettings>
@ -182,7 +183,7 @@ void QgsMapToolMeasureAngle::updateSettings()
void QgsMapToolMeasureAngle::configureDistanceArea()
{
QSettings settings;
QString ellipsoidId = settings.value( "/qgis/measure/ellipsoid", GEO_NONE ).toString();
QString ellipsoidId = QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE );
mDa.setSourceCrs( mCanvas->mapRenderer()->destinationCrs().srsid() );
mDa.setEllipsoid( ellipsoidId );
// Only use ellipsoidal calculation when project wide transformation is enabled.

View File

@ -22,6 +22,7 @@
#include "qgsdistancearea.h"
#include "qgsmapcanvas.h"
#include "qgsmaprenderer.h"
#include "qgsproject.h"
#include "qgscoordinatereferencesystem.h"
#include <QCloseEvent>
@ -60,7 +61,7 @@ void QgsMeasureDialog::updateSettings()
mDisplayUnits = QGis::fromLiteral( settings.value( "/qgis/measure/displayunits", QGis::toLiteral( QGis::Meters ) ).toString() );
// Configure QgsDistanceArea
mDa.setSourceCrs( mTool->canvas()->mapRenderer()->destinationCrs().srsid() );
mDa.setEllipsoid( settings.value( "/qgis/measure/ellipsoid", GEO_NONE ).toString() );
mDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
// Only use ellipsoidal calculation when project wide transformation is enabled.
if ( mTool->canvas()->mapRenderer()->hasCrsTransformEnabled() )
{

View File

@ -58,7 +58,6 @@
#include <cpl_conv.h> // for setting gdal options
#include "qgsconfig.h"
const char * QgsOptions::GEO_NONE_DESC = QT_TRANSLATE_NOOP( "QgsOptions", "None / Planimetric" );
/**
* \class QgsOptions - Set user options and preferences
@ -82,8 +81,6 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WFlags fl ) :
connect( mFontFamilyRadioCustom, SIGNAL( released() ), this, SLOT( updateAppStyleSheet() ) );
connect( mFontFamilyComboBox, SIGNAL( currentFontChanged( const QFont& ) ), this, SLOT( updateAppStyleSheet() ) );
connect( cmbEllipsoid, SIGNAL( currentIndexChanged( int ) ), this, SLOT( updateEllipsoidUI( int ) ) );
#ifdef Q_WS_X11
connect( chkEnableBackbuffer, SIGNAL( stateChanged( int ) ), this, SLOT( toggleEnableBackbuffer( int ) ) );
#endif
@ -286,34 +283,6 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WFlags fl ) :
//display the crs as friendly text rather than in wkt
leProjectGlobalCrs->setText( mDefaultCrs.authid() + " - " + mDefaultCrs.description() );
// populate combo box with ellipsoids
QgsDebugMsg( "Setting upp ellipsoid" );
mEllipsoidIndex = 0;
populateEllipsoidList();
// Reading ellipsoid from setttings
QStringList mySplitEllipsoid = settings.value( "/qgis/measure/ellipsoid", GEO_NONE ).toString().split( ':' );
int myIndex = 0;
int i;
for ( i = 0; i < mEllipsoidList.length(); i++ )
{
if ( mEllipsoidList[ i ].acronym.startsWith( mySplitEllipsoid[ 0 ] ) )
{
myIndex = i;
break;
}
}
// Update paramaters if present.
if ( mySplitEllipsoid.length() >= 3 )
{
mEllipsoidList[ myIndex ].semiMajor = mySplitEllipsoid[ 1 ].toDouble();
mEllipsoidList[ myIndex ].semiMinor = mySplitEllipsoid[ 2 ].toDouble();
}
updateEllipsoidUI( myIndex );
// Set the units for measuring
QGis::UnitType myDisplayUnits = QGis::fromLiteral( settings.value( "/qgis/measure/displayunits", QGis::toLiteral( QGis::Meters ) ).toString() );
@ -1000,26 +969,6 @@ void QgsOptions::saveOptions()
settings.setValue( "/Projections/otfTransformEnabled", chkOtfTransform->isChecked() );
settings.setValue( "/Projections/projectDefaultCrs", mDefaultCrs.authid() );
if ( mEllipsoidList[ mEllipsoidIndex ].acronym.startsWith( "PARAMETER" ) )
{
double major = mEllipsoidList[ mEllipsoidIndex ].semiMajor;
double minor = mEllipsoidList[ mEllipsoidIndex ].semiMinor;
// If the user fields have changed, use them instead.
if ( leSemiMajor->isModified() || leSemiMinor->isModified() )
{
QgsDebugMsg( "Using paramteric major/minor" );
major = QLocale::system().toDouble( leSemiMajor->text() );
minor = QLocale::system().toDouble( leSemiMinor->text() );
}
settings.setValue( "/qgis/measure/ellipsoid", QString( "PARAMETER:%1:%2" )
.arg( major, 0, 'g', 17 )
.arg( minor, 0, 'g', 17 ) );
}
else
{
settings.setValue( "/qgis/measure/ellipsoid", mEllipsoidList[ mEllipsoidIndex ].acronym );
}
if ( radFeet->isChecked() )
{
settings.setValue( "/qgis/measure/displayunits", QGis::toLiteral( QGis::Feet ) );
@ -1245,88 +1194,6 @@ bool QgsOptions::newVisible()
{
return chkAddedVisibility->isChecked();
}
void QgsOptions::populateEllipsoidList()
{
//
// Populate the ellipsoid list
//
sqlite3 *myDatabase;
const char *myTail;
sqlite3_stmt *myPreparedStatement;
int myResult;
EllipsoidDefs myItem, i;
myItem.acronym = GEO_NONE;
myItem.description = tr( GEO_NONE_DESC );
myItem.semiMajor = 0.0;
myItem.semiMinor = 0.0;
mEllipsoidList.append( myItem );
myItem.acronym = QString( "PARAMETER:6370997:6370997" );
myItem.description = tr( "Parameters :" );
myItem.semiMajor = 6370997.0;
myItem.semiMinor = 6370997.0;
mEllipsoidList.append( myItem );
//check the db is available
myResult = sqlite3_open_v2( QgsApplication::srsDbFilePath().toUtf8().data(), &myDatabase, SQLITE_OPEN_READONLY, NULL );
if ( myResult )
{
QgsDebugMsg( QString( "Can't open database: %1" ).arg( sqlite3_errmsg( myDatabase ) ) );
// XXX This will likely never happen since on open, sqlite creates the
// database if it does not exist.
Q_ASSERT( myResult == 0 );
}
// Set up the query to retrieve the projection information needed to populate the ELLIPSOID list
QString mySql = "select acronym, name, radius, parameter2 from tbl_ellipsoid order by name";
myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
// XXX Need to free memory from the error msg if one is set
if ( myResult == SQLITE_OK )
{
while ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
{
QString para1, para2;
myItem.acronym = ( const char * )sqlite3_column_text( myPreparedStatement, 0 );
myItem.description = ( const char * )sqlite3_column_text( myPreparedStatement, 1 );
// Copied from QgsDistanecArea. Should perhaps be moved there somehow?
// No error checking, this values are for show only, never used in calculations.
// Fall-back values
myItem.semiMajor = 0.0;
myItem.semiMinor = 0.0;
// Crash if no column?
para1 = ( const char * )sqlite3_column_text( myPreparedStatement, 2 );
para2 = ( const char * )sqlite3_column_text( myPreparedStatement, 3 );
myItem.semiMajor = para1.mid( 2 ).toDouble();
if ( para2.left( 2 ) == "b=" )
{
myItem.semiMinor = para2.mid( 2 ).toDouble();
}
else if ( para2.left( 3 ) == "rf=" )
{
double invFlattening = para2.mid( 3 ).toDouble();
if ( invFlattening != 0.0 )
{
myItem.semiMinor = myItem.semiMajor - ( myItem.semiMajor / invFlattening );
}
}
mEllipsoidList.append( myItem );
}
}
// close the sqlite3 statement
sqlite3_finalize( myPreparedStatement );
sqlite3_close( myDatabase );
// Add all items to selector
foreach ( i, mEllipsoidList )
{
cmbEllipsoid->addItem( i.description );
}
}
QStringList QgsOptions::i18nList()
{
@ -1736,53 +1603,3 @@ void QgsOptions::saveContrastEnhancement( QComboBox *cbox, QString name )
settings.setValue( "/Raster/defaultContrastEnhancementAlgorithm/" + name, value );
}
void QgsOptions::updateEllipsoidUI( int newIndex )
{
// Called whenever settings change, adjusts the UI accordingly
// Pre-select current ellipsoid
// Check if CRS transformation is on, or else turn everything off
double myMajor = mEllipsoidList[ newIndex ].semiMajor;
double myMinor = mEllipsoidList[ newIndex ].semiMinor;
// If user has modified the radii (only possible if parametric!), before
// changing ellipsoid, save the modified coordinates
if ( leSemiMajor->isModified() || leSemiMinor->isModified() )
{
QgsDebugMsg( "Saving major/minor" );
mEllipsoidList[ mEllipsoidIndex ].semiMajor = QLocale::system().toDouble( leSemiMajor->text() );
mEllipsoidList[ mEllipsoidIndex ].semiMinor = QLocale::system().toDouble( leSemiMinor->text() );
}
mEllipsoidIndex = newIndex;
leSemiMajor->setEnabled( false );
leSemiMinor->setEnabled( false );
leSemiMajor->setText( "" );
leSemiMinor->setText( "" );
if ( QgisApp::instance()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled() )
{
cmbEllipsoid->setEnabled( true );
cmbEllipsoid->setToolTip( "" );
if ( mEllipsoidList[ mEllipsoidIndex ].acronym.startsWith( "PARAMETER:" ) )
{
leSemiMajor->setEnabled( true );
leSemiMinor->setEnabled( true );
}
else
{
leSemiMajor->setToolTip( QString( "Select %1 from pull-down menu to adjust radii" ).arg( tr( "Parameters:" ) ) );
leSemiMinor->setToolTip( QString( "Select %1 from pull-down menu to adjust radii" ).arg( tr( "Parameters:" ) ) );
}
cmbEllipsoid->setCurrentIndex( mEllipsoidIndex ); // Not always necessary
if ( mEllipsoidList[ mEllipsoidIndex ].acronym != GEO_NONE )
{
leSemiMajor->setText( QLocale::system().toString( myMajor, 'f', 3 ) );
leSemiMinor->setText( QLocale::system().toString( myMinor, 'f', 3 ) );
}
}
else
{
cmbEllipsoid->setEnabled( false );
cmbEllipsoid->setToolTip( tr( "Can only use ellipsoidal calculations when CRS transformation is enabled" ) );
}
}

View File

@ -189,12 +189,6 @@ class QgsOptions : public QDialog, private Ui::QgsOptionsBase
*/
void saveGdalDriverList();
/* Update ComboBox accorindg to the selected new index
* Also sets the new selected Ellipsoid.
* @note added in 2.0
*/
void updateEllipsoidUI( int newIndex );
private:
QStringList i18nList();
void initContrastEnhancement( QComboBox *cbox, QString name, QString defaultVal );
@ -203,21 +197,6 @@ class QgsOptions : public QDialog, private Ui::QgsOptionsBase
QgsCoordinateReferenceSystem mLayerDefaultCrs;
bool mLoadedGdalDriverList;
// List for all ellispods, also None and Custom
struct EllipsoidDefs
{
QString acronym;
QString description;
double semiMajor;
double semiMinor;
};
QList<EllipsoidDefs> mEllipsoidList;
int mEllipsoidIndex;
//! Populates list with ellipsoids from Sqlite3 db
void populateEllipsoidList();
static const char * GEO_NONE_DESC;
};
#endif // #ifndef QGSOPTIONS_H

View File

@ -19,6 +19,8 @@
#include "qgsprojectproperties.h"
//qgis includes
#include "qgsapplication.h"
#include "qgsdistancearea.h"
#include "qgisapp.h"
#include "qgscomposer.h"
#include "qgscontexthelp.h"
@ -50,11 +52,16 @@
#include <QHeaderView> // Qt 4.4
#include <QMessageBox>
const char * QgsProjectProperties::GEO_NONE_DESC = QT_TRANSLATE_NOOP( "QgsOptions", "None / Planimetric" );
//stdc++ includes
QgsProjectProperties::QgsProjectProperties( QgsMapCanvas* mapCanvas, QWidget *parent, Qt::WFlags fl )
: QDialog( parent, fl )
, mMapCanvas( mapCanvas )
, mEllipsoidList()
, mEllipsoidIndex( 0 )
{
setupUi( this );
connect( buttonBox, SIGNAL( accepted() ), this, SLOT( accept() ) );
@ -63,6 +70,8 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas* mapCanvas, QWidget *pa
connect( this, SIGNAL( accepted() ), this, SLOT( apply() ) );
connect( projectionSelector, SIGNAL( sridSelected( QString ) ), this, SLOT( setMapUnitsToCurrentProjection() ) );
connect( cmbEllipsoid, SIGNAL( currentIndexChanged( int ) ), this, SLOT( updateEllipsoidUI( int ) ) );
///////////////////////////////////////////////////////////
// Properties stored in map canvas's QgsMapRenderer
// these ones are propagated to QgsProject by a signal
@ -104,6 +113,34 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas* mapCanvas, QWidget *pa
cbxAbsolutePath->setCurrentIndex( QgsProject::instance()->readBoolEntry( "Paths", "/Absolute", true ) ? 0 : 1 );
// populate combo box with ellipsoids
QgsDebugMsg( "Setting upp ellipsoid" );
populateEllipsoidList();
// Reading ellipsoid from setttings
QStringList mySplitEllipsoid = QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ).split( ':' );
int myIndex = 0;
for ( int i = 0; i < mEllipsoidList.length(); i++ )
{
if ( mEllipsoidList[ i ].acronym.startsWith( mySplitEllipsoid[ 0 ] ) )
{
myIndex = i;
break;
}
}
// Update paramaters if present.
if ( mySplitEllipsoid.length() >= 3 )
{
mEllipsoidList[ myIndex ].semiMajor = mySplitEllipsoid[ 1 ].toDouble();
mEllipsoidList[ myIndex ].semiMinor = mySplitEllipsoid[ 2 ].toDouble();
}
updateEllipsoidUI( myIndex );
int dp = QgsProject::instance()->readNumEntry( "PositionPrecision", "/DecimalPlaces" );
spinBoxDP->setValue( dp );
@ -507,6 +544,26 @@ void QgsProjectProperties::apply()
QgsProject::instance()->writeEntry( "Paths", "/Absolute", cbxAbsolutePath->currentIndex() == 0 );
if ( mEllipsoidList[ mEllipsoidIndex ].acronym.startsWith( "PARAMETER" ) )
{
double major = mEllipsoidList[ mEllipsoidIndex ].semiMajor;
double minor = mEllipsoidList[ mEllipsoidIndex ].semiMinor;
// If the user fields have changed, use them instead.
if ( leSemiMajor->isModified() || leSemiMinor->isModified() )
{
QgsDebugMsg( "Using paramteric major/minor" );
major = QLocale::system().toDouble( leSemiMajor->text() );
minor = QLocale::system().toDouble( leSemiMinor->text() );
}
QgsProject::instance()->writeEntry( "Measure", "/Ellipsoid", QString( "PARAMETER:%1:%2" )
.arg( major, 0, 'g', 17 )
.arg( minor, 0, 'g', 17 ) );
}
else
{
QgsProject::instance()->writeEntry( "Measure", "/Ellipsoid", mEllipsoidList[ mEllipsoidIndex ].acronym );
}
//set the color for selections
QColor myColor = pbnSelectionColor->color();
QgsProject::instance()->writeEntry( "Gui", "/SelectionColorRedPart", myColor.red() );
@ -773,6 +830,9 @@ void QgsProjectProperties::on_cbxProjectionEnabled_stateChanged( int state )
mLayerSrsId = projectionSelector->selectedCrsId();
projectionSelector->setSelectedCrsId( mProjectSrsId );
}
// Enable/Disabel selector and update tool-tip
updateEllipsoidUI( mEllipsoidIndex );
}
void QgsProjectProperties::on_cbxWFSPublied_stateChanged( int aIdx )
@ -1252,3 +1312,142 @@ void QgsProjectProperties::resetPythonMacros()
"def saveProject():\n pass\n\n" \
"def closeProject():\n pass\n" );
}
void QgsProjectProperties::populateEllipsoidList()
{
//
// Populate the ellipsoid list
//
sqlite3 *myDatabase;
const char *myTail;
sqlite3_stmt *myPreparedStatement;
int myResult;
EllipsoidDefs myItem, i;
myItem.acronym = GEO_NONE;
myItem.description = tr( GEO_NONE_DESC );
myItem.semiMajor = 0.0;
myItem.semiMinor = 0.0;
mEllipsoidList.append( myItem );
myItem.acronym = QString( "PARAMETER:6370997:6370997" );
myItem.description = tr( "Parameters :" );
myItem.semiMajor = 6370997.0;
myItem.semiMinor = 6370997.0;
mEllipsoidList.append( myItem );
//check the db is available
myResult = sqlite3_open_v2( QgsApplication::srsDbFilePath().toUtf8().data(), &myDatabase, SQLITE_OPEN_READONLY, NULL );
if ( myResult )
{
QgsDebugMsg( QString( "Can't open database: %1" ).arg( sqlite3_errmsg( myDatabase ) ) );
// XXX This will likely never happen since on open, sqlite creates the
// database if it does not exist.
Q_ASSERT( myResult == 0 );
}
// Set up the query to retrieve the projection information needed to populate the ELLIPSOID list
QString mySql = "select acronym, name, radius, parameter2 from tbl_ellipsoid order by name";
myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
// XXX Need to free memory from the error msg if one is set
if ( myResult == SQLITE_OK )
{
while ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
{
QString para1, para2;
myItem.acronym = ( const char * )sqlite3_column_text( myPreparedStatement, 0 );
myItem.description = ( const char * )sqlite3_column_text( myPreparedStatement, 1 );
// Copied from QgsDistanecArea. Should perhaps be moved there somehow?
// No error checking, this values are for show only, never used in calculations.
// Fall-back values
myItem.semiMajor = 0.0;
myItem.semiMinor = 0.0;
// Crash if no column?
para1 = ( const char * )sqlite3_column_text( myPreparedStatement, 2 );
para2 = ( const char * )sqlite3_column_text( myPreparedStatement, 3 );
myItem.semiMajor = para1.mid( 2 ).toDouble();
if ( para2.left( 2 ) == "b=" )
{
myItem.semiMinor = para2.mid( 2 ).toDouble();
}
else if ( para2.left( 3 ) == "rf=" )
{
double invFlattening = para2.mid( 3 ).toDouble();
if ( invFlattening != 0.0 )
{
myItem.semiMinor = myItem.semiMajor - ( myItem.semiMajor / invFlattening );
}
}
mEllipsoidList.append( myItem );
}
}
// close the sqlite3 statement
sqlite3_finalize( myPreparedStatement );
sqlite3_close( myDatabase );
// Add all items to selector
foreach ( i, mEllipsoidList )
{
cmbEllipsoid->addItem( i.description );
}
}
void QgsProjectProperties::updateEllipsoidUI( int newIndex )
{
// Just return if the list isn't populated yet
if ( mEllipsoidList.isEmpty() )
{
return;
}
// Called whenever settings change, adjusts the UI accordingly
// Pre-select current ellipsoid
// Check if CRS transformation is on, or else turn everything off
double myMajor = mEllipsoidList[ newIndex ].semiMajor;
double myMinor = mEllipsoidList[ newIndex ].semiMinor;
// If user has modified the radii (only possible if parametric!), before
// changing ellipsoid, save the modified coordinates
if ( leSemiMajor->isModified() || leSemiMinor->isModified() )
{
QgsDebugMsg( "Saving major/minor" );
mEllipsoidList[ mEllipsoidIndex ].semiMajor = QLocale::system().toDouble( leSemiMajor->text() );
mEllipsoidList[ mEllipsoidIndex ].semiMinor = QLocale::system().toDouble( leSemiMinor->text() );
}
mEllipsoidIndex = newIndex;
leSemiMajor->setEnabled( false );
leSemiMinor->setEnabled( false );
leSemiMajor->setText( "" );
leSemiMinor->setText( "" );
if ( cbxProjectionEnabled->isChecked() )
{
cmbEllipsoid->setEnabled( true );
cmbEllipsoid->setToolTip( "" );
if ( mEllipsoidList[ mEllipsoidIndex ].acronym.startsWith( "PARAMETER:" ) )
{
leSemiMajor->setEnabled( true );
leSemiMinor->setEnabled( true );
}
else
{
leSemiMajor->setToolTip( QString( "Select %1 from pull-down menu to adjust radii" ).arg( tr( "Parameters:" ) ) );
leSemiMinor->setToolTip( QString( "Select %1 from pull-down menu to adjust radii" ).arg( tr( "Parameters:" ) ) );
}
cmbEllipsoid->setCurrentIndex( mEllipsoidIndex ); // Not always necessary
if ( mEllipsoidList[ mEllipsoidIndex ].acronym != GEO_NONE )
{
leSemiMajor->setText( QLocale::system().toString( myMajor, 'f', 3 ) );
leSemiMinor->setText( QLocale::system().toString( myMinor, 'f', 3 ) );
}
}
else
{
cmbEllipsoid->setEnabled( false );
cmbEllipsoid->setToolTip( tr( "Can only use ellipsoidal calculations when CRS transformation is enabled" ) );
}
}

View File

@ -153,6 +153,12 @@ class QgsProjectProperties : public QDialog, private Ui::QgsProjectPropertiesBas
*/
void setMapUnitsToCurrentProjection();
/* Update ComboBox accorindg to the selected new index
* Also sets the new selected Ellipsoid.
* @note added in 2.0
*/
void updateEllipsoidUI( int newIndex );
signals:
//! Signal used to inform listeners that the mouse display precision may have changed
void displayPrecisionChanged();
@ -188,4 +194,21 @@ class QgsProjectProperties : public QDialog, private Ui::QgsProjectPropertiesBas
long mProjectSrsId;
long mLayerSrsId;
// List for all ellispods, also None and Custom
struct EllipsoidDefs
{
QString acronym;
QString description;
double semiMajor;
double semiMinor;
};
QList<EllipsoidDefs> mEllipsoidList;
int mEllipsoidIndex;
//! Populates list with ellipsoids from Sqlite3 db
void populateEllipsoidList();
static const char * GEO_NONE_DESC;
};

View File

@ -24,6 +24,7 @@
#include "qgssingleboxscalebarstyle.h"
#include "qgsticksscalebarstyle.h"
#include "qgsrectangle.h"
#include "qgsproject.h"
#include <QDomDocument>
#include <QDomElement>
#include <QFontMetricsF>
@ -189,8 +190,8 @@ double QgsComposerScaleBar::mapWidth() const
QgsDistanceArea da;
da.setEllipsoidalMode( mComposerMap->mapRenderer()->hasCrsTransformEnabled() );
da.setSourceCrs( mComposerMap->mapRenderer()->destinationCrs().srsid() );
QSettings s;
da.setEllipsoid( s.value( "/qgis/measure/ellipsoid", "WGS84" ).toString() );
da.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", "WGS84" ) );
double measure = da.measureLine( QgsPoint( composerMapRect.xMinimum(), composerMapRect.yMinimum() ), QgsPoint( composerMapRect.xMaximum(), composerMapRect.yMinimum() ) );
if ( mUnits == Feet )
{

View File

@ -1213,8 +1213,10 @@ QgsExpression::QgsExpression( const QString& expr )
: mExpression( expr )
, mRowNumber( 0 )
, mScale( 0 )
, mCalc( NULL )
{
initGeomCalculator();
mRootNode = ::parseExpression( mExpression, mParserErrorString );
if ( mParserErrorString.isNull() )
@ -1226,7 +1228,6 @@ QgsExpression::QgsExpression( const QString& expr )
QgsExpression::~QgsExpression()
{
delete mRootNode;
delete mCalc;
}
QStringList QgsExpression::referencedColumns()
@ -1261,11 +1262,16 @@ bool QgsExpression::needsGeometry()
void QgsExpression::initGeomCalculator()
{
mCalc = new QgsDistanceArea;
QSettings settings;
QString ellipsoid = settings.value( "/qgis/measure/ellipsoid", GEO_NONE ).toString();
mCalc->setEllipsoid( ellipsoid );
mCalc->setEllipsoidalMode( false );
// Use planimetric as default
mCalc.setEllipsoidalMode( false );
}
void QgsExpression::setGeomCalculator( QgsDistanceArea& calc )
{
// Copy from supplied calculator
mCalc.setEllipsoid( calc.ellipsoid() );
mCalc.setEllipsoidalMode( calc.ellipsoidalEnabled() );
mCalc.setSourceCrs( calc.sourceCrs() );
}
bool QgsExpression::prepare( const QgsFieldMap& fields )
@ -1311,7 +1317,6 @@ QString QgsExpression::dump() const
return mRootNode->dump();
}
void QgsExpression::toOgcFilter( QDomDocument &doc, QDomElement &element ) const
{
if ( !mRootNode )
@ -1393,7 +1398,6 @@ QString QgsExpression::replaceExpressionText( QString action, QgsFeature* feat,
int start = index;
index = pos + rx.matchedLength();
QString to_replace = rx.cap( 1 ).trimmed();
QgsDebugMsg( "Found expression: " + to_replace );

View File

@ -24,9 +24,9 @@
#include "qgsfield.h"
#include "qgsvectorlayer.h"
#include "qgsdistancearea.h"
#include "qgsgeometry.h"
class QgsDistanceArea;
class QgsFeature;
class QgsGeometry;
class QDomElement;
@ -140,7 +140,11 @@ class CORE_EXPORT QgsExpression
//! Return calculator used for distance and area calculations
//! (used by internal functions)
QgsDistanceArea* geomCalculator() { if ( !mCalc ) initGeomCalculator(); return mCalc; }
QgsDistanceArea* geomCalculator() { return & mCalc; }
//! Sets the geometry calculator used in evaluation of expressions,
// instead of the default.
void setGeomCalculator( QgsDistanceArea& calc );
/** This function currently replaces each expression between [% and %]
in the string with the result of its evaluation on the feature
@ -157,8 +161,6 @@ class CORE_EXPORT QgsExpression
static QString replaceExpressionText( QString action, QgsFeature& feat,
QgsVectorLayer* layer,
const QMap<QString, QVariant> *substitutionMap = 0 );
//
enum UnaryOperator
{
uoNot,
@ -589,7 +591,7 @@ class CORE_EXPORT QgsExpression
protected:
// internally used to create an empty expression
QgsExpression() : mRootNode( NULL ), mRowNumber( 0 ), mCalc( NULL ) {}
QgsExpression() : mRootNode( NULL ), mRowNumber( 0 ) {}
void initGeomCalculator();
@ -603,8 +605,8 @@ class CORE_EXPORT QgsExpression
double mScale;
static QMap<QString, QVariant> gmSpecialColumns;
QgsDistanceArea mCalc;
QgsDistanceArea* mCalc;
};
Q_DECLARE_METATYPE( QgsExpression::Interval );

View File

@ -55,3 +55,9 @@ void QgsExpressionBuilderDialog::closeEvent( QCloseEvent *event )
QSettings settings;
settings.setValue( "/Windows/ExpressionBuilderDialog/geometry", saveGeometry() );
}
void QgsExpressionBuilderDialog::setGeomCalculator( const QgsDistanceArea & da )
{
// Store in child widget only.
builder->setGeomCalculator( da );
}

View File

@ -17,6 +17,7 @@
#define QGSEXPRESSIONBUILDERDIALOG_H
#include <QDialog>
#include "qgsdistancearea.h"
#include "ui_qgsexpressionbuilderdialogbase.h"
/** A generic dialog for building expression strings
@ -34,6 +35,11 @@ class GUI_EXPORT QgsExpressionBuilderDialog : public QDialog, private Ui::QgsExp
QString expressionText();
/** Sets geometry calculator used in distance/area calculations.
* @note added in version 2.0
*/
void setGeomCalculator( const QgsDistanceArea & da );
protected:
/**
* Handle closing of the window

View File

@ -240,6 +240,11 @@ bool QgsExpressionBuilderWidget::isExpressionValid()
return mExpressionValid;
}
void QgsExpressionBuilderWidget::setGeomCalculator( const QgsDistanceArea & da )
{
mDa = da;
}
QString QgsExpressionBuilderWidget::expressionText()
{
return txtExpressionString->toPlainText();
@ -266,10 +271,15 @@ void QgsExpressionBuilderWidget::on_txtExpressionString_textChanged()
return;
}
QgsExpression exp( text );
if ( mLayer )
{
// Only set calculator if we have layer, else use default.
exp.setGeomCalculator( mDa );
if ( !mFeature.isValid() )
{
mLayer->select( mLayer->pendingAllAttributesList(), QgsRectangle(), mLayer->geometryType() != QGis::NoGeometry && exp.needsGeometry() );
@ -406,12 +416,12 @@ QString QgsExpressionBuilderWidget::loadFunctionHelp( QgsExpressionItem* express
return "";
QString helpContents;
// Return the function help that is set for the function if there is one.
// Return the function help that is set for the function if there is one.
if ( !expressionItem->getHelpText().isEmpty() )
{
QString myStyle = QgsApplication::reportStyleSheet();
helpContents = "<head><style>" + myStyle + "</style></head><body>" + expressionItem->getHelpText() + "</body>";
return helpContents;
QString myStyle = QgsApplication::reportStyleSheet();
helpContents = "<head><style>" + myStyle + "</style></head><body>" + expressionItem->getHelpText() + "</body>";
return helpContents;
}
// set up the path to the help file
QString helpFilesPath = QgsApplication::pkgDataPath() + "/resources/function_help/";

View File

@ -20,6 +20,7 @@
#include "ui_qgsexpressionbuilder.h"
#include "qgsvectorlayer.h"
#include "qgsexpressionhighlighter.h"
#include "qgsdistancearea.h"
#include "QStandardItemModel"
#include "QStandardItem"
@ -122,6 +123,11 @@ class GUI_EXPORT QgsExpressionBuilderWidget : public QWidget, private Ui::QgsExp
void loadFieldNames( QgsFieldMap fields );
/** Sets geometry calculator used in distance/area calculations.
* @note added in version 2.0
*/
void setGeomCalculator( const QgsDistanceArea & da );
/** Gets the expression string that has been set in the expression area.
* @returns The expression as a string. */
QString expressionText();
@ -176,6 +182,7 @@ class GUI_EXPORT QgsExpressionBuilderWidget : public QWidget, private Ui::QgsExp
QgsFeature mFeature;
QgsExpressionHighlighter* highlighter;
bool mExpressionValid;
QgsDistanceArea mDa;
};
#endif // QGSEXPRESSIONBUILDER_H

View File

@ -33,7 +33,7 @@
<item row="2" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
<number>4</number>
</property>
<property name="iconSize">
<size>
@ -1561,7 +1561,7 @@
<x>0</x>
<y>0</y>
<width>770</width>
<height>757</height>
<height>691</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_4">
@ -1780,21 +1780,14 @@
<string>Measure tool</string>
</property>
<layout class="QGridLayout" name="gridLayout_21">
<item row="2" column="3">
<widget class="QLabel" name="label_42">
<property name="text">
<string>Semi-minor</string>
</property>
</widget>
</item>
<item row="4" column="0">
<item row="2" column="0">
<widget class="QLabel" name="textLabel1_10">
<property name="text">
<string>Rubberband color</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="2" column="1">
<widget class="QgsColorButton" name="pbnMeasureColor">
<property name="minimumSize">
<size>
@ -1807,103 +1800,80 @@
</property>
</widget>
</item>
<item row="7" column="0">
<item row="5" column="0">
<widget class="QLabel" name="textLabel1_11">
<property name="text">
<string>Preferred measurements units</string>
</property>
</widget>
</item>
<item row="7" column="1">
<item row="5" column="1">
<widget class="QRadioButton" name="radMeters">
<property name="text">
<string>Meters</string>
</property>
</widget>
</item>
<item row="7" column="2">
<item row="5" column="2">
<widget class="QRadioButton" name="radFeet">
<property name="text">
<string>Feet</string>
</property>
</widget>
</item>
<item row="8" column="0">
<item row="6" column="0">
<widget class="QLabel" name="mAngleUnitsLabel">
<property name="text">
<string>Preferred angle units</string>
</property>
</widget>
</item>
<item row="8" column="1">
<item row="6" column="1">
<widget class="QRadioButton" name="mDegreesRadioButton">
<property name="text">
<string>Degrees</string>
</property>
</widget>
</item>
<item row="8" column="2">
<item row="6" column="2">
<widget class="QRadioButton" name="mRadiansRadioButton">
<property name="text">
<string>Radians</string>
</property>
</widget>
</item>
<item row="5" column="0">
<item row="3" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Decimal places</string>
</property>
</widget>
</item>
<item row="5" column="1">
<item row="3" column="1">
<widget class="QSpinBox" name="mDecimalPlacesSpinBox"/>
</item>
<item row="6" column="0">
<item row="4" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Keep base unit</string>
</property>
</widget>
</item>
<item row="6" column="1">
<item row="4" column="1">
<widget class="QCheckBox" name="mKeepBaseUnitCheckBox">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLineEdit" name="leSemiMajor"/>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_41">
<property name="text">
<string>Semi-major</string>
</property>
</widget>
</item>
<item row="8" column="3">
<item row="6" column="3">
<widget class="QRadioButton" name="mGonRadioButton">
<property name="text">
<string>Gon</string>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QLineEdit" name="leSemiMinor"/>
</item>
<item row="1" column="1" colspan="4">
<widget class="QComboBox" name="cmbEllipsoid"/>
</item>
<item row="1" column="0" rowspan="2">
<widget class="QLabel" name="textLabel1_8">
<property name="text">
<string>Ellipsoid for distance calculations</string>
</property>
</widget>
</item>
<item row="4" column="2" colspan="3">
<item row="2" column="2" colspan="3">
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
@ -1950,8 +1920,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>786</width>
<height>585</height>
<width>274</width>
<height>87</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_10">
@ -2031,7 +2001,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>770</width>
<width>581</width>
<height>606</height>
</rect>
</property>
@ -2407,8 +2377,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>786</width>
<height>585</height>
<width>653</width>
<height>415</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_15">
@ -2594,8 +2564,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>786</width>
<height>585</height>
<width>519</width>
<height>565</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_17">
@ -2691,8 +2661,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>786</width>
<height>585</height>
<width>505</width>
<height>573</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_20">
@ -2974,7 +2944,6 @@
<tabstop>cmbIdentifyMode</tabstop>
<tabstop>cbxAutoFeatureForm</tabstop>
<tabstop>spinBoxIdentifyValue</tabstop>
<tabstop>cmbEllipsoid</tabstop>
<tabstop>pbnMeasureColor</tabstop>
<tabstop>mDecimalPlacesSpinBox</tabstop>
<tabstop>mKeepBaseUnitCheckBox</tabstop>

View File

@ -197,6 +197,45 @@
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="btnGrpMeasureEllipsoid">
<property name="title">
<string>Measure tool</string>
</property>
<layout class="QGridLayout" name="gridLayoutMeasureTool">
<item row="1" column="0" rowspan="2">
<widget class="QLabel" name="textLabel1_8">
<property name="text">
<string>Ellipsoid for distance calculations</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="4">
<widget class="QComboBox" name="cmbEllipsoid"/>
</item>
<item row="2" column="4">
<widget class="QLineEdit" name="leSemiMinor"/>
</item>
<item row="2" column="3">
<widget class="QLabel" name="label_42">
<property name="text">
<string>Semi-minor</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLineEdit" name="leSemiMajor"/>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_41">
<property name="text">
<string>Semi-major</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QGroupBox" name="btnGrpMapUnits">
<property name="toolTip">
<string>Used when CRS transformation is turned off</string>
@ -232,7 +271,7 @@
</layout>
</widget>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="QGroupBox" name="btnGrpDegreeDisplay">
<property name="title">
<string>Degree display</string>
@ -262,7 +301,7 @@
</layout>
</widget>
</item>
<item row="3" column="0">
<item row="4" column="0">
<widget class="QGroupBox" name="btnGrpPrecision">
<property name="title">
<string>Precision</string>
@ -326,7 +365,7 @@
</layout>
</widget>
</item>
<item row="4" column="0">
<item row="5" column="0">
<widget class="QGroupBox" name="grpProjectScales">
<property name="title">
<string>Project scales</string>