Skip to content

Commit

Permalink
Merge branch 'master', remote-tracking branch 'nathan/expression-labels'
Browse files Browse the repository at this point in the history
  • Loading branch information
wonder-sk committed Oct 20, 2011
2 parents 3a15509 + 665e92e commit 847204e
Show file tree
Hide file tree
Showing 15 changed files with 1,497 additions and 122 deletions.
58 changes: 45 additions & 13 deletions src/app/qgslabelinggui.cpp
Expand Up @@ -24,18 +24,21 @@

#include "qgspallabeling.h"
#include "qgslabelengineconfigdialog.h"
#include "qgsexpressionbuilderdialog.h"
#include "qgsexpression.h"

#include <QColorDialog>
#include <QFontDialog>

#include <QTextEdit>
#include <iostream>
#include <QApplication>


#include <QMessageBox>

QgsLabelingGui::QgsLabelingGui( QgsPalLabeling* lbl, QgsVectorLayer* layer, QgsMapCanvas* mapCanvas, QWidget* parent )
: QDialog( parent ), mLBL( lbl ), mLayer( layer ), mMapCanvas( mapCanvas )
{
if ( !layer ) return;

setupUi( this );

connect( btnTextColor, SIGNAL( clicked() ), this, SLOT( changeTextColor() ) );
Expand All @@ -44,6 +47,7 @@ QgsLabelingGui::QgsLabelingGui( QgsPalLabeling* lbl, QgsVectorLayer* layer, QgsM
connect( btnBufferColor, SIGNAL( clicked() ), this, SLOT( changeBufferColor() ) );
connect( spinBufferSize, SIGNAL( valueChanged( double ) ), this, SLOT( updatePreview() ) );
connect( btnEngineSettings, SIGNAL( clicked() ), this, SLOT( showEngineConfigDialog() ) );
connect( btnExpression, SIGNAL(clicked()), this, SLOT( showExpressionDialog()));

// set placement methods page based on geometry type
switch ( layer->geometryType() )
Expand All @@ -61,19 +65,27 @@ QgsLabelingGui::QgsLabelingGui( QgsPalLabeling* lbl, QgsVectorLayer* layer, QgsM
Q_ASSERT( 0 && "NOOOO!" );
}

//mTabWidget->setEnabled( chkEnableLabeling->isChecked() );
chkMergeLines->setEnabled( layer->geometryType() == QGis::Line );
chkAddDirectionSymbol->setEnabled( layer->geometryType() == QGis::Line );
label_19->setEnabled( layer->geometryType() != QGis::Point );
mMinSizeSpinBox->setEnabled( layer->geometryType() != QGis::Point );

populateFieldNames();

// load labeling settings from layer
QgsPalLayerSettings lyr;
lyr.readFromLayer( layer );

populateFieldNames();
populateDataDefinedCombos( lyr );

chkEnableLabeling->setChecked( lyr.enabled );
mTabWidget->setEnabled( lyr.enabled );
cboFieldName->setEnabled( lyr.enabled );
btnExpression->setEnabled( lyr.enabled );

//Add the current expression to the bottom of the list.
if (lyr.isExpression && !lyr.fieldName.isEmpty())
cboFieldName->addItem(lyr.fieldName);

// placement
int distUnitIndex = lyr.distInMapUnits ? 1 : 0;
switch ( lyr.placement )
Expand Down Expand Up @@ -200,18 +212,22 @@ QgsLabelingGui::~QgsLabelingGui()

void QgsLabelingGui::apply()
{
layerSettings().writeToLayer( mLayer );
// trigger refresh
if ( mMapCanvas )
{
mMapCanvas->refresh();
}
QgsPalLayerSettings settings = layerSettings();
settings.writeToLayer( mLayer );
// trigger refresh
if ( mMapCanvas )
{
mMapCanvas->refresh();
}
}

QgsPalLayerSettings QgsLabelingGui::layerSettings()
{
QgsPalLayerSettings lyr;
lyr.fieldName = cboFieldName->currentText();
// Check if we are an expression. Also treats expressions with just a column name as non expressions,
// this saves time later so we don't have to parse the expression tree.
lyr.isExpression = mLayer->fieldNameIndex( lyr.fieldName ) == -1 && !lyr.fieldName.isEmpty();

lyr.dist = 0;
lyr.placementFlags = 0;
Expand Down Expand Up @@ -328,7 +344,6 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
return lyr;
}


void QgsLabelingGui::populateFieldNames()
{
const QgsFieldMap& fields = mLayer->pendingFields();
Expand Down Expand Up @@ -477,6 +492,23 @@ void QgsLabelingGui::showEngineConfigDialog()
dlg.exec();
}

void QgsLabelingGui::showExpressionDialog()
{
//TODO extract this out to a dialog.
QgsExpressionBuilderDialog dlg( mLayer, cboFieldName->currentText() , this );
dlg.setWindowTitle( tr("Expression based label") );
if ( dlg.exec() == QDialog::Accepted )
{
QString expression = dlg.expressionBuilder()->getExpressionString();
//Only add the expression if the user has entered some text.
if (!expression.isEmpty())
{
cboFieldName->addItem(expression);
cboFieldName->setCurrentIndex(cboFieldName->count() - 1);
}
}
}

void QgsLabelingGui::updateUi()
{
// enable/disable scale-based, buffer, decimals
Expand Down
1 change: 1 addition & 0 deletions src/app/qgslabelinggui.h
Expand Up @@ -41,6 +41,7 @@ class QgsLabelingGui : public QDialog, private Ui::QgsLabelingGuiBase
void changeTextColor();
void changeTextFont();
void showEngineConfigDialog();
void showExpressionDialog();
void changeBufferColor();

void updateUi();
Expand Down
73 changes: 42 additions & 31 deletions src/core/qgsexpression.cpp
Expand Up @@ -375,40 +375,46 @@ typedef QgsExpression::FunctionDef FnDef;
FnDef QgsExpression::BuiltinFunctions[] =
{
// math
FnDef( "sqrt", 1, fcnSqrt ),
FnDef( "sin", 1, fcnSin ),
FnDef( "cos", 1, fcnCos ),
FnDef( "tan", 1, fcnTan ),
FnDef( "asin", 1, fcnAsin ),
FnDef( "acos", 1, fcnAcos ),
FnDef( "atan", 1, fcnAtan ),
FnDef( "atan2", 2, fcnAtan2 ),
FnDef( "exp", 1, fcnExp ),
FnDef( "ln", 1, fcnLn ),
FnDef( "log10", 1, fcnLog10 ),
FnDef( "log", 2, fcnLog ),
FnDef( "sqrt", 1, fcnSqrt, "Math"),
FnDef( "sin", 1, fcnSin, "Math" ),
FnDef( "cos", 1, fcnCos, "Math"),
FnDef( "tan", 1, fcnTan, "Math" ),
FnDef( "asin", 1, fcnAsin, "Math" ),
FnDef( "acos", 1, fcnAcos, "Math" ),
FnDef( "atan", 1, fcnAtan, "Math" ),
FnDef( "atan2", 2, fcnAtan2, "Math" ),
FnDef( "exp", 1, fcnExp, "Math" ),
FnDef( "ln", 1, fcnLn, "Math" ),
FnDef( "log10", 1, fcnLog10, "Math" ),
FnDef( "log", 2, fcnLog, "Math" ),
// casts
FnDef( "toint", 1, fcnToInt ),
FnDef( "toreal", 1, fcnToReal ),
FnDef( "tostring", 1, fcnToString ),
FnDef( "toint", 1, fcnToInt, "Conversions" ),
FnDef( "toreal", 1, fcnToReal, "Conversions" ),
FnDef( "tostring", 1, fcnToString, "Conversions" ),
// string manipulation
FnDef( "lower", 1, fcnLower ),
FnDef( "upper", 1, fcnUpper ),
FnDef( "length", 1, fcnLength ),
FnDef( "replace", 3, fcnReplace ),
FnDef( "regexp_replace", 3, fcnRegexpReplace ),
FnDef( "substr", 3, fcnSubstr ),
FnDef( "lower", 1, fcnLower, "String", "<b>Convert to lower case</b> "\
"<br> Converts a string to lower case letters. " \
"<br> <i>Usage:</i><br>lower('HELLO WORLD') will return 'hello world'"),
FnDef( "upper", 1, fcnUpper, "String" , "<b>Convert to upper case</b> "\
"<br> Converts a string to upper case letters. " \
"<br> <i>Usage:</i><br>upper('hello world') will return 'HELLO WORLD'"),
FnDef( "length", 1, fcnLength, "String", "<b>Length of string</b> "\
"<br> Returns the legnth of a string. " \
"<br> <i>Usage:</i><br>length('hello') will return 5"),
FnDef( "replace", 3, fcnReplace, "String", "<b>Replace a section of a string.</b> "),
FnDef( "regexp_replace", 3, fcnRegexpReplace, "String" ),
FnDef( "substr", 3, fcnSubstr, "String" ),
// geometry accessors
FnDef( "xat", 1, fcnXat, true ),
FnDef( "yat", 1, fcnYat, true ),
FnDef( "xat", 1, fcnXat, "Geometry", "", true ),
FnDef( "yat", 1, fcnYat, "Geometry", "", true ),
FnDef( "$area", 0, fcnGeomArea, "Geometry", "", true ),
FnDef( "$length", 0, fcnGeomLength, "Geometry", "", true ),
FnDef( "$perimeter", 0, fcnGeomPerimeter, "Geometry", "", true ),
FnDef( "$x", 0, fcnX, "Geometry", "", true ),
FnDef( "$y", 0, fcnY, "Geometry", "" , true ),
// special columns
FnDef( "$rownum", 0, fcnRowNumber ),
FnDef( "$area", 0, fcnGeomArea, true ),
FnDef( "$length", 0, fcnGeomLength, true ),
FnDef( "$perimeter", 0, fcnGeomPerimeter, true ),
FnDef( "$x", 0, fcnX, true ),
FnDef( "$y", 0, fcnY, true ),
FnDef( "$id", 0, fcnFeatureId ),
FnDef( "$rownum", 0, fcnRowNumber, "Record" ),
FnDef( "$id", 0, fcnFeatureId, "Record")
};


Expand All @@ -419,7 +425,7 @@ bool QgsExpression::isFunctionName( QString name )

int QgsExpression::functionIndex( QString name )
{
int count = sizeof( BuiltinFunctions ) / sizeof( FunctionDef );
int count = functionCount();
for ( int i = 0; i < count; i++ )
{
if ( QString::compare( name, BuiltinFunctions[i].mName, Qt::CaseInsensitive ) == 0 )
Expand All @@ -428,6 +434,11 @@ int QgsExpression::functionIndex( QString name )
return -1;
}

int QgsExpression::functionCount()
{
return ( sizeof( BuiltinFunctions ) / sizeof( FunctionDef) );
}


QgsExpression::QgsExpression( const QString& expr )
: mExpression( expr ), mRowNumber( 0 ), mCalc( NULL )
Expand Down
19 changes: 16 additions & 3 deletions src/core/qgsexpression.h
Expand Up @@ -30,7 +30,7 @@ The expressions try to follow both syntax and semantics of SQL expressions.
Usage:
QgsExpression exp("gid*2 > 10 and type not in ('D','F');
QgsExpression exp("gid*2 > 10 and type not in ('D','F'));
if (exp.hasParserError())
{
// show error message with parserErrorString() and exit
Expand Down Expand Up @@ -170,12 +170,20 @@ class CORE_EXPORT QgsExpression

struct FunctionDef
{
FunctionDef( QString fnname, int params, FcnEval fcn, bool usesGeometry = false )
: mName( fnname ), mParams( params ), mFcn( fcn ), mUsesGeometry( usesGeometry ) {}
FunctionDef( QString fnname, int params, FcnEval fcn, QString group, QString helpText = "", bool usesGeometry = false )
: mName( fnname ), mParams( params ), mFcn( fcn ), mUsesGeometry( usesGeometry ), mGroup( group ), mHelpText( helpText ) {}
/** The name of the function. */
QString mName;
/** The number of parameters this function takes. */
int mParams;
/** Pointer to fucntion. */
FcnEval mFcn;
/** Does this function use a geometry object. */
bool mUsesGeometry;
/** The group the function belongs to. */
QString mGroup;
/** The help text for the function. */
QString mHelpText;
};

static FunctionDef BuiltinFunctions[];
Expand All @@ -186,6 +194,11 @@ class CORE_EXPORT QgsExpression
// return index of the function in BuiltinFunctions array
static int functionIndex( QString name );

/** Returns the number of functions defined in the parser
* @return The number of function defined in the parser.
*/
static int functionCount();

//! return quoted column reference (in double quotes)
static QString quotedColumnRef( QString name ) { return QString( "\"%1\"" ).arg( name.replace( "\"", "\"\"" ) ); }

Expand Down
4 changes: 1 addition & 3 deletions src/core/qgslabel.cpp
Expand Up @@ -84,11 +84,9 @@ QString QgsLabel::fieldValue( int attr, QgsFeature &feature )
}

void QgsLabel::renderLabel( QgsRenderContext &renderContext,
QgsFeature &feature,
bool selected,
QgsFeature &feature, bool selected,
QgsLabelAttributes *classAttributes )
{
Q_UNUSED( classAttributes );
if ( mLabelAttributes->selectedOnly() && !selected )
return;

Expand Down

0 comments on commit 847204e

Please sign in to comment.