/*************************************************************************** qgsuvalmadialog.cpp - unique value marker dialog ------------------- begin : September 2004 copyright : (C) 2004 by Lars Luthman email : larsl@users.sourceforge.net ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /* $Id$ */ #include "qgsuvalmadialog.h" #include "qgsvectordataprovider.h" #include "qgsvectorlayer.h" #include "qgsdlgvectorlayerproperties.h" #include "qgsfeature.h" #include "qgsfeatureattribute.h" #include "qgssimadialog.h" #include "qgssymbol.h" #include "qgsmarkersymbol.h" #include "qgssvgcache.h" #include "qgsrenderitem.h" #include "qgsuvalmarenderer.h" #include #include #include #include #include #include #include #ifdef WIN32 extern QString PKGDATAPATH; #endif QgsUValMaDialog::QgsUValMaDialog(QgsVectorLayer* vl): QgsUValMaDialogBase(), mVectorLayer(vl), madialog(vl) { setSizeGripEnabled(true); //find out the fields of mVectorLayer QgsVectorDataProvider *provider; if (provider = dynamic_cast(mVectorLayer->getDataProvider())) { std::vector < QgsField > &fields = provider->fields(); QString str; for (std::vector < QgsField >::iterator it = fields.begin(); it != fields.end(); ++it) { str = (*it).name(); str = str.left(1).upper() + str.right(str.length() - 1); //make the first letter uppercase mClassificationComboBox->insertItem(str); } } else { qWarning("Warning, data provider is null in QgsUValDialog::QgsUValDialog"); return; } QObject::connect(mClassificationComboBox, SIGNAL(activated(int)), this, SLOT(changeClassificationAttribute(int))); QObject::connect(mClassBreakBox, SIGNAL(selectionChanged()), this, SLOT(changeCurrentValue())); QObject::connect(&madialog, SIGNAL(settingsChanged()), this, SLOT(applySymbologyChanges())); mSymbolWidgetStack->addWidget(&madialog); mSymbolWidgetStack->raiseWidget(&madialog); //restore settings if unique value renderer was read from a project file QgsUValMaRenderer *renderer; //initial settings, use the buffer of the propertiesDialog if possible. If this is not possible, use the renderer of the vectorlayer directly if (mVectorLayer->propertiesDialog()) { renderer = dynamic_cast < QgsUValMaRenderer * >(mVectorLayer->propertiesDialog()->getBufferRenderer()); } else { renderer = dynamic_cast < QgsUValMaRenderer * >(mVectorLayer->renderer()); } if (renderer) { mClassBreakBox->clear(); std::list::iterator iter=renderer->classificationAttributes().begin(); int classattr=*iter; mClassificationComboBox->setCurrentItem(classattr); mClassBreakBox->setCurrentItem(0); changeClassificationAttribute(classattr); } } QgsUValMaDialog::~QgsUValMaDialog() { for(std::map::iterator it=mValues.begin();it!=mValues.end();++it) { delete it->second; it->second = NULL; } } void QgsUValMaDialog::apply() { //font tor the legend text QFont f("arial", 10, QFont::Normal); QFontMetrics fm(f); int symbolheight = 15; //height of an area where a symbol is painted int symbolwidth = 15; //width of an area where a symbol is painted int rowheight = (fm.height() > symbolheight) ? fm.height() : symbolheight; //height of a row in the symbology part int topspace = 5; int bottomspace = 5; int leftspace = 5; int rightspace = 5; int rowspace = 5; int wordspace = 5; //space between graphics/word int widestvalue = 0; int valuewidth; //find out the width of the widest label and of the broadest value string int maxlabelwidth=0; int maxvaluewidth=0; for(std::map::iterator it=mValues.begin();it!=mValues.end();++it) { int currentlabelwidth=fm.width(it->second->label()); if(currentlabelwidth>maxlabelwidth) { maxlabelwidth=currentlabelwidth; } int currentvwidth=fm.width(it->second->value()); if(currentvwidth>maxvaluewidth) { maxvaluewidth=currentvwidth; } } QgsUValMaRenderer *renderer = dynamic_cast < QgsUValMaRenderer * >(mVectorLayer->renderer()); //go through mValues and add the entries to the renderer int pixheight = topspace+2*fm.height()+rowspace; if(renderer) { renderer->clearValues(); for(std::map::iterator it=mValues.begin();it!=mValues.end();++it) { QgsMarkerSymbol* symbol = dynamic_cast(it->second->getSymbol()); QgsMarkerSymbol* newsymbol=new QgsMarkerSymbol(); newsymbol->setPicture(symbol->picture()); newsymbol->setScaleFactor(symbol->scaleFactor()); QgsRenderItem* ritem=new QgsRenderItem(newsymbol,it->first,""); renderer->insertValue(it->first,ritem); //find out the width of the string valuewidth = fm.width(it->first); if(valuewidth>widestvalue) { widestvalue=valuewidth; } // add to the total height QPixmap pm = QgsSVGCache::instance(). getPixmap(symbol->picture(), symbol->scaleFactor()); pixheight += ((rowheight > pm.height() ? rowheight : pm.height()) + rowspace); // find out the width of the symbols if (pm.width() > symbolwidth) symbolwidth = pm.width(); } renderer->setClassificationField(mClassificationComboBox->currentItem()); } else { #ifdef QGISDEBUG qWarning("Warning, typecast failed in qgsuvaldialog.cpp, l. 61"); #endif } //render the legend item QPixmap *pix = mVectorLayer->legendPixmap(); QString name; QString field=mClassificationComboBox->currentText(); int fieldwidth=fm.width(field); if(fieldwidth>widestvalue) { widestvalue=fieldwidth; } if (mVectorLayer->propertiesDialog()) { name = mVectorLayer->propertiesDialog()->displayName(); } else { name = ""; } int namewidth=fm.width(name); int pixwidth; if(namewidth>widestvalue) { if(namewidth>(symbolwidth+wordspace+widestvalue+maxlabelwidth)) { pixwidth = leftspace+wordspace+namewidth+rightspace; } else { pixwidth = leftspace+2*wordspace+symbolwidth+maxlabelwidth+widestvalue+rightspace; } } else { pixwidth = leftspace+2*wordspace+symbolwidth+widestvalue+maxlabelwidth+rightspace; } pixheight += bottomspace; pix->resize(pixwidth,pixheight); pix->fill(); QPainter p(pix); p.setFont(f); //draw the layer name and the name of the classification field into the pixmap p.drawText(leftspace, topspace + fm.height(), name); p.drawText(leftspace, topspace + 2 * fm.height(), field); // draw symbols and values for the different classes int intermheight=topspace+2*fm.height()+rowspace; int currentheight = intermheight; for(std::map::iterator it=mValues.begin();it!=mValues.end();++it) { QgsMarkerSymbol* sym = dynamic_cast(it->second->getSymbol()); QPixmap pm = QgsSVGCache::instance().getPixmap(sym->picture(), sym->scaleFactor()); p.drawPixmap(leftspace + (symbolwidth - pm.width()) / 2, currentheight, pm); p.setPen(Qt::black); p.drawText(leftspace+symbolwidth+wordspace, currentheight + rowheight, it->first); p.drawText(leftspace+symbolwidth+2*wordspace+widestvalue, currentheight + rowheight, it->second->label()); currentheight += (rowheight > pm.height() ? rowheight : pm.height()) + rowspace; } mVectorLayer->updateItemPixmap(); mVectorLayer->triggerRepaint(); } void QgsUValMaDialog::changeClassificationAttribute(int nr) { #ifdef QGISDEBUG qWarning("in changeClassificationAttribute, nr is: "+QString::number(nr)); #endif //delete old entries for(std::map::iterator it=mValues.begin();it!=mValues.end();++it) { delete it->second; } mValues.clear(); QgsVectorDataProvider *provider = dynamic_cast(mVectorLayer->getDataProvider()); if (provider) { QString value; std::list attlist; attlist.push_back(nr); std::vector < QgsFeatureAttribute > vec; QgsMarkerSymbol* symbol; QgsRenderItem* ritemptr; provider->reset(); QgsFeature* f; //go through all the features and insert their value into the map and into mClassBreakBox mClassBreakBox->clear(); while((f=provider->getNextFeature(attlist))) { vec = f->attributeMap(); value=vec[0].fieldValue(); if(mValues.find(value)==mValues.end()) { symbol=new QgsMarkerSymbol(); ritemptr=new QgsRenderItem(symbol,"",""); mValues.insert(std::make_pair(value,ritemptr)); } delete f; } //set symbology for all QgsSiMaDialogs QColor thecolor; double number=0; double frac; for(std::map::iterator it=mValues.begin();it!=mValues.end();++it) { // set all markers to svg/symbol/Cross4.svg with scale factor from // 0.4 to 1.0 const double minSize = 0.4, maxSize = 1.0; frac=number/mValues.size(); mClassBreakBox->insertItem(it->first); QgsMarkerSymbol* sym = dynamic_cast(it->second->getSymbol()); assert(sym != NULL); #if defined(WIN32) || defined(Q_OS_MACX) QString PKGDATAPATH = qApp->applicationDirPath() + "/share/qgis"; #endif sym->setPicture(QString(PKGDATAPATH) + "/svg/symbol/Cross4.svg"); sym->setScaleFactor(minSize + (maxSize - minSize) * frac); ++number; } } mClassBreakBox->setCurrentItem(0); } void QgsUValMaDialog::changeCurrentValue() { QListBoxItem* item=mClassBreakBox->selectedItem(); QString value=item->text(); std::map::iterator it=mValues.find(value); if(it!=mValues.end()) { QgsMarkerSymbol* ms = dynamic_cast(it->second->getSymbol()); assert(ms != NULL); madialog.setMarker(ms->picture(), ms->scaleFactor()); } else { //no entry found } } void QgsUValMaDialog::applySymbologyChanges() { QListBoxItem* item=mClassBreakBox->selectedItem(); QString value=item->text(); std::map::iterator it=mValues.find(value); if(it!=mValues.end()) { QgsMarkerSymbol* ms = dynamic_cast(it->second-> getSymbol()); assert(ms != NULL); std::cerr<<"madialog.getPicture() = "<setPicture(madialog.getPicture()); ms->setScaleFactor(madialog.getScaleFactor()); } }