mirror of
https://github.com/qgis/QGIS.git
synced 2025-03-01 00:46:20 -05:00
- made some functions const-correct [1] - minor code beautifying via calls to indent and manual tweaking Notes: [0] Generalized endian() to QgsDataProvider since most child implementations were just copies of the same code. Made endian() virtual so that children are free to provide their own implementations. Also now use htonl() for endian() detection and conversion. However QgsVectorLayer still has separate endian() implementation. This functionality should probably be further generalized to a QGIS utility function suite since endian detection is used in multiple locations. Also now use specific enumerated typedef for endian-ness instead of magic integer numbers. [1] Although made great strides in making some members const-correct, there are still so very many member functions that could be const in all classes that aren't. git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@2548 c8812cc2-4d05-0410-92ff-de0c093fc19c
380 lines
13 KiB
C++
380 lines
13 KiB
C++
/***************************************************************************
|
|
qgsgramadialog.cpp - description
|
|
-------------------
|
|
begin : April 2004
|
|
copyright : (C) 2004 by Marco Hugentobler
|
|
email : marco.hugentobler@autoform.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 "qgsgramadialog.h"
|
|
#include "qgsgramaextensionwidget.h"
|
|
#include "qgsmarkersymbol.h"
|
|
#include "qgsvectorlayer.h"
|
|
#include "qgsvectordataprovider.h"
|
|
#include "qgsgraduatedmarenderer.h"
|
|
#include "qgsdlgvectorlayerproperties.h"
|
|
#include "qgslegenditem.h"
|
|
#include "qgssvgcache.h"
|
|
#include <qcombobox.h>
|
|
#include <qlayout.h>
|
|
#include <qpainter.h>
|
|
#include <qpushbutton.h>
|
|
#include <qspinbox.h>
|
|
|
|
QgsGraMaDialog::QgsGraMaDialog(QgsVectorLayer* layer): QgsGraMaDialogBase(), ext(0), mVectorLayer(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 > const & fields = provider->fields();
|
|
int fieldnumber = 0;
|
|
QString str;
|
|
|
|
for (std::vector < QgsField >::const_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
|
|
mClassificationComboBox->insertItem(str);
|
|
mFieldMap.insert(std::make_pair(str, fieldnumber));
|
|
}
|
|
fieldnumber++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
qWarning("Warning, data provider is null in QgsGraSyDialog::QgsGraSyDialog(...)");
|
|
return;
|
|
}
|
|
|
|
mModeComboBox->insertItem("Empty");
|
|
mModeComboBox->insertItem("Equal Interval");
|
|
|
|
//restore the correct settings
|
|
QgsGraduatedMaRenderer *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 < QgsGraduatedMaRenderer * >(layer->propertiesDialog()->getBufferRenderer());
|
|
}
|
|
else
|
|
{
|
|
renderer = dynamic_cast < QgsGraduatedMaRenderer * >(layer->renderer());
|
|
}
|
|
|
|
std::list < QgsRangeRenderItem * >list;
|
|
|
|
if (renderer)
|
|
{
|
|
list = renderer->items();
|
|
ext = new QgsGraMaExtensionWidget(this, renderer->classificationField(), QgsGraSyDialog::EMPTY, list.size(), mVectorLayer);
|
|
}
|
|
|
|
mClassificationComboBox->setCurrentItem(renderer->classificationField());
|
|
|
|
//set the right colors and texts to the widgets
|
|
int number = 0;
|
|
for (std::list < QgsRangeRenderItem * >::iterator it = list.begin(); it != list.end(); ++it)
|
|
{
|
|
((QLineEdit *) (ext->getWidget(0, number)))->setText((*it)->value());
|
|
((QLineEdit *) ext->getWidget(1, number))->setText((*it)->upper_value());
|
|
((QLineEdit *) ext->getWidget(2, number))->setText((*it)->label());
|
|
((QPushButton *) ext->getWidget(3, number))->setName(((QgsMarkerSymbol*)((*it)->getSymbol()))->picture());
|
|
((QLineEdit *) ext->getWidget(4, number))->setText(QString::number(((QgsMarkerSymbol*)((*it)->getSymbol()))->scaleFactor(),'f',2));
|
|
number++;
|
|
}
|
|
|
|
|
|
mNumberOfClassesSpinbox->setValue(list.size());
|
|
QgsGraMaDialogBaseLayout->addMultiCellWidget(ext, 5, 5, 0, 3);
|
|
ext->show();
|
|
|
|
//do the necessary signal/slot connections
|
|
QObject::connect(mNumberOfClassesSpinbox, SIGNAL(valueChanged(int)), this, SLOT(adjustNumberOfClasses()));
|
|
QObject::connect(mClassificationComboBox, SIGNAL(activated(int)), this, SLOT(adjustClassification()));
|
|
QObject::connect(mModeComboBox, SIGNAL(activated(int)), this, SLOT(adjustClassification()));
|
|
}
|
|
|
|
QgsGraMaDialog::QgsGraMaDialog()
|
|
{
|
|
#ifdef QGISDEBUG
|
|
qWarning("constructor QgsGraSyDialog");
|
|
#endif
|
|
}
|
|
|
|
QgsGraMaDialog::~QgsGraMaDialog()
|
|
{
|
|
if (ext)
|
|
{
|
|
ext->hide();
|
|
delete ext;
|
|
}
|
|
#ifdef QGISDEBUG
|
|
qWarning("destructor QgsGraSyDialog");
|
|
#endif
|
|
}
|
|
|
|
void QgsGraMaDialog::apply()
|
|
{
|
|
if (ext)
|
|
{
|
|
ext->adjustMarkers();
|
|
|
|
if (mClassificationComboBox->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 markerheight; //height of a marker (is different for every row)
|
|
int markerwidth; //width of the broadest marker
|
|
int lowerupperwidth; // widht of the broadest lower-upper pair
|
|
int rowspace = 5; //spaces between rows of symbols
|
|
int rowheight = fm.height(); //height of a text row
|
|
int classesheight; //height of the classes section
|
|
|
|
//find out the width of the widest label and the widest lower - upper pair
|
|
int labelwidth=0;
|
|
lowerupperwidth=0;
|
|
|
|
for (int i = 0; i < mNumberOfClassesSpinbox->value(); i++)
|
|
{
|
|
int currentlabelwidth=fm.width(((QLineEdit *) (ext->getWidget(2, i)))->text());
|
|
if(currentlabelwidth>labelwidth)
|
|
{
|
|
labelwidth=currentlabelwidth;
|
|
}
|
|
|
|
int currentluwidth=fm.width(((QLineEdit *) (ext->getWidget(0, i)))->text() + " - " + ((QLineEdit *) (ext->getWidget(1, i)))->text());
|
|
if(currentluwidth>lowerupperwidth)
|
|
{
|
|
lowerupperwidth=currentluwidth;
|
|
}
|
|
}
|
|
|
|
//find out the width of the broadest marker and the total height of the class section
|
|
markerwidth=0;
|
|
classesheight=rowspace*(mNumberOfClassesSpinbox->value()-1);
|
|
for (int i = 0; i < mNumberOfClassesSpinbox->value(); i++)
|
|
{
|
|
QPixmap p = QgsSVGCache::instance().
|
|
getPixmap(((QPushButton*)(ext->getWidget(3,i)))->name(),
|
|
((QLineEdit*)(ext->getWidget(4,i)))->text().toDouble());
|
|
int width = p.width();
|
|
if(width>markerwidth) {
|
|
markerwidth=width;
|
|
qWarning("markerwidth: "+QString::number(markerwidth));
|
|
}
|
|
int height = p.height();
|
|
height = (height>rowheight) ? height : rowheight;
|
|
qWarning("height: " + QString::number(height));
|
|
classesheight+=height;
|
|
}
|
|
|
|
//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 + markerwidth + 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 + classesheight);
|
|
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(), mClassificationComboBox->currentText());
|
|
|
|
QgsGraduatedMaRenderer *renderer = dynamic_cast < QgsGraduatedMaRenderer * >(mVectorLayer->renderer());
|
|
|
|
if (!renderer)
|
|
{
|
|
qWarning("Warning, typecast failed in QgsGraSyDialog::apply()");
|
|
return;
|
|
}
|
|
|
|
renderer->removeItems();
|
|
|
|
int offset = topspace + 2 * fm.height();
|
|
for (int i = 0; i < mNumberOfClassesSpinbox->value(); i++)
|
|
{
|
|
QgsMarkerSymbol* sy = new QgsMarkerSymbol();
|
|
sy->setPicture(((QPushButton*)(ext->getWidget(3,i)))->name());
|
|
qWarning("SVG file: " + QString::fromAscii(((QPushButton*)(ext->getWidget(3,i)))->name()));
|
|
sy->setScaleFactor(((QLineEdit*)(ext->getWidget(4,i)))->text().toDouble());
|
|
|
|
QString lower_bound = ((QLineEdit *) (ext->getWidget(0, i)))->text();
|
|
QString upper_bound = ((QLineEdit *) (ext->getWidget(1, i)))->text();
|
|
QString label = ((QLineEdit *) (ext->getWidget(2, i)))->text();
|
|
|
|
//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);
|
|
qWarning("lower_bound: " +lower_bound);
|
|
qWarning("upper_bound: " +upper_bound);
|
|
qWarning("label: " +label);
|
|
renderer->addItem(item);
|
|
|
|
//add the symbol to the picture
|
|
QString legendstring = lower_bound + " - " + upper_bound;
|
|
//todo: paint the picture
|
|
double scalefactor=((QLineEdit*)(ext->getWidget(4,i)))->text().
|
|
toDouble();
|
|
QPixmap pix = QgsSVGCache::instance().
|
|
getPixmap(((QPushButton*)(ext->getWidget(3,i)))->name(),
|
|
scalefactor);
|
|
int actrowheight=(int)(pix.height() * scalefactor);
|
|
actrowheight = (actrowheight > rowheight ?
|
|
actrowheight : rowheight);
|
|
p.drawPixmap(leftspace, offset, pix);
|
|
p.setPen(Qt::black);
|
|
p.drawText(leftspace+markerwidth + wordspace, offset + actrowheight, legendstring);
|
|
p.drawText(leftspace+markerwidth+2*wordspace+lowerupperwidth, offset + actrowheight, label);
|
|
offset+=(rowspace+actrowheight);
|
|
}
|
|
}
|
|
|
|
renderer->setClassificationField(ext->classfield());
|
|
|
|
mVectorLayer->updateItemPixmap();
|
|
|
|
if (mVectorLayer->propertiesDialog())
|
|
{
|
|
mVectorLayer->propertiesDialog()->setRendererDirty(false);
|
|
}
|
|
mVectorLayer->triggerRepaint();
|
|
|
|
}
|
|
else //number of classes is 0
|
|
{
|
|
std::cout << "warning, number of classes is zero" << std::endl << std::flush;
|
|
}
|
|
}
|
|
|
|
void QgsGraMaDialog::adjustNumberOfClasses()
|
|
{
|
|
//find out the number of the classification field
|
|
QString fieldstring = mClassificationComboBox->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(ext)
|
|
{
|
|
QgsGraMaDialogBaseLayout->remove(ext);
|
|
delete ext;
|
|
}
|
|
|
|
//create a new extension dialog
|
|
if (mModeComboBox->currentText() == "Empty")
|
|
{
|
|
ext = new QgsGraMaExtensionWidget(this, field, QgsGraSyDialog::EMPTY, mNumberOfClassesSpinbox->value(), mVectorLayer);
|
|
}
|
|
else if (mModeComboBox->currentText() == "Equal Interval")
|
|
{
|
|
ext = new QgsGraMaExtensionWidget(this, field, QgsGraSyDialog::EQUAL_INTERVAL, mNumberOfClassesSpinbox->value(), mVectorLayer);
|
|
}
|
|
|
|
if (mNumberOfClassesSpinbox->value() == 0)
|
|
{
|
|
ext = 0;
|
|
return;
|
|
}
|
|
|
|
QgsGraMaDialogBaseLayout->addMultiCellWidget(ext, 5, 5, 0, 3);
|
|
ext->show();
|
|
}
|
|
|
|
void QgsGraMaDialog::adjustClassification()
|
|
{
|
|
//find out the number of the classification field
|
|
QString fieldstring = mClassificationComboBox->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(ext)
|
|
{
|
|
if (mModeComboBox->currentText() == "Empty")
|
|
{
|
|
ext->setClassification(QgsGraSyDialog::EMPTY,field);
|
|
}
|
|
else if(mModeComboBox->currentText() == "Equal Interval")
|
|
{
|
|
ext->setClassification(QgsGraSyDialog::EQUAL_INTERVAL,field);
|
|
}
|
|
}
|
|
}
|