Skip to content

Commit 175e70a

Browse files
author
wonder
committedAug 8, 2009
Labeling hooks replaced with labeling engine interface (nicer solution).
Added loading/saving of labeling into the project files (using layer's custom properties) git-svn-id: http://svn.osgeo.org/qgis/branches/symbology-ng-branch@11291 c8812cc2-4d05-0410-92ff-de0c093fc19c

File tree

8 files changed

+281
-211
lines changed

8 files changed

+281
-211
lines changed
 

‎src/core/qgsvectorlayer.cpp

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,7 @@ QgsVectorLayer::QgsVectorLayer( QString vectorLayerPath,
111111
mActiveCommand( NULL ),
112112
mRendererV2( NULL ),
113113
mUsingRendererV2( false ),
114-
mLabelingPrepareLayerHook( NULL ),
115-
mLabelingRegisterFeatureHook( NULL )
114+
mLabelingEngine( NULL )
116115
{
117116
mActions = new QgsAttributeAction;
118117

@@ -687,7 +686,7 @@ void QgsVectorLayer::drawRendererV2( QgsRenderContext& rendererContext, bool lab
687686
mRendererV2->renderFeature(fet, rendererContext);
688687

689688
if ( labeling )
690-
mLabelingRegisterFeatureHook(fet, mLabelingLayerContext);
689+
mLabelingEngine->registerFeature(this, fet);
691690
}
692691

693692
mRendererV2->stopRender(rendererContext);
@@ -712,7 +711,7 @@ void QgsVectorLayer::drawRendererV2Levels( QgsRenderContext& rendererContext, bo
712711
features[sym].append( fet );
713712

714713
if ( labeling )
715-
mLabelingRegisterFeatureHook(fet, mLabelingLayerContext);
714+
mLabelingEngine->registerFeature(this, fet);
716715
}
717716

718717
// find out the order
@@ -773,10 +772,10 @@ bool QgsVectorLayer::draw( QgsRenderContext& rendererContext )
773772
QgsDebugMsg("attrs: " + QString::number(attributes[0]));
774773

775774
bool labeling = FALSE;
776-
if ( mLabelingPrepareLayerHook && mLabelingRegisterFeatureHook )
775+
if ( mLabelingEngine )
777776
{
778777
int attrIndex;
779-
if (mLabelingPrepareLayerHook(mLabelingContext, mLabelingLayerContext, attrIndex))
778+
if (mLabelingEngine->prepareLayer(this, attrIndex))
780779
{
781780
if (!attributes.contains(attrIndex))
782781
attributes << attrIndex;
@@ -831,10 +830,10 @@ bool QgsVectorLayer::draw( QgsRenderContext& rendererContext )
831830
QgsAttributeList attributes = mRenderer->classificationAttributes();
832831

833832
bool labeling = FALSE;
834-
if (mLabelingPrepareLayerHook)
833+
if (mLabelingEngine)
835834
{
836835
int attrIndex;
837-
if (mLabelingPrepareLayerHook(mLabelingContext, mLabelingLayerContext, attrIndex))
836+
if (mLabelingEngine->prepareLayer(this, attrIndex))
838837
{
839838
if (!attributes.contains(attrIndex))
840839
attributes << attrIndex;
@@ -911,9 +910,9 @@ bool QgsVectorLayer::draw( QgsRenderContext& rendererContext )
911910
rendererContext.rasterScaleFactor(),
912911
rendererContext.drawEditingInformation() );
913912

914-
if (labeling && mLabelingRegisterFeatureHook)
913+
if (labeling && mLabelingEngine)
915914
{
916-
mLabelingRegisterFeatureHook(fet, mLabelingLayerContext);
915+
mLabelingEngine->registerFeature(this, fet);
917916
}
918917

919918
++featureCount;
@@ -2229,15 +2228,9 @@ bool QgsVectorLayer::hasLabelsEnabled( void ) const
22292228
return mLabelOn;
22302229
}
22312230

2232-
void QgsVectorLayer::setLabelingHooks(LabelingPrepareLayerHook prepareLayerHook,
2233-
LabelingRegisterFeatureHook registerFeatureHook,
2234-
void* context,
2235-
void* layerContext)
2231+
void QgsVectorLayer::setLabelingEngine(QgsLabelingEngineInterface* engine)
22362232
{
2237-
mLabelingPrepareLayerHook = prepareLayerHook;
2238-
mLabelingRegisterFeatureHook = registerFeatureHook;
2239-
mLabelingContext = context;
2240-
mLabelingLayerContext = layerContext;
2233+
mLabelingEngine = engine;
22412234
}
22422235

22432236

‎src/core/qgsvectorlayer.h

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,16 @@ typedef QList<int> QgsAttributeList;
5353
typedef QSet<int> QgsFeatureIds;
5454
typedef QSet<int> QgsAttributeIds;
5555

56-
typedef int (*LabelingPrepareLayerHook)(void*, void*, int&);
57-
typedef void (*LabelingRegisterFeatureHook)(QgsFeature&, void*);
56+
class QgsLabelingEngineInterface
57+
{
58+
public:
59+
virtual ~QgsLabelingEngineInterface() {}
60+
virtual int prepareLayer(QgsVectorLayer* layer, int& attrIndex) = 0;
61+
virtual void registerFeature(QgsVectorLayer* layer, QgsFeature& feat) = 0;
62+
//void calculateLabeling() = 0;
63+
//void drawLabeling(QgsRenderContext& context) = 0;
64+
};
65+
5866

5967

6068
/** \ingroup core
@@ -348,10 +356,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
348356
/** Label is on */
349357
bool hasLabelsEnabled( void ) const;
350358

351-
void setLabelingHooks(LabelingPrepareLayerHook prepareLayerHook,
352-
LabelingRegisterFeatureHook registerFeatureHook,
353-
void* mLabelingContext,
354-
void* mLabelingLayerContext);
359+
void setLabelingEngine(QgsLabelingEngineInterface* engine);
355360

356361
/** Returns true if the provider is in editing mode */
357362
virtual bool isEditable() const;
@@ -733,10 +738,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
733738
/** Label */
734739
QgsLabel *mLabel;
735740

736-
LabelingPrepareLayerHook mLabelingPrepareLayerHook;
737-
LabelingRegisterFeatureHook mLabelingRegisterFeatureHook;
738-
void* mLabelingContext;
739-
void* mLabelingLayerContext;
741+
QgsLabelingEngineInterface* mLabelingEngine;
740742

741743

742744
/** Display labels */

‎src/plugins/labeling/labeling.cpp

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <qgisgui.h>
2424
#include <qgsmapcanvas.h>
2525
#include <qgsvectorlayer.h>
26+
#include <qgsmaplayerregistry.h>
2627

2728
#include "labeling.h"
2829
#include "labelinggui.h"
@@ -124,6 +125,20 @@ void Labeling::initGui()
124125

125126
connect( mQGisIface->mapCanvas(), SIGNAL( renderComplete( QPainter * ) ), this, SLOT( doLabeling( QPainter * ) ) );
126127

128+
// connect to newly added layers so the labeling hook will be set up
129+
connect( QgsMapLayerRegistry::instance(), SIGNAL(layerWasAdded(QgsMapLayer*)), this, SLOT(layerWasAdded(QgsMapLayer*)) );
130+
131+
// add labeling hooks to all existing layers
132+
QMap<QString, QgsMapLayer*>& layers = QgsMapLayerRegistry::instance()->mapLayers();
133+
for (QMap<QString, QgsMapLayer*>::iterator it = layers.begin(); it != layers.end(); ++it)
134+
{
135+
QgsMapLayer* layer = it.value();
136+
if (layer->type() == QgsMapLayer::VectorLayer)
137+
{
138+
QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>(layer);
139+
vlayer->setLabelingEngine(mLBL);
140+
}
141+
}
127142
}
128143

129144
void Labeling::doLabeling( QPainter * painter )
@@ -143,15 +158,14 @@ void Labeling::run()
143158
QMessageBox::warning(mQGisIface->mainWindow(), "Labeling", "Please select a vector layer first.");
144159
return;
145160
}
146-
//QgsVectorLayer* vlayer = static_cast<QgsVectorLayer*>(layer);
161+
QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>(layer);
147162

148-
LabelingGui myPluginGui( mLBL, layer->getLayerID(), mQGisIface->mainWindow() );
163+
LabelingGui myPluginGui( mLBL, vlayer, mQGisIface->mainWindow() );
149164

150165
if (myPluginGui.exec())
151166
{
152-
// alter labeling
153-
mLBL->removeLayer(layer->getLayerID());
154-
mLBL->addLayer( myPluginGui.layerSettings() );
167+
// alter labeling - save the changes
168+
myPluginGui.layerSettings().writeToLayer(vlayer);
155169

156170
// trigger refresh
157171
mQGisIface->mapCanvas()->refresh();
@@ -170,6 +184,21 @@ void Labeling::unload()
170184
mQGisIface->mapCanvas()->unsetMapTool(mTool);
171185
delete mTool;
172186

187+
// remove labeling hook from all layers!
188+
QMap<QString, QgsMapLayer*>& layers = QgsMapLayerRegistry::instance()->mapLayers();
189+
for (QMap<QString, QgsMapLayer*>::iterator it = layers.begin(); it != layers.end(); ++it)
190+
{
191+
QgsMapLayer* layer = it.value();
192+
if (layer->type() == QgsMapLayer::VectorLayer)
193+
{
194+
QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>(layer);
195+
vlayer->setLabelingEngine(NULL);
196+
}
197+
}
198+
199+
disconnect( QgsMapLayerRegistry::instance(), SIGNAL(layerWasAdded(QgsMapLayer*)), this, SLOT(layerWasAdded(QgsMapLayer*)) );
200+
disconnect( mQGisIface->mapCanvas(), SIGNAL( renderComplete( QPainter * ) ), this, SLOT( doLabeling( QPainter * ) ) );
201+
173202
// remove the GUI
174203
mQGisIface->removePluginMenu( "&Labeling", mQActionPointer );
175204
mQGisIface->removeToolBarIcon( mQActionPointer );
@@ -181,6 +210,16 @@ void Labeling::unload()
181210
delete mLBL;
182211
}
183212

213+
void Labeling::layerWasAdded( QgsMapLayer* layer )
214+
{
215+
if (layer->type() != QgsMapLayer::VectorLayer)
216+
return; // not interested in rasters
217+
218+
QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>(layer);
219+
// add labeling hook for the newly added layer
220+
vlayer->setLabelingEngine(mLBL);
221+
}
222+
184223

185224
//////////////////////////////////////////////////////////////////////////
186225
//

‎src/plugins/labeling/labeling.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
//QGIS includes
2525
#include "../qgisplugin.h"
2626

27+
#include "qgsmaplayer.h" // for MOC
28+
2729
//forward declarations
2830
class QAction;
2931
class QPainter;
@@ -62,6 +64,8 @@ class Labeling: public QObject, public QgisPlugin
6264
//! start labeling map tool
6365
void setTool();
6466

67+
void layerWasAdded( QgsMapLayer* theMapLayer );
68+
6569
private:
6670

6771
//! Pointer to the QGIS interface object

‎src/plugins/labeling/labelinggui.cpp

Lines changed: 62 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232

3333

3434

35-
LabelingGui::LabelingGui( PalLabeling* lbl, QString layerId, QWidget* parent )
36-
: QDialog( parent ), mLBL( lbl ), mLayerId( layerId )
35+
LabelingGui::LabelingGui( PalLabeling* lbl, QgsVectorLayer* layer, QWidget* parent )
36+
: QDialog( parent ), mLBL( lbl ), mLayer( layer )
3737
{
3838
setupUi( this );
3939

@@ -45,7 +45,7 @@ LabelingGui::LabelingGui( PalLabeling* lbl, QString layerId, QWidget* parent )
4545
connect(btnEngineSettings, SIGNAL(clicked()), this, SLOT(showEngineConfigDialog()) );
4646

4747
// set placement methods page based on geometry type
48-
switch (layer()->geometryType())
48+
switch (layer->geometryType())
4949
{
5050
case QGis::Point:
5151
stackedPlacement->setCurrentWidget(pagePoint);
@@ -62,77 +62,69 @@ LabelingGui::LabelingGui( PalLabeling* lbl, QString layerId, QWidget* parent )
6262

6363
populateFieldNames();
6464

65-
const LayerSettings& lyr = lbl->layer(layerId);
66-
if (!lyr.layerId.isEmpty())
65+
// load labeling settings from layer
66+
LayerSettings lyr;
67+
lyr.readFromLayer(layer);
68+
69+
// placement
70+
switch (lyr.placement)
6771
{
68-
// load the labeling settings
69-
70-
// placement
71-
switch (lyr.placement)
72-
{
73-
case LayerSettings::AroundPoint:
74-
radAroundPoint->setChecked(true);
75-
radAroundCentroid->setChecked(true);
76-
spinDistPoint->setValue(lyr.dist);
77-
//spinAngle->setValue(lyr.angle);
78-
break;
79-
case LayerSettings::OverPoint:
80-
radOverPoint->setChecked(true);
81-
radOverCentroid->setChecked(true);
82-
break;
83-
case LayerSettings::Line:
84-
radLineParallel->setChecked(true);
85-
radPolygonPerimeter->setChecked(true);
86-
87-
spinDistLine->setValue(lyr.dist);
88-
chkLineAbove->setChecked( lyr.placementFlags & LayerSettings::AboveLine );
89-
chkLineBelow->setChecked( lyr.placementFlags & LayerSettings::BelowLine );
90-
chkLineOn->setChecked( lyr.placementFlags & LayerSettings::OnLine );
91-
if ( lyr.placementFlags & LayerSettings::MapOrientation )
92-
radOrientationMap->setChecked(true);
93-
else
94-
radOrientationLine->setChecked(true);
95-
break;
96-
case LayerSettings::Curved:
97-
radLineCurved->setChecked(true);
98-
break;
99-
case LayerSettings::Horizontal:
100-
radPolygonHorizontal->setChecked(true);
101-
radLineHorizontal->setChecked(true);
102-
break;
103-
case LayerSettings::Free:
104-
radPolygonFree->setChecked(true);
105-
break;
106-
default:
107-
Q_ASSERT(0 && "NOOO!");
108-
}
109-
110-
cboFieldName->setCurrentIndex( cboFieldName->findText(lyr.fieldName) );
111-
chkEnableLabeling->setChecked( lyr.enabled );
112-
sliderPriority->setValue( lyr.priority );
113-
chkNoObstacle->setChecked( !lyr.obstacle );
114-
chkLabelPerFeaturePart->setChecked( lyr.labelPerPart );
115-
116-
bool scaleBased = (lyr.scaleMin != 0 && lyr.scaleMax != 0);
117-
chkScaleBasedVisibility->setChecked(scaleBased);
118-
if (scaleBased)
119-
{
120-
spinScaleMin->setValue(lyr.scaleMin);
121-
spinScaleMax->setValue(lyr.scaleMax);
122-
}
123-
124-
bool buffer = (lyr.bufferSize != 0);
125-
chkBuffer->setChecked(buffer);
126-
if (buffer)
127-
spinBufferSize->setValue(lyr.bufferSize);
72+
case LayerSettings::AroundPoint:
73+
radAroundPoint->setChecked(true);
74+
radAroundCentroid->setChecked(true);
75+
spinDistPoint->setValue(lyr.dist);
76+
//spinAngle->setValue(lyr.angle);
77+
break;
78+
case LayerSettings::OverPoint:
79+
radOverPoint->setChecked(true);
80+
radOverCentroid->setChecked(true);
81+
break;
82+
case LayerSettings::Line:
83+
radLineParallel->setChecked(true);
84+
radPolygonPerimeter->setChecked(true);
85+
86+
spinDistLine->setValue(lyr.dist);
87+
chkLineAbove->setChecked( lyr.placementFlags & LayerSettings::AboveLine );
88+
chkLineBelow->setChecked( lyr.placementFlags & LayerSettings::BelowLine );
89+
chkLineOn->setChecked( lyr.placementFlags & LayerSettings::OnLine );
90+
if ( lyr.placementFlags & LayerSettings::MapOrientation )
91+
radOrientationMap->setChecked(true);
92+
else
93+
radOrientationLine->setChecked(true);
94+
break;
95+
case LayerSettings::Curved:
96+
radLineCurved->setChecked(true);
97+
break;
98+
case LayerSettings::Horizontal:
99+
radPolygonHorizontal->setChecked(true);
100+
radLineHorizontal->setChecked(true);
101+
break;
102+
case LayerSettings::Free:
103+
radPolygonFree->setChecked(true);
104+
break;
105+
default:
106+
Q_ASSERT(0 && "NOOO!");
128107
}
129-
else
130-
{
131-
// set enabled by default
132-
chkEnableLabeling->setChecked( true );
133108

109+
cboFieldName->setCurrentIndex( cboFieldName->findText(lyr.fieldName) );
110+
chkEnableLabeling->setChecked( lyr.enabled );
111+
sliderPriority->setValue( lyr.priority );
112+
chkNoObstacle->setChecked( !lyr.obstacle );
113+
chkLabelPerFeaturePart->setChecked( lyr.labelPerPart );
114+
115+
bool scaleBased = (lyr.scaleMin != 0 && lyr.scaleMax != 0);
116+
chkScaleBasedVisibility->setChecked(scaleBased);
117+
if (scaleBased)
118+
{
119+
spinScaleMin->setValue(lyr.scaleMin);
120+
spinScaleMax->setValue(lyr.scaleMax);
134121
}
135122

123+
bool buffer = (lyr.bufferSize != 0);
124+
chkBuffer->setChecked(buffer);
125+
if (buffer)
126+
spinBufferSize->setValue(lyr.bufferSize);
127+
136128
btnTextColor->setColor( lyr.textColor );
137129
btnBufferColor->setColor( lyr.bufferColor );
138130
updateFont( lyr.textFont );
@@ -157,18 +149,9 @@ LabelingGui::~LabelingGui()
157149
{
158150
}
159151

160-
QgsVectorLayer* LabelingGui::layer()
161-
{
162-
QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer(mLayerId);
163-
if (layer == NULL || layer->type() != QgsMapLayer::VectorLayer)
164-
return NULL;
165-
return static_cast<QgsVectorLayer*>(layer);
166-
}
167-
168152
LayerSettings LabelingGui::layerSettings()
169153
{
170154
LayerSettings lyr;
171-
lyr.layerId = mLayerId;
172155
lyr.fieldName = cboFieldName->currentText();
173156

174157
lyr.dist = 0;
@@ -249,7 +232,7 @@ LayerSettings LabelingGui::layerSettings()
249232

250233
void LabelingGui::populateFieldNames()
251234
{
252-
QgsFieldMap fields = layer()->dataProvider()->fields();
235+
QgsFieldMap fields = mLayer->dataProvider()->fields();
253236
for (QgsFieldMap::iterator it = fields.begin(); it != fields.end(); it++)
254237
{
255238
cboFieldName->addItem(it->name());

‎src/plugins/labeling/labelinggui.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@
2121
#include <QDialog>
2222
#include <ui_labelingguibase.h>
2323

24-
//class PalLabeling;
2524
class QgsVectorLayer;
26-
//struct PalLabeling::LayerSettings;
2725

2826
#include "pallabeling.h"
2927

@@ -32,7 +30,7 @@ class LabelingGui : public QDialog, private Ui::LabelingGuiBase
3230
Q_OBJECT
3331

3432
public:
35-
LabelingGui( PalLabeling* lbl, QString layerId, QWidget* parent );
33+
LabelingGui( PalLabeling* lbl, QgsVectorLayer* layer, QWidget* parent );
3634
~LabelingGui();
3735

3836
LayerSettings layerSettings();
@@ -52,11 +50,9 @@ class LabelingGui : public QDialog, private Ui::LabelingGuiBase
5250
void populateFieldNames();
5351
void updateFont(QFont font);
5452

55-
QgsVectorLayer* layer();
56-
5753
private:
5854
PalLabeling* mLBL;
59-
QString mLayerId;
55+
QgsVectorLayer* mLayer;
6056
};
6157

6258
#endif

‎src/plugins/labeling/pallabeling.cpp

Lines changed: 129 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,24 @@ class MyLabel : public PalGeometry
8989
LayerSettings::LayerSettings()
9090
: palLayer(NULL), fontMetrics(NULL), ct(NULL)
9191
{
92+
placement = AroundPoint;
93+
placementFlags = 0;
94+
//textFont = QFont();
95+
textColor = Qt::black;
96+
enabled = false;
97+
priority = 5;
98+
obstacle = true;
99+
dist = 0;
100+
scaleMin = 0;
101+
scaleMax = 0;
102+
bufferSize = 1;
92103
bufferColor = Qt::white;
104+
labelPerPart = false;
93105
}
94106

95107
LayerSettings::LayerSettings(const LayerSettings& s)
96108
{
97109
// copy only permanent stuff
98-
layerId = s.layerId;
99110
fieldName = s.fieldName;
100111
placement = s.placement;
101112
placementFlags = s.placementFlags;
@@ -124,6 +135,72 @@ LayerSettings::~LayerSettings()
124135
delete ct;
125136
}
126137

138+
static QColor _readColor(QgsVectorLayer* layer, QString property)
139+
{
140+
int r = layer->customProperty(property+"R").toInt();
141+
int g = layer->customProperty(property+"G").toInt();
142+
int b = layer->customProperty(property+"B").toInt();
143+
return QColor(r,g,b);
144+
}
145+
146+
static void _writeColor(QgsVectorLayer* layer, QString property, QColor color)
147+
{
148+
layer->setCustomProperty(property+"R", color.red());
149+
layer->setCustomProperty(property+"G", color.green());
150+
layer->setCustomProperty(property+"B", color.blue());
151+
}
152+
153+
void LayerSettings::readFromLayer(QgsVectorLayer* layer)
154+
{
155+
if (layer->customProperty("labeling").toString() != QString("pal"))
156+
return; // there's no information available
157+
158+
fieldName = layer->customProperty("labeling/fieldName").toString();
159+
placement = (Placement) layer->customProperty("labeling/placement").toInt();
160+
placementFlags = layer->customProperty("labeling/placementFlags").toUInt();
161+
QString fontFamily = layer->customProperty("labeling/fontFamily").toString();
162+
int fontSize = layer->customProperty("labeling/fontSize").toInt();
163+
int fontWeight = layer->customProperty("labeling/fontWeight").toInt();
164+
bool fontItalic = layer->customProperty("labeling/fontItalic").toBool();
165+
textFont = QFont(fontFamily, fontSize, fontWeight, fontItalic);
166+
textColor = _readColor(layer, "labeling/textColor");
167+
enabled = layer->customProperty("labeling/enabled").toBool();
168+
priority = layer->customProperty("labeling/priority").toInt();
169+
obstacle = layer->customProperty("labeling/obstacle").toBool();
170+
dist = layer->customProperty("labeling/dist").toDouble();
171+
scaleMin = layer->customProperty("labeling/scaleMin").toInt();
172+
scaleMax = layer->customProperty("labeling/scaleMax").toInt();
173+
bufferSize = layer->customProperty("labeling/bufferSize").toInt();
174+
bufferColor = _readColor(layer, "labeling/bufferColor");
175+
labelPerPart = layer->customProperty("labeling/labelPerPart").toInt();
176+
}
177+
178+
void LayerSettings::writeToLayer(QgsVectorLayer* layer)
179+
{
180+
// this is a mark that labeling information is present
181+
layer->setCustomProperty("labeling", "pal");
182+
183+
layer->setCustomProperty("labeling/fieldName", fieldName);
184+
layer->setCustomProperty("labeling/placement", placement);
185+
layer->setCustomProperty("labeling/placementFlags", (unsigned int)placementFlags);
186+
187+
layer->setCustomProperty("labeling/fontFamily", textFont.family());
188+
layer->setCustomProperty("labeling/fontSize", textFont.pointSize());
189+
layer->setCustomProperty("labeling/fontWeight", textFont.weight());
190+
layer->setCustomProperty("labeling/fontItalic", textFont.italic());
191+
192+
_writeColor(layer, "labeling/textColor", textColor);
193+
layer->setCustomProperty("labeling/enabled", enabled);
194+
layer->setCustomProperty("labeling/priority", priority);
195+
layer->setCustomProperty("labeling/obstacle", obstacle);
196+
layer->setCustomProperty("labeling/dist", dist);
197+
layer->setCustomProperty("labeling/scaleMin", scaleMin);
198+
layer->setCustomProperty("labeling/scaleMax", scaleMax);
199+
layer->setCustomProperty("labeling/bufferSize", bufferSize);
200+
_writeColor(layer, "labeling/bufferColor", bufferColor);
201+
layer->setCustomProperty("labeling/labelPerPart", labelPerPart);
202+
}
203+
127204
void LayerSettings::calculateLabelSize(QString text, double& labelX, double& labelY)
128205
{
129206
//QFontMetrics fontMetrics(textFont);
@@ -195,76 +272,32 @@ PalLabeling::PalLabeling(QgsMapRenderer* mapRenderer)
195272
PalLabeling::~PalLabeling()
196273
{
197274
delete mPal;
198-
199-
// make sure to remove hooks from all layers
200-
while (mLayers.count())
201-
{
202-
removeLayer(mLayers[0].layerId);
203-
}
204-
}
205-
206-
207-
void PalLabeling::addLayer(LayerSettings layerSettings)
208-
{
209-
mLayers.append(layerSettings);
210-
211-
QgsVectorLayer* vlayer = (QgsVectorLayer*) QgsMapLayerRegistry::instance()->mapLayer(layerSettings.layerId);
212-
213-
LayerSettings& lyr = mLayers[ mLayers.count()-1 ]; // make sure we have the right pointer
214-
vlayer->setLabelingHooks(PalLabeling::prepareLayerHook, PalLabeling::registerFeatureHook, this, &lyr);
215-
}
216-
217-
void PalLabeling::removeLayer(QString layerId)
218-
{
219-
for (int i = 0; i < mLayers.count(); i++)
220-
{
221-
if (mLayers.at(i).layerId == layerId)
222-
{
223-
QgsVectorLayer* vlayer = (QgsVectorLayer*) QgsMapLayerRegistry::instance()->mapLayer(mLayers.at(i).layerId);
224-
if (vlayer) { vlayer->setLabelingHooks(NULL, NULL, NULL, NULL); }
225-
226-
mLayers.removeAt(i);
227-
return;
228-
}
229-
}
230-
}
231-
232-
const LayerSettings& PalLabeling::layer(QString layerId)
233-
{
234-
for (int i = 0; i < mLayers.count(); i++)
235-
{
236-
if (mLayers.at(i).layerId == layerId)
237-
{
238-
return mLayers.at(i);
239-
}
240-
}
241-
return mInvalidLayer;
242275
}
243276

244277

245-
246-
int PalLabeling::prepareLayerHook(void* context, void* layerContext, int& attrIndex)
278+
int PalLabeling::prepareLayer(QgsVectorLayer* layer, int& attrIndex)
247279
{
248-
PalLabeling* thisClass = (PalLabeling*) context;
249-
LayerSettings* lyr = (LayerSettings*) layerContext;
250-
251-
if (!lyr->enabled)
252-
return 0;
280+
// start with a temporary settings class, find out labeling info
281+
LayerSettings lyrTmp;
282+
lyrTmp.readFromLayer(layer);
253283

254-
QgsVectorLayer* vlayer = (QgsVectorLayer*) QgsMapLayerRegistry::instance()->mapLayer(lyr->layerId);
255-
if (vlayer == NULL)
284+
if (!lyrTmp.enabled)
256285
return 0;
257286

258287
// find out which field will be needed
259-
int fldIndex = vlayer->dataProvider()->fieldNameIndex(lyr->fieldName);
288+
int fldIndex = layer->dataProvider()->fieldNameIndex(lyrTmp.fieldName);
260289
if (fldIndex == -1)
261290
return 0;
262291
attrIndex = fldIndex;
263292

293+
// add layer settings to the pallabeling hashtable: <QgsVectorLayer*, LayerSettings>
294+
mActiveLayers.insert(layer, lyrTmp);
295+
// start using the reference to the layer in hashtable instead of local instance
296+
LayerSettings& lyr = mActiveLayers[layer];
264297

265298
// how to place the labels
266299
Arrangement arrangement;
267-
switch (lyr->placement)
300+
switch (lyr.placement)
268301
{
269302
case LayerSettings::AroundPoint: arrangement = P_POINT; break;
270303
case LayerSettings::OverPoint: arrangement = P_POINT_OVER; break;
@@ -275,42 +308,44 @@ int PalLabeling::prepareLayerHook(void* context, void* layerContext, int& attrIn
275308
}
276309

277310
// create the pal layer
278-
double priority = 1 - lyr->priority/10.0; // convert 0..10 --> 1..0
311+
double priority = 1 - lyr.priority/10.0; // convert 0..10 --> 1..0
279312
double min_scale = -1, max_scale = -1;
280-
if (lyr->scaleMin != 0 && lyr->scaleMax != 0)
313+
if (lyr.scaleMin != 0 && lyr.scaleMax != 0)
281314
{
282-
min_scale = lyr->scaleMin;
283-
max_scale = lyr->scaleMax;
315+
min_scale = lyr.scaleMin;
316+
max_scale = lyr.scaleMax;
284317
}
285318

286-
Layer* l = thisClass->mPal->addLayer(lyr->layerId.toLocal8Bit().data(), min_scale, max_scale, arrangement, METER, priority, lyr->obstacle, true, true);
319+
Layer* l = mPal->addLayer(layer->getLayerID().toLocal8Bit().data(),
320+
min_scale, max_scale, arrangement,
321+
METER, priority, lyr.obstacle, true, true);
287322

288-
if ( lyr->placementFlags )
289-
l->setArrangementFlags( lyr->placementFlags );
323+
if ( lyr.placementFlags )
324+
l->setArrangementFlags( lyr.placementFlags );
290325

291326
// set label mode (label per feature is the default)
292-
l->setLabelMode( lyr->labelPerPart ? Layer::LabelPerFeaturePart : Layer::LabelPerFeature );
327+
l->setLabelMode( lyr.labelPerPart ? Layer::LabelPerFeaturePart : Layer::LabelPerFeature );
293328

294329
// save the pal layer to our layer context (with some additional info)
295-
lyr->palLayer = l;
296-
lyr->fieldIndex = fldIndex;
297-
lyr->fontMetrics = new QFontMetrics(lyr->textFont);
298-
lyr->fontBaseline = lyr->fontMetrics->boundingRect("X").bottom(); // dummy text to find out how many pixels of the text are below the baseline
299-
lyr->xform = thisClass->mMapRenderer->coordinateTransform();
300-
if (thisClass->mMapRenderer->hasCrsTransformEnabled())
301-
lyr->ct = new QgsCoordinateTransform( vlayer->srs(), thisClass->mMapRenderer->destinationSrs() );
330+
lyr.palLayer = l;
331+
lyr.fieldIndex = fldIndex;
332+
lyr.fontMetrics = new QFontMetrics(lyr.textFont);
333+
lyr.fontBaseline = lyr.fontMetrics->boundingRect("X").bottom(); // dummy text to find out how many pixels of the text are below the baseline
334+
lyr.xform = mMapRenderer->coordinateTransform();
335+
if (mMapRenderer->hasCrsTransformEnabled())
336+
lyr.ct = new QgsCoordinateTransform( layer->srs(), mMapRenderer->destinationSrs() );
302337
else
303-
lyr->ct = NULL;
304-
lyr->ptZero = lyr->xform->toMapCoordinates( 0,0 );
305-
lyr->ptOne = lyr->xform->toMapCoordinates( 1,0 );
338+
lyr.ct = NULL;
339+
lyr.ptZero = lyr.xform->toMapCoordinates( 0,0 );
340+
lyr.ptOne = lyr.xform->toMapCoordinates( 1,0 );
306341

307342
return 1; // init successful
308343
}
309344

310-
void PalLabeling::registerFeatureHook(QgsFeature& f, void* layerContext)
345+
346+
void PalLabeling::registerFeature(QgsVectorLayer* layer, QgsFeature& f)
311347
{
312-
LayerSettings* lyr = (LayerSettings*) layerContext;
313-
lyr->registerFeature(f);
348+
mActiveLayers[layer].registerFeature(f);
314349
}
315350

316351

@@ -339,6 +374,17 @@ void PalLabeling::initPal()
339374
mPal->setPolyP(mCandPolygon);
340375
}
341376

377+
LayerSettings& PalLabeling::layer(const char* layerName)
378+
{
379+
QHash<QgsVectorLayer*, LayerSettings>::iterator lit;
380+
for (lit = mActiveLayers.begin(); lit != mActiveLayers.end(); ++lit)
381+
{
382+
LayerSettings& lyr = lit.value();
383+
if (lyr.palLayer->getName() == layerName)
384+
return lyr;
385+
}
386+
return mInvalidLayerSettings;
387+
}
342388

343389

344390
void PalLabeling::doLabeling(QPainter* painter, QgsRectangle extent)
@@ -361,6 +407,7 @@ void PalLabeling::doLabeling(QPainter* painter, QgsRectangle extent)
361407
catch ( std::exception& e )
362408
{
363409
std::cerr << "PAL EXCEPTION :-( " << e.what() << std::endl;
410+
mActiveLayers.clear(); // clean up
364411
return;
365412
}
366413

@@ -409,13 +456,16 @@ void PalLabeling::doLabeling(QPainter* painter, QgsRectangle extent)
409456
delete labels;
410457

411458
// delete all allocated geometries for features
412-
for (int i = 0; i < mLayers.count(); i++)
459+
QHash<QgsVectorLayer*, LayerSettings>::iterator lit;
460+
for (lit = mActiveLayers.begin(); lit != mActiveLayers.end(); ++lit)
413461
{
414-
LayerSettings& lyr = mLayers[i];
462+
LayerSettings& lyr = lit.value();
415463
for (QList<MyLabel*>::iterator git = lyr.geometries.begin(); git != lyr.geometries.end(); ++git)
416464
delete *git;
417465
lyr.geometries.clear();
418466
}
467+
// labeling is done: clear the active layers hashtable
468+
mActiveLayers.clear();
419469

420470
// re-create PAL
421471
initPal();

‎src/plugins/labeling/pallabeling.h

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ class QgsMapToPixel;
2323
class QgsFeature;
2424
#include "qgspoint.h"
2525

26+
#include "qgsvectorlayer.h" // definition of QgsLabelingEngineInterface
27+
2628
class MyLabel;
2729

2830
class LayerSettings
@@ -50,10 +52,9 @@ class LayerSettings
5052
MapOrientation = 8
5153
};
5254

53-
QString layerId;
5455
QString fieldName;
5556
Placement placement;
56-
unsigned long placementFlags;
57+
unsigned int placementFlags;
5758
QFont textFont;
5859
QColor textColor;
5960
bool enabled;
@@ -71,6 +72,9 @@ class LayerSettings
7172
// implementation of register feature hook
7273
void registerFeature(QgsFeature& f);
7374

75+
void readFromLayer(QgsVectorLayer* layer);
76+
void writeToLayer(QgsVectorLayer* layer);
77+
7478
// temporary stuff: set when layer gets prepared
7579
pal::Layer* palLayer;
7680
int fieldIndex;
@@ -91,19 +95,15 @@ class LabelCandidate
9195
double cost;
9296
};
9397

94-
class PalLabeling
98+
class PalLabeling : public QgsLabelingEngineInterface
9599
{
96100
public:
97101
PalLabeling(QgsMapRenderer* renderer);
98102
~PalLabeling();
99103

100-
void doLabeling(QPainter* painter, QgsRectangle extent);
101-
102-
void addLayer(LayerSettings layerSettings);
104+
LayerSettings& layer(const char* layerName);
103105

104-
void removeLayer(QString layerId);
105-
106-
const LayerSettings& layer(QString layerId);
106+
void doLabeling(QPainter* painter, QgsRectangle extent);
107107

108108
void numCandidatePositions(int& candPoint, int& candLine, int& candPolygon);
109109
void setNumCandidatePositions(int candPoint, int candLine, int candPolygon);
@@ -120,10 +120,12 @@ class PalLabeling
120120
bool isShowingAllLabels() const { return mShowingAllLabels; }
121121
void setShowingAllLabels(bool showing) { mShowingAllLabels = showing; }
122122

123+
// implemented methods from labeling engine interface
124+
123125
//! hook called when drawing layer before issuing select()
124-
static int prepareLayerHook(void* context, void* layerContext, int& attrIndex);
126+
virtual int prepareLayer(QgsVectorLayer* layer, int& attrIndex);
125127
//! hook called when drawing for every feature in a layer
126-
static void registerFeatureHook(QgsFeature& f, void* layerContext);
128+
virtual void registerFeature(QgsVectorLayer* layer, QgsFeature& feat);
127129

128130

129131
void drawLabelCandidateRect( pal::LabelPosition* lp, QPainter* painter, const QgsMapToPixel* xform );
@@ -135,9 +137,10 @@ class PalLabeling
135137
void initPal();
136138

137139
protected:
138-
QList<LayerSettings> mLayers;
139-
LayerSettings mInvalidLayer;
140-
140+
// temporary hashtable of layer settings, being filled during labeling, cleared once labeling's done
141+
QHash<QgsVectorLayer*, LayerSettings> mActiveLayers;
142+
LayerSettings mInvalidLayerSettings;
143+
141144
QgsMapRenderer* mMapRenderer;
142145
int mCandPoint, mCandLine, mCandPolygon;
143146
Search mSearch;

0 commit comments

Comments
 (0)
Please sign in to comment.