QGIS/src/core/renderer/qgsuniquevaluerenderer.cpp
jef 43278d720b handling vector data geometry and attribute updates refactored
QgsVectorLayer:
  - move attribute part of editing to vector layer class and unify with geometry handling:
    * remove commitAttributeChanges(), addedFeatures(), deletedFeatureIds(), changedAttributes()
      and replace with changeAttributeValue(), deleteFeature(), addAttribute()
      and deleteAttribute()
    * add pendingFields(), pendingAttributeList(), pendingFeatureCount()
    * emit signals on start editing and commit, change of attribute values, adding/deleting of
      attributes and layer or feature removal (currently used in the attribute table)
  - new commitErrors() method to query errors from commitChanges()
  - replaced featuresInRectangle with select/getNextFeature combo
  - edit types added to support more input widgets and input constraints

QgsFeature:
  - remove update aware ctor
  - unify geometry handling in ctors

QgsVectorDataProvider:
  - add QVariant::Type to supportNativeTypes()

QgisApp:
  - add instance() method to query QgisApp object
  - replace code at various place to use it instead of passing the pointer
    arround or searching it in the widget tree.
  - move toggleEditing() code from the legend here

QgsAttributeTable/QgsAttributeTableDisplay:
  - move attribute table creation legend here
  - make attribute table dockable (from Tim)
  - most editing logic moved to QgsVectorLayer
  - adding/deleting attributes moved to QgsVectorLayerProperties

QgsIdentifyResults:
  - add support for attribute editing when it edit mode

QgsVectorLayerProperties:
  add a new tab to show attribute list:
    * start/stop editing
    * add/delete attributes
    * assign edit type to attributes (unique values, value map, ranges)

QgsAttributeDialog:
  add support for attribute edit types:
   * selection from unique value render classes (combobox)
   * selection from unique values of existing features (combobox or line edits with completion)
   * spinboxes for ranges

QgsPostgresProvider:
 - use read-only connection for cursors and read-write connection for updates
 - updated native types

QgsOgrProvider:
 - remove unused references to GEOS geometry factory
 - updated native types


git-svn-id: http://svn.osgeo.org/qgis/trunk@9092 c8812cc2-4d05-0410-92ff-de0c093fc19c
2008-08-20 12:15:14 +00:00

275 lines
7.8 KiB
C++

/***************************************************************************
qgsuniquevaluerenderer.cpp - description
-------------------
begin : July 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: qgsuniquevaluerenderer.cpp 5371 2006-04-25 01:52:13Z wonder $ */
#include "qgsuniquevaluerenderer.h"
#include "qgsfeature.h"
#include "qgsvectorlayer.h"
#include "qgssymbol.h"
#include "qgssymbologyutils.h"
#include "qgslogger.h"
#include <math.h>
#include <QDomNode>
#include <QPainter>
#include <QImage>
#include <vector>
QgsUniqueValueRenderer::QgsUniqueValueRenderer(QGis::VectorType type): mClassificationField(0)
{
mVectorType = type;
mSymbolAttributesDirty = false;
}
QgsUniqueValueRenderer::QgsUniqueValueRenderer(const QgsUniqueValueRenderer& other)
{
mVectorType = other.mVectorType;
mClassificationField = other.mClassificationField;
QMap<QString, QgsSymbol*> s = other.mSymbols;
for(QMap<QString, QgsSymbol*>::iterator it=s.begin(); it!=s.end(); ++it)
{
QgsSymbol* s = new QgsSymbol(* it.value());
insertValue(it.key(), s);
}
updateSymbolAttributes();
}
QgsUniqueValueRenderer& QgsUniqueValueRenderer::operator=(const QgsUniqueValueRenderer& other)
{
if(this != &other)
{
mVectorType = other.mVectorType;
mClassificationField = other.mClassificationField;
clearValues();
for(QMap<QString, QgsSymbol*>::iterator it=mSymbols.begin(); it!=mSymbols.end(); ++it)
{
QgsSymbol* s = new QgsSymbol(*it.value());
insertValue(it.key(), s);
}
updateSymbolAttributes();
}
return *this;
}
QgsUniqueValueRenderer::~QgsUniqueValueRenderer()
{
for(QMap<QString,QgsSymbol*>::iterator it=mSymbols.begin();it!=mSymbols.end();++it)
{
delete it.value();
}
}
const QList<QgsSymbol*> QgsUniqueValueRenderer::symbols() const
{
QList <QgsSymbol*> symbollist;
for(QMap<QString, QgsSymbol*>::const_iterator it = mSymbols.begin(); it!=mSymbols.end(); ++it)
{
symbollist.append(it.value());
}
return symbollist;
}
void QgsUniqueValueRenderer::insertValue(QString name, QgsSymbol* symbol)
{
mSymbols.insert(name, symbol);
mSymbolAttributesDirty=true;
}
void QgsUniqueValueRenderer::setClassificationField(int field)
{
mClassificationField=field;
}
int QgsUniqueValueRenderer::classificationField() const
{
return mClassificationField;
}
bool QgsUniqueValueRenderer::willRenderFeature(QgsFeature *f)
{
return (symbolForFeature(f) != 0);
}
void QgsUniqueValueRenderer::renderFeature(QPainter* p, QgsFeature& f,QImage* img, bool selected, double widthScale, double rasterScaleFactor)
{
QgsSymbol* symbol = symbolForFeature(&f);
if(!symbol) //no matching symbol
{
if ( img && mVectorType == QGis::Point )
{
img->fill(0);
}
else if ( mVectorType != QGis::Point )
{
p->setPen(Qt::NoPen);
p->setBrush(Qt::NoBrush);
}
return;
}
// Point
if ( img && mVectorType == QGis::Point )
{
double fieldScale = 1.0;
double rotation = 0.0;
if ( symbol->scaleClassificationField() >= 0)
{
//first find out the value for the scale classification attribute
const QgsAttributeMap& attrs = f.attributeMap();
fieldScale = sqrt(fabs(attrs[symbol->scaleClassificationField()].toDouble()));
QgsDebugMsg(QString("Feature has field scale factor %1").arg(fieldScale));
}
if ( symbol->rotationClassificationField() >= 0 )
{
const QgsAttributeMap& attrs = f.attributeMap();
rotation = attrs[symbol->rotationClassificationField()].toDouble();
QgsDebugMsg(QString("Feature has rotation factor %1").arg(rotation));
}
*img = symbol->getPointSymbolAsImage( widthScale, selected, mSelectionColor,
fieldScale, rotation, rasterScaleFactor);
}
// Line, polygon
else if ( mVectorType != QGis::Point )
{
if( !selected )
{
QPen pen=symbol->pen();
pen.setWidthF ( widthScale * pen.widthF() );
p->setPen(pen);
p->setBrush(symbol->brush());
}
else
{
QPen pen=symbol->pen();
pen.setWidthF ( widthScale * pen.widthF() );
pen.setColor(mSelectionColor);
QBrush brush=symbol->brush();
brush.setColor(mSelectionColor);
p->setPen(pen);
p->setBrush(brush);
}
}
}
QgsSymbol *QgsUniqueValueRenderer::symbolForFeature(const QgsFeature *f)
{
//first find out the value
const QgsAttributeMap& attrs = f->attributeMap();
QString value = attrs[mClassificationField].toString();
QMap<QString,QgsSymbol*>::iterator it=mSymbols.find(value);
if(it == mSymbols.end())
{
return 0;
}
else
{
return it.value();
}
}
void QgsUniqueValueRenderer::readXML(const QDomNode& rnode, QgsVectorLayer& vl)
{
mVectorType = vl.vectorType();
QDomNode classnode = rnode.namedItem("classificationfield");
int classificationfield = classnode.toElement().text().toInt();
this->setClassificationField(classificationfield);
QDomNode symbolnode = rnode.namedItem("symbol");
while (!symbolnode.isNull())
{
QgsSymbol* msy = new QgsSymbol(mVectorType);
msy->readXML ( symbolnode );
insertValue(msy->lowerValue(),msy);
symbolnode = symbolnode.nextSibling();
}
updateSymbolAttributes();
vl.setRenderer(this);
}
void QgsUniqueValueRenderer::clearValues()
{
for(QMap<QString,QgsSymbol*>::iterator it=mSymbols.begin();it!=mSymbols.end();++it)
{
delete it.value();
}
mSymbols.clear();
updateSymbolAttributes();
}
void QgsUniqueValueRenderer::updateSymbolAttributes()
{
mSymbolAttributesDirty = false;
mSymbolAttributes.clear();
QMap<QString, QgsSymbol*>::iterator it;
for (it = mSymbols.begin(); it != mSymbols.end(); ++it)
{
int rotationField = (*it)->rotationClassificationField();
if ( rotationField >= 0 && !(mSymbolAttributes.contains(rotationField)) )
{
mSymbolAttributes.append(rotationField);
}
int scaleField = (*it)->scaleClassificationField();
if ( scaleField >= 0 && !(mSymbolAttributes.contains(scaleField)) )
{
mSymbolAttributes.append(scaleField);
}
}
}
QString QgsUniqueValueRenderer::name() const
{
return "Unique Value";
}
QgsAttributeList QgsUniqueValueRenderer::classificationAttributes() const
{
QgsAttributeList list(mSymbolAttributes);
if ( ! list.contains(mClassificationField) )
{
list.append(mClassificationField);
}
return list;
}
bool QgsUniqueValueRenderer::writeXML( QDomNode & layer_node, QDomDocument & document ) const
{
bool returnval=true;
QDomElement uniquevalue=document.createElement("uniquevalue");
layer_node.appendChild(uniquevalue);
QDomElement classificationfield=document.createElement("classificationfield");
QDomText classificationfieldtxt=document.createTextNode(QString::number(mClassificationField));
classificationfield.appendChild(classificationfieldtxt);
uniquevalue.appendChild(classificationfield);
for(QMap<QString,QgsSymbol*>::const_iterator it=mSymbols.begin();it!=mSymbols.end();++it)
{
if(!(it.value()->writeXML(uniquevalue,document)))
{
returnval=false;
}
}
return returnval;
}
QgsRenderer* QgsUniqueValueRenderer::clone() const
{
QgsUniqueValueRenderer* r = new QgsUniqueValueRenderer(*this);
return r;
}