1
/***************************************************************************
2
qgsgrasydialog.cpp - description
5
copyright : (C) 2003 by Marco Hugentobler
6
email : mhugent@geo.unizh.ch
7
***************************************************************************/
9
/***************************************************************************
11
* This program is free software; you can redistribute it and/or modify *
12
* it under the terms of the GNU General Public License as published by *
13
* the Free Software Foundation; either version 2 of the License, or *
14
* (at your option) any later version. *
16
***************************************************************************/
17
/* $Id: qgsgrasydialog.cpp,v 1.46.2.1 2005/08/31 03:45:17 telwertowski Exp $ */
20
#include "qgsgrasydialog.h"
22
#include "qpushbutton.h"
23
#include <qcombobox.h>
25
#include "qgssymbologyutils.h"
26
#include "qgsrangerenderitem.h"
27
#include "qlineedit.h"
28
#include "qgsludialog.h"
29
#include "qgsgraduatedsymrenderer.h"
30
#include "qgsvectorlayer.h"
31
#include "qgslegenditem.h"
32
#include "qgsvectordataprovider.h"
34
#include "qscrollview.h"
36
#include <qwidgetstack.h>
38
QgsGraSyDialog::QgsGraSyDialog(QgsVectorLayer * layer):QgsGraSyDialogBase(), mVectorLayer(layer), sydialog(layer)
43
qWarning("constructor QgsGraSyDialog");
46
setOrientation(Qt::Vertical);
47
setSizeGripEnabled(true);
49
//find out the numerical fields of mVectorLayer
50
QgsVectorDataProvider *provider;
51
if (provider = dynamic_cast<QgsVectorDataProvider *>(mVectorLayer->getDataProvider()))
53
std::vector < QgsField > const & fields = provider->fields();
57
for (std::vector < QgsField >::const_iterator it = fields.begin();
61
QString type = (*it).type();
62
if (type != "String" && type != "varchar" && type != "geometry")
65
str = str.left(1).upper() + str.right(str.length() - 1); //make the first letter uppercase
66
classificationComboBox->insertItem(str);
67
mFieldMap.insert(std::make_pair(str, fieldnumber));
74
qWarning("Warning, data provider is null in QgsGraSyDialog::QgsGraSyDialog(...)");
78
modeComboBox->insertItem("Empty");
79
modeComboBox->insertItem("Equal Interval");
81
//restore the correct settings
82
QgsGraduatedSymRenderer *renderer;
84
//initial settings, use the buffer of the propertiesDialog if possible. If this is not possible, use the renderer of the vectorlayer directly
85
if (mVectorLayer->propertiesDialog())
87
renderer = dynamic_cast < QgsGraduatedSymRenderer * >(layer->propertiesDialog()->getBufferRenderer());
91
renderer = dynamic_cast < QgsGraduatedSymRenderer * >(layer->renderer());
97
std::list < QgsRangeRenderItem * >list = renderer->items();
99
//display the classification field
100
QString classfield="";
101
for(std::map<QString,int>::iterator it=mFieldMap.begin();it!=mFieldMap.end();++it)
103
if(it->second==renderer->classificationField())
105
classfield=it->first;
109
classificationComboBox->setCurrentText(classfield);
111
QGis::VectorType m_type = mVectorLayer->vectorType();
112
numberofclassesspinbox->setValue(list.size());
113
//fill the items of the renderer into mValues
114
for(std::list<QgsRangeRenderItem*>::iterator it=list.begin();it!=list.end();++it)
116
QgsRangeRenderItem* item=(*it);
117
QString classbreak=item->value()+" - "+item->upper_value();
118
QgsSymbol* sym=new QgsSymbol();
119
QgsRangeRenderItem* rritem=new QgsRangeRenderItem(sym,item->value(),item->upper_value(),item->label());
120
sym->setPen(item->getSymbol()->pen());
121
sym->setBrush(item->getSymbol()->brush());
122
sym->setNamedPointSymbol(item->getSymbol()->pointSymbolName());
123
sym->setPointSize(item->getSymbol()->pointSize());
124
mEntries.insert(std::make_pair(classbreak,rritem));
125
mClassBreakBox->insertItem(classbreak);
130
//do the necessary signal/slot connections
131
QObject::connect(numberofclassesspinbox, SIGNAL(valueChanged(int)), this, SLOT(adjustClassification()));
132
QObject::connect(classificationComboBox, SIGNAL(activated(int)), this, SLOT(adjustClassification()));
133
QObject::connect(modeComboBox, SIGNAL(activated(int)), this, SLOT(adjustClassification()));
134
QObject::connect(mClassBreakBox, SIGNAL(selectionChanged()), this, SLOT(changeCurrentValue()));
135
QObject::connect(&sydialog, SIGNAL(settingsChanged()), this, SLOT(applySymbologyChanges()));
136
QObject::connect(mClassBreakBox, SIGNAL(doubleClicked(QListBoxItem*)), this, SLOT(changeClass(QListBoxItem*)));
138
mSymbolWidgetStack->addWidget(&sydialog);
139
mSymbolWidgetStack->raiseWidget(&sydialog);
141
mClassBreakBox->setCurrentItem(0);
144
QgsGraSyDialog::QgsGraSyDialog(): QgsGraSyDialogBase(), mVectorLayer(0), sydialog(0)
147
qWarning("constructor QgsGraSyDialog");
151
QgsGraSyDialog::~QgsGraSyDialog()
154
qWarning("destructor QgsGraSyDialog");
158
void QgsGraSyDialog::adjustNumberOfClasses()
160
//find out the number of the classification field
161
QString fieldstring = classificationComboBox->currentText();
163
if (fieldstring.isEmpty()) //don't do anything, it there is no classification field
169
std::map < QString, int >::iterator iter = mFieldMap.find(fieldstring);
170
int field = iter->second;
173
void QgsGraSyDialog::apply()
175
if (classificationComboBox->currentText().isEmpty()) //don't do anything, it there is no classification field
180
//font tor the legend text
181
QFont f("arial", 10, QFont::Normal);
187
int leftspace = 10; //space between left side of the pixmap and the text/graphics
188
int rightspace = 5; //space between text/graphics and right side of the pixmap
189
int wordspace = 5; //space between graphics/word
190
int symbolheight = 15; //height of an area where a symbol is painted
191
int symbolwidth = 15; //width of an area where a symbol is painted
192
int lowerupperwidth; //widht of the broadest lower-upper pair
193
int rowspace = 5; //spaces between rows of symbols
194
int rowheight = (fm.height() > symbolheight) ? fm.height() : symbolheight; //height of a row in the symbology part
196
//find out the width of the widest label and of the broadest lower-upper pair
200
for(std::map<QString,QgsRangeRenderItem*>::iterator it=mEntries.begin();it!=mEntries.end();++it)
202
int currentlabelwidth=fm.width(it->second->label());
203
if(currentlabelwidth>labelwidth)
205
labelwidth=currentlabelwidth;
207
int currentluwidth=fm.width(it->second->value())+fm.width(" - ")+fm.width(it->second->upper_value());
208
if(currentluwidth>lowerupperwidth)
210
//widestlu = string2;
211
lowerupperwidth=currentluwidth;
215
//create the pixmap for the render item
216
QPixmap *pix = mVectorLayer->legendPixmap();
218
if (mVectorLayer->propertiesDialog())
220
name = mVectorLayer->propertiesDialog()->displayName();
226
//query the name and the maximum upper value to estimate the necessary width of the pixmap
227
int pixwidth = leftspace + rightspace + symbolwidth + 2 * wordspace + labelwidth + lowerupperwidth; //width of the pixmap with symbol and values
228
//consider 240 pixel for labels
229
int namewidth = leftspace + fm.width(name) + rightspace;
230
int width = (pixwidth > namewidth) ? pixwidth : namewidth;
231
pix->resize(width, topspace + 2 * fm.height() + bottomspace + (rowheight + rowspace) * numberofclassesspinbox->value());
235
//draw the layer name and the name of the classification field into the pixmap
236
p.drawText(leftspace, topspace + fm.height(), name);
237
p.drawText(leftspace, topspace + 2 * fm.height(), classificationComboBox->currentText());
239
QgsGraduatedSymRenderer *renderer = dynamic_cast < QgsGraduatedSymRenderer * >(mVectorLayer->renderer());
243
qWarning("Warning, typecast failed in QgsGraSyDialog::apply()");
247
renderer->removeItems();
249
int offset = topspace + 2 * fm.height();
250
int rowincrement = rowheight + rowspace;
253
for (int item=0;item<mClassBreakBox->count();++item)
255
QString classbreak=mClassBreakBox->text(item);
256
std::map<QString,QgsRangeRenderItem*>::iterator it=mEntries.find(classbreak);
257
if(it==mEntries.end())
262
QgsSymbol* sy = new QgsSymbol();
264
sy->setColor(it->second->getSymbol()->pen().color());
265
sy->setLineStyle(it->second->getSymbol()->pen().style());
266
sy->setLineWidth(it->second->getSymbol()->pen().width());
268
if (mVectorLayer->vectorType() == QGis::Point)
270
sy->setNamedPointSymbol(it->second->getSymbol()->pointSymbolName());
271
sy->setPointSize(it->second->getSymbol()->pointSize());
275
if (mVectorLayer->vectorType() != QGis::Line)
277
sy->setFillColor(it->second->getSymbol()->brush().color());
278
sy->setFillStyle(it->second->getSymbol()->brush().style());
281
QString lower_bound = it->second->value();
282
QString upper_bound = it->second->upper_value();
283
QString label = it->second->label();
285
//test, if lower_bound is numeric or not (making a subclass of QString would be the proper solution)
286
bool lbcontainsletter = false;
287
for (uint j = 0; j < lower_bound.length(); j++)
289
if (lower_bound.ref(j).isLetter())
291
lbcontainsletter = true;
295
//test, if upper_bound is numeric or not (making a subclass of QString would be the proper solution)
296
bool ubcontainsletter = false;
297
for (uint j = 0; j < upper_bound.length(); j++)
299
if (upper_bound.ref(j).isLetter())
301
ubcontainsletter = true;
304
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
306
QgsRangeRenderItem *item = new QgsRangeRenderItem(sy, lower_bound, upper_bound, label);
307
renderer->addItem(item);
308
//add the symbol to the picture
310
QString legendstring = lower_bound + " - " + upper_bound;
312
p.setBrush(sy->brush());
313
if (mVectorLayer->vectorType() == QGis::Polygon)
315
p.drawRect(leftspace, offset + rowincrement * i + (rowheight - symbolheight), symbolwidth, symbolheight); //implement different painting for lines and points here
317
else if (mVectorLayer->vectorType() == QGis::Line)
319
p.drawLine(leftspace, offset + rowincrement * i + (rowheight - symbolheight), leftspace + symbolwidth,
320
offset + rowincrement * i + rowheight);
322
else if (mVectorLayer->vectorType() == QGis::Point)
324
//p.drawRect(leftspace + symbolwidth / 2, offset + (int) (rowincrement * (i + 0.5)), 5, 5);
325
QPixmap pm = sy->getPointSymbolAsPixmap();
326
p.drawPixmap ( (int) (leftspace+symbolwidth/2-pm.width()/2), (int) (offset+rowincrement*(i+0.5)-pm.height()/2), pm );
329
p.drawText(leftspace + symbolwidth + wordspace, offset + rowincrement * i + rowheight, legendstring);
330
p.drawText(pixwidth - labelwidth - rightspace, offset + rowincrement * i + rowheight, label);
335
std::map<QString,int>::iterator iter=mFieldMap.find(classificationComboBox->currentText());
336
if(iter!=mFieldMap.end())
338
renderer->setClassificationField(iter->second);
341
mVectorLayer->updateItemPixmap();
343
if (mVectorLayer->propertiesDialog())
345
mVectorLayer->propertiesDialog()->setRendererDirty(false);
347
mVectorLayer->triggerRepaint();
350
void QgsGraSyDialog::adjustClassification()
352
mClassBreakBox->clear();
353
QGis::VectorType m_type = mVectorLayer->vectorType();
354
QgsVectorDataProvider *provider = dynamic_cast<QgsVectorDataProvider *>(mVectorLayer->getDataProvider());
355
double minimum, maximum;
357
//delete all previous entries
358
for(std::map<QString, QgsRangeRenderItem*>::iterator it=mEntries.begin();it!=mEntries.end();++it)
364
//find out the number of the classification field
365
QString fieldstring = classificationComboBox->currentText();
367
if (fieldstring.isEmpty()) //don't do anything, it there is no classification field
373
std::map < QString, int >::iterator iter = mFieldMap.find(fieldstring);
374
int field = iter->second;
378
if (modeComboBox->currentText() == "Equal Interval")
380
minimum = provider->minValue(field).toDouble();
381
maximum = provider->maxValue(field).toDouble();
383
else //don't waste performance if mMode is QgsGraSyDialog::EMPTY
392
for(int i=0;i<numberofclassesspinbox->value();++i)
394
QgsRangeRenderItem* rritem = new QgsRangeRenderItem();
395
QgsSymbol* symbol = new QgsSymbol();
396
rritem->setLabel("");
400
if (modeComboBox->currentText() == "Empty")
402
listboxtext="Empty"+QString::number(i+1);
403
mClassBreakBox->insertItem(listboxtext);
405
else if(modeComboBox->currentText() == "Equal Interval")
407
double lower=minimum + (maximum - minimum) / numberofclassesspinbox->value() * i;
408
double upper=minimum + (maximum - minimum) / numberofclassesspinbox->value() * (i+1);
409
if(i==0)//make sure all feature attributes are between minimum and maximum value (round off problem)
413
if(i==numberofclassesspinbox->value()-1)
417
rritem->setValue(QString::number(lower,'f',3));
418
rritem->setUpperValue(QString::number(upper,'f',3));
419
listboxtext=QString::number(lower,'f',3)+" - " +QString::number(upper,'f',3);
420
mClassBreakBox->insertItem(listboxtext);
422
//set default symbology
424
//apply a nice color range from blue to red as default
427
if (m_type == QGis::Line)
429
pen.setColor(QColor(0, 0, 255));
431
else //point or polygon
433
brush.setColor(QColor(0, 0, 255));
434
pen.setColor(Qt::black);
439
if (m_type == QGis::Line)
441
pen.setColor(QColor(255 / numberofclassesspinbox->value() * (i+1), 0, 255 - (255 / numberofclassesspinbox->value() * (i+1))));
443
else //point or polygon
445
brush.setColor(QColor(255 / numberofclassesspinbox->value() * (i+1), 0, 255 - (255 / numberofclassesspinbox->value() * (i+1))));
446
pen.setColor(Qt::black);
450
brush.setStyle(Qt::SolidPattern);
452
symbol->setBrush(brush);
453
rritem->setSymbol(symbol);
455
mEntries.insert(std::make_pair(listboxtext,rritem));
457
mClassBreakBox->setCurrentItem(0);
460
void QgsGraSyDialog::changeCurrentValue()
462
sydialog.blockSignals(true);//block signals to prevent sydialog from changing the current QgsRenderItem
463
QListBoxItem* item=mClassBreakBox->selectedItem();
466
QString value=item->text();
467
std::map<QString,QgsRangeRenderItem*>::iterator it=mEntries.find(value);
468
if(it!=mEntries.end())
470
sydialog.set(it->second->getSymbol() );
471
sydialog.setLabel(it->second->label());
474
sydialog.blockSignals(false);
477
void QgsGraSyDialog::applySymbologyChanges()
479
QListBoxItem* item=mClassBreakBox->selectedItem();
482
QString value=item->text();
483
std::map<QString,QgsRangeRenderItem*>::iterator it=mEntries.find(value);
484
if(it!=mEntries.end())
486
sydialog.apply( it->second->getSymbol() );
487
it->second->setLabel(sydialog.label());
492
void QgsGraSyDialog::changeClass(QListBoxItem* item)
494
QString currenttext=item->text();
495
QgsRangeRenderItem* rritem=0;
496
std::map<QString,QgsRangeRenderItem*>::iterator iter=mEntries.find(currenttext);
497
if(iter!=mEntries.end())
501
QgsLUDialog dialog(this);
505
dialog.setLowerValue(rritem->value());
506
dialog.setUpperValue(rritem->upper_value());
509
if(dialog.exec()==QDialog::Accepted)
513
mEntries.erase(currenttext);
514
rritem->setValue(dialog.lowerValue());
515
rritem->setUpperValue(dialog.upperValue());
516
QString newclass=dialog.lowerValue()+"-"+dialog.upperValue();
517
mEntries.insert(std::make_pair(newclass,rritem));
518
int index=mClassBreakBox->index(item);
519
QObject::disconnect(mClassBreakBox, SIGNAL(selectionChanged()), this, SLOT(changeCurrentValue()));
520
mClassBreakBox->removeItem(index);
521
mClassBreakBox->insertItem(newclass,index);
522
mClassBreakBox->setSelected(index,true);
523
QObject::connect(mClassBreakBox, SIGNAL(selectionChanged()), this, SLOT(changeCurrentValue()));