QGIS API Documentation  master-59fd5e0
src/core/composer/qgscomposerattributetable.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                          qgscomposerattributetable.cpp
00003                          -----------------------------
00004     begin                : April 2010
00005     copyright            : (C) 2010 by Marco Hugentobler
00006     email                : marco at hugis dot net
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include "qgscomposerattributetable.h"
00019 #include "qgscomposermap.h"
00020 #include "qgsmaplayerregistry.h"
00021 #include "qgsvectorlayer.h"
00022 
00023 QgsComposerAttributeTableCompare::QgsComposerAttributeTableCompare(): mCurrentSortColumn( 0 ), mAscending( true )
00024 {
00025 }
00026 
00027 
00028 bool QgsComposerAttributeTableCompare::operator()( const QgsAttributes& m1, const QgsAttributes& m2 )
00029 {
00030   QVariant v1 = m1[mCurrentSortColumn];
00031   QVariant v2 = m2[mCurrentSortColumn];
00032 
00033   bool less = false;
00034   if ( v1.type() == QVariant::String && v2.type() == QVariant::String )
00035   {
00036     less = v1.toString() < v2.toString();
00037   }
00038   else
00039   {
00040     less = v1.toDouble() < v2.toDouble();
00041   }
00042   return ( mAscending ? less : !less );
00043 }
00044 
00045 
00046 QgsComposerAttributeTable::QgsComposerAttributeTable( QgsComposition* composition )
00047     : QgsComposerTable( composition ), mVectorLayer( 0 ), mComposerMap( 0 ),
00048     mMaximumNumberOfFeatures( 5 ), mShowOnlyVisibleFeatures( true )
00049 {
00050   //set first vector layer from layer registry as default one
00051   QMap<QString, QgsMapLayer*> layerMap =  QgsMapLayerRegistry::instance()->mapLayers();
00052   QMap<QString, QgsMapLayer*>::const_iterator mapIt = layerMap.constBegin();
00053   for ( ; mapIt != layerMap.constEnd(); ++mapIt )
00054   {
00055     QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( mapIt.value() );
00056     if ( vl )
00057     {
00058       mVectorLayer = vl;
00059       break;
00060     }
00061   }
00062   connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( removeLayer( const QString& ) ) );
00063 }
00064 
00065 QgsComposerAttributeTable::~QgsComposerAttributeTable()
00066 {
00067 
00068 }
00069 
00070 void QgsComposerAttributeTable::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
00071 {
00072   if ( mComposerMap && mComposerMap->isDrawing() )
00073   {
00074     return;
00075   }
00076   QgsComposerTable::paint( painter, itemStyle, pWidget );
00077 }
00078 
00079 void QgsComposerAttributeTable::initializeAliasMap()
00080 {
00081   mFieldAliasMap.clear();
00082   if ( mVectorLayer )
00083   {
00084     const QgsFields& fields = mVectorLayer->pendingFields();
00085     for ( int idx = 0; idx < fields.count(); ++idx )
00086     {
00087       QString currentAlias = mVectorLayer->attributeAlias( idx );
00088       if ( !currentAlias.isEmpty() )
00089       {
00090         mFieldAliasMap.insert( idx, currentAlias );
00091       }
00092     }
00093   }
00094 }
00095 
00096 void QgsComposerAttributeTable::setVectorLayer( QgsVectorLayer* vl )
00097 {
00098   if ( vl != mVectorLayer )
00099   {
00100     mDisplayAttributes.clear();
00101     mVectorLayer = vl;
00102     initializeAliasMap();
00103   }
00104 }
00105 
00106 void QgsComposerAttributeTable::setComposerMap( const QgsComposerMap* map )
00107 {
00108   if ( mComposerMap )
00109   {
00110     QObject::disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( repaint() ) );
00111   }
00112   mComposerMap = map;
00113   if ( mComposerMap )
00114   {
00115     QObject::connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( repaint() ) );
00116   }
00117 }
00118 
00119 bool QgsComposerAttributeTable::getFeatureAttributes( QList<QgsAttributes>& attributes )
00120 {
00121   if ( !mVectorLayer )
00122   {
00123     return false;
00124   }
00125   attributes.clear();
00126 
00127   QgsRectangle selectionRect;
00128   if ( mComposerMap && mShowOnlyVisibleFeatures )
00129   {
00130     selectionRect = mComposerMap->extent();
00131     if ( mVectorLayer && mComposerMap->mapRenderer()
00132          && mComposerMap->mapRenderer()->hasCrsTransformEnabled() )
00133     {
00134       //transform back to layer CRS
00135       QgsCoordinateTransform coordTransform( mVectorLayer->crs(), mComposerMap->mapRenderer()->destinationCrs() );
00136       try
00137       {
00138         selectionRect = coordTransform.transformBoundingBox( selectionRect, QgsCoordinateTransform::ReverseTransform );
00139       }
00140       catch ( QgsCsException &cse )
00141       {
00142         Q_UNUSED( cse );
00143         return false;
00144       }
00145     }
00146   }
00147 
00148   QgsFeatureRequest req;
00149   if ( !selectionRect.isEmpty() )
00150   {
00151     req.setFilterRect( selectionRect );
00152   }
00153   req.setFlags( mShowOnlyVisibleFeatures ? QgsFeatureRequest::ExactIntersect : QgsFeatureRequest::NoGeometry );
00154   if ( mDisplayAttributes.size() > 0 )
00155     req.setSubsetOfAttributes( mDisplayAttributes.toList() );
00156 
00157   QgsFeature f;
00158   int counter = 0;
00159   QgsFeatureIterator fit = mVectorLayer->getFeatures( req );
00160   while ( fit.nextFeature( f ) && counter < mMaximumNumberOfFeatures )
00161   {
00162     attributes.push_back( f.attributes() );
00163     ++counter;
00164   }
00165 
00166   //sort the list, starting with the last attribute
00167   QgsComposerAttributeTableCompare c;
00168   for ( int i = mSortInformation.size() - 1; i >= 0; --i )
00169   {
00170     c.setSortColumn( mSortInformation.at( i ).first );
00171     c.setAscending( mSortInformation.at( i ).second );
00172     qStableSort( attributes.begin(), attributes.end(), c );
00173   }
00174   return true;
00175 }
00176 
00177 QMap<int, QString> QgsComposerAttributeTable::getHeaderLabels() const
00178 {
00179   QMap<int, QString> header;
00180   if ( mVectorLayer )
00181   {
00182     const QgsFields& vectorFields = mVectorLayer->pendingFields();
00183     for ( int idx = 0; idx < vectorFields.count(); ++idx )
00184     {
00185       if ( mDisplayAttributes.size() > 0 && !mDisplayAttributes.contains( idx ) )
00186       {
00187         continue;
00188       }
00189       header.insert( idx, attributeDisplayName( idx, vectorFields[idx].name() ) );
00190     }
00191   }
00192   return header;
00193 }
00194 
00195 QString QgsComposerAttributeTable::attributeDisplayName( int attributeIndex, const QString& name ) const
00196 {
00197   QMap<int, QString>::const_iterator it = mFieldAliasMap.find( attributeIndex );
00198   if ( it != mFieldAliasMap.constEnd() )
00199   {
00200     return it.value();
00201   }
00202   else
00203   {
00204     return name;
00205   }
00206 }
00207 
00208 void QgsComposerAttributeTable::removeLayer( QString layerId )
00209 {
00210   if ( mVectorLayer )
00211   {
00212     if ( layerId == mVectorLayer->id() )
00213     {
00214       mVectorLayer = 0;
00215     }
00216   }
00217 }
00218 
00219 void QgsComposerAttributeTable::setSceneRect( const QRectF& rectangle )
00220 {
00221   double titleHeight =  2 * mGridStrokeWidth + 2 * mLineTextDistance + fontAscentMillimeters( mHeaderFont );
00222   double attributeHeight = mGridStrokeWidth + 2 * mLineTextDistance + fontAscentMillimeters( mContentFont );
00223   if (( rectangle.height() - titleHeight ) > 0 )
00224   {
00225     mMaximumNumberOfFeatures = ( rectangle.height() - titleHeight ) / attributeHeight;
00226   }
00227   else
00228   {
00229     mMaximumNumberOfFeatures = 0;
00230   }
00231   QgsComposerItem::setSceneRect( rectangle );
00232   emit maximumNumberOfFeaturesChanged( mMaximumNumberOfFeatures );
00233 }
00234 
00235 bool QgsComposerAttributeTable::writeXML( QDomElement& elem, QDomDocument & doc ) const
00236 {
00237   QDomElement composerTableElem = doc.createElement( "ComposerAttributeTable" );
00238   composerTableElem.setAttribute( "showOnlyVisibleFeatures", mShowOnlyVisibleFeatures );
00239   composerTableElem.setAttribute( "maxFeatures", mMaximumNumberOfFeatures );
00240 
00241   if ( mComposerMap )
00242   {
00243     composerTableElem.setAttribute( "composerMap", mComposerMap->id() );
00244   }
00245   else
00246   {
00247     composerTableElem.setAttribute( "composerMap", -1 );
00248   }
00249   if ( mVectorLayer )
00250   {
00251     composerTableElem.setAttribute( "vectorLayer", mVectorLayer->id() );
00252   }
00253 
00254   //display attributes
00255   QDomElement displayAttributesElem = doc.createElement( "displayAttributes" );
00256   QSet<int>::const_iterator attIt = mDisplayAttributes.constBegin();
00257   for ( ; attIt != mDisplayAttributes.constEnd(); ++attIt )
00258   {
00259     QDomElement attributeIndexElem = doc.createElement( "attributeEntry" );
00260     attributeIndexElem.setAttribute( "index", *attIt );
00261     displayAttributesElem.appendChild( attributeIndexElem );
00262   }
00263   composerTableElem.appendChild( displayAttributesElem );
00264 
00265   //alias map
00266   QDomElement aliasMapElem = doc.createElement( "attributeAliasMap" );
00267   QMap<int, QString>::const_iterator aliasIt = mFieldAliasMap.constBegin();
00268   for ( ; aliasIt != mFieldAliasMap.constEnd(); ++aliasIt )
00269   {
00270     QDomElement mapEntryElem = doc.createElement( "aliasEntry" );
00271     mapEntryElem.setAttribute( "key", aliasIt.key() );
00272     mapEntryElem.setAttribute( "value", aliasIt.value() );
00273     aliasMapElem.appendChild( mapEntryElem );
00274   }
00275   composerTableElem.appendChild( aliasMapElem );
00276 
00277   //sort info
00278   QDomElement sortColumnsElem = doc.createElement( "sortColumns" );
00279   QList< QPair<int, bool> >::const_iterator sortIt = mSortInformation.constBegin();
00280   for ( ; sortIt != mSortInformation.constEnd(); ++sortIt )
00281   {
00282     QDomElement columnElem = doc.createElement( "column" );
00283     columnElem.setAttribute( "index", QString::number( sortIt->first ) );
00284     columnElem.setAttribute( "ascending", sortIt->second == true ? "true" : "false" );
00285     sortColumnsElem.appendChild( columnElem );
00286   }
00287   composerTableElem.appendChild( sortColumnsElem );
00288   elem.appendChild( composerTableElem );
00289   bool ok = tableWriteXML( composerTableElem, doc );
00290   return ok;
00291 }
00292 
00293 bool QgsComposerAttributeTable::readXML( const QDomElement& itemElem, const QDomDocument& doc )
00294 {
00295   if ( itemElem.isNull() )
00296   {
00297     return false;
00298   }
00299 
00300   mShowOnlyVisibleFeatures = itemElem.attribute( "showOnlyVisibleFeatures", "1" ).toInt();
00301 
00302   //composer map
00303   int composerMapId = itemElem.attribute( "composerMap", "-1" ).toInt();
00304   if ( composerMapId == -1 )
00305   {
00306     mComposerMap = 0;
00307   }
00308 
00309   if ( composition() )
00310   {
00311     mComposerMap = composition()->getComposerMapById( composerMapId );
00312   }
00313   else
00314   {
00315     mComposerMap = 0;
00316   }
00317 
00318   //vector layer
00319   QString layerId = itemElem.attribute( "vectorLayer", "not_existing" );
00320   if ( layerId == "not_existing" )
00321   {
00322     mVectorLayer = 0;
00323   }
00324   else
00325   {
00326     QgsMapLayer* ml = QgsMapLayerRegistry::instance()->mapLayer( layerId );
00327     if ( ml )
00328     {
00329       mVectorLayer = dynamic_cast<QgsVectorLayer*>( ml );
00330     }
00331   }
00332 
00333   //restore display attribute map
00334   mDisplayAttributes.clear();
00335   QDomNodeList displayAttributeList = itemElem.elementsByTagName( "displayAttributes" );
00336   if ( displayAttributeList.size() > 0 )
00337   {
00338     QDomElement displayAttributesElem =  displayAttributeList.at( 0 ).toElement();
00339     QDomNodeList attributeEntryList = displayAttributesElem.elementsByTagName( "attributeEntry" );
00340     for ( int i = 0; i < attributeEntryList.size(); ++i )
00341     {
00342       QDomElement attributeEntryElem = attributeEntryList.at( i ).toElement();
00343       int index = attributeEntryElem.attribute( "index", "-1" ).toInt();
00344       if ( index != -1 )
00345       {
00346         mDisplayAttributes.insert( index );
00347       }
00348     }
00349   }
00350 
00351   //restore alias map
00352   mFieldAliasMap.clear();
00353   QDomNodeList aliasMapNodeList = itemElem.elementsByTagName( "attributeAliasMap" );
00354   if ( aliasMapNodeList.size() > 0 )
00355   {
00356     QDomElement attributeAliasMapElem = aliasMapNodeList.at( 0 ).toElement();
00357     QDomNodeList aliasMepEntryList = attributeAliasMapElem.elementsByTagName( "aliasEntry" );
00358     for ( int i = 0; i < aliasMepEntryList.size(); ++i )
00359     {
00360       QDomElement aliasEntryElem = aliasMepEntryList.at( i ).toElement();
00361       int key = aliasEntryElem.attribute( "key", "-1" ).toInt();
00362       QString value = aliasEntryElem.attribute( "value", "" );
00363       mFieldAliasMap.insert( key, value );
00364     }
00365   }
00366 
00367   //restore sort columns
00368   mSortInformation.clear();
00369   QDomElement sortColumnsElem = itemElem.firstChildElement( "sortColumns" );
00370   if ( !sortColumnsElem.isNull() )
00371   {
00372     QDomNodeList columns = sortColumnsElem.elementsByTagName( "column" );
00373     for ( int i = 0; i < columns.size(); ++i )
00374     {
00375       QDomElement columnElem = columns.at( i ).toElement();
00376       int attribute = columnElem.attribute( "index" ).toInt();
00377       bool ascending = columnElem.attribute( "ascending" ) == "true" ? true : false;
00378       mSortInformation.push_back( qMakePair( attribute, ascending ) );
00379     }
00380   }
00381   bool success = tableReadXML( itemElem, doc );
00382 
00383   //must be done here because tableReadXML->setSceneRect changes mMaximumNumberOfFeatures
00384   mMaximumNumberOfFeatures = itemElem.attribute( "maxFeatures", "5" ).toInt();
00385 
00386   emit itemChanged();
00387   return success;
00388 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines