Skip to content

Commit

Permalink
Added expression based labels, simple dialog for entering expressions.
Browse files Browse the repository at this point in the history
Code still needs some clean up and testing.
  • Loading branch information
NathanW2 committed Jun 4, 2011
1 parent 0e318b0 commit 2b5fb21
Show file tree
Hide file tree
Showing 12 changed files with 257 additions and 54 deletions.
60 changes: 49 additions & 11 deletions src/app/qgslabelinggui.cpp
Expand Up @@ -24,13 +24,15 @@


#include "qgspallabeling.h" #include "qgspallabeling.h"
#include "qgslabelengineconfigdialog.h" #include "qgslabelengineconfigdialog.h"
#include "qgssearchstring.h"
#include "qgsexpressionbuilder.h"


#include <QColorDialog> #include <QColorDialog>
#include <QFontDialog> #include <QFontDialog>

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

#include <QMessageBox>




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


// set placement methods page based on geometry type // set placement methods page based on geometry type
switch ( layer->geometryType() ) switch ( layer->geometryType() )
Expand All @@ -65,12 +68,14 @@ QgsLabelingGui::QgsLabelingGui( QgsPalLabeling* lbl, QgsVectorLayer* layer, QgsM
label_19->setEnabled( layer->geometryType() != QGis::Point ); label_19->setEnabled( layer->geometryType() != QGis::Point );
mMinSizeSpinBox->setEnabled( layer->geometryType() != QGis::Point ); mMinSizeSpinBox->setEnabled( layer->geometryType() != QGis::Point );


populateFieldNames();

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


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


// placement // placement
Expand Down Expand Up @@ -184,18 +189,23 @@ QgsLabelingGui::~QgsLabelingGui()


void QgsLabelingGui::apply() void QgsLabelingGui::apply()
{ {
layerSettings().writeToLayer( mLayer ); QgsPalLayerSettings settings = layerSettings();
// trigger refresh // If we get here we are good to go.
if ( mMapCanvas ) settings.writeToLayer( mLayer );
{ // trigger refresh
mMapCanvas->refresh(); if ( mMapCanvas )
} {
mMapCanvas->refresh();
}
} }


QgsPalLayerSettings QgsLabelingGui::layerSettings() QgsPalLayerSettings QgsLabelingGui::layerSettings()
{ {
QgsPalLayerSettings lyr; QgsPalLayerSettings lyr;
lyr.fieldName = cboFieldName->currentText(); 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.dist = 0; lyr.dist = 0;
lyr.placementFlags = 0; lyr.placementFlags = 0;
Expand Down Expand Up @@ -300,7 +310,6 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
return lyr; return lyr;
} }



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


void QgsLabelingGui::showExpressionDialog()
{
QDialog* dlg = new QDialog();
QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
| QDialogButtonBox::Cancel);
QgsExpressionBuilder* builder = new QgsExpressionBuilder();
QGridLayout* layout = new QGridLayout();
dlg->setLayout(layout);
layout->addWidget(builder);
layout->addWidget(buttonBox);

if ( dlg->exec() )
{
QString expression = builder->getExpressionString();
//Do validation here first before applying
QgsSearchString searchString;
if ( !searchString.setString( expression ) )
{
//expression not valid
QMessageBox::critical( 0, "Syntax error",
"Invalid expression syntax. The error message of the parser is: '" + searchString.parserErrorMsg() + "'" );
return;
}

cboFieldName->addItem(expression);
cboFieldName->setCurrentIndex(cboFieldName->count() - 1);
}
}

void QgsLabelingGui::updateUi() void QgsLabelingGui::updateUi()
{ {
// enable/disable scale-based, buffer // enable/disable scale-based, buffer
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 changeTextColor();
void changeTextFont(); void changeTextFont();
void showEngineConfigDialog(); void showEngineConfigDialog();
void showExpressionDialog();
void changeBufferColor(); void changeBufferColor();


void updateUi(); void updateUi();
Expand Down
31 changes: 27 additions & 4 deletions src/core/qgslabel.cpp
Expand Up @@ -34,10 +34,14 @@
#include "qgsmaptopixel.h" #include "qgsmaptopixel.h"
#include "qgscoordinatetransform.h" #include "qgscoordinatetransform.h"
#include "qgsrendercontext.h" #include "qgsrendercontext.h"
#include "qgssearchtreenode.h"
#include "qgssearchstring.h"


#include "qgslabelattributes.h" #include "qgslabelattributes.h"
#include "qgslabel.h" #include "qgslabel.h"


#include <QMessageBox>

// use M_PI define PI 3.141592654 // use M_PI define PI 3.141592654
#ifdef WIN32 #ifdef WIN32
#undef M_PI #undef M_PI
Expand Down Expand Up @@ -103,16 +107,37 @@ void QgsLabel::renderLabel( QgsRenderContext &renderContext,
double x2 = point.x(); double x2 = point.x();
double scale = ( x2 - x1 ) * 0.001; double scale = ( x2 - x1 ) * 0.001;


QgsSearchString searchString;
if ( !searchString.setString( " to string (Diameter) + 'mm'" ) )
{
//expression not valid
QMessageBox::critical( 0, "Syntax error", "Invalid expression syntax. The error message of the parser is: '" + searchString.parserErrorMsg() + "'" );
return;
}

//get QgsSearchTreeNode
QgsSearchTreeNode* searchTree = searchString.tree();
if ( !searchTree )
{
return;
}

QgsSearchTreeValue outValue;
searchTree->getValue( outValue, searchTree, mField , feature );
if (outValue.isError())
QMessageBox::critical( 0, "Error in expression tree" , "Error" );
text = outValue.string();

/* Text */ /* Text */
value = fieldValue( Text, feature ); /*value = fieldValue( Text, feature );
if ( value.isEmpty() ) if ( value.isEmpty() )
{ {
text = mLabelAttributes->text(); text = mLabelAttributes->text();
} }
else else
{ {
text = value; text = value;
} } */


/* Font */ /* Font */
value = fieldValue( Family, feature ); value = fieldValue( Family, feature );
Expand Down Expand Up @@ -1030,8 +1055,6 @@ void QgsLabel::readXML( const QDomNode& node )


} // QgsLabel::readXML() } // QgsLabel::readXML()




void QgsLabel::writeXML( QDomNode & layer_node, QDomDocument & document ) const void QgsLabel::writeXML( QDomNode & layer_node, QDomDocument & document ) const
{ {
QDomElement labelattributes = document.createElement( "labelattributes" ); QDomElement labelattributes = document.createElement( "labelattributes" );
Expand Down
60 changes: 48 additions & 12 deletions src/core/qgspallabeling.cpp
Expand Up @@ -41,13 +41,16 @@
#include "qgsdiagram.h" #include "qgsdiagram.h"
#include "qgsdiagramrendererv2.h" #include "qgsdiagramrendererv2.h"
#include "qgslabelsearchtree.h" #include "qgslabelsearchtree.h"
#include "qgssearchtreenode.h"
#include "qgssearchstring.h"

#include <qgslogger.h> #include <qgslogger.h>
#include <qgsvectorlayer.h> #include <qgsvectorlayer.h>
#include <qgsmaplayerregistry.h> #include <qgsmaplayerregistry.h>
#include <qgsvectordataprovider.h> #include <qgsvectordataprovider.h>
#include <qgsgeometry.h> #include <qgsgeometry.h>
#include <qgsmaprenderer.h> #include <qgsmaprenderer.h>

#include <QMessageBox>


using namespace pal; using namespace pal;


Expand Down Expand Up @@ -155,6 +158,7 @@ QgsPalLayerSettings::QgsPalLayerSettings( const QgsPalLayerSettings& s )
{ {
// copy only permanent stuff // copy only permanent stuff
fieldName = s.fieldName; fieldName = s.fieldName;
isExpression = s.isExpression;
placement = s.placement; placement = s.placement;
placementFlags = s.placementFlags; placementFlags = s.placementFlags;
textFont = s.textFont; textFont = s.textFont;
Expand Down Expand Up @@ -276,6 +280,7 @@ void QgsPalLayerSettings::readFromLayer( QgsVectorLayer* layer )
return; // there's no information available return; // there's no information available


fieldName = layer->customProperty( "labeling/fieldName" ).toString(); fieldName = layer->customProperty( "labeling/fieldName" ).toString();
isExpression = layer->customProperty( "labeling/isExpression").toBool();
placement = ( Placement ) layer->customProperty( "labeling/placement" ).toInt(); placement = ( Placement ) layer->customProperty( "labeling/placement" ).toInt();
placementFlags = layer->customProperty( "labeling/placementFlags" ).toUInt(); placementFlags = layer->customProperty( "labeling/placementFlags" ).toUInt();
QString fontFamily = layer->customProperty( "labeling/fontFamily" ).toString(); QString fontFamily = layer->customProperty( "labeling/fontFamily" ).toString();
Expand Down Expand Up @@ -311,6 +316,7 @@ void QgsPalLayerSettings::writeToLayer( QgsVectorLayer* layer )
layer->setCustomProperty( "labeling", "pal" ); layer->setCustomProperty( "labeling", "pal" );


layer->setCustomProperty( "labeling/fieldName", fieldName ); layer->setCustomProperty( "labeling/fieldName", fieldName );
layer->setCustomProperty( "labeling/isExpression", isExpression );
layer->setCustomProperty( "labeling/placement", placement ); layer->setCustomProperty( "labeling/placement", placement );
layer->setCustomProperty( "labeling/placementFlags", ( unsigned int )placementFlags ); layer->setCustomProperty( "labeling/placementFlags", ( unsigned int )placementFlags );


Expand Down Expand Up @@ -427,9 +433,36 @@ void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF* fm, QString t
labelY = qAbs( ptSize.y() - ptZero.y() ); labelY = qAbs( ptSize.y() - ptZero.y() );
} }


void QgsPalLayerSettings::registerFeature( QgsFeature& f, const QgsRenderContext& context ) void QgsPalLayerSettings::registerFeature(QgsVectorLayer* layer, QgsFeature& f, const QgsRenderContext& context )
{ {
QString labelText = f.attributeMap()[fieldIndex].toString(); QString labelText;
if (isExpression)
{
QgsSearchString searchString;
// We don't do any validating here as we should only have a vaild expression at this point.
searchString.setString( fieldName );

QgsSearchTreeNode* searchTree = searchString.tree();
if ( !searchTree )
{
return;
}

QgsSearchTreeValue outValue;
searchTree->getValue( outValue, searchTree, layer->dataProvider()->fields() , f );

if (outValue.isError())
{
QgsDebugMsg("EXPRESSION ERROR = " + outValue.string());
return;
}
QgsDebugMsg("EXPRESSION OUT VALUE = " + outValue.string());
labelText = outValue.string();
}
else
{
labelText = f.attributeMap()[fieldIndex].toString();
}
double labelX, labelY; // will receive label size double labelX, labelY; // will receive label size
QFont labelFont = textFont; QFont labelFont = textFont;


Expand Down Expand Up @@ -569,7 +602,7 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, const QgsRenderContext
// record the created geometry - it will be deleted at the end. // record the created geometry - it will be deleted at the end.
geometries.append( lbl ); geometries.append( lbl );


// register feature to the layer // feature to the layer
try try
{ {
if ( !palLayer->registerFeature( lbl->strId(), lbl, labelX, labelY, labelText.toUtf8().constData(), if ( !palLayer->registerFeature( lbl->strId(), lbl, labelX, labelY, labelText.toUtf8().constData(),
Expand Down Expand Up @@ -689,11 +722,15 @@ int QgsPalLabeling::prepareLayer( QgsVectorLayer* layer, QSet<int>& attrIndices,
if ( !lyrTmp.enabled ) if ( !lyrTmp.enabled )
return 0; return 0;


// find out which field will be needed // If we aren't an expression, we check to see if we can find the column.
int fldIndex = layer->fieldNameIndex( lyrTmp.fieldName ); int fldIndex ;
if ( fldIndex == -1 ) if (!lyrTmp.isExpression)
return 0; {
attrIndices.insert( fldIndex ); fldIndex = layer->fieldNameIndex( lyrTmp.fieldName );
if ( fldIndex == -1)
return 0;
attrIndices.insert( fldIndex );
}


//add indices of data defined fields //add indices of data defined fields
QMap< QgsPalLayerSettings::DataDefinedProperties, int >::const_iterator dIt = lyrTmp.dataDefinedProperties.constBegin(); QMap< QgsPalLayerSettings::DataDefinedProperties, int >::const_iterator dIt = lyrTmp.dataDefinedProperties.constBegin();
Expand Down Expand Up @@ -782,7 +819,7 @@ int QgsPalLabeling::addDiagramLayer( QgsVectorLayer* layer, QgsDiagramLayerSetti
void QgsPalLabeling::registerFeature( QgsVectorLayer* layer, QgsFeature& f, const QgsRenderContext& context ) void QgsPalLabeling::registerFeature( QgsVectorLayer* layer, QgsFeature& f, const QgsRenderContext& context )
{ {
QgsPalLayerSettings& lyr = mActiveLayers[layer]; QgsPalLayerSettings& lyr = mActiveLayers[layer];
lyr.registerFeature( f, context ); lyr.registerFeature(layer, f, context );
} }


void QgsPalLabeling::registerDiagramFeature( QgsVectorLayer* layer, QgsFeature& feat, const QgsRenderContext& context ) void QgsPalLabeling::registerDiagramFeature( QgsVectorLayer* layer, QgsFeature& feat, const QgsRenderContext& context )
Expand Down Expand Up @@ -836,7 +873,7 @@ void QgsPalLabeling::registerDiagramFeature( QgsVectorLayer* layer, QgsFeature&
} }
} }


// register feature to the layer // feature to the layer
int ddColX = layerIt.value().xPosColumn; int ddColX = layerIt.value().xPosColumn;
int ddColY = layerIt.value().yPosColumn; int ddColY = layerIt.value().yPosColumn;
double ddPosX = 0.0; double ddPosX = 0.0;
Expand Down Expand Up @@ -1212,7 +1249,6 @@ void QgsPalLabeling::drawLabel( pal::LabelPosition* label, QPainter* painter, co


// TODO: optimize access :) // TODO: optimize access :)
const QgsPalLayerSettings& lyr = layer( label->getLayerName() ); const QgsPalLayerSettings& lyr = layer( label->getLayerName() );

QString text = (( QgsPalGeometry* )label->getFeaturePart()->getUserGeometry() )->text(); QString text = (( QgsPalGeometry* )label->getFeaturePart()->getUserGeometry() )->text();
QString txt = ( label->getPartId() == -1 ? text : QString( text[label->getPartId()] ) ); QString txt = ( label->getPartId() == -1 ? text : QString( text[label->getPartId()] ) );


Expand Down
3 changes: 2 additions & 1 deletion src/core/qgspallabeling.h
Expand Up @@ -98,6 +98,7 @@ class CORE_EXPORT QgsPalLayerSettings
}; };


QString fieldName; QString fieldName;
bool isExpression;
Placement placement; Placement placement;
unsigned int placementFlags; unsigned int placementFlags;
QFont textFont; QFont textFont;
Expand Down Expand Up @@ -125,7 +126,7 @@ class CORE_EXPORT QgsPalLayerSettings
void calculateLabelSize( const QFontMetricsF* fm, QString text, double& labelX, double& labelY ); void calculateLabelSize( const QFontMetricsF* fm, QString text, double& labelX, double& labelY );


// implementation of register feature hook // implementation of register feature hook
void registerFeature( QgsFeature& f, const QgsRenderContext& context ); void registerFeature(QgsVectorLayer* layer, QgsFeature& f, const QgsRenderContext& context );


void readFromLayer( QgsVectorLayer* layer ); void readFromLayer( QgsVectorLayer* layer );
void writeToLayer( QgsVectorLayer* layer ); void writeToLayer( QgsVectorLayer* layer );
Expand Down

0 comments on commit 2b5fb21

Please sign in to comment.