rulebasedrenderer_v2.diff
src/gui/symbology-ng/qgsrulebasedrendererv2widget.h (revision 0) | ||
---|---|---|
1 |
/*************************************************************************** |
|
2 |
qgsrulebasedrendererv2widget.h - Settings widget for rule-based renderer |
|
3 |
--------------------- |
|
4 |
begin : May 2010 |
|
5 |
copyright : (C) 2010 by Martin Dobias |
|
6 |
email : wonder.sk at gmail.com |
|
7 |
*************************************************************************** |
|
8 |
* * |
|
9 |
* This program is free software; you can redistribute it and/or modify * |
|
10 |
* it under the terms of the GNU General Public License as published by * |
|
11 |
* the Free Software Foundation; either version 2 of the License, or * |
|
12 |
* (at your option) any later version. * |
|
13 |
* * |
|
14 |
***************************************************************************/ |
|
15 | ||
16 |
#ifndef QGSRULEBASEDRENDERERV2WIDGET_H |
|
17 |
#define QGSRULEBASEDRENDERERV2WIDGET_H |
|
18 | ||
19 |
#include "qgsrendererv2widget.h" |
|
20 | ||
21 |
#include "qgsrulebasedrendererv2.h" |
|
22 |
class QMenu; |
|
23 | ||
24 |
/////// |
|
25 | ||
26 |
#include <QTreeWidget> |
|
27 | ||
28 |
class QgsRendererRulesTreeWidget : public QTreeWidget |
|
29 |
{ |
|
30 |
public: |
|
31 |
QgsRendererRulesTreeWidget( QWidget* parent = 0 ); |
|
32 | ||
33 |
void setRenderer( QgsRuleBasedRendererV2* r ); |
|
34 | ||
35 |
enum Grouping { NoGrouping, GroupingByScale, GroupingByFilter }; |
|
36 | ||
37 |
void setGrouping( Grouping g ); |
|
38 | ||
39 |
void populateRules(); |
|
40 | ||
41 |
protected: |
|
42 |
void populateRulesNoGrouping(); |
|
43 |
void populateRulesGroupByScale(); |
|
44 |
void populateRulesGroupByFilter(); |
|
45 | ||
46 |
QgsRuleBasedRendererV2* mR; |
|
47 |
Grouping mGrouping; |
|
48 |
}; |
|
49 | ||
50 |
/////// |
|
51 | ||
52 |
#include "ui_qgsrulebasedrendererv2widget.h" |
|
53 | ||
54 |
class GUI_EXPORT QgsRuleBasedRendererV2Widget : public QgsRendererV2Widget, private Ui::QgsRuleBasedRendererV2Widget |
|
55 |
{ |
|
56 |
Q_OBJECT |
|
57 | ||
58 |
public: |
|
59 | ||
60 |
static QgsRendererV2Widget* create( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer ); |
|
61 | ||
62 |
QgsRuleBasedRendererV2Widget( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer ); |
|
63 |
~QgsRuleBasedRendererV2Widget(); |
|
64 | ||
65 |
virtual QgsFeatureRendererV2* renderer(); |
|
66 | ||
67 |
public slots: |
|
68 | ||
69 |
void addRule(); |
|
70 |
void editRule(); |
|
71 |
void removeRule(); |
|
72 | ||
73 |
void setGrouping(); |
|
74 | ||
75 |
void refineRuleScales(); |
|
76 |
void refineRuleCategories(); |
|
77 |
void refineRuleRanges(); |
|
78 | ||
79 |
protected: |
|
80 | ||
81 |
void refineRule( int type ); |
|
82 |
QList<QgsRuleBasedRendererV2::Rule> refineRuleCategoriesGui( QgsRuleBasedRendererV2::Rule& initialRule ); |
|
83 |
QList<QgsRuleBasedRendererV2::Rule> refineRuleRangesGui( QgsRuleBasedRendererV2::Rule& initialRule ); |
|
84 |
QList<QgsRuleBasedRendererV2::Rule> refineRuleScalesGui( QgsRuleBasedRendererV2::Rule& initialRule ); |
|
85 | ||
86 |
QgsRuleBasedRendererV2* mRenderer; |
|
87 | ||
88 |
QMenu* mRefineMenu; |
|
89 |
}; |
|
90 | ||
91 |
/////// |
|
92 | ||
93 |
#include <QDialog> |
|
94 | ||
95 |
#include "ui_qgsrendererrulepropsdialogbase.h" |
|
96 | ||
97 |
class GUI_EXPORT QgsRendererRulePropsDialog : public QDialog, private Ui::QgsRendererRulePropsDialog |
|
98 |
{ |
|
99 |
Q_OBJECT |
|
100 | ||
101 |
public: |
|
102 |
QgsRendererRulePropsDialog( const QgsRuleBasedRendererV2::Rule& rule, QgsVectorLayer* layer, QgsStyleV2* style ); |
|
103 | ||
104 |
void updateRuleFromGui(); |
|
105 |
const QgsRuleBasedRendererV2::Rule& rule() { return mRule; } |
|
106 | ||
107 |
public slots: |
|
108 |
void testFilter(); |
|
109 | ||
110 |
protected: |
|
111 |
QgsRuleBasedRendererV2::Rule mRule; |
|
112 |
QgsVectorLayer* mLayer; |
|
113 |
QgsStyleV2* mStyle; |
|
114 |
}; |
|
115 | ||
116 | ||
117 |
#endif // QGSRULEBASEDRENDERERV2WIDGET_H |
src/gui/symbology-ng/qgsrulebasedrendererv2widget.cpp (revision 0) | ||
---|---|---|
1 |
/*************************************************************************** |
|
2 |
qgsrulebasedrendererv2widget.cpp - Settings widget for rule-based renderer |
|
3 |
--------------------- |
|
4 |
begin : May 2010 |
|
5 |
copyright : (C) 2010 by Martin Dobias |
|
6 |
email : wonder.sk at gmail.com |
|
7 |
*************************************************************************** |
|
8 |
* * |
|
9 |
* This program is free software; you can redistribute it and/or modify * |
|
10 |
* it under the terms of the GNU General Public License as published by * |
|
11 |
* the Free Software Foundation; either version 2 of the License, or * |
|
12 |
* (at your option) any later version. * |
|
13 |
* * |
|
14 |
***************************************************************************/ |
|
15 | ||
16 |
#include "qgsrulebasedrendererv2widget.h" |
|
17 | ||
18 |
#include "qgsrulebasedrendererv2.h" |
|
19 |
#include "qgssymbollayerv2utils.h" |
|
20 |
#include "qgssymbolv2.h" |
|
21 |
#include "qgsvectorlayer.h" |
|
22 |
#include "qgsapplication.h" |
|
23 |
#include "qgssearchtreenode.h" |
|
24 |
#include "qgssymbolv2selectordialog.h" |
|
25 | ||
26 |
#include <QMenu> |
|
27 |
#include <QTreeWidgetItem> |
|
28 |
#include <QVBoxLayout> |
|
29 |
#include <QMessageBox> |
|
30 | ||
31 |
QgsRendererV2Widget* QgsRuleBasedRendererV2Widget::create( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer ) |
|
32 |
{ |
|
33 |
return new QgsRuleBasedRendererV2Widget( layer, style, renderer ); |
|
34 |
} |
|
35 | ||
36 |
QgsRuleBasedRendererV2Widget::QgsRuleBasedRendererV2Widget( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer ) |
|
37 |
: QgsRendererV2Widget( layer, style ) |
|
38 |
{ |
|
39 | ||
40 |
// try to recognize the previous renderer |
|
41 |
// (null renderer means "no previous renderer") |
|
42 |
if ( !renderer || renderer->type() != "RuleRenderer" ) |
|
43 |
{ |
|
44 |
// we're not going to use it - so let's delete the renderer |
|
45 |
delete renderer; |
|
46 | ||
47 |
// some default options |
|
48 |
QgsSymbolV2* symbol = QgsSymbolV2::defaultSymbol( mLayer->geometryType() ); |
|
49 | ||
50 |
mRenderer = new QgsRuleBasedRendererV2( symbol ); |
|
51 |
} |
|
52 |
else |
|
53 |
{ |
|
54 |
mRenderer = static_cast<QgsRuleBasedRendererV2*>( renderer ); |
|
55 |
} |
|
56 | ||
57 |
setupUi( this ); |
|
58 | ||
59 |
treeRules->setRenderer( mRenderer ); |
|
60 | ||
61 |
mRefineMenu = new QMenu( btnRefineRule ); |
|
62 |
mRefineMenu->addAction( tr( "Add scales" ), this, SLOT( refineRuleScales() ) ); |
|
63 |
mRefineMenu->addAction( tr( "Add categories" ), this, SLOT( refineRuleCategories() ) ); |
|
64 |
mRefineMenu->addAction( tr( "Add ranges" ), this, SLOT( refineRuleRanges() ) ); |
|
65 |
btnRefineRule->setMenu( mRefineMenu ); |
|
66 | ||
67 |
btnAddRule->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.png" ) ) ); |
|
68 |
btnEditRule->setIcon( QIcon( QgsApplication::iconPath( "symbologyEdit.png" ) ) ); |
|
69 |
btnRemoveRule->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.png" ) ) ); |
|
70 | ||
71 |
connect( treeRules, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( editRule() ) ); |
|
72 | ||
73 |
connect( btnAddRule, SIGNAL( clicked() ), this, SLOT( addRule() ) ); |
|
74 |
connect( btnEditRule, SIGNAL( clicked() ), this, SLOT( editRule() ) ); |
|
75 |
connect( btnRemoveRule, SIGNAL( clicked() ), this, SLOT( removeRule() ) ); |
|
76 | ||
77 |
connect( radNoGrouping, SIGNAL( clicked() ), this, SLOT( setGrouping() ) ); |
|
78 |
connect( radGroupFilter, SIGNAL( clicked() ), this, SLOT( setGrouping() ) ); |
|
79 |
connect( radGroupScale, SIGNAL( clicked() ), this, SLOT( setGrouping() ) ); |
|
80 | ||
81 |
treeRules->populateRules(); |
|
82 |
} |
|
83 | ||
84 |
QgsRuleBasedRendererV2Widget::~QgsRuleBasedRendererV2Widget() |
|
85 |
{ |
|
86 |
delete mRenderer; |
|
87 |
} |
|
88 | ||
89 |
QgsFeatureRendererV2* QgsRuleBasedRendererV2Widget::renderer() |
|
90 |
{ |
|
91 |
return mRenderer; |
|
92 |
} |
|
93 | ||
94 |
void QgsRuleBasedRendererV2Widget::setGrouping() |
|
95 |
{ |
|
96 |
QObject* origin = sender(); |
|
97 |
if ( origin == radNoGrouping ) |
|
98 |
treeRules->setGrouping( QgsRendererRulesTreeWidget::NoGrouping ); |
|
99 |
else if ( origin == radGroupFilter ) |
|
100 |
treeRules->setGrouping( QgsRendererRulesTreeWidget::GroupingByFilter ); |
|
101 |
else if ( origin == radGroupScale ) |
|
102 |
treeRules->setGrouping( QgsRendererRulesTreeWidget::GroupingByScale ); |
|
103 |
} |
|
104 | ||
105 |
void QgsRuleBasedRendererV2Widget::addRule() |
|
106 |
{ |
|
107 |
QgsRuleBasedRendererV2::Rule newrule( QgsSymbolV2::defaultSymbol( mLayer->geometryType() ) ); |
|
108 | ||
109 |
QgsRendererRulePropsDialog dlg( newrule, mLayer, mStyle ); |
|
110 |
if ( dlg.exec() ) |
|
111 |
{ |
|
112 |
// add rule |
|
113 |
dlg.updateRuleFromGui(); |
|
114 |
mRenderer->addRule( dlg.rule() ); |
|
115 |
treeRules->populateRules(); |
|
116 |
} |
|
117 |
} |
|
118 | ||
119 | ||
120 | ||
121 |
void QgsRuleBasedRendererV2Widget::editRule() |
|
122 |
{ |
|
123 |
QTreeWidgetItem * item = treeRules->currentItem(); |
|
124 |
if ( ! item ) return; |
|
125 | ||
126 |
int rule_index = item->data( 0, Qt::UserRole + 1 ).toInt(); |
|
127 |
if ( rule_index < 0 ) |
|
128 |
{ |
|
129 |
QMessageBox::information( this, tr( "Edit rule" ), tr( "Groups of rules cannot be edited." ) ); |
|
130 |
return; |
|
131 |
} |
|
132 |
QgsRuleBasedRendererV2::Rule& rule = mRenderer->ruleAt( rule_index ); |
|
133 | ||
134 |
QgsRendererRulePropsDialog dlg( rule, mLayer, mStyle ); |
|
135 |
if ( dlg.exec() ) |
|
136 |
{ |
|
137 |
// update rule |
|
138 |
dlg.updateRuleFromGui(); |
|
139 |
mRenderer->updateRuleAt( rule_index, dlg.rule() ); |
|
140 | ||
141 |
treeRules->populateRules(); |
|
142 |
} |
|
143 |
} |
|
144 | ||
145 |
void QgsRuleBasedRendererV2Widget::removeRule() |
|
146 |
{ |
|
147 |
QTreeWidgetItem * item = treeRules->currentItem(); |
|
148 |
if ( ! item ) return; |
|
149 | ||
150 |
int rule_index = item->data( 0, Qt::UserRole + 1 ).toInt(); |
|
151 |
if ( rule_index < 0 ) |
|
152 |
{ |
|
153 |
QList<int> rule_indexes; |
|
154 |
// this is a group |
|
155 |
for ( int i = 0; i < item->childCount(); i++ ) |
|
156 |
{ |
|
157 |
int idx = item->child( i )->data( 0, Qt::UserRole + 1 ).toInt(); |
|
158 |
rule_indexes.append( idx ); |
|
159 |
} |
|
160 |
// delete in decreasing order to avoid shifting of indexes |
|
161 |
qSort( rule_indexes.begin(), rule_indexes.end(), qGreater<int>() ); |
|
162 |
foreach( int idx, rule_indexes ) |
|
163 |
mRenderer->removeRuleAt( idx ); |
|
164 |
} |
|
165 |
else |
|
166 |
{ |
|
167 |
// this is a rule |
|
168 |
mRenderer->removeRuleAt( rule_index ); |
|
169 |
} |
|
170 | ||
171 |
treeRules->populateRules(); |
|
172 |
} |
|
173 | ||
174 | ||
175 |
#include "qgscategorizedsymbolrendererv2.h" |
|
176 |
#include "qgscategorizedsymbolrendererv2widget.h" |
|
177 |
#include "qgsgraduatedsymbolrendererv2.h" |
|
178 |
#include "qgsgraduatedsymbolrendererv2widget.h" |
|
179 |
#include <QDialogButtonBox> |
|
180 |
#include <QInputDialog> |
|
181 | ||
182 |
void QgsRuleBasedRendererV2Widget::refineRule( int type ) |
|
183 |
{ |
|
184 |
QTreeWidgetItem * item = treeRules->currentItem(); |
|
185 |
if ( ! item ) return; |
|
186 | ||
187 |
int rule_index = item->data( 0, Qt::UserRole + 1 ).toInt(); |
|
188 |
if ( rule_index < 0 ) return; |
|
189 | ||
190 |
QgsRuleBasedRendererV2::Rule& initialRule = mRenderer->ruleAt( rule_index ); |
|
191 | ||
192 | ||
193 |
QList<QgsRuleBasedRendererV2::Rule> refinedRules; |
|
194 |
if ( type == 0 ) // categories |
|
195 |
refinedRules = refineRuleCategoriesGui( initialRule ); |
|
196 |
else if ( type == 1 ) // ranges |
|
197 |
refinedRules = refineRuleRangesGui( initialRule ); |
|
198 |
else // scales |
|
199 |
refinedRules = refineRuleScalesGui( initialRule ); |
|
200 | ||
201 |
if ( refinedRules.count() == 0 ) |
|
202 |
return; |
|
203 | ||
204 |
// delete original rule |
|
205 |
mRenderer->removeRuleAt( rule_index ); |
|
206 | ||
207 |
// add new rules |
|
208 |
for ( int i = 0; i < refinedRules.count(); i++ ) |
|
209 |
{ |
|
210 |
mRenderer->insertRule( rule_index + i, refinedRules.at( i ) ); |
|
211 |
} |
|
212 | ||
213 |
treeRules->populateRules(); |
|
214 |
} |
|
215 | ||
216 |
void QgsRuleBasedRendererV2Widget::refineRuleCategories() |
|
217 |
{ |
|
218 |
refineRule( 0 ); |
|
219 |
} |
|
220 | ||
221 |
void QgsRuleBasedRendererV2Widget::refineRuleRanges() |
|
222 |
{ |
|
223 |
refineRule( 1 ); |
|
224 |
} |
|
225 | ||
226 |
void QgsRuleBasedRendererV2Widget::refineRuleScales() |
|
227 |
{ |
|
228 |
refineRule( 2 ); |
|
229 |
} |
|
230 | ||
231 |
QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2Widget::refineRuleCategoriesGui( QgsRuleBasedRendererV2::Rule& initialRule ) |
|
232 |
{ |
|
233 |
QDialog dlg; |
|
234 |
dlg.setWindowTitle( tr( "Refine a rule to categories" ) ); |
|
235 |
QVBoxLayout* l = new QVBoxLayout(); |
|
236 |
QgsCategorizedSymbolRendererV2Widget* w = new QgsCategorizedSymbolRendererV2Widget( mLayer, mStyle, NULL ); |
|
237 |
l->addWidget( w ); |
|
238 |
QDialogButtonBox* bb = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel ); |
|
239 |
l->addWidget( bb ); |
|
240 |
connect( bb, SIGNAL( accepted() ), &dlg, SLOT( accept() ) ); |
|
241 |
connect( bb, SIGNAL( rejected() ), &dlg, SLOT( reject() ) ); |
|
242 |
dlg.setLayout( l ); |
|
243 | ||
244 |
if ( !dlg.exec() ) |
|
245 |
return QList<QgsRuleBasedRendererV2::Rule>(); |
|
246 | ||
247 |
// create new rules |
|
248 |
QgsCategorizedSymbolRendererV2* r = static_cast<QgsCategorizedSymbolRendererV2*>( w->renderer() ); |
|
249 |
return QgsRuleBasedRendererV2::refineRuleCategories( initialRule, r ); |
|
250 |
} |
|
251 | ||
252 | ||
253 |
QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2Widget::refineRuleRangesGui( QgsRuleBasedRendererV2::Rule& initialRule ) |
|
254 |
{ |
|
255 |
QDialog dlg; |
|
256 |
dlg.setWindowTitle( tr( "Refine a rule to ranges" ) ); |
|
257 |
QVBoxLayout* l = new QVBoxLayout(); |
|
258 |
QgsGraduatedSymbolRendererV2Widget* w = new QgsGraduatedSymbolRendererV2Widget( mLayer, mStyle, NULL ); |
|
259 |
l->addWidget( w ); |
|
260 |
QDialogButtonBox* bb = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel ); |
|
261 |
l->addWidget( bb ); |
|
262 |
connect( bb, SIGNAL( accepted() ), &dlg, SLOT( accept() ) ); |
|
263 |
connect( bb, SIGNAL( rejected() ), &dlg, SLOT( reject() ) ); |
|
264 |
dlg.setLayout( l ); |
|
265 | ||
266 |
if ( !dlg.exec() ) |
|
267 |
return QList<QgsRuleBasedRendererV2::Rule>(); |
|
268 | ||
269 |
// create new rules |
|
270 |
QgsGraduatedSymbolRendererV2* r = static_cast<QgsGraduatedSymbolRendererV2*>( w->renderer() ); |
|
271 |
return QgsRuleBasedRendererV2::refineRuleRanges( initialRule, r ); |
|
272 |
} |
|
273 | ||
274 |
QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2Widget::refineRuleScalesGui( QgsRuleBasedRendererV2::Rule& initialRule ) |
|
275 |
{ |
|
276 |
QString txt = QInputDialog::getText( this, |
|
277 |
tr( "Scale refinement" ), |
|
278 |
tr( "Please enter scale denominators at which will split the rule, separate them by commas (e.g. 1000,5000):" ) ); |
|
279 |
if ( txt.isEmpty() ) |
|
280 |
return QList<QgsRuleBasedRendererV2::Rule>(); |
|
281 | ||
282 |
QList<int> scales; |
|
283 |
bool ok; |
|
284 |
foreach( QString item, txt.split( ',' ) ) |
|
285 |
{ |
|
286 |
int scale = item.toInt( &ok ); |
|
287 |
if ( ok ) |
|
288 |
scales.append( scale ); |
|
289 |
else |
|
290 |
QMessageBox::information( this, tr( "Error" ), QString( tr( "\"%1\" is not valid scale denominator, ignoring it." ) ).arg( item ) ); |
|
291 |
} |
|
292 | ||
293 |
return QgsRuleBasedRendererV2::refineRuleScales( initialRule, scales ); |
|
294 |
} |
|
295 | ||
296 | ||
297 |
/////////// |
|
298 | ||
299 |
QgsRendererRulePropsDialog::QgsRendererRulePropsDialog( const QgsRuleBasedRendererV2::Rule& rule, QgsVectorLayer* layer, QgsStyleV2* style ) |
|
300 |
: mRule( rule ), mLayer( layer ) |
|
301 |
{ |
|
302 |
setupUi( this ); |
|
303 | ||
304 |
editFilter->setText( mRule.filterExpression() ); |
|
305 | ||
306 |
if ( mRule.dependsOnScale() ) |
|
307 |
{ |
|
308 |
groupScale->setChecked( true ); |
|
309 |
spinMinScale->setValue( rule.scaleMinDenom() ); |
|
310 |
spinMaxScale->setValue( rule.scaleMaxDenom() ); |
|
311 |
} |
|
312 | ||
313 |
QgsSymbolV2SelectorDialog* symbolSel = new QgsSymbolV2SelectorDialog( mRule.symbol(), style, this, true ); |
|
314 |
QVBoxLayout* l = new QVBoxLayout; |
|
315 |
l->addWidget( symbolSel ); |
|
316 |
groupSymbol->setLayout( l ); |
|
317 | ||
318 |
connect( btnTestFilter, SIGNAL( clicked() ), this, SLOT( testFilter() ) ); |
|
319 |
} |
|
320 | ||
321 |
void QgsRendererRulePropsDialog::testFilter() |
|
322 |
{ |
|
323 |
QgsSearchString filterParsed; |
|
324 |
if ( ! filterParsed.setString( editFilter->text() ) ) |
|
325 |
{ |
|
326 |
QMessageBox::critical( this, tr( "Error" ), tr( "Filter expression parsing error:\n" ) + filterParsed.parserErrorMsg() ); |
|
327 |
return; |
|
328 |
} |
|
329 | ||
330 |
QgsSearchTreeNode* tree = filterParsed.tree(); |
|
331 |
if ( ! tree ) |
|
332 |
{ |
|
333 |
QMessageBox::critical( this, tr( "Error" ), tr( "Filter is empty" ) ); |
|
334 |
return; |
|
335 |
} |
|
336 | ||
337 |
QApplication::setOverrideCursor( Qt::WaitCursor ); |
|
338 | ||
339 |
const QgsFieldMap& fields = mLayer->pendingFields(); |
|
340 |
mLayer->select( fields.keys(), QgsRectangle(), false ); |
|
341 | ||
342 |
int count = 0; |
|
343 |
QgsFeature f; |
|
344 |
while ( mLayer->nextFeature( f ) ) |
|
345 |
{ |
|
346 |
if ( tree->checkAgainst( fields, f.attributeMap() ) ) |
|
347 |
count++; |
|
348 |
if ( tree->hasError() ) |
|
349 |
break; |
|
350 |
} |
|
351 | ||
352 |
QApplication::restoreOverrideCursor(); |
|
353 | ||
354 |
QMessageBox::information( this, tr( "Filter" ), tr( "Filter returned %1 features" ).arg( count ) ); |
|
355 |
} |
|
356 | ||
357 |
void QgsRendererRulePropsDialog::updateRuleFromGui() |
|
358 |
{ |
|
359 |
mRule.setFilterExpression( editFilter->text() ); |
|
360 |
mRule.setScaleMinDenom( groupScale->isChecked() ? spinMinScale->value() : 0 ); |
|
361 |
mRule.setScaleMaxDenom( groupScale->isChecked() ? spinMaxScale->value() : 0 ); |
|
362 |
} |
|
363 | ||
364 |
//////// |
|
365 | ||
366 |
QgsRendererRulesTreeWidget::QgsRendererRulesTreeWidget( QWidget* parent ) |
|
367 |
: QTreeWidget( parent ), mR( NULL ), mGrouping( NoGrouping ) |
|
368 |
{ |
|
369 |
setSelectionMode( QAbstractItemView::SingleSelection ); |
|
370 |
/* |
|
371 |
setDragEnabled(true); |
|
372 |
viewport()->setAcceptDrops(true); |
|
373 |
setDropIndicatorShown(true); |
|
374 |
setDragDropMode(QAbstractItemView::InternalMove); |
|
375 |
*/ |
|
376 |
} |
|
377 | ||
378 |
void QgsRendererRulesTreeWidget::setRenderer( QgsRuleBasedRendererV2* r ) |
|
379 |
{ |
|
380 |
mR = r; |
|
381 |
} |
|
382 | ||
383 |
void QgsRendererRulesTreeWidget::setGrouping( Grouping g ) |
|
384 |
{ |
|
385 |
mGrouping = g; |
|
386 |
setRootIsDecorated( mGrouping != NoGrouping ); |
|
387 |
populateRules(); |
|
388 |
} |
|
389 | ||
390 |
void QgsRendererRulesTreeWidget::populateRules() |
|
391 |
{ |
|
392 |
if ( !mR ) return; |
|
393 | ||
394 |
clear(); |
|
395 |
if ( mGrouping == NoGrouping ) |
|
396 |
populateRulesNoGrouping(); |
|
397 |
else if ( mGrouping == GroupingByScale ) |
|
398 |
populateRulesGroupByScale(); |
|
399 |
else |
|
400 |
populateRulesGroupByFilter(); |
|
401 |
} |
|
402 | ||
403 |
void QgsRendererRulesTreeWidget::populateRulesNoGrouping() |
|
404 |
{ |
|
405 |
QList<QTreeWidgetItem *> lst; |
|
406 |
for ( int i = 0; i < mR->ruleCount(); ++i ) |
|
407 |
{ |
|
408 |
QgsRuleBasedRendererV2::Rule& rule = mR->ruleAt( i ); |
|
409 | ||
410 |
QTreeWidgetItem* item = new QTreeWidgetItem; |
|
411 |
QString txt = rule.filterExpression(); |
|
412 |
if ( txt.isEmpty() ) txt = tr( "(no filter)" ); |
|
413 |
if ( rule.dependsOnScale() ) |
|
414 |
{ |
|
415 |
txt += QString( ", scale <1:%1, 1:%2>" ).arg( rule.scaleMinDenom() ).arg( rule.scaleMaxDenom() ); |
|
416 |
} |
|
417 | ||
418 |
item->setText( 0, txt ); |
|
419 |
item->setData( 0, Qt::UserRole + 1, i ); |
|
420 |
item->setIcon( 0, QgsSymbolLayerV2Utils::symbolPreviewIcon( rule.symbol(), QSize( 16, 16 ) ) ); |
|
421 | ||
422 |
lst << item; |
|
423 |
} |
|
424 | ||
425 |
addTopLevelItems( lst ); |
|
426 |
} |
|
427 | ||
428 |
void QgsRendererRulesTreeWidget::populateRulesGroupByScale() |
|
429 |
{ |
|
430 |
QMap< QPair<int, int>, QTreeWidgetItem*> scale_items; |
|
431 | ||
432 |
for ( int i = 0; i < mR->ruleCount(); ++i ) |
|
433 |
{ |
|
434 |
QgsRuleBasedRendererV2::Rule& rule = mR->ruleAt( i ); |
|
435 | ||
436 |
QPair<int, int> scale = qMakePair( rule.scaleMinDenom(), rule.scaleMaxDenom() ); |
|
437 |
if ( ! scale_items.contains( scale ) ) |
|
438 |
{ |
|
439 |
QString txt; |
|
440 |
if ( rule.dependsOnScale() ) |
|
441 |
txt = QString( "scale <1:%1, 1:%2>" ).arg( rule.scaleMinDenom() ).arg( rule.scaleMaxDenom() ); |
|
442 |
else |
|
443 |
txt = "any scale"; |
|
444 | ||
445 |
QTreeWidgetItem* scale_item = new QTreeWidgetItem; |
|
446 |
scale_item->setText( 0, txt ); |
|
447 |
scale_item->setData( 0, Qt::UserRole + 1, -2 ); |
|
448 |
scale_item->setFlags( scale_item->flags() & ~Qt::ItemIsDragEnabled ); // groups cannot be dragged |
|
449 |
scale_items[scale] = scale_item; |
|
450 |
} |
|
451 | ||
452 |
QString filter = rule.filterExpression(); |
|
453 | ||
454 |
QTreeWidgetItem* item = new QTreeWidgetItem( scale_items[scale] ); |
|
455 |
item->setText( 0, filter.isEmpty() ? tr( "(no filter)" ) : filter ); |
|
456 |
item->setData( 0, Qt::UserRole + 1, i ); |
|
457 |
item->setIcon( 0, QgsSymbolLayerV2Utils::symbolPreviewIcon( rule.symbol(), QSize( 16, 16 ) ) ); |
|
458 |
} |
|
459 |
addTopLevelItems( scale_items.values() ); |
|
460 |
} |
|
461 | ||
462 |
void QgsRendererRulesTreeWidget::populateRulesGroupByFilter() |
|
463 |
{ |
|
464 |
QMap<QString, QTreeWidgetItem *> filter_items; |
|
465 | ||
466 |
for ( int i = 0; i < mR->ruleCount(); ++i ) |
|
467 |
{ |
|
468 |
QgsRuleBasedRendererV2::Rule& rule = mR->ruleAt( i ); |
|
469 | ||
470 |
QString filter = rule.filterExpression(); |
|
471 |
if ( ! filter_items.contains( filter ) ) |
|
472 |
{ |
|
473 |
QTreeWidgetItem* filter_item = new QTreeWidgetItem; |
|
474 |
filter_item->setText( 0, filter.isEmpty() ? tr( "(no filter)" ) : filter ); |
|
475 |
filter_item->setData( 0, Qt::UserRole + 1, -1 ); |
|
476 |
filter_item->setFlags( filter_item->flags() & ~Qt::ItemIsDragEnabled ); // groups cannot be dragged |
|
477 |
filter_items[filter] = filter_item; |
|
478 |
} |
|
479 | ||
480 |
QString txt; |
|
481 |
if ( rule.dependsOnScale() ) |
|
482 |
txt = QString( "scale <1:%1, 1:%2>" ).arg( rule.scaleMinDenom() ).arg( rule.scaleMaxDenom() ); |
|
483 |
else |
|
484 |
txt = "any scale"; |
|
485 | ||
486 |
QTreeWidgetItem* item = new QTreeWidgetItem( filter_items[filter] ); |
|
487 |
item->setText( 0, txt ); |
|
488 |
item->setData( 0, Qt::UserRole + 1, i ); |
|
489 |
item->setIcon( 0, QgsSymbolLayerV2Utils::symbolPreviewIcon( rule.symbol(), QSize( 16, 16 ) ) ); |
|
490 | ||
491 |
} |
|
492 |
addTopLevelItems( filter_items.values() ); |
|
493 |
} |
src/gui/symbology-ng/qgsrendererv2propertiesdialog.cpp (working copy) | ||
---|---|---|
8 | 8 |
#include "qgssinglesymbolrendererv2widget.h" |
9 | 9 |
#include "qgscategorizedsymbolrendererv2widget.h" |
10 | 10 |
#include "qgsgraduatedsymbolrendererv2widget.h" |
11 |
#include "qgsrulebasedrendererv2widget.h" |
|
11 | 12 | |
12 | 13 |
#include "qgssymbollevelsv2dialog.h" |
13 | 14 | |
... | ... | |
18 | 19 |
#include <QKeyEvent> |
19 | 20 |
#include <QMessageBox> |
20 | 21 | |
21 |
static bool _initRenderer( QString name, QgsRendererV2WidgetFunc f, QString iconName ) |
|
22 |
static bool _initRenderer( QString name, QgsRendererV2WidgetFunc f, QString iconName = QString() )
|
|
22 | 23 |
{ |
23 | 24 |
QgsRendererV2Registry* reg = QgsRendererV2Registry::instance(); |
24 | 25 |
QgsRendererV2AbstractMetadata* am = reg->rendererMetadata( name ); |
... | ... | |
30 | 31 | |
31 | 32 |
m->setWidgetFunction( f ); |
32 | 33 | |
33 |
QString iconPath = QgsApplication::defaultThemePath() + iconName; |
|
34 |
QPixmap pix; |
|
35 |
if ( pix.load( iconPath, "png" ) ) |
|
36 |
m->setIcon( pix ); |
|
34 |
if ( !iconName.isEmpty() ) |
|
35 |
{ |
|
36 |
QString iconPath = QgsApplication::defaultThemePath() + iconName; |
|
37 |
QPixmap pix; |
|
38 |
if ( pix.load( iconPath, "png" ) ) |
|
39 |
m->setIcon( pix ); |
|
40 |
} |
|
37 | 41 | |
38 | 42 |
QgsDebugMsg( "Set for " + name ); |
39 | 43 |
return true; |
... | ... | |
48 | 52 |
_initRenderer( "singleSymbol", QgsSingleSymbolRendererV2Widget::create, "rendererSingleSymbol.png" ); |
49 | 53 |
_initRenderer( "categorizedSymbol", QgsCategorizedSymbolRendererV2Widget::create, "rendererCategorizedSymbol.png" ); |
50 | 54 |
_initRenderer( "graduatedSymbol", QgsGraduatedSymbolRendererV2Widget::create, "rendererGraduatedSymbol.png" ); |
55 |
_initRenderer( "RuleRenderer", QgsRuleBasedRendererV2Widget::create ); |
|
51 | 56 |
initialized = true; |
52 | 57 |
} |
53 | 58 |
src/gui/CMakeLists.txt (working copy) | ||
---|---|---|
10 | 10 |
symbology-ng/qgssinglesymbolrendererv2widget.cpp |
11 | 11 |
symbology-ng/qgscategorizedsymbolrendererv2widget.cpp |
12 | 12 |
symbology-ng/qgsgraduatedsymbolrendererv2widget.cpp |
13 |
symbology-ng/qgsrulebasedrendererv2widget.cpp |
|
13 | 14 |
symbology-ng/qgsrendererv2propertiesdialog.cpp |
14 | 15 |
symbology-ng/qgsstylev2managerdialog.cpp |
15 | 16 |
symbology-ng/qgssymbollevelsv2dialog.cpp |
... | ... | |
63 | 64 |
symbology-ng/qgssinglesymbolrendererv2widget.h |
64 | 65 |
symbology-ng/qgscategorizedsymbolrendererv2widget.h |
65 | 66 |
symbology-ng/qgsgraduatedsymbolrendererv2widget.h |
67 |
symbology-ng/qgsrulebasedrendererv2widget.h |
|
66 | 68 |
symbology-ng/qgsrendererv2propertiesdialog.h |
67 | 69 |
symbology-ng/qgsstylev2managerdialog.h |
68 | 70 |
symbology-ng/qgssymbollevelsv2dialog.h |
src/core/symbology-ng/qgsrendererv2registry.cpp (working copy) | ||
---|---|---|
4 | 4 |
#include "qgssinglesymbolrendererv2.h" |
5 | 5 |
#include "qgscategorizedsymbolrendererv2.h" |
6 | 6 |
#include "qgsgraduatedsymbolrendererv2.h" |
7 |
#include "qgsrulebasedrendererv2.h" |
|
7 | 8 | |
8 | ||
9 | 9 |
QgsRendererV2Registry* QgsRendererV2Registry::mInstance = NULL; |
10 | 10 | |
11 | 11 |
QgsRendererV2Registry::QgsRendererV2Registry() |
... | ... | |
20 | 20 |
addRenderer( new QgsRendererV2Metadata( "graduatedSymbol", |
21 | 21 |
QObject::tr( "Graduated" ), |
22 | 22 |
QgsGraduatedSymbolRendererV2::create ) ); |
23 | ||
24 |
addRenderer( new QgsRendererV2Metadata( "RuleRenderer", |
|
25 |
QObject::tr( "Rule-based" ), |
|
26 |
QgsRuleBasedRendererV2::create ) ); |
|
23 | 27 |
} |
24 | 28 | |
25 | 29 |
QgsRendererV2Registry::~QgsRendererV2Registry() |
src/core/symbology-ng/qgsrulebasedrendererv2.h (revision 0) | ||
---|---|---|
1 |
/*************************************************************************** |
|
2 |
qgsrulebasedrendererv2.h - Rule-based renderer (symbology-ng) |
|
3 |
--------------------- |
|
4 |
begin : May 2010 |
|
5 |
copyright : (C) 2010 by Martin Dobias |
|
6 |
email : wonder.sk at gmail.com |
|
7 |
*************************************************************************** |
|
8 |
* * |
|
9 |
* This program is free software; you can redistribute it and/or modify * |
|
10 |
* it under the terms of the GNU General Public License as published by * |
|
11 |
* the Free Software Foundation; either version 2 of the License, or * |
|
12 |
* (at your option) any later version. * |
|
13 |
* * |
|
14 |
***************************************************************************/ |
|
15 | ||
16 |
#ifndef QGSRULEBASEDRENDERERV2_H |
|
17 |
#define QGSRULEBASEDRENDERERV2_H |
|
18 | ||
19 |
#include "qgsfield.h" |
|
20 |
#include "qgssearchstring.h" |
|
21 | ||
22 |
#include "qgsrendererv2.h" |
|
23 | ||
24 |
class QgsCategorizedSymbolRendererV2; |
|
25 |
class QgsGraduatedSymbolRendererV2; |
|
26 | ||
27 |
/** |
|
28 |
When drawing a vector layer with rule-based renderer, it goes through |
|
29 |
the rules and draws features with symbols from rules that match. |
|
30 |
*/ |
|
31 |
class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2 |
|
32 |
{ |
|
33 |
public: |
|
34 | ||
35 |
/** |
|
36 |
This class keeps data about a rules for rule-based renderer. |
|
37 |
A rule consists of a symbol, filter expression and range of scales. |
|
38 |
If filter is empty, it matches all features. |
|
39 |
If scale range has both values zero, it matches all scales. |
|
40 |
If one of the min/max scale denominators is zero, there is no lower/upper bound for scales. |
|
41 |
A rule matches if both filter and scale range match. |
|
42 |
*/ |
|
43 |
class Rule |
|
44 |
{ |
|
45 |
public: |
|
46 |
//! Constructor takes ownership of the symbol |
|
47 |
Rule( QgsSymbolV2* symbol, int scaleMinDenom = 0, int scaleMaxDenom = 0, QString filterExp = QString() ); |
|
48 |
Rule( const Rule& other ); |
|
49 |
~Rule(); |
|
50 |
QString dump() const; |
|
51 |
QStringList needsFields() const; |
|
52 |
bool isFilterOK( const QgsFieldMap& fields, QgsFeature& f ) const; |
|
53 |
bool isScaleOK( double scale ) const; |
|
54 | ||
55 |
QgsSymbolV2* symbol() { return mSymbol; } |
|
56 |
bool dependsOnScale() const { return mScaleMinDenom != 0 || mScaleMaxDenom != 0; } |
|
57 |
int scaleMinDenom() const { return mScaleMinDenom; } |
|
58 |
int scaleMaxDenom() const { return mScaleMaxDenom; } |
|
59 |
QString filterExpression() const { return mFilterExp; } |
|
60 | ||
61 |
void setScaleMinDenom( int scaleMinDenom ) { mScaleMinDenom = scaleMinDenom; } |
|
62 |
void setScaleMaxDenom( int scaleMaxDenom ) { mScaleMaxDenom = scaleMaxDenom; } |
|
63 |
void setFilterExpression( QString filterExp ) { mFilterExp = filterExp; initFilter(); } |
|
64 | ||
65 |
Rule& operator=( const Rule& other ); |
|
66 | ||
67 |
protected: |
|
68 | ||
69 |
void initFilter(); |
|
70 | ||
71 |
QgsSymbolV2* mSymbol; |
|
72 |
int mScaleMinDenom, mScaleMaxDenom; |
|
73 |
QString mFilterExp; |
|
74 | ||
75 |
// temporary |
|
76 |
QgsSearchString mFilterParsed; |
|
77 |
QgsSearchTreeNode* mFilterTree; |
|
78 |
}; |
|
79 | ||
80 |
///// |
|
81 | ||
82 |
static QgsFeatureRendererV2* create( QDomElement& element ); |
|
83 | ||
84 |
//! Constructor. Takes ownership of the defult symbol. |
|
85 |
QgsRuleBasedRendererV2( QgsSymbolV2* defaultSymbol ); |
|
86 | ||
87 |
//! return symbol for current feature. Should not be used individually: there could be more symbols for a feature |
|
88 |
virtual QgsSymbolV2* symbolForFeature( QgsFeature& feature ); |
|
89 | ||
90 |
virtual void renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer = -1, bool selected = false, bool drawVertexMarker = false ); |
|
91 | ||
92 |
virtual void startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer ); |
|
93 | ||
94 |
virtual void stopRender( QgsRenderContext& context ); |
|
95 | ||
96 |
virtual QList<QString> usedAttributes(); |
|
97 | ||
98 |
virtual QgsFeatureRendererV2* clone(); |
|
99 | ||
100 |
virtual QgsSymbolV2List symbols(); |
|
101 | ||
102 |
//! store renderer info to XML element |
|
103 |
virtual QDomElement save( QDomDocument& doc ); |
|
104 | ||
105 |
///// |
|
106 | ||
107 |
//! return the total number of rules |
|
108 |
int ruleCount(); |
|
109 |
//! get reference to rule at index (valid indexes: 0...count-1) |
|
110 |
Rule& ruleAt( int index ); |
|
111 |
//! add rule to the end of the list of rules |
|
112 |
void addRule( const Rule& rule ); |
|
113 |
//! insert rule to a specific position of the list of rules |
|
114 |
void insertRule( int index, const Rule& rule ); |
|
115 |
//! modify the rule at a specific position of the list of rules |
|
116 |
void updateRuleAt( int index, const Rule& rule ); |
|
117 |
//! remove the rule at the specified index |
|
118 |
void removeRuleAt( int index ); |
|
119 | ||
120 |
////// |
|
121 | ||
122 |
//! take a rule and create a list of new rules based on the categories from categorized symbol renderer |
|
123 |
static QList<Rule> refineRuleCategories( Rule& initialRule, QgsCategorizedSymbolRendererV2* r ); |
|
124 |
//! take a rule and create a list of new rules based on the ranges from graduated symbol renderer |
|
125 |
static QList<Rule> refineRuleRanges( Rule& initialRule, QgsGraduatedSymbolRendererV2* r ); |
|
126 |
//! take a rule and create a list of new rules with intervals of scales given by the passed scale denominators |
|
127 |
static QList<Rule> refineRuleScales( Rule& initialRule, QList<int> scales ); |
|
128 | ||
129 |
protected: |
|
130 |
//! the list of rules |
|
131 |
QList<Rule> mRules; |
|
132 |
//! the default symbol, used for the first rule with no filter |
|
133 |
QgsSymbolV2* mDefaultSymbol; |
|
134 | ||
135 |
// temporary |
|
136 |
QList<Rule*> mCurrentRules; |
|
137 |
QgsFieldMap mCurrentFields; |
|
138 |
QgsSymbolV2* mCurrentSymbol; |
|
139 |
}; |
|
140 | ||
141 |
#endif // QGSRULEBASEDRENDERERV2_H |
src/core/symbology-ng/qgsrulebasedrendererv2.cpp (revision 0) | ||
---|---|---|
1 |
/*************************************************************************** |
|
2 |
qgsrulebasedrendererv2.cpp - Rule-based renderer (symbology-ng) |
|
3 |
--------------------- |
|
4 |
begin : May 2010 |
|
5 |
copyright : (C) 2010 by Martin Dobias |
|
6 |
email : wonder.sk at gmail.com |
|
7 |
*************************************************************************** |
|
8 |
* * |
|
9 |
* This program is free software; you can redistribute it and/or modify * |
|
10 |
* it under the terms of the GNU General Public License as published by * |
|
11 |
* the Free Software Foundation; either version 2 of the License, or * |
|
12 |
* (at your option) any later version. * |
|
13 |
* * |
|
14 |
***************************************************************************/ |
|
15 | ||
16 |
#include "qgsrulebasedrendererv2.h" |
|
17 | ||
18 |
#include "qgssearchtreenode.h" |
|
19 |
#include "qgssymbollayerv2utils.h" |
|
20 |
#include "qgsrendercontext.h" |
|
21 |
#include "qgsvectorlayer.h" |
|
22 |
#include "qgslogger.h" |
|
23 | ||
24 |
#include <QSet> |
|
25 | ||
26 |
#include <QDomDocument> |
|
27 |
#include <QDomElement> |
|
28 | ||
29 | ||
30 | ||
31 |
QgsRuleBasedRendererV2::Rule::Rule( QgsSymbolV2* symbol, int scaleMinDenom, int scaleMaxDenom, QString filterExp ) |
|
32 |
: mSymbol( symbol ), |
|
33 |
mScaleMinDenom( scaleMinDenom ), mScaleMaxDenom( scaleMaxDenom ), |
|
34 |
mFilterExp( filterExp ) |
|
35 |
{ |
|
36 |
initFilter(); |
|
37 |
} |
|
38 | ||
39 |
QgsRuleBasedRendererV2::Rule::Rule( const QgsRuleBasedRendererV2::Rule& other ) |
|
40 |
: mSymbol( NULL ) |
|
41 |
{ |
|
42 |
*this = other; |
|
43 |
} |
|
44 | ||
45 |
QgsRuleBasedRendererV2::Rule::~Rule() |
|
46 |
{ |
|
47 |
delete mSymbol; |
|
48 |
} |
|
49 | ||
50 |
void QgsRuleBasedRendererV2::Rule::initFilter() |
|
51 |
{ |
|
52 |
if ( !mFilterExp.isEmpty() ) |
|
53 |
{ |
|
54 |
mFilterParsed.setString( mFilterExp ); |
|
55 |
mFilterTree = mFilterParsed.tree(); // may be NULL if there's no input |
|
56 |
} |
|
57 |
else |
|
58 |
{ |
|
59 |
mFilterTree = NULL; |
|
60 |
} |
|
61 |
} |
|
62 | ||
63 |
QString QgsRuleBasedRendererV2::Rule::dump() const |
|
64 |
{ |
|
65 |
return QString( "RULE - scale [%1,%2] - filter %3 - symbol %4" ) |
|
66 |
.arg( mScaleMinDenom ).arg( mScaleMaxDenom ) |
|
67 |
.arg( mFilterExp ).arg( mSymbol->dump() ); |
|
68 | ||
69 |
} |
|
70 | ||
71 |
QStringList QgsRuleBasedRendererV2::Rule::needsFields() const |
|
72 |
{ |
|
73 |
if ( ! mFilterTree ) |
|
74 |
return QStringList(); |
|
75 | ||
76 |
return mFilterTree->referencedColumns(); |
|
77 |
} |
|
78 | ||
79 |
bool QgsRuleBasedRendererV2::Rule::isFilterOK( const QgsFieldMap& fields, QgsFeature& f ) const |
|
80 |
{ |
|
81 |
if ( ! mFilterTree ) |
|
82 |
return true; |
|
83 | ||
84 |
bool res = mFilterTree->checkAgainst( fields, f.attributeMap() ); |
|
85 |
//print "is_ok", res, feature.id(), feature.attributeMap() |
|
86 |
return res; |
|
87 |
} |
|
88 | ||
89 |
bool QgsRuleBasedRendererV2::Rule::isScaleOK( double scale ) const |
|
90 |
{ |
|
91 |
if ( mScaleMinDenom == 0 && mScaleMaxDenom == 0 ) |
|
92 |
return true; |
|
93 |
if ( mScaleMinDenom != 0 && mScaleMinDenom > scale ) |
|
94 |
return false; |
|
95 |
if ( mScaleMaxDenom != 0 && mScaleMaxDenom < scale ) |
|
96 |
return false; |
|
97 |
return true; |
|
98 |
} |
|
99 | ||
100 |
QgsRuleBasedRendererV2::Rule& QgsRuleBasedRendererV2::Rule::operator=( const QgsRuleBasedRendererV2::Rule & other ) |
|
101 |
{ |
|
102 |
if ( this != &other ) |
|
103 |
{ |
|
104 |
delete mSymbol; |
|
105 |
mSymbol = other.mSymbol->clone(); |
|
106 | ||
107 |
mScaleMinDenom = other.mScaleMinDenom; |
|
108 |
mScaleMaxDenom = other.mScaleMaxDenom; |
|
109 |
mFilterExp = other.mFilterExp; |
|
110 |
initFilter(); |
|
111 |
} |
|
112 |
return *this; |
|
113 |
} |
|
114 | ||
115 |
///////////////////// |
|
116 | ||
117 |
QgsRuleBasedRendererV2::QgsRuleBasedRendererV2( QgsSymbolV2* defaultSymbol ) |
|
118 |
: QgsFeatureRendererV2( "RuleRenderer" ) |
|
119 |
{ |
|
120 |
mDefaultSymbol = defaultSymbol; |
|
121 | ||
122 |
// add the default rule |
|
123 |
mRules << Rule( defaultSymbol->clone() ); |
|
124 |
} |
|
125 | ||
126 | ||
127 |
QgsSymbolV2* QgsRuleBasedRendererV2::symbolForFeature( QgsFeature& feature ) |
|
128 |
{ |
|
129 |
return mCurrentSymbol; |
|
130 |
} |
|
131 | ||
132 |
void QgsRuleBasedRendererV2::renderFeature( QgsFeature& feature, |
|
133 |
QgsRenderContext& context, |
|
134 |
int layer, |
|
135 |
bool selected, |
|
136 |
bool drawVertexMarker ) |
|
137 |
{ |
|
138 |
for ( QList<Rule*>::iterator it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it ) |
|
139 |
{ |
|
140 |
Rule* rule = *it; |
|
141 |
if ( rule->isFilterOK( mCurrentFields, feature ) ) |
|
142 |
{ |
|
143 |
mCurrentSymbol = rule->symbol(); |
|
144 |
// will ask for mCurrentSymbol |
|
145 |
QgsFeatureRendererV2::renderFeature( feature, context, layer, selected, drawVertexMarker ); |
|
146 |
} |
|
147 |
} |
|
148 |
} |
|
149 | ||
150 | ||
151 |
void QgsRuleBasedRendererV2::startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer ) |
|
152 |
{ |
|
153 |
double currentScale = context.rendererScale(); |
|
154 |
// filter out rules which are not compatible with this scale |
|
155 | ||
156 |
mCurrentRules.clear(); |
|
157 |
for ( QList<Rule>::iterator it = mRules.begin(); it != mRules.end(); ++it ) |
|
158 |
{ |
|
159 |
Rule& rule = *it; |
|
160 |
if ( rule.isScaleOK( currentScale ) ) |
|
161 |
mCurrentRules.append( &rule ); |
|
162 |
} |
|
163 | ||
164 |
mCurrentFields = vlayer->pendingFields(); |
|
165 | ||
166 |
for ( QList<Rule*>::iterator it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it ) |
|
167 |
{ |
|
168 |
Rule* rule = *it; |
|
169 |
rule->symbol()->startRender( context ); |
|
170 |
} |
|
171 |
} |
|
172 | ||
173 |
void QgsRuleBasedRendererV2::stopRender( QgsRenderContext& context ) |
|
174 |
{ |
|
175 |
for ( QList<Rule*>::iterator it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it ) |
|
176 |
{ |
|
177 |
Rule* rule = *it; |
|
178 |
rule->symbol()->stopRender( context ); |
|
179 |
} |
|
180 | ||
181 |
mCurrentRules.clear(); |
|
182 |
mCurrentFields.clear(); |
|
183 |
} |
|
184 | ||
185 |
QList<QString> QgsRuleBasedRendererV2::usedAttributes() |
|
186 |
{ |
|
187 |
QSet<QString> attrs; |
|
188 |
for ( QList<Rule>::iterator it = mRules.begin(); it != mRules.end(); ++it ) |
|
189 |
{ |
|
190 |
Rule& rule = *it; |
|
191 |
attrs.unite( rule.needsFields().toSet() ); |
|
192 |
} |
|
193 |
return attrs.values(); |
|
194 |
} |
|
195 | ||
196 |
QgsFeatureRendererV2* QgsRuleBasedRendererV2::clone() |
|
197 |
{ |
|
198 |
QgsSymbolV2* s = mDefaultSymbol->clone(); |
|
199 |
QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2( s ); |
|
200 |
r->mRules = mRules; |
|
201 |
return r; |
|
202 |
} |
|
203 | ||
204 |
QgsSymbolV2List QgsRuleBasedRendererV2::symbols() |
|
205 |
{ |
|
206 |
QgsSymbolV2List lst; |
|
207 |
for ( QList<Rule>::iterator it = mRules.begin(); it != mRules.end(); ++it ) |
|
208 |
{ |
|
209 |
Rule& rule = *it; |
|
210 |
lst.append( rule.symbol() ); |
|
211 |
} |
|
212 | ||
213 |
return lst; |
|
214 |
} |
|
215 | ||
216 |
QDomElement QgsRuleBasedRendererV2::save( QDomDocument& doc ) |
|
217 |
{ |
|
218 |
QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME ); |
|
219 |
rendererElem.setAttribute( "type", "RuleRenderer" ); |
|
220 | ||
221 |
QDomElement rulesElem = doc.createElement( "rules" ); |
|
222 | ||
223 |
QgsSymbolV2Map symbols; |
|
224 |
symbols["default"] = mDefaultSymbol; |
|
225 | ||
226 |
int i = 0; |
|
227 |
for ( QList<Rule>::iterator it = mRules.begin(); it != mRules.end(); ++i, ++it ) |
|
228 |
{ |
|
229 |
Rule& rule = *it; |
|
230 |
symbols[QString::number( i )] = rule.symbol(); |
|
231 |
QDomElement ruleElem = doc.createElement( "rule" ); |
|
232 |
ruleElem.setAttribute( "symbol", i ); |
|
233 |
ruleElem.setAttribute( "filter", rule.filterExpression() ); |
|
234 |
ruleElem.setAttribute( "scalemindenom", rule.scaleMinDenom() ); |
|
235 |
ruleElem.setAttribute( "scalemaxdenom", rule.scaleMaxDenom() ); |
|
236 |
rulesElem.appendChild( ruleElem ); |
|
237 |
} |
|
238 |
rendererElem.appendChild( rulesElem ); |
|
239 | ||
240 |
QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc ); |
|
241 |
rendererElem.appendChild( symbolsElem ); |
|
242 | ||
243 |
return rendererElem; |
|
244 |
} |
|
245 | ||
246 | ||
247 |
QgsFeatureRendererV2* QgsRuleBasedRendererV2::create( QDomElement& element ) |
|
248 |
{ |
|
249 |
// load symbols |
|
250 |
QDomElement symbolsElem = element.firstChildElement( "symbols" ); |
|
251 |
if ( symbolsElem.isNull() ) |
|
252 |
return NULL; |
|
253 | ||
254 |
QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem ); |
|
255 | ||
256 |
if ( !symbolMap.contains( "default" ) ) |
|
257 |
{ |
|
258 |
QgsDebugMsg( "default symbol not found!" ); |
|
259 |
return NULL; |
|
260 |
} |
|
261 | ||
262 |
QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2( symbolMap.take( "default" ) ); |
|
263 |
r->mRules.clear(); |
|
264 | ||
265 |
QDomElement rulesElem = element.firstChildElement( "rules" ); |
|
266 |
QDomElement ruleElem = rulesElem.firstChildElement( "rule" ); |
|
267 |
while ( !ruleElem.isNull() ) |
|
268 |
{ |
|
269 |
QString symbolIdx = ruleElem.attribute( "symbol" ); |
|
270 |
if ( symbolMap.contains( symbolIdx ) ) |
|
271 |
{ |
|
272 |
QString filterExp = ruleElem.attribute( "filter" ); |
|
273 |
int scaleMinDenom = ruleElem.attribute( "scalemindenom", "0" ).toInt(); |
|
274 |
int scaleMaxDenom = ruleElem.attribute( "scalemaxdenom", "0" ).toInt(); |
|
275 |
r->mRules.append( Rule( symbolMap.take( symbolIdx ), scaleMinDenom, scaleMaxDenom, filterExp ) ); |
|
276 |
} |
|
277 |
else |
|
278 |
{ |
|
279 |
QgsDebugMsg( "symbol for rule " + symbolIdx + " not found! (skipping)" ); |
|
280 |
} |
|
281 |
ruleElem = ruleElem.nextSiblingElement( "rule" ); |
|
282 |
} |
|
283 | ||
284 |
// delete symbols if there are any more |
|
285 |
QgsSymbolLayerV2Utils::clearSymbolMap( symbolMap ); |
|
286 | ||
287 |
return r; |
|
288 |
} |
|
289 | ||
290 | ||
291 |
int QgsRuleBasedRendererV2::ruleCount() |
|
292 |
{ |
|
293 |
return mRules.count(); |
|
294 |
} |
|
295 | ||
296 |
QgsRuleBasedRendererV2::Rule& QgsRuleBasedRendererV2::ruleAt( int index ) |
|
297 |
{ |
|
298 |
return mRules[index]; |
|
299 |
} |
|
300 | ||
301 |
void QgsRuleBasedRendererV2::addRule( const QgsRuleBasedRendererV2::Rule& rule ) |
|
302 |
{ |
|
303 |
mRules.append( rule ); |
|
304 |
} |
|
305 | ||
306 |
void QgsRuleBasedRendererV2::insertRule( int index, const QgsRuleBasedRendererV2::Rule& rule ) |
|
307 |
{ |
|
308 |
mRules.insert( index, rule ); |
|
309 |
} |
|
310 | ||
311 |
void QgsRuleBasedRendererV2::updateRuleAt( int index, const QgsRuleBasedRendererV2::Rule& rule ) |
|
312 |
{ |
|
313 |
mRules[index] = rule; |
|
314 |
} |
|
315 | ||
316 |
void QgsRuleBasedRendererV2::removeRuleAt( int index ) |
|
317 |
{ |
|
318 |
mRules.removeAt( index ); |
|
319 |
} |
|
320 | ||
321 |
#include "qgscategorizedsymbolrendererv2.h" |
|
322 |
#include "qgsgraduatedsymbolrendererv2.h" |
|
323 | ||
324 |
QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2::refineRuleCategories( QgsRuleBasedRendererV2::Rule& initialRule, QgsCategorizedSymbolRendererV2* r ) |
|
325 |
{ |
|
326 |
QList<Rule> rules; |
|
327 |
foreach( const QgsRendererCategoryV2& cat, r->categories() ) |
|
328 |
{ |
|
329 |
QString newfilter = QString( "%1 = '%2'" ).arg( r->classAttribute() ).arg( cat.value().toString() ); |
|
330 |
QString filter = initialRule.filterExpression(); |
|
331 |
if ( filter.isEmpty() ) |
|
332 |
filter = newfilter; |
|
333 |
else |
|
334 |
filter = QString( "(%1) AND (%2)" ).arg( filter ).arg( newfilter ); |
|
335 |
rules.append( Rule( cat.symbol()->clone(), initialRule.scaleMinDenom(), initialRule.scaleMaxDenom(), filter ) ); |
|
336 |
} |
|
337 |
return rules; |
|
338 |
} |
|
339 | ||
340 |
QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2::refineRuleRanges( QgsRuleBasedRendererV2::Rule& initialRule, QgsGraduatedSymbolRendererV2* r ) |
|
341 |
{ |
|
342 |
QList<Rule> rules; |
|
343 |
foreach( const QgsRendererRangeV2& rng, r->ranges() ) |
|
344 |
{ |
|
345 |
QString newfilter = QString( "%1 >= '%2' AND %1 <= '%3'" ).arg( r->classAttribute() ).arg( rng.lowerValue() ).arg( rng.upperValue() ); |
|
346 |
QString filter = initialRule.filterExpression(); |
|
347 |
if ( filter.isEmpty() ) |
|
348 |
filter = newfilter; |
|
349 |
else |
|
350 |
filter = QString( "(%1) AND (%2)" ).arg( filter ).arg( newfilter ); |
|
351 |
rules.append( Rule( rng.symbol()->clone(), initialRule.scaleMinDenom(), initialRule.scaleMaxDenom(), filter ) ); |
|
352 |
} |
|
353 |
return rules; |
|
354 |
} |
|
355 | ||
356 |
QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2::refineRuleScales( QgsRuleBasedRendererV2::Rule& initialRule, QList<int> scales ) |
|
357 |
{ |
|
358 |
QList<Rule> rules; |
|
359 |
int oldScale = 0; |
|
360 |
foreach( int scale, scales ) |
|
361 |
{ |
|
362 |
rules.append( Rule( initialRule.symbol()->clone(), oldScale, scale, initialRule.filterExpression() ) ); |
|
363 |
oldScale = scale; |
|
364 |
} |
|
365 |
// last rule |
|
366 |
rules.append( Rule( initialRule.symbol()->clone(), oldScale, 0, initialRule.filterExpression() ) ); |
|
367 |
return rules; |
|
368 |
} |
src/core/CMakeLists.txt (working copy) | ||
---|---|---|
32 | 32 |
symbology-ng/qgssinglesymbolrendererv2.cpp |
33 | 33 |
symbology-ng/qgscategorizedsymbolrendererv2.cpp |
34 | 34 |
symbology-ng/qgsgraduatedsymbolrendererv2.cpp |
35 |
symbology-ng/qgsrulebasedrendererv2.cpp |
|
35 | 36 |
symbology-ng/qgsvectorcolorrampv2.cpp |
36 | 37 |
symbology-ng/qgsstylev2.cpp |
37 | 38 |
symbology-ng/qgssymbologyv2conversion.cpp |
src/ui/qgsrulebasedrendererv2widget.ui (revision 0) | ||
---|---|---|
1 |
<?xml version="1.0" encoding="UTF-8"?> |
|
2 |
<ui version="4.0"> |
|
3 |
<class>QgsRuleBasedRendererV2Widget</class> |
|
4 |
<widget class="QWidget" name="QgsRuleBasedRendererV2Widget"> |
|
5 |
<property name="geometry"> |
|
6 |
<rect> |
|
7 |
<x>0</x> |
|
8 |
<y>0</y> |
|
9 |
<width>460</width> |
|
10 |
<height>221</height> |
|
11 |
</rect> |
|
12 |
</property> |
|
13 |
<property name="windowTitle"> |
|
14 |
<string>Form</string> |
|
15 |
</property> |
|
16 |
<layout class="QGridLayout" name="gridLayout"> |
|
17 |
<item row="0" column="0"> |
|
18 |
<widget class="QLabel" name="label"> |
|
19 |
<property name="text"> |
|
20 |
<string>Rules:</string> |
|
21 |
</property> |
|
22 |
</widget> |
|
23 |
</item> |
|
24 |
<item row="1" column="0"> |
|
25 |
<widget class="QgsRendererRulesTreeWidget" name="treeRules"> |
|
26 |
<property name="rootIsDecorated"> |
|
27 |
<bool>false</bool> |
|
28 |
</property> |
|
29 |
<property name="headerHidden"> |
|
30 |
<bool>true</bool> |
|
31 |
</property> |
|
32 |
<column> |
|
33 |
<property name="text"> |
|
34 |
<string>Rule</string> |
|
35 |
</property> |
|
36 |
</column> |
|
37 |
</widget> |
|
38 |
</item> |
|
39 |
<item row="1" column="1"> |
|
40 |
<layout class="QVBoxLayout" name="verticalLayout"> |
|
41 |
<item> |
|
42 |
<widget class="QPushButton" name="btnAddRule"> |
|
43 |
<property name="text"> |
|
44 |
<string>Add</string> |
|
45 |
</property> |
|
46 |
</widget> |
|
47 |
</item> |
|
48 |
<item> |
|
49 |
<widget class="QPushButton" name="btnRefineRule"> |
|
50 |
<property name="text"> |
|
51 |
<string>Refine</string> |
|
52 |
</property> |
|
53 |
</widget> |
|
54 |
</item> |
|
55 |
<item> |
|
56 |
<widget class="QPushButton" name="btnEditRule"> |
|
57 |
<property name="text"> |
|
58 |
<string>Edit</string> |
|
59 |
</property> |
|
60 |
</widget> |
|
61 |
</item> |
|
62 |
<item> |
|
63 |
<widget class="QPushButton" name="btnRemoveRule"> |
|
64 |
<property name="text"> |
|
65 |
<string>Remove</string> |
|
66 |
</property> |
|
67 |
</widget> |
|
68 |
</item> |
|
69 |
</layout> |
|
70 |
</item> |
|
71 |
<item row="2" column="0" colspan="2"> |
|
72 |
<widget class="QGroupBox" name="groupBox"> |
|
73 |
<property name="title"> |
|
74 |
<string>Rule grouping</string> |
|
75 |
</property> |
|
76 |
<layout class="QHBoxLayout" name="horizontalLayout"> |
|
77 |
<item> |
|
78 |
<widget class="QRadioButton" name="radNoGrouping"> |
|
79 |
<property name="text"> |
|
80 |
<string>No grouping</string> |
|
81 |
</property> |
|
82 |
<property name="checked"> |
|
83 |
<bool>true</bool> |
|
84 |
</property> |
|
85 |
</widget> |
|
86 |
</item> |
|
87 |
<item> |
|
88 |
<widget class="QRadioButton" name="radGroupFilter"> |
|
89 |
<property name="text"> |
|
90 |
<string>Group by filter</string> |
|
91 |
</property> |
|
92 |
</widget> |
|
93 |
</item> |
|
94 |
<item> |
|
95 |
<widget class="QRadioButton" name="radGroupScale"> |
|
96 |
<property name="text"> |
|
97 |
<string>Group by scale</string> |
|
98 |
</property> |
|
99 |
</widget> |
|
100 |
</item> |
|
101 |
</layout> |
|
102 |
</widget> |
|
103 |
</item> |
|
104 |
</layout> |
|
105 |
</widget> |
|
106 |
<customwidgets> |
|
107 |
<customwidget> |
|
108 |
<class>QgsRendererRulesTreeWidget</class> |
|
109 |
<extends>QTreeWidget</extends> |
|
110 |
<header>qgsrulebasedrendererv2widget.h</header> |
|
111 |
</customwidget> |
|
112 |
</customwidgets> |
|
113 |
<resources/> |
|
114 |
<connections/> |
|
115 |
</ui> |
src/ui/qgsrendererrulepropsdialogbase.ui (revision 0) | ||
---|---|---|
1 |
<?xml version="1.0" encoding="UTF-8"?> |
|
2 |
<ui version="4.0"> |
|
3 |
<class>QgsRendererRulePropsDialog</class> |
|
4 |
<widget class="QDialog" name="QgsRendererRulePropsDialog"> |
|
5 |
<property name="geometry"> |
|
6 |
<rect> |
|
7 |
<x>0</x> |
|
8 |
<y>0</y> |
|
9 |
<width>547</width> |
|
10 |
<height>300</height> |
|
11 |
</rect> |
|
12 |
</property> |
|
13 |
<property name="windowTitle"> |
|
14 |
<string>Rule properties</string> |
|
15 |
</property> |
|
16 |
<layout class="QVBoxLayout" name="verticalLayout"> |
|
17 |
<item> |
|
18 |
<layout class="QHBoxLayout" name="horizontalLayout"> |
|
19 |
<item> |
|
20 |
<widget class="QLabel" name="label"> |
|
21 |
<property name="text"> |
|
22 |
<string>Filter</string> |
|
23 |
</property> |
|
24 |
</widget> |
|
25 |
</item> |
|
26 |
<item> |
|
27 |
<widget class="QLineEdit" name="editFilter"/> |
|
28 |
</item> |
|
29 |
<item> |
|
30 |
<widget class="QPushButton" name="btnTestFilter"> |
|
31 |
<property name="text"> |
|
32 |
<string>Test</string> |
|
33 |
</property> |
|
34 |
</widget> |
|
35 |
</item> |
|
36 |
</layout> |
|
37 |
</item> |
|
38 |
<item> |
|
39 |
<widget class="QGroupBox" name="groupScale"> |
|
40 |
<property name="title"> |
|
41 |
<string>Scale range</string> |
|
42 |
</property> |
|
43 |
<property name="checkable"> |
|
44 |
<bool>true</bool> |
|
45 |
</property> |
|
46 |
<property name="checked"> |
|
47 |
<bool>false</bool> |
|
48 |
</property> |
|
49 |
<layout class="QHBoxLayout" name="horizontalLayout_2"> |
|
50 |
<item> |
|
51 |
<widget class="QLabel" name="label_2"> |
|
52 |
<property name="text"> |
|
53 |
<string>Min. scale</string> |
|
54 |
</property> |
|
55 |
<property name="alignment"> |
|
56 |
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> |
|
57 |
</property> |
|
58 |
</widget> |
|
59 |
</item> |
|
60 |
<item> |
|
61 |
<widget class="QSpinBox" name="spinMinScale"> |
|
62 |
<property name="prefix"> |
|
63 |
<string>1 : </string> |
|
64 |
</property> |
|
65 |
<property name="minimum"> |
|
66 |
<number>0</number> |
|
67 |
</property> |
|
68 |
<property name="maximum"> |
|
69 |
<number>1000000000</number> |
|
70 |
</property> |
|
71 |
<property name="singleStep"> |
|
72 |
<number>1000</number> |
|
73 |
</property> |
|
74 |
<property name="value"> |
|
75 |
<number>1000</number> |
|
76 |
</property> |
|
77 |
</widget> |
|
78 |
</item> |
|
79 |
<item> |
|
80 |
<widget class="QLabel" name="label_3"> |
|
81 |
<property name="text"> |
|
82 |
<string>Max. scale</string> |
|
83 |
</property> |
|
84 |
<property name="alignment"> |
|
85 |
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> |
|
86 |
</property> |
|
87 |
</widget> |
|
88 |
</item> |
|
89 |
<item> |
|
90 |
<widget class="QSpinBox" name="spinMaxScale"> |
|
91 |
<property name="prefix"> |
|
92 |
<string>1 : </string> |
|
93 |
</property> |
|
94 |
<property name="minimum"> |
|
95 |
<number>0</number> |
|
96 |
</property> |
|
97 |
<property name="maximum"> |
|
98 |
<number>1000000000</number> |
|
99 |
</property> |
|
100 |
<property name="singleStep"> |
|
101 |
<number>1000</number> |
|
102 |
</property> |
|
103 |
<property name="value"> |
|
104 |
<number>1000</number> |
|
105 |
</property> |
|
106 |
</widget> |
|
107 |
</item> |
|
108 |
</layout> |
|
109 |
</widget> |
|
110 |
</item> |
|
111 |
<item> |
|
112 |
<widget class="QGroupBox" name="groupSymbol"> |
|
113 |
<property name="sizePolicy"> |
|
114 |
<sizepolicy hsizetype="Preferred" vsizetype="Expanding"> |
|
115 |
<horstretch>0</horstretch> |
|
116 |
<verstretch>0</verstretch> |
|
117 |
</sizepolicy> |
|
118 |
</property> |
|
119 |
<property name="title"> |
|
120 |
<string>Symbol</string> |
|
121 |
</property> |
|
122 |
</widget> |
|
123 |
</item> |
|
124 |
<item> |
|
125 |
<widget class="QDialogButtonBox" name="buttonBox"> |
|
126 |
<property name="orientation"> |
|
127 |
<enum>Qt::Horizontal</enum> |
|
128 |
</property> |
|
129 |
<property name="standardButtons"> |
|
130 |
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> |
|
131 |
</property> |
|
132 |
</widget> |
|
133 |
</item> |