Skip to content

Commit adbf171

Browse files
author
mhugent
committedSep 30, 2009
[FEATURE]: A field calculator, accessible with a button in the attribute section of the vector properties
git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@11735 c8812cc2-4d05-0410-92ff-de0c093fc19c

12 files changed

+807
-65
lines changed
 
1011 Bytes
Loading

‎src/app/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ SET(QGIS_APP_SRCS
2020
qgsspatialitefilterproxymodel.cpp
2121
qgsspatialitetablemodel.cpp
2222
qgsdelattrdialog.cpp
23+
qgsfieldcalculator.cpp
2324
qgsnewvectorlayerdialog.cpp
2425
qgsgraduatedsymboldialog.cpp
2526
qgshelpviewer.cpp
@@ -122,6 +123,7 @@ SET (QGIS_APP_MOC_HDRS
122123
qgsconfigureshortcutsdialog.h
123124
qgscustomprojectiondialog.h
124125
qgsdelattrdialog.h
126+
qgsfieldcalculator.h
125127
qgsnewvectorlayerdialog.h
126128
qgsgraduatedsymboldialog.h
127129
qgshelpviewer.h

‎src/app/qgsfieldcalculator.cpp

Lines changed: 353 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,353 @@
1+
/***************************************************************************
2+
qgsfieldcalculator.cpp
3+
---------------------
4+
begin : September 2009
5+
copyright : (C) 2009 by Marco Hugentobler
6+
email : marco at hugis dot net
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 "qgsfieldcalculator.h"
17+
#include "qgssearchtreenode.h"
18+
#include "qgssearchstring.h"
19+
#include "qgsvectorlayer.h"
20+
#include <QMessageBox>
21+
22+
QgsFieldCalculator::QgsFieldCalculator( QgsVectorLayer* vl ): QDialog(), mVectorLayer( vl )
23+
{
24+
setupUi( this );
25+
mOutputFieldTypeComboBox->addItem( tr( "Double" ) );
26+
mOutputFieldTypeComboBox->addItem( tr( "Integer" ) );
27+
mOutputFieldTypeComboBox->addItem( tr( "String" ) );
28+
29+
populateFields();
30+
31+
//default values for field width and precision
32+
mOuputFieldWidthSpinBox->setValue( 10 );
33+
mOutputFieldPrecisionSpinBox->setValue( 3 );
34+
35+
//disable ok button until there is text for output field and expression
36+
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( false );
37+
}
38+
39+
QgsFieldCalculator::~QgsFieldCalculator()
40+
{
41+
42+
}
43+
44+
void QgsFieldCalculator::accept()
45+
{
46+
if ( mVectorLayer && mVectorLayer->isEditable() )
47+
{
48+
QString calcString = mExpressionTextEdit->toPlainText();
49+
50+
//create QgsSearchString
51+
QgsSearchString searchString;
52+
if ( !searchString.setString( calcString ) )
53+
{
54+
//expression not valid
55+
QMessageBox::critical( 0, tr( "Syntax error" ), tr( QString( "Invalid expression syntax. The error message of the parser is: '" + searchString.parserErrorMsg() + "'" ).toLocal8Bit().data() ) );
56+
return;
57+
}
58+
59+
//get QgsSearchTreeNode
60+
QgsSearchTreeNode* searchTree = searchString.tree();
61+
if ( !searchTree )
62+
{
63+
return;
64+
}
65+
66+
mVectorLayer->beginEditCommand( "Field calculator" );
67+
68+
//create new field
69+
QgsField newField( mOutputFieldNameLineEdit->text() );
70+
if ( mOutputFieldTypeComboBox->currentText() == tr( "Double" ) )
71+
{
72+
newField.setType( QVariant::Double );
73+
}
74+
else if ( mOutputFieldTypeComboBox->currentText() == tr( "Integer" ) )
75+
{
76+
newField.setType( QVariant::Int );
77+
}
78+
else if ( mOutputFieldTypeComboBox->currentText() == tr( "String" ) )
79+
{
80+
newField.setType( QVariant::String );
81+
}
82+
83+
newField.setLength( mOuputFieldWidthSpinBox->value() );
84+
newField.setPrecision( mOutputFieldPrecisionSpinBox->value() );
85+
86+
87+
if ( !mVectorLayer->addAttribute( newField ) )
88+
{
89+
mVectorLayer->destroyEditCommand();
90+
return;
91+
}
92+
93+
//get index of the new field
94+
const QgsFieldMap fieldList = mVectorLayer->pendingFields();
95+
int attributeId = -1;
96+
QgsFieldMap::const_iterator it = fieldList.constBegin();
97+
for ( ; it != fieldList.constEnd(); ++it )
98+
{
99+
if ( it.value().name() == mOutputFieldNameLineEdit->text() )
100+
{
101+
attributeId = it.key();
102+
break;
103+
}
104+
}
105+
if ( attributeId == -1 )
106+
{
107+
mVectorLayer->destroyEditCommand();
108+
return;
109+
}
110+
111+
//go through all the features and change the new attribute
112+
QgsFeature feature;
113+
bool calculationSuccess = true;
114+
115+
mVectorLayer->select( mVectorLayer->pendingAllAttributesList(), QgsRectangle(), false, false );
116+
while ( mVectorLayer->nextFeature( feature ) )
117+
{
118+
QgsSearchTreeValue value = searchTree->valueAgainst( mVectorLayer->pendingFields(), feature.attributeMap() );
119+
if ( value.isError() )
120+
{
121+
calculationSuccess = false;
122+
break;
123+
}
124+
if ( value.isNumeric() )
125+
{
126+
mVectorLayer->changeAttributeValue( feature.id(), attributeId, value.number(), false );
127+
}
128+
else
129+
{
130+
mVectorLayer->changeAttributeValue( feature.id(), attributeId, value.string(), false );
131+
}
132+
133+
}
134+
135+
if ( !calculationSuccess )
136+
{
137+
QMessageBox::critical( 0, tr( "Error" ), tr( "An error occured while evaluating the calculation string." ) );
138+
139+
//remove new attribute
140+
mVectorLayer->deleteAttribute( attributeId );
141+
mVectorLayer->destroyEditCommand();
142+
return;
143+
}
144+
145+
mVectorLayer->endEditCommand();
146+
}
147+
QDialog::accept();
148+
}
149+
150+
void QgsFieldCalculator::populateFields()
151+
{
152+
if ( !mVectorLayer )
153+
{
154+
return;
155+
}
156+
157+
const QgsFieldMap fieldMap = mVectorLayer->pendingFields();
158+
QgsFieldMap::const_iterator fieldIt = fieldMap.constBegin();
159+
for ( ; fieldIt != fieldMap.constEnd(); ++fieldIt )
160+
{
161+
QString fieldName = fieldIt.value().name();
162+
mFieldMap.insert( fieldName, fieldIt.key() );
163+
mFieldsListWidget->addItem( fieldName );
164+
}
165+
}
166+
167+
void QgsFieldCalculator::on_mFieldsListWidget_itemDoubleClicked( QListWidgetItem * item )
168+
{
169+
if ( !item )
170+
{
171+
return;
172+
}
173+
mExpressionTextEdit->insertPlainText( item->text() );
174+
}
175+
176+
void QgsFieldCalculator::on_mValueListWidget_itemDoubleClicked( QListWidgetItem * item )
177+
{
178+
if ( !item )
179+
{
180+
return;
181+
}
182+
mExpressionTextEdit->insertPlainText( " " + item->text() + " " );
183+
}
184+
185+
void QgsFieldCalculator::on_mPlusPushButton_clicked()
186+
{
187+
mExpressionTextEdit->insertPlainText( " + " );
188+
}
189+
190+
void QgsFieldCalculator::on_mMinusPushButton_clicked()
191+
{
192+
mExpressionTextEdit->insertPlainText( " - " );
193+
}
194+
195+
void QgsFieldCalculator::on_mMultiplyPushButton_clicked()
196+
{
197+
mExpressionTextEdit->insertPlainText( " * " );
198+
}
199+
200+
void QgsFieldCalculator::on_mDividePushButton_clicked()
201+
{
202+
mExpressionTextEdit->insertPlainText( " / " );
203+
}
204+
205+
void QgsFieldCalculator::on_mSqrtButton_clicked()
206+
{
207+
mExpressionTextEdit->insertPlainText( " sqrt ( " );
208+
}
209+
210+
void QgsFieldCalculator::on_mExpButton_clicked()
211+
{
212+
mExpressionTextEdit->insertPlainText( " ^ " );
213+
}
214+
215+
void QgsFieldCalculator::on_mSinButton_clicked()
216+
{
217+
mExpressionTextEdit->insertPlainText( " sin ( " );
218+
}
219+
220+
void QgsFieldCalculator::on_mCosButton_clicked()
221+
{
222+
mExpressionTextEdit->insertPlainText( " cos ( " );
223+
}
224+
225+
void QgsFieldCalculator::on_mTanButton_clicked()
226+
{
227+
mExpressionTextEdit->insertPlainText( " tan ( " );
228+
}
229+
230+
void QgsFieldCalculator::on_mASinButton_clicked()
231+
{
232+
mExpressionTextEdit->insertPlainText( " asin ( " );
233+
}
234+
235+
void QgsFieldCalculator::on_mACosButton_clicked()
236+
{
237+
mExpressionTextEdit->insertPlainText( " acos ( " );
238+
}
239+
240+
void QgsFieldCalculator::on_mATanButton_clicked()
241+
{
242+
mExpressionTextEdit->insertPlainText( " atan ( " );
243+
}
244+
245+
void QgsFieldCalculator::on_mOpenBracketPushButton_clicked()
246+
{
247+
mExpressionTextEdit->insertPlainText( " ( " );
248+
}
249+
250+
void QgsFieldCalculator::on_mCloseBracketPushButton_clicked()
251+
{
252+
mExpressionTextEdit->insertPlainText( " ) " );
253+
}
254+
255+
void QgsFieldCalculator::on_mSamplePushButton_clicked()
256+
{
257+
getFieldValues( 25 );
258+
}
259+
260+
void QgsFieldCalculator::on_mAllPushButton_clicked()
261+
{
262+
getFieldValues( 0 );
263+
}
264+
265+
void QgsFieldCalculator::on_mOutputFieldNameLineEdit_textChanged( const QString& text )
266+
{
267+
setOkButtonState();
268+
}
269+
270+
void QgsFieldCalculator::on_mExpressionTextEdit_textChanged()
271+
{
272+
setOkButtonState();
273+
}
274+
275+
void QgsFieldCalculator::on_mOutputFieldTypeComboBox_currentIndexChanged( const QString& text )
276+
{
277+
if ( text == tr( "Double" ) )
278+
{
279+
mOutputFieldPrecisionSpinBox->setEnabled( true );
280+
}
281+
else
282+
{
283+
mOutputFieldPrecisionSpinBox->setEnabled( false );
284+
}
285+
}
286+
287+
void QgsFieldCalculator::getFieldValues( int limit )
288+
{
289+
mValueListWidget->clear();
290+
291+
if ( !mVectorLayer )
292+
{
293+
return;
294+
}
295+
296+
QListWidgetItem* currentItem = mFieldsListWidget->currentItem();
297+
if ( !currentItem )
298+
{
299+
return;
300+
}
301+
302+
QMap<QString, int>::const_iterator attIt = mFieldMap.find( currentItem->text() );
303+
if ( attIt == mFieldMap.constEnd() )
304+
{
305+
return;
306+
}
307+
308+
int attributeIndex = attIt.value();
309+
QgsField field = mVectorLayer->pendingFields()[attributeIndex];
310+
bool numeric = ( field.type() == QVariant::Int || field.type() == QVariant::Double );
311+
312+
QgsAttributeList attList;
313+
attList << attributeIndex;
314+
315+
mVectorLayer->select( attList, QgsRectangle(), false );
316+
QgsFeature f;
317+
int resultCounter = 0;
318+
319+
mValueListWidget->setUpdatesEnabled( false );
320+
mValueListWidget->blockSignals( true );
321+
QSet<QString> insertedValues;
322+
323+
while ( mVectorLayer->nextFeature( f ) && ( limit == 0 || resultCounter != limit ) )
324+
{
325+
QString value = f.attributeMap()[attributeIndex].toString();
326+
if ( !numeric )
327+
{
328+
value = ( "'" + value + "'" );
329+
}
330+
//QList<QListWidgetItem *> existingItems = mValueListWidget->findItems(value, Qt::MatchExactly);
331+
//if(existingItems.isEmpty())
332+
if ( !insertedValues.contains( value ) )
333+
{
334+
mValueListWidget->addItem( value );
335+
insertedValues.insert( value );
336+
++resultCounter;
337+
}
338+
}
339+
mValueListWidget->setUpdatesEnabled( true );
340+
mValueListWidget->blockSignals( false );
341+
}
342+
343+
void QgsFieldCalculator::setOkButtonState()
344+
{
345+
bool okEnabled = true;
346+
if ( mOutputFieldNameLineEdit->text().isEmpty() || mExpressionTextEdit->toPlainText().isEmpty() )
347+
{
348+
okEnabled = false;
349+
}
350+
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( okEnabled );
351+
}
352+
353+

0 commit comments

Comments
 (0)
Please sign in to comment.