Skip to content
Permalink
Browse files

Added expression based labels, simple dialog for entering expressions.

Code still needs some clean up and testing.
  • Loading branch information
NathanW2 committed Jun 4, 2011
1 parent 0e318b0 commit 2b5fb2138692b0677cea795bcfbf4275a2434d4f
@@ -24,13 +24,15 @@

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

#include <QColorDialog>
#include <QFontDialog>

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

#include <QMessageBox>


QgsLabelingGui::QgsLabelingGui( QgsPalLabeling* lbl, QgsVectorLayer* layer, QgsMapCanvas* mapCanvas, QWidget* parent )
@@ -44,6 +46,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() )
@@ -65,12 +68,14 @@ QgsLabelingGui::QgsLabelingGui( QgsPalLabeling* lbl, QgsVectorLayer* layer, QgsM
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();

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

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

void QgsLabelingGui::apply()
{
layerSettings().writeToLayer( mLayer );
// trigger refresh
if ( mMapCanvas )
{
mMapCanvas->refresh();
}
QgsPalLayerSettings settings = layerSettings();
// If we get here we are good to go.
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.dist = 0;
lyr.placementFlags = 0;
@@ -300,7 +310,6 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
return lyr;
}


void QgsLabelingGui::populateFieldNames()
{
const QgsFieldMap& fields = mLayer->pendingFields();
@@ -449,6 +458,35 @@ void QgsLabelingGui::showEngineConfigDialog()
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()
{
// enable/disable scale-based, buffer
@@ -41,6 +41,7 @@ class QgsLabelingGui : public QDialog, private Ui::QgsLabelingGuiBase
void changeTextColor();
void changeTextFont();
void showEngineConfigDialog();
void showExpressionDialog();
void changeBufferColor();

void updateUi();
@@ -34,10 +34,14 @@
#include "qgsmaptopixel.h"
#include "qgscoordinatetransform.h"
#include "qgsrendercontext.h"
#include "qgssearchtreenode.h"
#include "qgssearchstring.h"

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

#include <QMessageBox>

// use M_PI define PI 3.141592654
#ifdef WIN32
#undef M_PI
@@ -103,16 +107,37 @@ void QgsLabel::renderLabel( QgsRenderContext &renderContext,
double x2 = point.x();
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 */
value = fieldValue( Text, feature );
/*value = fieldValue( Text, feature );
if ( value.isEmpty() )
{
text = mLabelAttributes->text();
}
else
{
text = value;
}
} */

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

} // QgsLabel::readXML()



void QgsLabel::writeXML( QDomNode & layer_node, QDomDocument & document ) const
{
QDomElement labelattributes = document.createElement( "labelattributes" );
@@ -41,13 +41,16 @@
#include "qgsdiagram.h"
#include "qgsdiagramrendererv2.h"
#include "qgslabelsearchtree.h"
#include "qgssearchtreenode.h"
#include "qgssearchstring.h"

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

#include <QMessageBox>

using namespace pal;

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

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

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

@@ -427,9 +433,36 @@ void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF* fm, QString t
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
QFont labelFont = textFont;

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

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

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

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

void QgsPalLabeling::registerDiagramFeature( QgsVectorLayer* layer, QgsFeature& feat, const QgsRenderContext& context )
@@ -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 ddColY = layerIt.value().yPosColumn;
double ddPosX = 0.0;
@@ -1212,7 +1249,6 @@ void QgsPalLabeling::drawLabel( pal::LabelPosition* label, QPainter* painter, co

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

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

@@ -98,6 +98,7 @@ class CORE_EXPORT QgsPalLayerSettings
};

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

// 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 writeToLayer( QgsVectorLayer* layer );

0 comments on commit 2b5fb21

Please sign in to comment.
You can’t perform that action at this time.