void QgsComposerAttributeTableV2::atlasLayerChanged( QgsVectorLayer *layer )
{
  if ( mSource != QgsComposerAttributeTableV2::AtlasFeature || layer == mCurrentAtlasLayer )
  {
    //nothing to do
    return;
  }

  //atlas feature mode, atlas layer changed, so we need to reset columns
  if ( mCurrentAtlasLayer )
  {
    //disconnect from previous layer
    disconnect( mCurrentAtlasLayer, SIGNAL( layerModified() ), this, SLOT( refreshAttributes() ) );
  }

  mCurrentAtlasLayer = layer;

  //rebuild column list to match all columns from layer
  resetColumns();
  refreshAttributes();

  //listen for modifications to layer and refresh table when they occur
  connect( layer, SIGNAL( layerModified() ), this, SLOT( refreshAttributes() ) );
}
void QgsComposerAttributeTable::setDisplayAttributes( const QSet<int>& attr, bool refresh )
{
  if ( !mVectorLayer )
  {
    return;
  }

  //rebuild columns list, taking only attributes with index in supplied QSet
  qDeleteAll( mColumns );
  mColumns.clear();

  const QgsFields& fields = mVectorLayer->fields();

  if ( !attr.empty() )
  {
    QSet<int>::const_iterator attIt = attr.constBegin();
    for ( ; attIt != attr.constEnd(); ++attIt )
    {
      int attrIdx = ( *attIt );
      if ( !fields.exists( attrIdx ) )
      {
        continue;
      }
      QString currentAlias = mVectorLayer->attributeDisplayName( attrIdx );
      QgsComposerTableColumn* col = new QgsComposerTableColumn;
      col->setAttribute( fields[attrIdx].name() );
      col->setHeading( currentAlias );
      mColumns.append( col );
    }
  }
  else
  {
    //resetting, so add all attributes to columns
    for ( int idx = 0; idx < fields.count(); ++idx )
    {
      QString currentAlias = mVectorLayer->attributeDisplayName( idx );
      QgsComposerTableColumn* col = new QgsComposerTableColumn;
      col->setAttribute( fields[idx].name() );
      col->setHeading( currentAlias );
      mColumns.append( col );
    }
  }

  if ( refresh )
  {
    refreshAttributes();
  }
}
QgsComposerAttributeTableV2::QgsComposerAttributeTableV2( QgsComposition *composition, bool createUndoCommands )
  : QgsComposerTableV2( composition, createUndoCommands )
  , mSource( LayerAttributes )
  , mCurrentAtlasLayer( nullptr )
  , mComposerMap( nullptr )
  , mMaximumNumberOfFeatures( 30 )
  , mShowUniqueRowsOnly( false )
  , mShowOnlyVisibleFeatures( false )
  , mFilterToAtlasIntersection( false )
  , mFilterFeatures( false )
  , mFeatureFilter( QLatin1String( "" ) )
{
  //set first vector layer from layer registry as default one
  QMap<QString, QgsMapLayer *> layerMap =  mComposition->project()->mapLayers();
  QMap<QString, QgsMapLayer *>::const_iterator mapIt = layerMap.constBegin();
  for ( ; mapIt != layerMap.constEnd(); ++mapIt )
  {
    QgsVectorLayer *vl = dynamic_cast<QgsVectorLayer *>( mapIt.value() );
    if ( vl )
    {
      mVectorLayer.setLayer( vl );
      break;
    }
  }
  if ( mVectorLayer )
  {
    resetColumns();
    //listen for modifications to layer and refresh table when they occur
    connect( mVectorLayer.get(), &QgsVectorLayer::layerModified, this, &QgsComposerTableV2::refreshAttributes );
  }

  if ( mComposition )
  {
    connect( mComposition->project(), static_cast < void ( QgsProject::* )( const QString & ) >( &QgsProject::layerWillBeRemoved ), this, &QgsComposerAttributeTableV2::removeLayer );

    //refresh table attributes when composition is refreshed
    connect( mComposition, &QgsComposition::refreshItemsTriggered, this, &QgsComposerTableV2::refreshAttributes );

    //connect to atlas feature changes to update table rows
    connect( &mComposition->atlasComposition(), &QgsAtlasComposition::featureChanged, this, &QgsComposerTableV2::refreshAttributes );

    //atlas coverage layer change = regenerate columns
    connect( &mComposition->atlasComposition(), &QgsAtlasComposition::coverageLayerChanged, this, &QgsComposerAttributeTableV2::atlasLayerChanged );
  }
  refreshAttributes();
}
示例#4
0
bool SproutDevice::changeMode(std::string value)
{
	bool success = false;
	std::string result;

	if( value.compare("AutoDetect") == 0 )
	{
		//result = serialController->queryDevice("OPMODE?", rs232QuerySleep_ms);
		//string::size_type equalPos = result.find_first_of("=");
		//std::string newMode = result.substr(equalPos + 1);

		////Convert to expected capitalization of attribute name
		//std::transform(newMode.begin(), newMode.end(), newMode.begin(), ::tolower);
		//std::string::iterator stopIter = newMode.begin();
		//stopIter++;
		//std::transform(newMode.begin(), stopIter, newMode.begin(), ::toupper);
		//
		////if(newMode.at(newMode.size() - 1) == '\b')
		//newMode = newMode.substr(0, newMode.size() - 1);



		//for(unsigned i = 0; i < newMode.size(); i++)
		//{
		//	std::cout << "{" << (char)newMode.at(i) << "}" << std::endl;
		//}
		//std::cout << "Equal? " << ((newMode.compare("Off")==0) ? "Yes" : "No") << std::endl;

		success = true;
		refreshAttributes();
//		success = setAttribute("Mode", getMode());
	}
	else
	{
		result = serialController->queryDevice("OPMODE=" + value, rs232QuerySleep_ms);
		string::size_type zeroPos = result.find_first_of("0");	//sprout returns 0 on success
		string::size_type twoPos = result.find_first_of("2");	//and 2 on failure
//		cout << "mode change response: " << result << std::endl;
		success = (zeroPos != std::string::npos && twoPos == std::string::npos);
	}

	return success;
}
void QgsComposerAttributeTable::setSceneRect( const QRectF& rectangle )
{
  double titleHeight =  2 * mGridStrokeWidth + 2 * mLineTextDistance + fontAscentMillimeters( mHeaderFont );
  double attributeHeight = mGridStrokeWidth + 2 * mLineTextDistance + fontAscentMillimeters( mContentFont );
  if (( rectangle.height() - titleHeight ) > 0 )
  {
    mMaximumNumberOfFeatures = ( rectangle.height() - titleHeight ) / attributeHeight;
  }
  else
  {
    mMaximumNumberOfFeatures = 0;
  }
  QgsComposerItem::setSceneRect( rectangle );

  //refresh table attributes, since number of features has likely changed
  refreshAttributes();

  emit maximumNumberOfFeaturesChanged( mMaximumNumberOfFeatures );
}
void QgsComposerAttributeTableV2::setComposerMap( const QgsComposerMap *map )
{
  if ( map == mComposerMap )
  {
    //no change
    return;
  }

  if ( mComposerMap )
  {
    //disconnect from previous map
    disconnect( mComposerMap, &QgsComposerMap::extentChanged, this, &QgsComposerTableV2::refreshAttributes );
  }
  mComposerMap = map;
  if ( mComposerMap )
  {
    //listen out for extent changes in linked map
    connect( mComposerMap, &QgsComposerMap::extentChanged, this, &QgsComposerTableV2::refreshAttributes );
  }
  refreshAttributes();
  emit changed();
}
QgsComposerAttributeTable::QgsComposerAttributeTable( QgsComposition* composition )
    : QgsComposerTable( composition )
    , mVectorLayer( nullptr )
    , mComposerMap( nullptr )
    , mMaximumNumberOfFeatures( 5 )
    , mShowOnlyVisibleFeatures( false )
    , mFilterFeatures( false )
    , mFeatureFilter( "" )
{
  //set first vector layer from layer registry as default one
  QMap<QString, QgsMapLayer*> layerMap =  QgsMapLayerRegistry::instance()->mapLayers();
  QMap<QString, QgsMapLayer*>::const_iterator mapIt = layerMap.constBegin();
  for ( ; mapIt != layerMap.constEnd(); ++mapIt )
  {
    QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( mapIt.value() );
    if ( vl )
    {
      mVectorLayer = vl;
      break;
    }
  }
  if ( mVectorLayer )
  {
    resetColumns();
  }
  connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( removeLayer( const QString& ) ) );

  if ( mComposition )
  {
    //refresh table attributes when composition is refreshed
    connect( mComposition, SIGNAL( refreshItemsTriggered() ), this, SLOT( refreshAttributes() ) );

    //connect to atlas feature changes to update table rows
    connect( &mComposition->atlasComposition(), SIGNAL( featureChanged( QgsFeature* ) ), this, SLOT( refreshAttributes() ) );
  }
}
bool QgsComposerAttributeTable::readXML( const QDomElement& itemElem, const QDomDocument& doc )
{
  if ( itemElem.isNull() )
  {
    return false;
  }

  mShowOnlyVisibleFeatures = itemElem.attribute( "showOnlyVisibleFeatures", "1" ).toInt();
  mFilterFeatures = itemElem.attribute( "filterFeatures", "false" ) == "true" ? true : false;
  mFeatureFilter = itemElem.attribute( "featureFilter", "" );

  //composer map
  int composerMapId = itemElem.attribute( "composerMap", "-1" ).toInt();
  if ( composerMapId == -1 )
  {
    mComposerMap = 0;
  }

  if ( composition() )
  {
    mComposerMap = composition()->getComposerMapById( composerMapId );
  }
  else
  {
    mComposerMap = 0;
  }

  if ( mComposerMap )
  {
    //if we have found a valid map item, listen out to extent changes on it and refresh the table
    QObject::connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( refreshAttributes() ) );
  }

  //vector layer
  QString layerId = itemElem.attribute( "vectorLayer", "not_existing" );
  if ( layerId == "not_existing" )
  {
    mVectorLayer = 0;
  }
  else
  {
    QgsMapLayer* ml = QgsMapLayerRegistry::instance()->mapLayer( layerId );
    if ( ml )
    {
      mVectorLayer = dynamic_cast<QgsVectorLayer*>( ml );
      if ( mVectorLayer )
      {
        //if we have found a valid vector layer, listen for modifications on it and refresh the table
        QObject::connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( refreshAttributes() ) );
      }
    }
  }

  //restore display attribute map
  mDisplayAttributes.clear();
  QDomNodeList displayAttributeList = itemElem.elementsByTagName( "displayAttributes" );
  if ( displayAttributeList.size() > 0 )
  {
    QDomElement displayAttributesElem =  displayAttributeList.at( 0 ).toElement();
    QDomNodeList attributeEntryList = displayAttributesElem.elementsByTagName( "attributeEntry" );
    for ( int i = 0; i < attributeEntryList.size(); ++i )
    {
      QDomElement attributeEntryElem = attributeEntryList.at( i ).toElement();
      int index = attributeEntryElem.attribute( "index", "-1" ).toInt();
      if ( index != -1 )
      {
        mDisplayAttributes.insert( index );
      }
    }
  }

  //restore alias map
  mFieldAliasMap.clear();
  QDomNodeList aliasMapNodeList = itemElem.elementsByTagName( "attributeAliasMap" );
  if ( aliasMapNodeList.size() > 0 )
  {
    QDomElement attributeAliasMapElem = aliasMapNodeList.at( 0 ).toElement();
    QDomNodeList aliasMepEntryList = attributeAliasMapElem.elementsByTagName( "aliasEntry" );
    for ( int i = 0; i < aliasMepEntryList.size(); ++i )
    {
      QDomElement aliasEntryElem = aliasMepEntryList.at( i ).toElement();
      int key = aliasEntryElem.attribute( "key", "-1" ).toInt();
      QString value = aliasEntryElem.attribute( "value", "" );
      mFieldAliasMap.insert( key, value );
    }
  }

  //restore sort columns
  mSortInformation.clear();
  QDomElement sortColumnsElem = itemElem.firstChildElement( "sortColumns" );
  if ( !sortColumnsElem.isNull() )
  {
    QDomNodeList columns = sortColumnsElem.elementsByTagName( "column" );
    for ( int i = 0; i < columns.size(); ++i )
    {
      QDomElement columnElem = columns.at( i ).toElement();
      int attribute = columnElem.attribute( "index" ).toInt();
      bool ascending = columnElem.attribute( "ascending" ) == "true" ? true : false;
      mSortInformation.push_back( qMakePair( attribute, ascending ) );
    }
  }
  bool success = tableReadXML( itemElem, doc );

  //must be done here because tableReadXML->setSceneRect changes mMaximumNumberOfFeatures
  mMaximumNumberOfFeatures = itemElem.attribute( "maxFeatures", "5" ).toInt();

  refreshAttributes();

  emit itemChanged();
  return success;
}
示例#9
0
void QgsComposerTableV2::render( QPainter *p, const QRectF &renderExtent, const int frameIndex )
{
  if ( !p )
  {
    return;
  }

  bool emptyTable = mTableContents.length() == 0;
  if ( emptyTable && mEmptyTableMode == QgsComposerTableV2::HideTable )
  {
    //empty table set to hide table mode, so don't draw anything
    return;
  }

  //calculate which rows to show in this frame
  QPair< int, int > rowsToShow = rowRange( renderExtent, frameIndex );

  if ( mComposition->plotStyle() == QgsComposition::Print ||
       mComposition->plotStyle() == QgsComposition::Postscript )
  {
    //exporting composition, so force an attribute refresh
    //we do this in case vector layer has changed via an external source (eg, another database user)
    refreshAttributes();
  }

  p->save();
  //antialiasing on
  p->setRenderHint( QPainter::Antialiasing, true );

  p->setPen( Qt::SolidLine );

  //now draw the text
  double currentX = ( mShowGrid ? mGridStrokeWidth : 0 );
  double currentY;

  QList<QgsComposerTableColumn*>::const_iterator columnIt = mColumns.constBegin();

  int col = 0;
  double cellHeaderHeight = QgsComposerUtils::fontAscentMM( mHeaderFont ) + 2 * mCellMargin;
  double cellBodyHeight = QgsComposerUtils::fontAscentMM( mContentFont ) + 2 * mCellMargin;
  QRectF cell;

  //calculate whether a header is required
  bool drawHeader = (( mHeaderMode == QgsComposerTableV2::FirstFrame && frameIndex < 1 )
                     || ( mHeaderMode == QgsComposerTableV2::AllFrames ) );
  //calculate whether drawing table contents is required
  bool drawContents = !( emptyTable && mEmptyTableMode == QgsComposerTableV2::ShowMessage );

  for ( ; columnIt != mColumns.constEnd(); ++columnIt )
  {
    currentY = ( mShowGrid ? mGridStrokeWidth : 0 );
    currentX += mCellMargin;

    Qt::TextFlag textFlag = ( Qt::TextFlag )0;
    if (( *columnIt )->width() <= 0 )
    {
      //automatic column width, so we use the Qt::TextDontClip flag when drawing contents, as this works nicer for italicised text
      //which may slightly exceed the calculated width
      //if column size was manually set then we do apply text clipping, to avoid painting text outside of columns width
      textFlag = Qt::TextDontClip;
    }

    if ( drawHeader )
    {
      //draw the header
      cell = QRectF( currentX, currentY, mMaxColumnWidthMap[col], cellHeaderHeight );

      //calculate alignment of header
      Qt::AlignmentFlag headerAlign = Qt::AlignLeft;
      switch ( mHeaderHAlignment )
      {
        case FollowColumn:
          headerAlign = ( *columnIt )->hAlignment();
          break;
        case HeaderLeft:
          headerAlign = Qt::AlignLeft;
          break;
        case HeaderCenter:
          headerAlign = Qt::AlignHCenter;
          break;
        case HeaderRight:
          headerAlign = Qt::AlignRight;
          break;
      }

      QgsComposerUtils::drawText( p, cell, ( *columnIt )->heading(), mHeaderFont, mHeaderFontColor, headerAlign, Qt::AlignVCenter, textFlag );

      currentY += cellHeaderHeight;
      currentY += ( mShowGrid ? mGridStrokeWidth : 0 );
    }

    if ( drawContents )
    {
      //draw the attribute values
      for ( int row = rowsToShow.first; row < rowsToShow.second; ++row )
      {
        cell = QRectF( currentX, currentY, mMaxColumnWidthMap[col], cellBodyHeight );

        QVariant cellContents = mTableContents.at( row ).at( col );
        QString str = cellContents.toString();

        QgsComposerUtils::drawText( p, cell, str, mContentFont, mContentFontColor, ( *columnIt )->hAlignment(), Qt::AlignVCenter, textFlag );

        currentY += cellBodyHeight;
        currentY += ( mShowGrid ? mGridStrokeWidth : 0 );
      }
    }

    currentX += mMaxColumnWidthMap[ col ];
    currentX += mCellMargin;
    currentX += ( mShowGrid ? mGridStrokeWidth : 0 );
    col++;
  }

  //and the borders
  if ( mShowGrid )
  {
    int numberRowsToDraw = rowsToShow.second - rowsToShow.first;
    if ( mEmptyTableMode == QgsComposerTableV2::DrawEmptyCells )
    {
      numberRowsToDraw = rowsVisible( frameIndex );
    }
    bool mergeCells = false;
    if ( emptyTable && mEmptyTableMode == QgsComposerTableV2::ShowMessage )
    {
      //draw a merged row for the empty table message
      numberRowsToDraw++;
      mergeCells = true;
    }

    QPen gridPen;
    gridPen.setWidthF( mGridStrokeWidth );
    gridPen.setColor( mGridColor );
    gridPen.setJoinStyle( Qt::MiterJoin );
    p->setPen( gridPen );
    drawHorizontalGridLines( p, numberRowsToDraw, drawHeader );
    drawVerticalGridLines( p, mMaxColumnWidthMap, numberRowsToDraw, drawHeader, mergeCells );
  }

  //special case - no records and table is set to ShowMessage mode
  if ( emptyTable && mEmptyTableMode == QgsComposerTableV2::ShowMessage )
  {
    double messageX = ( mShowGrid ? mGridStrokeWidth : 0 ) + mCellMargin;
    double messageY = ( mShowGrid ? mGridStrokeWidth : 0 ) +
                      ( drawHeader ? cellHeaderHeight + ( mShowGrid ? mGridStrokeWidth : 0 ) : 0 );
    cell = QRectF( messageX, messageY, mTableSize.width() - messageX, cellBodyHeight );
    QgsComposerUtils::drawText( p, cell, mEmptyTableMessage, mContentFont, mContentFontColor, Qt::AlignHCenter, Qt::AlignVCenter, ( Qt::TextFlag )0 );
  }

  p->restore();

}
示例#10
0
void QgsLayoutTable::render( QgsLayoutItemRenderContext &context, const QRectF &, const int frameIndex )
{
  bool emptyTable = mTableContents.length() == 0;
  if ( emptyTable && mEmptyTableMode == QgsLayoutTable::HideTable )
  {
    //empty table set to hide table mode, so don't draw anything
    return;
  }

  if ( !mLayout->renderContext().isPreviewRender() )
  {
    //exporting composition, so force an attribute refresh
    //we do this in case vector layer has changed via an external source (e.g., another database user)
    refreshAttributes();
  }

  //calculate which rows to show in this frame
  QPair< int, int > rowsToShow = rowRange( frameIndex );

  double gridSizeX = mShowGrid && mVerticalGrid ? mGridStrokeWidth : 0;
  double gridSizeY = mShowGrid && mHorizontalGrid ? mGridStrokeWidth : 0;
  double cellHeaderHeight = QgsLayoutUtils::fontAscentMM( mHeaderFont ) + 2 * mCellMargin;
  double cellBodyHeight = QgsLayoutUtils::fontAscentMM( mContentFont ) + 2 * mCellMargin;
  QRectF cell;

  //calculate whether a header is required
  bool drawHeader = ( ( mHeaderMode == QgsLayoutTable::FirstFrame && frameIndex < 1 )
                      || ( mHeaderMode == QgsLayoutTable::AllFrames ) );
  //calculate whether drawing table contents is required
  bool drawContents = !( emptyTable && mEmptyTableMode == QgsLayoutTable::ShowMessage );

  int numberRowsToDraw = rowsToShow.second - rowsToShow.first;
  int numberEmptyRows = 0;
  if ( drawContents && mShowEmptyRows )
  {
    numberRowsToDraw = rowsVisible( frameIndex, rowsToShow.first, true );
    numberEmptyRows = numberRowsToDraw - rowsToShow.second + rowsToShow.first;
  }
  bool mergeCells = false;
  if ( emptyTable && mEmptyTableMode == QgsLayoutTable::ShowMessage )
  {
    //draw a merged row for the empty table message
    numberRowsToDraw++;
    rowsToShow.second++;
    mergeCells = true;
  }

  QPainter *p = context.renderContext().painter();
  p->save();
  // painter is scaled to dots, so scale back to layout units
  p->scale( context.renderContext().scaleFactor(), context.renderContext().scaleFactor() );

  //draw the text
  p->setPen( Qt::SolidLine );

  double currentX = gridSizeX;
  double currentY = gridSizeY;
  if ( drawHeader )
  {
    //draw the headers
    int col = 0;
    for ( const QgsLayoutTableColumn *column : qgis::as_const( mColumns ) )
    {
      //draw background
      p->save();
      p->setPen( Qt::NoPen );
      p->setBrush( backgroundColor( -1, col ) );
      p->drawRect( QRectF( currentX, currentY, mMaxColumnWidthMap[col] + 2 * mCellMargin, cellHeaderHeight ) );
      p->restore();

      currentX += mCellMargin;

      Qt::TextFlag textFlag = static_cast< Qt::TextFlag >( 0 );
      if ( column->width() <= 0 )
      {
        //automatic column width, so we use the Qt::TextDontClip flag when drawing contents, as this works nicer for italicised text
        //which may slightly exceed the calculated width
        //if column size was manually set then we do apply text clipping, to avoid painting text outside of columns width
        textFlag = Qt::TextDontClip;
      }

      cell = QRectF( currentX, currentY, mMaxColumnWidthMap[col], cellHeaderHeight );

      //calculate alignment of header
      Qt::AlignmentFlag headerAlign = Qt::AlignLeft;
      switch ( mHeaderHAlignment )
      {
        case FollowColumn:
          headerAlign = column->hAlignment();
          break;
        case HeaderLeft:
          headerAlign = Qt::AlignLeft;
          break;
        case HeaderCenter:
          headerAlign = Qt::AlignHCenter;
          break;
        case HeaderRight:
          headerAlign = Qt::AlignRight;
          break;
      }

      QgsLayoutUtils::drawText( p, cell, column->heading(), mHeaderFont, mHeaderFontColor, headerAlign, Qt::AlignVCenter, textFlag );

      currentX += mMaxColumnWidthMap[ col ];
      currentX += mCellMargin;
      currentX += gridSizeX;
      col++;
    }

    currentY += cellHeaderHeight;
    currentY += gridSizeY;
  }

  //now draw the body cells
  int rowsDrawn = 0;
  if ( drawContents )
  {
    //draw the attribute values
    for ( int row = rowsToShow.first; row < rowsToShow.second; ++row )
    {
      rowsDrawn++;
      currentX = gridSizeX;
      int col = 0;

      //calculate row height
      double rowHeight = mMaxRowHeightMap[row + 1] + 2 * mCellMargin;


      for ( const QgsLayoutTableColumn *column : qgis::as_const( mColumns ) )
      {
        //draw background
        p->save();
        p->setPen( Qt::NoPen );
        p->setBrush( backgroundColor( row, col ) );
        p->drawRect( QRectF( currentX, currentY, mMaxColumnWidthMap[col] + 2 * mCellMargin, rowHeight ) );
        p->restore();

        // currentY = gridSize;
        currentX += mCellMargin;

        QVariant cellContents = mTableContents.at( row ).at( col );
        QString str = cellContents.toString();

        Qt::TextFlag textFlag = static_cast< Qt::TextFlag >( 0 );
        if ( column->width() <= 0 && mWrapBehavior == TruncateText )
        {
          //automatic column width, so we use the Qt::TextDontClip flag when drawing contents, as this works nicer for italicised text
          //which may slightly exceed the calculated width
          //if column size was manually set then we do apply text clipping, to avoid painting text outside of columns width
          textFlag = Qt::TextDontClip;
        }
        else if ( textRequiresWrapping( str, column->width(), mContentFont ) )
        {
          str = wrappedText( str, column->width(), mContentFont );
        }

        cell = QRectF( currentX, currentY, mMaxColumnWidthMap[col], rowHeight );
        QgsLayoutUtils::drawText( p, cell, str, mContentFont, mContentFontColor, column->hAlignment(), column->vAlignment(), textFlag );

        currentX += mMaxColumnWidthMap[ col ];
        currentX += mCellMargin;
        currentX += gridSizeX;
        col++;
      }
      currentY += rowHeight;
      currentY += gridSizeY;
    }
  }

  if ( numberRowsToDraw > rowsDrawn )
  {
    p->save();
    p->setPen( Qt::NoPen );

    //draw background of empty rows
    for ( int row = rowsDrawn; row < numberRowsToDraw; ++row )
    {
      currentX = gridSizeX;
      int col = 0;

      if ( mergeCells )
      {
        p->setBrush( backgroundColor( row + 10000, 0 ) );
        p->drawRect( QRectF( gridSizeX, currentY, mTableSize.width() - 2 * gridSizeX, cellBodyHeight ) );
      }
      else
      {
        for ( QgsLayoutTableColumn *column : qgis::as_const( mColumns ) )
        {
          Q_UNUSED( column );

          //draw background

          //we use a bit of a hack here - since we don't want these extra blank rows to match the firstrow/lastrow rule, add 10000 to row number
          p->setBrush( backgroundColor( row + 10000, col ) );
          p->drawRect( QRectF( currentX, currentY, mMaxColumnWidthMap[col] + 2 * mCellMargin, cellBodyHeight ) );

          // currentY = gridSize;
          currentX += mMaxColumnWidthMap[ col ] + 2 * mCellMargin;
          currentX += gridSizeX;
          col++;
        }
      }
      currentY += cellBodyHeight + gridSizeY;
    }
    p->restore();
  }

  //and the borders
  if ( mShowGrid )
  {
    QPen gridPen;
    gridPen.setWidthF( mGridStrokeWidth );
    gridPen.setColor( mGridColor );
    gridPen.setJoinStyle( Qt::MiterJoin );
    p->setPen( gridPen );
    if ( mHorizontalGrid )
    {
      drawHorizontalGridLines( p, rowsToShow.first, rowsToShow.second + numberEmptyRows, drawHeader );
    }
    if ( mVerticalGrid )
    {
      drawVerticalGridLines( p, mMaxColumnWidthMap, rowsToShow.first, rowsToShow.second + numberEmptyRows, drawHeader, mergeCells );
    }
  }

  //special case - no records and table is set to ShowMessage mode
  if ( emptyTable && mEmptyTableMode == QgsLayoutTable::ShowMessage )
  {
    double messageX = gridSizeX + mCellMargin;
    double messageY = gridSizeY + ( drawHeader ? cellHeaderHeight + gridSizeY : 0 );
    cell = QRectF( messageX, messageY, mTableSize.width() - messageX, cellBodyHeight );
    QgsLayoutUtils::drawText( p, cell, mEmptyTableMessage, mContentFont, mContentFontColor, Qt::AlignHCenter, Qt::AlignVCenter, static_cast< Qt::TextFlag >( 0 ) );
  }

  p->restore();

}
示例#11
0
void QgsLayoutTable::refresh()
{
  QgsLayoutMultiFrame::refresh();
  refreshAttributes();
}
void QgsComposerAttributeTable::setFieldAliasMap( const QMap<int, QString>& map )
{
  restoreFieldAliasMap( map );
  refreshAttributes();
}
bool QgsComposerAttributeTableV2::readXML( const QDomElement& itemElem, const QDomDocument& doc, bool ignoreFrames )
{
  if ( itemElem.isNull() )
  {
    return false;
  }

  //read general table properties
  if ( !QgsComposerTableV2::readXML( itemElem, doc, ignoreFrames ) )
  {
    return false;
  }

  QgsVectorLayer* prevLayer = sourceLayer();
  if ( prevLayer )
  {
    //disconnect from previous layer
    disconnect( prevLayer, SIGNAL( layerModified() ), this, SLOT( refreshAttributes() ) );
  }

  mSource = QgsComposerAttributeTableV2::ContentSource( itemElem.attribute( "source", "0" ).toInt() );
  mRelationId = itemElem.attribute( "relationId", "" );

  if ( mSource == QgsComposerAttributeTableV2::AtlasFeature )
  {
    mCurrentAtlasLayer = mComposition->atlasComposition().coverageLayer();
  }

  mShowUniqueRowsOnly = itemElem.attribute( "showUniqueRowsOnly", "0" ).toInt();
  mShowOnlyVisibleFeatures = itemElem.attribute( "showOnlyVisibleFeatures", "1" ).toInt();
  mFilterToAtlasIntersection = itemElem.attribute( "filterToAtlasIntersection", "0" ).toInt();
  mFilterFeatures = itemElem.attribute( "filterFeatures", "false" ) == "true" ? true : false;
  mFeatureFilter = itemElem.attribute( "featureFilter", "" );
  mMaximumNumberOfFeatures = itemElem.attribute( "maxFeatures", "5" ).toInt();

  //composer map
  int composerMapId = itemElem.attribute( "composerMap", "-1" ).toInt();
  if ( composerMapId == -1 )
  {
    mComposerMap = 0;
  }

  if ( composition() )
  {
    mComposerMap = composition()->getComposerMapById( composerMapId );
  }
  else
  {
    mComposerMap = 0;
  }

  if ( mComposerMap )
  {
    //if we have found a valid map item, listen out to extent changes on it and refresh the table
    connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( refreshAttributes() ) );
  }

  //vector layer
  QString layerId = itemElem.attribute( "vectorLayer", "not_existing" );
  if ( layerId == "not_existing" )
  {
    mVectorLayer = 0;
  }
  else
  {
    QgsMapLayer* ml = QgsMapLayerRegistry::instance()->mapLayer( layerId );
    if ( ml )
    {
      mVectorLayer = dynamic_cast<QgsVectorLayer*>( ml );
    }
  }

  //connect to new layer
  connect( sourceLayer(), SIGNAL( layerModified() ), this, SLOT( refreshAttributes() ) );

  refreshAttributes();

  emit changed();
  return true;
}
示例#14
0
bool QgsComposerAttributeTable::readXML( const QDomElement& itemElem, const QDomDocument& doc )
{
  if ( itemElem.isNull() )
  {
    return false;
  }

  //read general table properties
  if ( !tableReadXML( itemElem, doc ) )
  {
    return false;
  }

  mShowOnlyVisibleFeatures = itemElem.attribute( "showOnlyVisibleFeatures", "1" ).toInt();
  mFilterFeatures = itemElem.attribute( "filterFeatures", "false" ) == "true" ? true : false;
  mFeatureFilter = itemElem.attribute( "featureFilter", "" );

  //composer map
  int composerMapId = itemElem.attribute( "composerMap", "-1" ).toInt();
  if ( composerMapId == -1 )
  {
    mComposerMap = 0;
  }

  if ( composition() )
  {
    mComposerMap = composition()->getComposerMapById( composerMapId );
  }
  else
  {
    mComposerMap = 0;
  }

  if ( mComposerMap )
  {
    //if we have found a valid map item, listen out to extent changes on it and refresh the table
    QObject::connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( refreshAttributes() ) );
  }

  //vector layer
  QString layerId = itemElem.attribute( "vectorLayer", "not_existing" );
  if ( layerId == "not_existing" )
  {
    mVectorLayer = 0;
  }
  else
  {
    QgsMapLayer* ml = QgsMapLayerRegistry::instance()->mapLayer( layerId );
    if ( ml )
    {
      mVectorLayer = dynamic_cast<QgsVectorLayer*>( ml );
      if ( mVectorLayer )
      {
        //if we have found a valid vector layer, listen for modifications on it and refresh the table
        QObject::connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( refreshAttributes() ) );
      }
    }
  }

  //restore display attribute map. This is required to upgrade pre 2.4 projects.
  QSet<int> displayAttributes;
  QDomNodeList displayAttributeList = itemElem.elementsByTagName( "displayAttributes" );
  if ( displayAttributeList.size() > 0 )
  {
    QDomElement displayAttributesElem =  displayAttributeList.at( 0 ).toElement();
    QDomNodeList attributeEntryList = displayAttributesElem.elementsByTagName( "attributeEntry" );
    for ( int i = 0; i < attributeEntryList.size(); ++i )
    {
      QDomElement attributeEntryElem = attributeEntryList.at( i ).toElement();
      int index = attributeEntryElem.attribute( "index", "-1" ).toInt();
      if ( index != -1 )
      {
        displayAttributes.insert( index );
      }
    }
    setDisplayAttributes( displayAttributes, false );
  }

  //restore alias map. This is required to upgrade pre 2.4 projects.
  QMap<int, QString> fieldAliasMap;
  QDomNodeList aliasMapNodeList = itemElem.elementsByTagName( "attributeAliasMap" );
  if ( aliasMapNodeList.size() > 0 )
  {
    QDomElement attributeAliasMapElem = aliasMapNodeList.at( 0 ).toElement();
    QDomNodeList aliasMepEntryList = attributeAliasMapElem.elementsByTagName( "aliasEntry" );
    for ( int i = 0; i < aliasMepEntryList.size(); ++i )
    {
      QDomElement aliasEntryElem = aliasMepEntryList.at( i ).toElement();
      int key = aliasEntryElem.attribute( "key", "-1" ).toInt();
      QString value = aliasEntryElem.attribute( "value", "" );
      fieldAliasMap.insert( key, value );
    }
    restoreFieldAliasMap( fieldAliasMap );
  }

  //restore sort columns. This is required to upgrade pre 2.4 projects.
  QDomElement sortColumnsElem = itemElem.firstChildElement( "sortColumns" );
  if ( !sortColumnsElem.isNull() && mVectorLayer )
  {
    QDomNodeList columns = sortColumnsElem.elementsByTagName( "column" );
    const QgsFields& fields = mVectorLayer->pendingFields();

    for ( int i = 0; i < columns.size(); ++i )
    {
      QDomElement columnElem = columns.at( i ).toElement();
      int attribute = columnElem.attribute( "index" ).toInt();
      Qt::SortOrder order = columnElem.attribute( "ascending" ) == "true" ? Qt::AscendingOrder : Qt::DescendingOrder;
      //find corresponding column
      QList<QgsComposerTableColumn*>::iterator columnIt = mColumns.begin();
      for ( ; columnIt != mColumns.end(); ++columnIt )
      {
        if (( *columnIt )->attribute() == fields[attribute].name() )
        {
          ( *columnIt )->setSortByRank( i + 1 );
          ( *columnIt )->setSortOrder( order );
          break;
        }
      }
    }
  }

  //must be done here because tableReadXML->setSceneRect changes mMaximumNumberOfFeatures
  mMaximumNumberOfFeatures = itemElem.attribute( "maxFeatures", "5" ).toInt();

  refreshAttributes();

  emit itemChanged();
  return true;
}
示例#15
0
void QgsComposerTable::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
{
  Q_UNUSED( itemStyle );
  Q_UNUSED( pWidget );
  if ( !painter )
  {
    return;
  }

  if ( mComposition->plotStyle() == QgsComposition::Print ||
       mComposition->plotStyle() == QgsComposition::Postscript )
  {
    //exporting composition, so force an attribute refresh
    //we do this in case vector layer has changed via an external source (eg, another database user)
    refreshAttributes();
  }

  drawBackground( painter );
  painter->save();
  //antialiasing on
  painter->setRenderHint( QPainter::Antialiasing, true );

  painter->setPen( Qt::SolidLine );

  //now draw the text
  double currentX = mGridStrokeWidth;
  double currentY;

  QList<QgsComposerTableColumn*>::const_iterator columnIt = mColumns.constBegin();

  int col = 0;
  double cellHeaderHeight = fontAscentMillimeters( mHeaderFont ) + 2 * mLineTextDistance;
  double cellBodyHeight = fontAscentMillimeters( mContentFont ) + 2 * mLineTextDistance;
  QRectF cell;
  for ( ; columnIt != mColumns.constEnd(); ++columnIt )
  {
    currentY = mGridStrokeWidth;
    currentX += mLineTextDistance;

    cell = QRectF( currentX, currentY, mMaxColumnWidthMap[col], cellHeaderHeight );

    //calculate alignment of header
    Qt::AlignmentFlag headerAlign = Qt::AlignLeft;
    switch ( mHeaderHAlignment )
    {
      case FollowColumn:
        headerAlign = ( *columnIt )->hAlignment();
        break;
      case HeaderLeft:
        headerAlign = Qt::AlignLeft;
        break;
      case HeaderCenter:
        headerAlign = Qt::AlignHCenter;
        break;
      case HeaderRight:
        headerAlign = Qt::AlignRight;
        break;
    }

    drawText( painter, cell, ( *columnIt )->heading(), mHeaderFont, headerAlign, Qt::AlignVCenter, Qt::TextDontClip );

    currentY += cellHeaderHeight;
    currentY += mGridStrokeWidth;

    //draw the attribute values
    QList<QgsAttributeMap>::const_iterator attIt = mAttributeMaps.begin();
    for ( ; attIt != mAttributeMaps.end(); ++attIt )
    {
      cell = QRectF( currentX, currentY, mMaxColumnWidthMap[col], cellBodyHeight );

      const QgsAttributeMap &currentAttributeMap = *attIt;
      QString str = currentAttributeMap[ col ].toString();
      drawText( painter, cell, str, mContentFont, ( *columnIt )->hAlignment(), Qt::AlignVCenter, Qt::TextDontClip );

      currentY += cellBodyHeight;
      currentY += mGridStrokeWidth;
    }

    currentX += mMaxColumnWidthMap[ col ];
    currentX += mLineTextDistance;
    currentX += mGridStrokeWidth;
    col++;
  }

  //and the borders
  if ( mShowGrid )
  {
    QPen gridPen;
    gridPen.setWidthF( mGridStrokeWidth );
    gridPen.setColor( mGridColor );
    gridPen.setJoinStyle( Qt::MiterJoin );
    painter->setPen( gridPen );
    drawHorizontalGridLines( painter, mAttributeMaps.size() );
    drawVerticalGridLines( painter, mMaxColumnWidthMap );
  }

  painter->restore();

  //draw frame and selection boxes if necessary
  drawFrame( painter );
  if ( isSelected() )
  {
    drawSelectionBoxes( painter );
  }
}
示例#16
0
void QgsComposerTableV2::render( QPainter *p, const QRectF &, const int frameIndex )
{
  if ( !p )
  {
    return;
  }

  bool emptyTable = mTableContents.length() == 0;
  if ( emptyTable && mEmptyTableMode == QgsComposerTableV2::HideTable )
  {
    //empty table set to hide table mode, so don't draw anything
    return;
  }

  if ( mComposition->plotStyle() == QgsComposition::Print ||
       mComposition->plotStyle() == QgsComposition::Postscript )
  {
    //exporting composition, so force an attribute refresh
    //we do this in case vector layer has changed via an external source (eg, another database user)
    refreshAttributes();
  }

  //calculate which rows to show in this frame
  QPair< int, int > rowsToShow = rowRange( frameIndex );

  double gridSize = mShowGrid ? mGridStrokeWidth : 0;
  double cellHeaderHeight = QgsComposerUtils::fontAscentMM( mHeaderFont ) + 2 * mCellMargin;
  double cellBodyHeight = QgsComposerUtils::fontAscentMM( mContentFont ) + 2 * mCellMargin;
  QRectF cell;

  //calculate whether a header is required
  bool drawHeader = (( mHeaderMode == QgsComposerTableV2::FirstFrame && frameIndex < 1 )
                     || ( mHeaderMode == QgsComposerTableV2::AllFrames ) );
  //calculate whether drawing table contents is required
  bool drawContents = !( emptyTable && mEmptyTableMode == QgsComposerTableV2::ShowMessage );

  int numberRowsToDraw = rowsToShow.second - rowsToShow.first;
  int numberEmptyRows = 0;
  if ( drawContents && mShowEmptyRows )
  {
    numberRowsToDraw = rowsVisible( frameIndex, rowsToShow.first, true );
    numberEmptyRows = numberRowsToDraw - rowsToShow.second + rowsToShow.first;
  }
  bool mergeCells = false;
  if ( emptyTable && mEmptyTableMode == QgsComposerTableV2::ShowMessage )
  {
    //draw a merged row for the empty table message
    numberRowsToDraw++;
    rowsToShow.second++;
    mergeCells = true;
  }

  p->save();
  //antialiasing on
  p->setRenderHint( QPainter::Antialiasing, true );

  //draw the text
  p->setPen( Qt::SolidLine );

  double currentX = gridSize;
  double currentY = gridSize;
  if ( drawHeader )
  {
    //draw the headers
    int col = 0;
    Q_FOREACH ( const QgsComposerTableColumn* column, mColumns )
    {
      //draw background
      p->save();
      p->setPen( Qt::NoPen );
      p->setBrush( backgroundColor( -1, col ) );
      p->drawRect( QRectF( currentX, currentY, mMaxColumnWidthMap[col] + 2 * mCellMargin, cellHeaderHeight ) );
      p->restore();

      currentX += mCellMargin;

      Qt::TextFlag textFlag = static_cast< Qt::TextFlag >( 0 );
      if ( column->width() <= 0 )
      {
        //automatic column width, so we use the Qt::TextDontClip flag when drawing contents, as this works nicer for italicised text
        //which may slightly exceed the calculated width
        //if column size was manually set then we do apply text clipping, to avoid painting text outside of columns width
        textFlag = Qt::TextDontClip;
      }

      cell = QRectF( currentX, currentY, mMaxColumnWidthMap[col], cellHeaderHeight );

      //calculate alignment of header
      Qt::AlignmentFlag headerAlign = Qt::AlignLeft;
      switch ( mHeaderHAlignment )
      {
        case FollowColumn:
          headerAlign = column->hAlignment();
          break;
        case HeaderLeft:
          headerAlign = Qt::AlignLeft;
          break;
        case HeaderCenter:
          headerAlign = Qt::AlignHCenter;
          break;
        case HeaderRight:
          headerAlign = Qt::AlignRight;
          break;
      }

      QgsComposerUtils::drawText( p, cell, column->heading(), mHeaderFont, mHeaderFontColor, headerAlign, Qt::AlignVCenter, textFlag );

      currentX += mMaxColumnWidthMap[ col ];
      currentX += mCellMargin;
      currentX += gridSize;
      col++;
    }

    currentY += cellHeaderHeight;
    currentY += gridSize;
  }
示例#17
0
void QgsComposerTextTableV2::setContents( const QList<QStringList>& contents )
{
    mRowText = contents;
    refreshAttributes();
}
示例#18
0
void QgsComposerTextTableV2::addRow( const QStringList& row )
{
    mRowText.append( row );
    refreshAttributes();
}