Quantum GIS API Documentation
1.7.4
|
00001 00002 #include "qgscategorizedsymbolrendererv2.h" 00003 00004 #include "qgssymbolv2.h" 00005 #include "qgssymbollayerv2utils.h" 00006 #include "qgsvectorcolorrampv2.h" 00007 00008 #include "qgsfeature.h" 00009 #include "qgsvectorlayer.h" 00010 #include "qgslogger.h" 00011 00012 #include <QDomDocument> 00013 #include <QDomElement> 00014 #include <QSettings> // for legend 00015 00016 QgsRendererCategoryV2::QgsRendererCategoryV2( QVariant value, QgsSymbolV2* symbol, QString label ) 00017 : mValue( value ), mSymbol( symbol ), mLabel( label ) 00018 { 00019 } 00020 00021 QgsRendererCategoryV2::QgsRendererCategoryV2( const QgsRendererCategoryV2& cat ) 00022 : mValue( cat.mValue ), mLabel( cat.mLabel ) 00023 { 00024 mSymbol = cat.mSymbol->clone(); 00025 } 00026 00027 00028 QgsRendererCategoryV2::~QgsRendererCategoryV2() 00029 { 00030 delete mSymbol; 00031 } 00032 00033 QVariant QgsRendererCategoryV2::value() const 00034 { 00035 return mValue; 00036 } 00037 00038 QgsSymbolV2* QgsRendererCategoryV2::symbol() const 00039 { 00040 return mSymbol; 00041 } 00042 00043 QString QgsRendererCategoryV2::label() const 00044 { 00045 return mLabel; 00046 } 00047 00048 void QgsRendererCategoryV2::setValue( const QVariant &value ) 00049 { 00050 mValue = value; 00051 } 00052 00053 void QgsRendererCategoryV2::setSymbol( QgsSymbolV2* s ) 00054 { 00055 if ( mSymbol == s ) 00056 return; 00057 delete mSymbol; 00058 mSymbol = s; 00059 } 00060 00061 void QgsRendererCategoryV2::setLabel( const QString &label ) 00062 { 00063 mLabel = label; 00064 } 00065 00066 QString QgsRendererCategoryV2::dump() 00067 { 00068 return QString( "%1::%2::%3\n" ).arg( mValue.toString() ).arg( mLabel ).arg( mSymbol->dump() ); 00069 } 00070 00072 00073 QgsCategorizedSymbolRendererV2::QgsCategorizedSymbolRendererV2( QString attrName, QgsCategoryList categories ) 00074 : QgsFeatureRendererV2( "categorizedSymbol" ), 00075 mAttrName( attrName ), 00076 mCategories( categories ), 00077 mSourceSymbol( NULL ), 00078 mSourceColorRamp( NULL ), 00079 mRotationFieldIdx( -1 ), 00080 mSizeScaleFieldIdx( -1 ) 00081 { 00082 for ( int i = 0; i < mCategories.count(); ++i ) 00083 { 00084 QgsRendererCategoryV2& cat = mCategories[i]; 00085 if ( cat.symbol() == NULL ) 00086 { 00087 QgsDebugMsg( "invalid symbol in a category! ignoring..." ); 00088 mCategories.removeAt( i-- ); 00089 } 00090 //mCategories.insert(cat.value().toString(), cat); 00091 } 00092 } 00093 00094 QgsCategorizedSymbolRendererV2::~QgsCategorizedSymbolRendererV2() 00095 { 00096 mCategories.clear(); // this should also call destructors of symbols 00097 delete mSourceSymbol; 00098 delete mSourceColorRamp; 00099 } 00100 00101 void QgsCategorizedSymbolRendererV2::rebuildHash() 00102 { 00103 mSymbolHash.clear(); 00104 00105 for ( int i = 0; i < mCategories.count(); ++i ) 00106 { 00107 QgsRendererCategoryV2& cat = mCategories[i]; 00108 mSymbolHash.insert( cat.value().toString(), cat.symbol() ); 00109 } 00110 } 00111 00112 QgsSymbolV2* QgsCategorizedSymbolRendererV2::symbolForValue( QVariant value ) 00113 { 00114 // TODO: special case for int, double 00115 00116 QHash<QString, QgsSymbolV2*>::iterator it = mSymbolHash.find( value.toString() ); 00117 if ( it == mSymbolHash.end() ) 00118 { 00119 if ( mSymbolHash.count() == 0 ) 00120 QgsDebugMsg( "there are no hashed symbols!!!" ); 00121 else 00122 QgsDebugMsg( "attribute value not found: " + value.toString() ); 00123 return NULL; 00124 } 00125 00126 return *it; 00127 } 00128 00129 QgsSymbolV2* QgsCategorizedSymbolRendererV2::symbolForFeature( QgsFeature& feature ) 00130 { 00131 const QgsAttributeMap& attrMap = feature.attributeMap(); 00132 QgsAttributeMap::const_iterator ita = attrMap.find( mAttrNum ); 00133 if ( ita == attrMap.end() ) 00134 { 00135 QgsDebugMsg( "attribute '" + mAttrName + "' (index " + QString::number( mAttrNum ) + ") required by renderer not found" ); 00136 return NULL; 00137 } 00138 00139 // find the right symbol for the category 00140 QgsSymbolV2* symbol = symbolForValue( *ita ); 00141 if ( symbol == NULL ) 00142 { 00143 // if no symbol found use default one 00144 return symbolForValue( QVariant( "" ) ); 00145 } 00146 00147 if ( mRotationFieldIdx == -1 && mSizeScaleFieldIdx == -1 ) 00148 return symbol; // no data-defined rotation/scaling - just return the symbol 00149 00150 // find out rotation, size scale 00151 double rotation = 0; 00152 double sizeScale = 1; 00153 if ( mRotationFieldIdx != -1 ) 00154 rotation = attrMap[mRotationFieldIdx].toDouble(); 00155 if ( mSizeScaleFieldIdx != -1 ) 00156 sizeScale = attrMap[mSizeScaleFieldIdx].toDouble(); 00157 00158 // take a temporary symbol (or create it if doesn't exist) 00159 QgsSymbolV2* tempSymbol = mTempSymbols[ita->toString()]; 00160 00161 // modify the temporary symbol and return it 00162 if ( tempSymbol->type() == QgsSymbolV2::Marker ) 00163 { 00164 QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( tempSymbol ); 00165 if ( mRotationFieldIdx != -1 ) 00166 markerSymbol->setAngle( rotation ); 00167 if ( mSizeScaleFieldIdx != -1 ) 00168 markerSymbol->setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->size() ); 00169 } 00170 else if ( tempSymbol->type() == QgsSymbolV2::Line ) 00171 { 00172 QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( tempSymbol ); 00173 if ( mSizeScaleFieldIdx != -1 ) 00174 lineSymbol->setWidth( sizeScale * static_cast<QgsLineSymbolV2*>( symbol )->width() ); 00175 } 00176 00177 return tempSymbol; 00178 } 00179 00180 int QgsCategorizedSymbolRendererV2::categoryIndexForValue( QVariant val ) 00181 { 00182 for ( int i = 0; i < mCategories.count(); i++ ) 00183 { 00184 if ( mCategories[i].value() == val ) 00185 return i; 00186 } 00187 return -1; 00188 } 00189 00190 bool QgsCategorizedSymbolRendererV2::updateCategoryValue( int catIndex, const QVariant &value ) 00191 { 00192 if ( catIndex < 0 || catIndex >= mCategories.size() ) 00193 return false; 00194 mCategories[catIndex].setValue( value ); 00195 return true; 00196 } 00197 00198 bool QgsCategorizedSymbolRendererV2::updateCategorySymbol( int catIndex, QgsSymbolV2* symbol ) 00199 { 00200 if ( catIndex < 0 || catIndex >= mCategories.size() ) 00201 return false; 00202 mCategories[catIndex].setSymbol( symbol ); 00203 return true; 00204 } 00205 00206 bool QgsCategorizedSymbolRendererV2::updateCategoryLabel( int catIndex, QString label ) 00207 { 00208 if ( catIndex < 0 || catIndex >= mCategories.size() ) 00209 return false; 00210 mCategories[catIndex].setLabel( label ); 00211 return true; 00212 } 00213 00214 void QgsCategorizedSymbolRendererV2::addCategory( const QgsRendererCategoryV2 &cat ) 00215 { 00216 if ( cat.symbol() == NULL ) 00217 { 00218 QgsDebugMsg( "invalid symbol in a category! ignoring..." ); 00219 } 00220 else 00221 { 00222 mCategories.append( cat ); 00223 } 00224 } 00225 00226 bool QgsCategorizedSymbolRendererV2::deleteCategory( int catIndex ) 00227 { 00228 if ( catIndex < 0 || catIndex >= mCategories.size() ) 00229 return false; 00230 00231 mCategories.removeAt( catIndex ); 00232 return true; 00233 } 00234 00235 void QgsCategorizedSymbolRendererV2::deleteAllCategories() 00236 { 00237 mCategories.clear(); 00238 } 00239 00240 void QgsCategorizedSymbolRendererV2::startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer ) 00241 { 00242 // make sure that the hash table is up to date 00243 rebuildHash(); 00244 00245 // find out classification attribute index from name 00246 mAttrNum = vlayer ? vlayer->fieldNameIndex( mAttrName ) : -1; 00247 00248 mRotationFieldIdx = ( mRotationField.isEmpty() ? -1 : vlayer->fieldNameIndex( mRotationField ) ); 00249 mSizeScaleFieldIdx = ( mSizeScaleField.isEmpty() ? -1 : vlayer->fieldNameIndex( mSizeScaleField ) ); 00250 00251 QgsCategoryList::iterator it = mCategories.begin(); 00252 for ( ; it != mCategories.end(); ++it ) 00253 { 00254 it->symbol()->startRender( context ); 00255 00256 if ( mRotationFieldIdx != -1 || mSizeScaleFieldIdx != -1 ) 00257 { 00258 QgsSymbolV2* tempSymbol = it->symbol()->clone(); 00259 tempSymbol->setRenderHints(( mRotationFieldIdx != -1 ? QgsSymbolV2::DataDefinedRotation : 0 ) | 00260 ( mSizeScaleFieldIdx != -1 ? QgsSymbolV2::DataDefinedSizeScale : 0 ) ); 00261 tempSymbol->startRender( context ); 00262 mTempSymbols[ it->value().toString()] = tempSymbol; 00263 } 00264 } 00265 00266 } 00267 00268 void QgsCategorizedSymbolRendererV2::stopRender( QgsRenderContext& context ) 00269 { 00270 QgsCategoryList::iterator it = mCategories.begin(); 00271 for ( ; it != mCategories.end(); ++it ) 00272 it->symbol()->stopRender( context ); 00273 00274 // cleanup mTempSymbols 00275 QHash<QString, QgsSymbolV2*>::iterator it2 = mTempSymbols.begin(); 00276 for ( ; it2 != mTempSymbols.end(); ++it2 ) 00277 { 00278 it2.value()->stopRender( context ); 00279 delete it2.value(); 00280 } 00281 mTempSymbols.clear(); 00282 } 00283 00284 QList<QString> QgsCategorizedSymbolRendererV2::usedAttributes() 00285 { 00286 QList<QString> lst; 00287 lst.append( mAttrName ); 00288 if ( !mRotationField.isEmpty() ) 00289 lst.append( mRotationField ); 00290 if ( !mSizeScaleField.isEmpty() ) 00291 lst.append( mSizeScaleField ); 00292 return lst; 00293 } 00294 00295 QString QgsCategorizedSymbolRendererV2::dump() 00296 { 00297 QString s = QString( "CATEGORIZED: idx %1\n" ).arg( mAttrName ); 00298 for ( int i = 0; i < mCategories.count(); i++ ) 00299 s += mCategories[i].dump(); 00300 return s; 00301 } 00302 00303 QgsFeatureRendererV2* QgsCategorizedSymbolRendererV2::clone() 00304 { 00305 QgsCategorizedSymbolRendererV2* r = new QgsCategorizedSymbolRendererV2( mAttrName, mCategories ); 00306 if ( mSourceSymbol ) 00307 r->setSourceSymbol( mSourceSymbol->clone() ); 00308 if ( mSourceColorRamp ) 00309 r->setSourceColorRamp( mSourceColorRamp->clone() ); 00310 r->setUsingSymbolLevels( usingSymbolLevels() ); 00311 r->setRotationField( rotationField() ); 00312 r->setSizeScaleField( sizeScaleField() ); 00313 return r; 00314 } 00315 00316 QgsSymbolV2List QgsCategorizedSymbolRendererV2::symbols() 00317 { 00318 QgsSymbolV2List lst; 00319 for ( int i = 0; i < mCategories.count(); i++ ) 00320 lst.append( mCategories[i].symbol() ); 00321 return lst; 00322 } 00323 00324 QgsFeatureRendererV2* QgsCategorizedSymbolRendererV2::create( QDomElement& element ) 00325 { 00326 QDomElement symbolsElem = element.firstChildElement( "symbols" ); 00327 if ( symbolsElem.isNull() ) 00328 return NULL; 00329 00330 QDomElement catsElem = element.firstChildElement( "categories" ); 00331 if ( catsElem.isNull() ) 00332 return NULL; 00333 00334 QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem ); 00335 QgsCategoryList cats; 00336 00337 QDomElement catElem = catsElem.firstChildElement(); 00338 while ( !catElem.isNull() ) 00339 { 00340 if ( catElem.tagName() == "category" ) 00341 { 00342 QVariant value = QVariant( catElem.attribute( "value" ) ); 00343 QString symbolName = catElem.attribute( "symbol" ); 00344 QString label = catElem.attribute( "label" ); 00345 if ( symbolMap.contains( symbolName ) ) 00346 { 00347 QgsSymbolV2* symbol = symbolMap.take( symbolName ); 00348 cats.append( QgsRendererCategoryV2( value, symbol, label ) ); 00349 } 00350 } 00351 catElem = catElem.nextSiblingElement(); 00352 } 00353 00354 QString attrName = element.attribute( "attr" ); 00355 00356 QgsCategorizedSymbolRendererV2* r = new QgsCategorizedSymbolRendererV2( attrName, cats ); 00357 00358 // delete symbols if there are any more 00359 QgsSymbolLayerV2Utils::clearSymbolMap( symbolMap ); 00360 00361 // try to load source symbol (optional) 00362 QDomElement sourceSymbolElem = element.firstChildElement( "source-symbol" ); 00363 if ( !sourceSymbolElem.isNull() ) 00364 { 00365 QgsSymbolV2Map sourceSymbolMap = QgsSymbolLayerV2Utils::loadSymbols( sourceSymbolElem ); 00366 if ( sourceSymbolMap.contains( "0" ) ) 00367 { 00368 r->setSourceSymbol( sourceSymbolMap.take( "0" ) ); 00369 } 00370 QgsSymbolLayerV2Utils::clearSymbolMap( sourceSymbolMap ); 00371 } 00372 00373 // try to load color ramp (optional) 00374 QDomElement sourceColorRampElem = element.firstChildElement( "colorramp" ); 00375 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( "name" ) == "[source]" ) 00376 { 00377 r->setSourceColorRamp( QgsSymbolLayerV2Utils::loadColorRamp( sourceColorRampElem ) ); 00378 } 00379 00380 QDomElement rotationElem = element.firstChildElement( "rotation" ); 00381 if ( !rotationElem.isNull() ) 00382 r->setRotationField( rotationElem.attribute( "field" ) ); 00383 00384 QDomElement sizeScaleElem = element.firstChildElement( "sizescale" ); 00385 if ( !sizeScaleElem.isNull() ) 00386 r->setSizeScaleField( sizeScaleElem.attribute( "field" ) ); 00387 00388 // TODO: symbol levels 00389 return r; 00390 } 00391 00392 QDomElement QgsCategorizedSymbolRendererV2::save( QDomDocument& doc ) 00393 { 00394 QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME ); 00395 rendererElem.setAttribute( "type", "categorizedSymbol" ); 00396 rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) ); 00397 rendererElem.setAttribute( "attr", mAttrName ); 00398 00399 // categories 00400 int i = 0; 00401 QgsSymbolV2Map symbols; 00402 QDomElement catsElem = doc.createElement( "categories" ); 00403 QgsCategoryList::const_iterator it = mCategories.constBegin(); 00404 for ( ; it != mCategories.end(); it++ ) 00405 { 00406 const QgsRendererCategoryV2& cat = *it; 00407 QString symbolName = QString::number( i ); 00408 symbols.insert( symbolName, cat.symbol() ); 00409 00410 QDomElement catElem = doc.createElement( "category" ); 00411 catElem.setAttribute( "value", cat.value().toString() ); 00412 catElem.setAttribute( "symbol", symbolName ); 00413 catElem.setAttribute( "label", cat.label() ); 00414 catsElem.appendChild( catElem ); 00415 i++; 00416 } 00417 00418 rendererElem.appendChild( catsElem ); 00419 00420 // save symbols 00421 QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc ); 00422 rendererElem.appendChild( symbolsElem ); 00423 00424 // save source symbol 00425 if ( mSourceSymbol ) 00426 { 00427 QgsSymbolV2Map sourceSymbols; 00428 sourceSymbols.insert( "0", mSourceSymbol ); 00429 QDomElement sourceSymbolElem = QgsSymbolLayerV2Utils::saveSymbols( sourceSymbols, "source-symbol", doc ); 00430 rendererElem.appendChild( sourceSymbolElem ); 00431 } 00432 00433 // save source color ramp 00434 if ( mSourceColorRamp ) 00435 { 00436 QDomElement colorRampElem = QgsSymbolLayerV2Utils::saveColorRamp( "[source]", mSourceColorRamp, doc ); 00437 rendererElem.appendChild( colorRampElem ); 00438 } 00439 00440 QDomElement rotationElem = doc.createElement( "rotation" ); 00441 rotationElem.setAttribute( "field", mRotationField ); 00442 rendererElem.appendChild( rotationElem ); 00443 00444 QDomElement sizeScaleElem = doc.createElement( "sizescale" ); 00445 sizeScaleElem.setAttribute( "field", mSizeScaleField ); 00446 rendererElem.appendChild( sizeScaleElem ); 00447 00448 return rendererElem; 00449 } 00450 00451 QgsLegendSymbologyList QgsCategorizedSymbolRendererV2::legendSymbologyItems( QSize iconSize ) 00452 { 00453 QSettings settings; 00454 bool showClassifiers = settings.value( "/qgis/showLegendClassifiers", false ).toBool(); 00455 00456 QgsLegendSymbologyList lst; 00457 if ( showClassifiers ) 00458 { 00459 lst << qMakePair( classAttribute(), QPixmap() ); 00460 } 00461 00462 int count = categories().count(); 00463 for ( int i = 0; i < count; i++ ) 00464 { 00465 const QgsRendererCategoryV2& cat = categories()[i]; 00466 QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( cat.symbol(), iconSize ); 00467 lst << qMakePair( cat.label(), pix ); 00468 } 00469 return lst; 00470 } 00471 00472 QgsLegendSymbolList QgsCategorizedSymbolRendererV2::legendSymbolItems() 00473 { 00474 QSettings settings; 00475 bool showClassifiers = settings.value( "/qgis/showLegendClassifiers", false ).toBool(); 00476 00477 QgsLegendSymbolList lst; 00478 if ( showClassifiers ) 00479 { 00480 lst << qMakePair( classAttribute(), ( QgsSymbolV2* )0 ); 00481 } 00482 00483 QgsCategoryList::const_iterator catIt = mCategories.constBegin(); 00484 for ( ; catIt != mCategories.constEnd(); ++catIt ) 00485 { 00486 lst << qMakePair( catIt->label(), catIt->symbol() ); 00487 } 00488 return lst; 00489 } 00490 00491 00492 QgsSymbolV2* QgsCategorizedSymbolRendererV2::sourceSymbol() 00493 { 00494 return mSourceSymbol; 00495 } 00496 void QgsCategorizedSymbolRendererV2::setSourceSymbol( QgsSymbolV2* sym ) 00497 { 00498 delete mSourceSymbol; 00499 mSourceSymbol = sym; 00500 } 00501 00502 QgsVectorColorRampV2* QgsCategorizedSymbolRendererV2::sourceColorRamp() 00503 { 00504 return mSourceColorRamp; 00505 } 00506 void QgsCategorizedSymbolRendererV2::setSourceColorRamp( QgsVectorColorRampV2* ramp ) 00507 { 00508 delete mSourceColorRamp; 00509 mSourceColorRamp = ramp; 00510 }