mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-25 00:58:06 -05:00
Hopefully all renderers will work now. git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@2257 c8812cc2-4d05-0410-92ff-de0c093fc19c
507 lines
17 KiB
C++
507 lines
17 KiB
C++
/***************************************************************************
|
|
qgsgrasydialog.cpp - description
|
|
-------------------
|
|
begin : Oct 2003
|
|
copyright : (C) 2003 by Marco Hugentobler
|
|
email : mhugent@geo.unizh.ch
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* 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 "qgsgrasydialog.h"
|
|
#include "qspinbox.h"
|
|
#include "qpushbutton.h"
|
|
#include <qcombobox.h>
|
|
#include <qlistbox.h>
|
|
#include "qgssymbologyutils.h"
|
|
#include "qgsrangerenderitem.h"
|
|
#include "qlineedit.h"
|
|
#include "qgsludialog.h"
|
|
#include "qgsgraduatedsymrenderer.h"
|
|
#include "qgsvectorlayer.h"
|
|
#include "qgslegenditem.h"
|
|
#include "qgsvectordataprovider.h"
|
|
#include "qgsfield.h"
|
|
#include "qscrollview.h"
|
|
#include <qlayout.h>
|
|
#include <qwidgetstack.h>
|
|
|
|
QgsGraSyDialog::QgsGraSyDialog(QgsVectorLayer * layer):QgsGraSyDialogBase(), mVectorLayer(layer), sydialog(layer)
|
|
{
|
|
|
|
|
|
#ifdef QGISDEBUG
|
|
qWarning("constructor QgsGraSyDialog");
|
|
#endif
|
|
|
|
setOrientation(Qt::Vertical);
|
|
setSizeGripEnabled(true);
|
|
|
|
//find out the numerical fields of mVectorLayer
|
|
QgsVectorDataProvider *provider;
|
|
if (provider = dynamic_cast<QgsVectorDataProvider *>(mVectorLayer->getDataProvider()))
|
|
{
|
|
std::vector < QgsField > &fields = provider->fields();
|
|
int fieldnumber = 0;
|
|
QString str;
|
|
|
|
for (std::vector < QgsField >::iterator it = fields.begin(); it != fields.end(); ++it)
|
|
{
|
|
QString type = (*it).type();
|
|
if (type != "String" && type != "varchar" && type != "geometry")
|
|
{
|
|
str = (*it).name();
|
|
str = str.left(1).upper() + str.right(str.length() - 1); //make the first letter uppercase
|
|
classificationComboBox->insertItem(str);
|
|
mFieldMap.insert(std::make_pair(str, fieldnumber));
|
|
}
|
|
fieldnumber++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
qWarning("Warning, data provider is null in QgsGraSyDialog::QgsGraSyDialog(...)");
|
|
return;
|
|
}
|
|
|
|
modeComboBox->insertItem("Empty");
|
|
modeComboBox->insertItem("Equal Interval");
|
|
|
|
//restore the correct settings
|
|
QgsGraduatedSymRenderer *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 < QgsGraduatedSymRenderer * >(layer->propertiesDialog()->getBufferRenderer());
|
|
}
|
|
else
|
|
{
|
|
renderer = dynamic_cast < QgsGraduatedSymRenderer * >(layer->renderer());
|
|
}
|
|
|
|
|
|
if (renderer)
|
|
{
|
|
std::list < QgsRangeRenderItem * >list = renderer->items();
|
|
classificationComboBox->setCurrentItem(renderer->classificationField());
|
|
QGis::VectorType m_type = mVectorLayer->vectorType();
|
|
numberofclassesspinbox->setValue(list.size());
|
|
//fill the items of the renderer into mValues
|
|
for(std::list<QgsRangeRenderItem*>::iterator it=list.begin();it!=list.end();++it)
|
|
{
|
|
QgsRangeRenderItem* item=(*it);
|
|
QString classbreak=item->value()+" - "+item->upper_value();
|
|
QgsSymbol* sym=new QgsSymbol();
|
|
QgsRangeRenderItem* rritem=new QgsRangeRenderItem(sym,item->value(),item->upper_value(),item->label());
|
|
sym->setPen(item->getSymbol()->pen());
|
|
sym->setBrush(item->getSymbol()->brush());
|
|
mEntries.insert(std::make_pair(classbreak,rritem));
|
|
mClassBreakBox->insertItem(classbreak);
|
|
}
|
|
|
|
}
|
|
|
|
//do the necessary signal/slot connections
|
|
//QObject::connect(numberofclassesspinbox, SIGNAL(valueChanged(int)), this, SLOT(adjustNumberOfClasses()));
|
|
QObject::connect(numberofclassesspinbox, SIGNAL(valueChanged(int)), this, SLOT(adjustClassification()));
|
|
QObject::connect(classificationComboBox, SIGNAL(activated(int)), this, SLOT(adjustClassification()));
|
|
QObject::connect(modeComboBox, SIGNAL(activated(int)), this, SLOT(adjustClassification()));
|
|
QObject::connect(mClassBreakBox, SIGNAL(selectionChanged()), this, SLOT(changeCurrentValue()));
|
|
QObject::connect(&sydialog, SIGNAL(settingsChanged()), this, SLOT(applySymbologyChanges()));
|
|
QObject::connect(mClassBreakBox, SIGNAL(doubleClicked(QListBoxItem*)), this, SLOT(changeClass(QListBoxItem*)));
|
|
|
|
mSymbolWidgetStack->addWidget(&sydialog);
|
|
mSymbolWidgetStack->raiseWidget(&sydialog);
|
|
|
|
mClassBreakBox->setCurrentItem(0);
|
|
}
|
|
|
|
QgsGraSyDialog::QgsGraSyDialog(): QgsGraSyDialogBase(), mVectorLayer(0), sydialog(0)
|
|
{
|
|
#ifdef QGISDEBUG
|
|
qWarning("constructor QgsGraSyDialog");
|
|
#endif
|
|
}
|
|
|
|
QgsGraSyDialog::~QgsGraSyDialog()
|
|
{
|
|
#ifdef QGISDEBUG
|
|
qWarning("destructor QgsGraSyDialog");
|
|
#endif
|
|
}
|
|
|
|
void QgsGraSyDialog::adjustNumberOfClasses()
|
|
{
|
|
//find out the number of the classification field
|
|
QString fieldstring = classificationComboBox->currentText();
|
|
|
|
if (fieldstring.isEmpty()) //don't do anything, it there is no classification field
|
|
{
|
|
show();
|
|
return;
|
|
}
|
|
|
|
std::map < QString, int >::iterator iter = mFieldMap.find(fieldstring);
|
|
int field = iter->second;
|
|
}
|
|
|
|
void QgsGraSyDialog::apply()
|
|
{
|
|
if (classificationComboBox->currentText().isEmpty()) //don't do anything, it there is no classification field
|
|
{
|
|
return;
|
|
}
|
|
|
|
//font tor the legend text
|
|
QFont f("arial", 10, QFont::Normal);
|
|
QFontMetrics fm(f);
|
|
|
|
//spaces
|
|
int topspace = 5;
|
|
int bottomspace = 5;
|
|
int leftspace = 10; //space between left side of the pixmap and the text/graphics
|
|
int rightspace = 5; //space between text/graphics and right side of the pixmap
|
|
int wordspace = 5; //space between graphics/word
|
|
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 lowerupperwidth; //widht of the broadest lower-upper pair
|
|
int rowspace = 5; //spaces between rows of symbols
|
|
int rowheight = (fm.height() > symbolheight) ? fm.height() : symbolheight; //height of a row in the symbology part
|
|
|
|
//find out the width of the widest label and of the broadest lower-upper pair
|
|
int labelwidth=0;
|
|
lowerupperwidth=0;
|
|
|
|
for(std::map<QString,QgsRangeRenderItem*>::iterator it=mEntries.begin();it!=mEntries.end();++it)
|
|
{
|
|
int currentlabelwidth=fm.width(it->second->label());
|
|
if(currentlabelwidth>labelwidth)
|
|
{
|
|
labelwidth=currentlabelwidth;
|
|
}
|
|
int currentluwidth=fm.width(it->second->value())+fm.width(" - ")+fm.width(it->second->upper_value());
|
|
if(currentluwidth>lowerupperwidth)
|
|
{
|
|
//widestlu = string2;
|
|
lowerupperwidth=currentluwidth;
|
|
}
|
|
}
|
|
|
|
//create the pixmap for the render item
|
|
QPixmap *pix = mVectorLayer->legendPixmap();
|
|
QString name;
|
|
if (mVectorLayer->propertiesDialog())
|
|
{
|
|
name = mVectorLayer->propertiesDialog()->displayName();
|
|
}
|
|
else
|
|
{
|
|
name = "";
|
|
}
|
|
//query the name and the maximum upper value to estimate the necessary width of the pixmap
|
|
int pixwidth = leftspace + rightspace + symbolwidth + 2 * wordspace + labelwidth + lowerupperwidth; //width of the pixmap with symbol and values
|
|
//consider 240 pixel for labels
|
|
int namewidth = leftspace + fm.width(name) + rightspace;
|
|
int width = (pixwidth > namewidth) ? pixwidth : namewidth;
|
|
pix->resize(width, topspace + 2 * fm.height() + bottomspace + (rowheight + rowspace) * numberofclassesspinbox->value());
|
|
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(), classificationComboBox->currentText());
|
|
|
|
QgsGraduatedSymRenderer *renderer = dynamic_cast < QgsGraduatedSymRenderer * >(mVectorLayer->renderer());
|
|
|
|
if (!renderer)
|
|
{
|
|
qWarning("Warning, typecast failed in QgsGraSyDialog::apply()");
|
|
return;
|
|
}
|
|
|
|
renderer->removeItems();
|
|
|
|
int offset = topspace + 2 * fm.height();
|
|
int rowincrement = rowheight + rowspace;
|
|
int i=0;
|
|
|
|
for (std::map<QString,QgsRangeRenderItem*>::iterator it=mEntries.begin();it!=mEntries.end();++it)
|
|
{
|
|
QgsSymbol* sy = new QgsSymbol();
|
|
|
|
sy->pen().setColor(it->second->getSymbol()->pen().color());
|
|
sy->pen().setStyle(it->second->getSymbol()->pen().style());
|
|
sy->pen().setWidth(it->second->getSymbol()->pen().width());
|
|
|
|
|
|
if (mVectorLayer->vectorType() != QGis::Line)
|
|
{
|
|
sy->brush().setColor(it->second->getSymbol()->brush().color());
|
|
}
|
|
|
|
if (mVectorLayer->vectorType() == QGis::Polygon)
|
|
{
|
|
sy->brush().setStyle(it->second->getSymbol()->brush().style());
|
|
}
|
|
else if (mVectorLayer->vectorType() == QGis::Point)
|
|
{
|
|
sy->brush().setStyle(Qt::SolidPattern);
|
|
}
|
|
QString lower_bound = it->second->value();
|
|
QString upper_bound = it->second->upper_value();
|
|
QString label = it->second->label();
|
|
|
|
//test, if lower_bound is numeric or not (making a subclass of QString would be the proper solution)
|
|
bool lbcontainsletter = false;
|
|
for (uint j = 0; j < lower_bound.length(); j++)
|
|
{
|
|
if (lower_bound.ref(j).isLetter())
|
|
{
|
|
lbcontainsletter = true;
|
|
}
|
|
}
|
|
|
|
//test, if upper_bound is numeric or not (making a subclass of QString would be the proper solution)
|
|
bool ubcontainsletter = false;
|
|
for (uint j = 0; j < upper_bound.length(); j++)
|
|
{
|
|
if (upper_bound.ref(j).isLetter())
|
|
{
|
|
ubcontainsletter = true;
|
|
}
|
|
}
|
|
if (lbcontainsletter == false && ubcontainsletter == false && lower_bound.length() > 0 && upper_bound.length() > 0) //only add the item if the value bounds do not contain letters and are not null strings
|
|
{
|
|
QgsRangeRenderItem *item = new QgsRangeRenderItem(sy, lower_bound, upper_bound, label);
|
|
renderer->addItem(item);
|
|
//add the symbol to the picture
|
|
|
|
QString legendstring = lower_bound + " - " + upper_bound;
|
|
p.setPen(sy->pen());
|
|
p.setBrush(sy->brush());
|
|
if (mVectorLayer->vectorType() == QGis::Polygon)
|
|
{
|
|
p.drawRect(leftspace, offset + rowincrement * i + (rowheight - symbolheight), symbolwidth, symbolheight); //implement different painting for lines and points here
|
|
}
|
|
else if (mVectorLayer->vectorType() == QGis::Line)
|
|
{
|
|
p.drawLine(leftspace, offset + rowincrement * i + (rowheight - symbolheight), leftspace + symbolwidth,
|
|
offset + rowincrement * i + rowheight);
|
|
}
|
|
else if (mVectorLayer->vectorType() == QGis::Point)
|
|
{
|
|
p.drawRect(leftspace + symbolwidth / 2, offset + (int) (rowincrement * (i + 0.5)), 5, 5);
|
|
}
|
|
p.setPen(Qt::black);
|
|
p.drawText(leftspace + symbolwidth + wordspace, offset + rowincrement * i + rowheight, legendstring);
|
|
p.drawText(pixwidth - labelwidth - rightspace, offset + rowincrement * i + rowheight, label);
|
|
}
|
|
++i;
|
|
}
|
|
|
|
std::map<QString,int>::iterator iter=mFieldMap.find(classificationComboBox->currentText());
|
|
if(iter!=mFieldMap.end())
|
|
{
|
|
renderer->setClassificationField(iter->second);
|
|
}
|
|
|
|
mVectorLayer->updateItemPixmap();
|
|
|
|
if (mVectorLayer->propertiesDialog())
|
|
{
|
|
mVectorLayer->propertiesDialog()->setRendererDirty(false);
|
|
}
|
|
mVectorLayer->triggerRepaint();
|
|
}
|
|
|
|
void QgsGraSyDialog::adjustClassification()
|
|
{
|
|
mClassBreakBox->clear();
|
|
QGis::VectorType m_type = mVectorLayer->vectorType();
|
|
QgsVectorDataProvider *provider = dynamic_cast<QgsVectorDataProvider *>(mVectorLayer->getDataProvider());
|
|
double minimum, maximum;
|
|
|
|
//delete all previous entries
|
|
for(std::map<QString, QgsRangeRenderItem*>::iterator it=mEntries.begin();it!=mEntries.end();++it)
|
|
{
|
|
delete it->second;
|
|
}
|
|
mEntries.clear();
|
|
|
|
//find out the number of the classification field
|
|
QString fieldstring = classificationComboBox->currentText();
|
|
|
|
if (fieldstring.isEmpty()) //don't do anything, it there is no classification field
|
|
{
|
|
show();
|
|
return;
|
|
}
|
|
|
|
std::map < QString, int >::iterator iter = mFieldMap.find(fieldstring);
|
|
int field = iter->second;
|
|
|
|
if (provider)
|
|
{
|
|
if (modeComboBox->currentText() == "Equal Interval")
|
|
{
|
|
minimum = provider->minValue(field).toDouble();
|
|
maximum = provider->maxValue(field).toDouble();
|
|
}
|
|
else //don't waste performance if mMode is QgsGraSyDialog::EMPTY
|
|
{
|
|
minimum = 0;
|
|
maximum = 0;
|
|
}
|
|
}
|
|
|
|
|
|
QString listboxtext;
|
|
for(int i=0;i<numberofclassesspinbox->value();++i)
|
|
{
|
|
QgsRangeRenderItem* rritem = new QgsRangeRenderItem();
|
|
QgsSymbol* symbol = new QgsSymbol();
|
|
rritem->setLabel(sydialog.label());
|
|
QPen pen;
|
|
QBrush brush;
|
|
|
|
if (modeComboBox->currentText() == "Empty")
|
|
{
|
|
listboxtext="Empty"+QString::number(i+1);
|
|
mClassBreakBox->insertItem(listboxtext);
|
|
}
|
|
else if(modeComboBox->currentText() == "Equal Interval")
|
|
{
|
|
double lower=minimum + (maximum - minimum) / numberofclassesspinbox->value() * i;
|
|
double upper=minimum + (maximum - minimum) / numberofclassesspinbox->value() * (i+1);
|
|
rritem->setValue(QString::number(lower,'f',3));
|
|
rritem->setUpperValue(QString::number(upper,'f',3));
|
|
listboxtext=QString::number(lower,'f',3)+" - " +QString::number(upper,'f',3);
|
|
mClassBreakBox->insertItem(listboxtext);
|
|
}
|
|
//set default symbology
|
|
|
|
//apply a nice color range from blue to red as default
|
|
if (i == 0)
|
|
{
|
|
if (m_type == QGis::Line)
|
|
{
|
|
pen.setColor(QColor(0, 0, 255));
|
|
}
|
|
else //point or polygon
|
|
{
|
|
brush.setColor(QColor(0, 0, 255));
|
|
pen.setColor(Qt::black);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_type == QGis::Line)
|
|
{
|
|
pen.setColor(QColor(255 / numberofclassesspinbox->value() * (i+1), 0, 255 - (255 / numberofclassesspinbox->value() * (i+1))));
|
|
}
|
|
else //point or polygon
|
|
{
|
|
brush.setColor(QColor(255 / numberofclassesspinbox->value() * (i+1), 0, 255 - (255 / numberofclassesspinbox->value() * (i+1))));
|
|
pen.setColor(Qt::black);
|
|
}
|
|
}
|
|
pen.setWidth(1);
|
|
brush.setStyle(Qt::SolidPattern);
|
|
symbol->setPen(pen);
|
|
symbol->setBrush(brush);
|
|
rritem->setSymbol(symbol);
|
|
|
|
mEntries.insert(std::make_pair(listboxtext,rritem));
|
|
}
|
|
mClassBreakBox->setCurrentItem(0);
|
|
}
|
|
|
|
void QgsGraSyDialog::changeCurrentValue()
|
|
{
|
|
QListBoxItem* item=mClassBreakBox->selectedItem();
|
|
QString value=item->text();
|
|
std::map<QString,QgsRangeRenderItem*>::iterator it=mEntries.find(value);
|
|
if(it!=mEntries.end())
|
|
{
|
|
QPen& pen=it->second->getSymbol()->pen();
|
|
QBrush& brush=it->second->getSymbol()->brush();
|
|
QColor fcolor(brush.color().red(),brush.color().green(),brush.color().blue());
|
|
QColor ocolor(pen.color().red(),pen.color().green(),pen.color().blue());
|
|
if(mVectorLayer->vectorType()!=QGis::Line)
|
|
{
|
|
sydialog.setFillColor(fcolor);
|
|
sydialog.setFillStyle(brush.style());
|
|
}
|
|
sydialog.setOutlineColor(ocolor);
|
|
sydialog.setOutlineStyle(pen.style());
|
|
sydialog.setOutlineWidth(pen.width());
|
|
sydialog.setLabel(it->second->label());
|
|
}
|
|
else
|
|
{
|
|
//no entry found
|
|
}
|
|
}
|
|
|
|
void QgsGraSyDialog::applySymbologyChanges()
|
|
{
|
|
QListBoxItem* item=mClassBreakBox->selectedItem();
|
|
QString value=item->text();
|
|
std::map<QString,QgsRangeRenderItem*>::iterator it=mEntries.find(value);
|
|
if(it!=mEntries.end())
|
|
{
|
|
QPen& pen=it->second->getSymbol()->pen();
|
|
QBrush& brush=it->second->getSymbol()->brush();
|
|
pen.setWidth(sydialog.getOutlineWidth());
|
|
pen.setColor(sydialog.getOutlineColor());
|
|
pen.setStyle(sydialog.getOutlineStyle());
|
|
brush.setColor(sydialog.getFillColor());
|
|
brush.setStyle(sydialog.getFillStyle());
|
|
it->second->setLabel(sydialog.label());
|
|
}
|
|
}
|
|
|
|
void QgsGraSyDialog::changeClass(QListBoxItem* item)
|
|
{
|
|
QString currenttext=item->text();
|
|
QgsRangeRenderItem* rritem=0;
|
|
std::map<QString,QgsRangeRenderItem*>::iterator iter=mEntries.find(currenttext);
|
|
if(iter!=mEntries.end())
|
|
{
|
|
rritem=iter->second;
|
|
}
|
|
QgsLUDialog dialog;
|
|
|
|
if(rritem)
|
|
{
|
|
dialog.setLowerValue(rritem->value());
|
|
dialog.setUpperValue(rritem->upper_value());
|
|
}
|
|
|
|
if(dialog.exec()==QDialog::Accepted)
|
|
{
|
|
if(rritem)
|
|
{
|
|
mEntries.erase(currenttext);
|
|
rritem->setValue(dialog.lowerValue());
|
|
rritem->setUpperValue(dialog.upperValue());
|
|
QString newclass=dialog.lowerValue()+"-"+dialog.upperValue();
|
|
mEntries.insert(std::make_pair(newclass,rritem));
|
|
int index=mClassBreakBox->index(item);
|
|
QObject::disconnect(mClassBreakBox, SIGNAL(selectionChanged()), this, SLOT(changeCurrentValue()));
|
|
mClassBreakBox->removeItem(index);
|
|
mClassBreakBox->insertItem(newclass,index);
|
|
mClassBreakBox->setSelected(index,true);
|
|
QObject::connect(mClassBreakBox, SIGNAL(selectionChanged()), this, SLOT(changeCurrentValue()));
|
|
}
|
|
}
|
|
}
|