Ejemplo n.º 1
0
QSet<QString> QgsGraduatedSymbolRenderer::usedAttributes( const QgsRenderContext &context ) const
{
  QSet<QString> attributes;

  // mAttrName can contain either attribute name or an expression.
  // Sometimes it is not possible to distinguish between those two,
  // e.g. "a - b" can be both a valid attribute name or expression.
  // Since we do not have access to fields here, try both options.
  attributes << mAttrName;

  QgsExpression testExpr( mAttrName );
  if ( !testExpr.hasParserError() )
    attributes.unite( testExpr.referencedColumns() );

  QgsRangeList::const_iterator range_it = mRanges.constBegin();
  for ( ; range_it != mRanges.constEnd(); ++range_it )
  {
    QgsSymbol *symbol = range_it->symbol();
    if ( symbol )
    {
      attributes.unite( symbol->usedAttributes( context ) );
    }
  }
  return attributes;
}
Ejemplo n.º 2
0
void QgsStyleManagerDialog::populateSymbols( const QStringList& symbolNames, bool check )
{
  QStandardItemModel* model = qobject_cast<QStandardItemModel*>( listItems->model() );
  model->clear();

  int type = currentItemType();

  for ( int i = 0; i < symbolNames.count(); ++i )
  {
    QString name = symbolNames[i];
    QgsSymbol* symbol = mStyle->symbol( name );
    if ( symbol && symbol->type() == type )
    {
      QStandardItem* item = new QStandardItem( name );
      QIcon icon = QgsSymbolLayerUtils::symbolPreviewIcon( symbol, listItems->iconSize() );
      item->setIcon( icon );
      item->setData( name ); // used to find out original name when user edited the name
      item->setCheckable( check );
      item->setToolTip( name );
      // add to model
      model->appendRow( item );
    }
    delete symbol;
  }
  selectedSymbolsChanged( QItemSelection(), QItemSelection() );
  symbolSelected( listItems->currentIndex() );
}
void QgsUniqueValueDialog::applySymbologyChanges()
{
  QgsDebugMsg( "called." );
  QList<QListWidgetItem *> selection = mClassListWidget->selectedItems();
  for ( int i = 0; i < selection.size(); i++ )
  {
    QListWidgetItem* item = selection[i];
    if ( !item )
    {
      QgsDebugMsg( QString( "selected item %1 not found" ).arg( i ) );
      continue;
    }

    QString value = item->text();
    if ( !mValues.contains( value ) )
    {
      QgsDebugMsg( QString( "value %1 not found" ).arg( value ) );
      continue;
    }

    QgsSymbol *symbol = mValues[ value ];
    symbol->setLowerValue( value );
    sydialog.apply( symbol );

    item->setToolTip( symbol->label() );
    item->setData( Qt::UserRole, value );
    updateEntryIcon( symbol, item );
  }
}
QgsSingleSymbolRenderer::QgsSingleSymbolRenderer( QGis::GeometryType type )
{
  mGeometryType = type;

  //initial setting based on random color
  QgsSymbol* sy = new QgsSymbol( mGeometryType );

  //random fill colors for points and polygons and pen colors for lines
  int red = 1 + ( int )( 255.0 * rand() / ( RAND_MAX + 1.0 ) );
  int green = 1 + ( int )( 255.0 * rand() / ( RAND_MAX + 1.0 ) );
  int blue = 1 + ( int )( 255.0 * rand() / ( RAND_MAX + 1.0 ) );

  if ( type == QGis::Line )
  {
    sy->setColor( QColor( red, green, blue ) );
  }
  else
  {
    sy->setFillColor( QColor( red, green, blue ) );
    sy->setFillStyle( Qt::SolidPattern );
    sy->setColor( QColor( 0, 0, 0 ) );
  }
  mSymbol = sy;
  updateSymbolAttributes();
}
int QgsUniqueValueRenderer::readXML( const QDomNode& rnode, QgsVectorLayer& vl )
{
  mGeometryType = vl.geometryType();
  QDomNode classnode = rnode.namedItem( "classificationfield" );
  QString classificationField = classnode.toElement().text();

  QgsVectorDataProvider* theProvider = vl.dataProvider();
  if ( !theProvider )
  {
    return 1;
  }

  int classificationId = vl.fieldNameIndex( classificationField );
  if ( classificationId == -1 )
  {
    //go on. Because with joins, it might be the joined layer is not loaded yet
  }
  setClassificationField( classificationId );

  QDomNode symbolnode = rnode.namedItem( "symbol" );
  while ( !symbolnode.isNull() )
  {
    QgsSymbol* msy = new QgsSymbol( mGeometryType );
    msy->readXML( symbolnode, &vl );
    insertValue( msy->lowerValue(), msy );
    symbolnode = symbolnode.nextSibling();
  }
  updateSymbolAttributes();
  vl.setRenderer( this );
  return 0;
}
Ejemplo n.º 6
0
void QgsSymbolSelectorWidget::changeLayer( QgsSymbolLayer *newLayer )
{
  SymbolLayerItem *item = currentLayerItem();
  QgsSymbolLayer *layer = item->layer();

  if ( layer->subSymbol() )
  {
    item->removeRow( 0 );
  }
  // update symbol layer item
  item->setLayer( newLayer );
  // When it is a marker symbol
  if ( newLayer->subSymbol() )
  {
    loadSymbol( newLayer->subSymbol(), item );
    layersTree->setExpanded( item->index(), true );
  }

  // Change the symbol at last to avoid deleting item's layer
  QgsSymbol *symbol = static_cast<SymbolLayerItem *>( item->parent() )->symbol();
  int layerIdx = item->parent()->rowCount() - item->row() - 1;
  symbol->changeSymbolLayer( layerIdx, newLayer );

  item->updatePreview();
  updatePreview();
  // Important: This lets the layer have its own layer properties widget
  layerChanged();
}
Ejemplo n.º 7
0
void QgsGraduatedSymbolRendererWidget::updateSymbolsFromWidget()
{
  QgsSymbolSelectorWidget* dlg = qobject_cast<QgsSymbolSelectorWidget*>( sender() );
  delete mGraduatedSymbol;
  mGraduatedSymbol = dlg->symbol()->clone();

  mSizeUnitWidget->blockSignals( true );
  mSizeUnitWidget->setUnit( mGraduatedSymbol->outputUnit() );
  mSizeUnitWidget->setMapUnitScale( mGraduatedSymbol->mapUnitScale() );
  mSizeUnitWidget->blockSignals( false );

  QItemSelectionModel* m = viewGraduated->selectionModel();
  QModelIndexList selectedIndexes = m->selectedRows( 1 );
  if ( m && !selectedIndexes.isEmpty() )
  {
    Q_FOREACH ( const QModelIndex& idx, selectedIndexes )
    {
      if ( idx.isValid() )
      {
        int rangeIdx = idx.row();
        QgsSymbol* newRangeSymbol = mGraduatedSymbol->clone();
        if ( selectedIndexes.count() > 1 )
        {
          //if updating multiple ranges, retain the existing range colors
          newRangeSymbol->setColor( mRenderer->ranges().at( rangeIdx ).symbol()->color() );
        }
        mRenderer->updateRangeSymbol( rangeIdx, newRangeSymbol );
      }
    }
  }
Ejemplo n.º 8
0
void QgsSymbolSelectorWidget::moveLayerByOffset( int offset )
{
  SymbolLayerItem *item = currentLayerItem();
  if ( !item )
    return;
  int row = item->row();

  SymbolLayerItem *parent = static_cast<SymbolLayerItem *>( item->parent() );
  QgsSymbol *parentSymbol = parent->symbol();

  int layerIdx = parent->rowCount() - row - 1;
  // switch layers
  QgsSymbolLayer *tmpLayer = parentSymbol->takeSymbolLayer( layerIdx );
  parentSymbol->insertSymbolLayer( layerIdx - offset, tmpLayer );

  QList<QStandardItem *> rowItems = parent->takeRow( row );
  parent->insertRows( row + offset, rowItems );
  parent->updatePreview();

  QModelIndex newIdx = rowItems[ 0 ]->index();
  layersTree->setCurrentIndex( newIdx );

  updatePreview();
  updateUi();
}
void QgsGraduatedSymbolRendererWidget::applyChangeToSymbol()
{
  mSizeUnitWidget->blockSignals( true );
  mSizeUnitWidget->setUnit( mGraduatedSymbol->outputUnit() );
  mSizeUnitWidget->setMapUnitScale( mGraduatedSymbol->mapUnitScale() );
  mSizeUnitWidget->blockSignals( false );

  QItemSelectionModel *m = viewGraduated->selectionModel();
  QModelIndexList selectedIndexes = m->selectedRows( 1 );
  if ( m && !selectedIndexes.isEmpty() )
  {
    const auto constSelectedIndexes = selectedIndexes;
    for ( const QModelIndex &idx : constSelectedIndexes )
    {
      if ( idx.isValid() )
      {
        int rangeIdx = idx.row();
        QgsSymbol *newRangeSymbol = mGraduatedSymbol->clone();
        if ( selectedIndexes.count() > 1 )
        {
          //if updating multiple ranges, retain the existing range colors
          newRangeSymbol->setColor( mRenderer->ranges().at( rangeIdx ).symbol()->color() );
        }
        mRenderer->updateRangeSymbol( rangeIdx, newRangeSymbol );
      }
    }
  }
  else
  {
    mRenderer->updateSymbols( mGraduatedSymbol.get() );
  }

  refreshSymbolView();
  emit widgetChanged();
}
int QgsContinuousColorRenderer::readXML( const QDomNode& rnode, QgsVectorLayer& vl )
{
  mGeometryType = vl.geometryType();
  QDomNode classnode = rnode.namedItem( "classificationfield" );
  QString classificationField = classnode.toElement().text();

  QgsVectorDataProvider* theProvider = vl.dataProvider();
  if ( !theProvider )
  {
    return 1;
  }
  int classificationId = vl.fieldNameIndex( classificationField );
  if ( classificationId == -1 )
  {
    //go on. Because with joins, it might be the joined layer is not loaded yet
  }
  setClassificationField( classificationId );

  //polygon outline
  QDomNode polyoutlinenode = rnode.namedItem( "polygonoutline" );
  QString polyoutline = polyoutlinenode.toElement().text();
  if ( polyoutline == "0" )
  {
    mDrawPolygonOutline = false;
  }
  else if ( polyoutline == "1" )
  {
    mDrawPolygonOutline = true;
  }

  //read the settings for the renderitem of the minimum value
  QDomNode lowernode = rnode.namedItem( "lowestsymbol" );
  QDomNode lsymbolnode = lowernode.namedItem( "symbol" );
  if ( ! lsymbolnode.isNull() )
  {
    QgsSymbol* lsy = new QgsSymbol( mGeometryType );
    lsy->readXML( lsymbolnode, &vl );
    setMinimumSymbol( lsy );
  }
  QDomNode uppernode = rnode.namedItem( "highestsymbol" );
  QDomNode usymbolnode = uppernode.namedItem( "symbol" );
  if ( ! usymbolnode.isNull() )
  {
    QgsSymbol* usy = new QgsSymbol( mGeometryType );
    usy->readXML( usymbolnode, &vl );
    setMaximumSymbol( usy );
  }
  vl.setRenderer( this );
  return 0;
}
Ejemplo n.º 11
0
static QString _getLayerSvgMarkerPath( const QgsProject &prj, const QString &layerName )
{
  QList<QgsMapLayer *> layers = prj.mapLayersByName( layerName );
  Q_ASSERT( layers.count() == 1 );
  Q_ASSERT( layers[0]->type() == QgsMapLayerType::VectorLayer );
  QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( layers[0] );
  Q_ASSERT( layer->renderer() );
  Q_ASSERT( layer->renderer()->type() == "singleSymbol" );
  QgsSingleSymbolRenderer *r = static_cast<QgsSingleSymbolRenderer *>( layer->renderer() );
  QgsSymbol *s = r->symbol();
  Q_ASSERT( s && s->symbolLayerCount() == 1 );
  Q_ASSERT( s->symbolLayer( 0 )->layerType() == "SvgMarker" );
  QgsSvgMarkerSymbolLayer *sl = static_cast<QgsSvgMarkerSymbolLayer *>( s->symbolLayer( 0 ) );
  return sl->path();
}
void QgsUniqueValueDialog::selectionChanged()
{
  QgsDebugMsg( "called." );
  sydialog.blockSignals( true );//block signal to prevent sydialog from changing the current QgsRenderItem
  QList<QListWidgetItem *> selection = mClassListWidget->selectedItems();

  if ( selection.size() == 0 )
  {
    mDeletePushButton->setEnabled( false );
    sydialog.unset();
  }
  else
  {
    mDeletePushButton->setEnabled( true );

    if ( selection.size() == 1 || !mCommonPropertyLock->isChecked() )
    {
      QListWidgetItem *item = selection[0];
      if ( !item )
        return;

      if ( !mValues.contains( item->text() ) )
        return;

      QgsSymbol *symbol = mValues[ item->text()];
      sydialog.set( symbol );
      sydialog.setLabel( symbol->label() );
    }
    else if ( selection.size() > 1 && mCommonPropertyLock->isChecked() )
    {
      if ( !mValues.contains( selection[0]->text() ) )
        return;

      sydialog.set( mValues[ selection[0]->text()] );

      for ( int i = 1; i < selection.size(); i++ )
      {
        if ( !mValues.contains( selection[i]->text() ) )
          continue;

        sydialog.updateSet( mValues[ selection[i]->text()] );
      }
    }
  }
  sydialog.blockSignals( false );
}
int QgsGraduatedSymbolRenderer::readXML( const QDomNode& rnode, QgsVectorLayer& vl )
{
  mGeometryType = vl.geometryType();
  QDomNode modeNode = rnode.namedItem( "mode" );
  QString modeValue = modeNode.toElement().text();
  QDomNode classnode = rnode.namedItem( "classificationfield" );
  QString classificationField = classnode.toElement().text();

  QgsVectorDataProvider* theProvider = vl.dataProvider();
  if ( !theProvider )
  {
    return 1;
  }
  if ( modeValue == "Empty" )
  {
    mMode = QgsGraduatedSymbolRenderer::Empty;
  }
  else if ( modeValue == "Quantile" )
  {
    mMode = QgsGraduatedSymbolRenderer::Quantile;
  }
  else //default
  {
    mMode = QgsGraduatedSymbolRenderer::EqualInterval;
  }

  int classificationId = theProvider->fieldNameIndex( classificationField );
  if ( classificationId == -1 )
  {
    return 2; //@todo: handle gracefully in gui situation where user needs to nominate field
  }
  setClassificationField( classificationId );

  QDomNode symbolnode = rnode.namedItem( "symbol" );
  while ( !symbolnode.isNull() )
  {
    QgsSymbol* sy = new QgsSymbol( mGeometryType );
    sy->readXML( symbolnode, &vl );
    addSymbol( sy );

    symbolnode = symbolnode.nextSibling();
  }
  updateSymbolAttributes();
  vl.setRenderer( this );
  return 0;
}
int QgsGraduatedSymbolRenderer::readXML( const QDomNode& rnode, QgsVectorLayer& vl )
{
  mGeometryType = vl.geometryType();
  QDomNode modeNode = rnode.namedItem( "mode" );
  QString modeValue = modeNode.toElement().text();
  QDomNode classnode = rnode.namedItem( "classificationfield" );
  QString classificationField = classnode.toElement().text();

  QgsVectorDataProvider* theProvider = vl.dataProvider();
  if ( !theProvider )
  {
    return 1;
  }
  if ( modeValue == "Empty" )
  {
    mMode = QgsGraduatedSymbolRenderer::Empty;
  }
  else if ( modeValue == "Quantile" )
  {
    mMode = QgsGraduatedSymbolRenderer::Quantile;
  }
  else //default
  {
    mMode = QgsGraduatedSymbolRenderer::EqualInterval;
  }

  int classificationId = vl.fieldNameIndex( classificationField );
  if ( classificationId == -1 )
  {
    //go on. Because with joins, it might be the joined layer is not loaded yet
  }
  setClassificationField( classificationId );

  QDomNode symbolnode = rnode.namedItem( "symbol" );
  while ( !symbolnode.isNull() )
  {
    QgsSymbol* sy = new QgsSymbol( mGeometryType );
    sy->readXML( symbolnode, &vl );
    addSymbol( sy );

    symbolnode = symbolnode.nextSibling();
  }
  updateSymbolAttributes();
  vl.setRenderer( this );
  return 0;
}
void QgsUniqueValueDialog::itemChanged( QListWidgetItem *item )
{
  QString oldValue = item->data( Qt::UserRole ).toString();
  QString newValue = item->text();

  if ( oldValue == newValue )
    return;

  if ( !mValues.contains( newValue ) )
  {
    QgsSymbol *sy = mValues[oldValue];
    mValues.remove( oldValue );
    mValues.insert( newValue, sy );
    sy->setLowerValue( newValue );
    item->setData( Qt::UserRole, newValue );
    updateEntryIcon( sy, item );
  }
  else
    item->setText( oldValue );
}
Ejemplo n.º 16
0
void QgsSymbolSelectorWidget::removeLayer()
{
  SymbolLayerItem *item = currentLayerItem();
  int row = item->row();
  SymbolLayerItem *parent = static_cast<SymbolLayerItem *>( item->parent() );

  int layerIdx = parent->rowCount() - row - 1; // IMPORTANT
  QgsSymbol *parentSymbol = parent->symbol();
  QgsSymbolLayer *tmpLayer = parentSymbol->takeSymbolLayer( layerIdx );

  parent->removeRow( row );
  parent->updatePreview();

  QModelIndex newIdx = parent->child( 0 )->index();
  layersTree->setCurrentIndex( newIdx );

  updateUi();
  updatePreview();
  //finally delete the removed layer pointer
  delete tmpLayer;
}
void QgsUniqueValueDialog::addClass( QString value )
{
  QgsDebugMsg( "called." );
  if ( mValues.contains( value ) )
  {
    int i;
    for ( i = 0; mValues.contains( value + QString::number( i ) ); i++ )
      ;
    value += QString::number( i );
  }

  QgsSymbol *symbol = new QgsSymbol( mVectorLayer->geometryType(), value, value, value.isNull() ? tr( "default" ) : "" );
  mValues.insert( value, symbol );

  QListWidgetItem *item = new QListWidgetItem( value );
  item->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled );
  item->setData( Qt::UserRole, value );
  item->setToolTip( symbol->label() );
  mClassListWidget->addItem( item );

  setSymbolColor( symbol, randomColor() );
  updateEntryIcon( symbol, item );
}
int QgsSingleSymbolRenderer::readXML( const QDomNode& rnode, QgsVectorLayer& vl )
{
  mGeometryType = vl.geometryType();
  QgsSymbol* sy = new QgsSymbol( mGeometryType );

  QDomNode synode = rnode.namedItem( "symbol" );

  if ( synode.isNull() )
  {
    QgsDebugMsg( "No symbol node in project file's renderitem Dom" );
    // XXX abort?
  }
  else
  {
    sy->readXML( synode, &vl );
  }
  updateSymbolAttributes();

  //create a renderer and add it to the vector layer
  addSymbol( sy );
  vl.setRenderer( this );
  return 0;
}
void QgsCategorizedSymbolRendererWidget::changeSelectedSymbols()
{
  QList<int> selectedCats = selectedCategories();

  if ( !selectedCats.isEmpty() )
  {
    QgsSymbol *newSymbol = mCategorizedSymbol->clone();
    QgsSymbolSelectorDialog dlg( newSymbol, mStyle, mLayer, this );
    dlg.setContext( context() );
    if ( !dlg.exec() )
    {
      delete newSymbol;
      return;
    }

    Q_FOREACH ( int idx, selectedCats )
    {
      QgsRendererCategory category = mRenderer->categories().value( idx );

      QgsSymbol *newCatSymbol = newSymbol->clone();
      newCatSymbol->setColor( mRenderer->categories()[idx].symbol()->color() );
      mRenderer->updateCategorySymbol( idx, newCatSymbol );
    }
Ejemplo n.º 20
0
void QgsSymbolSelectorWidget::duplicateLayer()
{
  QModelIndex idx = layersTree->currentIndex();
  if ( !idx.isValid() )
    return;

  SymbolLayerItem *item = static_cast<SymbolLayerItem *>( model->itemFromIndex( idx ) );
  if ( !item->isLayer() )
    return;

  QgsSymbolLayer *source = item->layer();

  int insertIdx = item->row();
  item = static_cast<SymbolLayerItem *>( item->parent() );

  QgsSymbol *parentSymbol = item->symbol();

  QgsSymbolLayer *newLayer = source->clone();
  if ( insertIdx == -1 )
    parentSymbol->appendSymbolLayer( newLayer );
  else
    parentSymbol->insertSymbolLayer( item->rowCount() - insertIdx, newLayer );

  SymbolLayerItem *newLayerItem = new SymbolLayerItem( newLayer );
  item->insertRow( insertIdx == -1 ? 0 : insertIdx, newLayerItem );
  if ( newLayer->subSymbol() )
  {
    loadSymbol( newLayer->subSymbol(), newLayerItem );
    layersTree->setExpanded( newLayerItem->index(), true );
  }
  item->updatePreview();

  layersTree->setCurrentIndex( model->indexFromItem( newLayerItem ) );
  updateUi();
  updatePreview();
}
Ejemplo n.º 21
0
QgsSymbol *QgsGrassEditRenderer::symbolForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
{
  int symbolCode = feature.attribute( QStringLiteral( "topo_symbol" ) ).toInt();
  QgsDebugMsgLevel( QString( "fid = %1 symbolCode = %2" ).arg( feature.id() ).arg( symbolCode ), 3 );

  QgsSymbol *symbol = nullptr;
  if ( symbolCode == QgsGrassVectorMap::TopoPoint || symbolCode == QgsGrassVectorMap::TopoCentroidIn ||
       symbolCode == QgsGrassVectorMap::TopoCentroidOut || symbolCode == QgsGrassVectorMap::TopoCentroidDupl ||
       symbolCode == QgsGrassVectorMap::TopoNode0 || symbolCode == QgsGrassVectorMap::TopoNode1 ||
       symbolCode == QgsGrassVectorMap::TopoNode2 )
  {
    symbol = mMarkerRenderer->symbolForFeature( feature, context );
  }
  else if ( symbolCode == QgsGrassVectorMap::TopoLine || symbolCode == QgsGrassVectorMap::TopoBoundaryError ||
            symbolCode == QgsGrassVectorMap::TopoBoundaryErrorLeft || symbolCode == QgsGrassVectorMap::TopoBoundaryErrorRight ||
            symbolCode == QgsGrassVectorMap::TopoBoundaryOk )
  {
    symbol = mLineRenderer->symbolForFeature( feature, context );
  }
  else
  {
    // should not happen
    QgsDebugMsg( "unknown symbol code" );
  }

  if ( symbol )
  {
    QgsDebugMsgLevel( "color = " + symbol->color().name(), 3 );
  }
  else
  {
    QgsDebugMsgLevel( "no symbol", 3 );
  }

  return symbol;
}
Ejemplo n.º 22
0
void QgsSymbolSelectorWidget::addLayer()
{
  QModelIndex idx = layersTree->currentIndex();
  if ( !idx.isValid() )
    return;

  int insertIdx = -1;
  SymbolLayerItem *item = static_cast<SymbolLayerItem *>( model->itemFromIndex( idx ) );
  if ( item->isLayer() )
  {
    insertIdx = item->row();
    item = static_cast<SymbolLayerItem *>( item->parent() );
  }

  QgsSymbol *parentSymbol = item->symbol();

  // save data-defined values at marker level
  QgsProperty ddSize( parentSymbol->type() == QgsSymbol::Marker
                      ? static_cast<QgsMarkerSymbol *>( parentSymbol )->dataDefinedSize()
                      : QgsProperty() );
  QgsProperty ddAngle( parentSymbol->type() == QgsSymbol::Marker
                       ? static_cast<QgsMarkerSymbol *>( parentSymbol )->dataDefinedAngle()
                       : QgsProperty() );
  QgsProperty ddWidth( parentSymbol->type() == QgsSymbol::Line
                       ? static_cast<QgsLineSymbol *>( parentSymbol )->dataDefinedWidth()
                       : QgsProperty() );

  QgsSymbolLayer *newLayer = QgsApplication::symbolLayerRegistry()->defaultSymbolLayer( parentSymbol->type() );
  if ( insertIdx == -1 )
    parentSymbol->appendSymbolLayer( newLayer );
  else
    parentSymbol->insertSymbolLayer( item->rowCount() - insertIdx, newLayer );

  // restore data-defined values at marker level
  if ( ddSize )
    static_cast<QgsMarkerSymbol *>( parentSymbol )->setDataDefinedSize( ddSize );
  if ( ddAngle )
    static_cast<QgsMarkerSymbol *>( parentSymbol )->setDataDefinedAngle( ddAngle );
  if ( ddWidth )
    static_cast<QgsLineSymbol *>( parentSymbol )->setDataDefinedWidth( ddWidth );

  SymbolLayerItem *newLayerItem = new SymbolLayerItem( newLayer );
  item->insertRow( insertIdx == -1 ? 0 : insertIdx, newLayerItem );
  item->updatePreview();

  layersTree->setCurrentIndex( model->indexFromItem( newLayerItem ) );
  updateUi();
  updatePreview();
}
Ejemplo n.º 23
0
void QgsComposerSymbolItem::readXML( const QDomElement& itemElem )
{
  if ( itemElem.isNull() )
  {
    return;
  }
  setText( itemElem.attribute( "text", "" ) );
  setLayerID( itemElem.attribute( "layerId", "" ) );

  QgsVectorLayer* vLayer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( mLayerID ) );
  if ( vLayer )
  {
    QDomElement symbolElem = itemElem.firstChildElement( "symbol" );
    if ( !symbolElem.isNull() )
    {
      QgsSymbol* symbol = new QgsSymbol( vLayer->geometryType() );
      symbol->readXML( symbolElem, vLayer );
      setSymbol( symbol );

      //add icon
      switch ( symbol->type() )
      {
        case QGis::Point:
          setIcon( QIcon( QPixmap::fromImage( symbol->getPointSymbolAsImage() ) ) );
          break;
        case QGis::Line:
          setIcon( QIcon( QPixmap::fromImage( symbol->getLineSymbolAsImage() ) ) );
          break;
        case QGis::Polygon:
          setIcon( QIcon( QPixmap::fromImage( symbol->getPolygonSymbolAsImage() ) ) );
          break;
        case QGis::NoGeometry:
          setIcon( QIcon( QgsApplication::activeThemePath() + "/mIconTableLayer.png" ) );
          break;
        case QGis::UnknownGeometry:
          // should not occur
          break;
      }
    }
  }
}
Ejemplo n.º 24
0
QSizeF QgsSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const
{
  QgsSymbol *s = mItem.symbol();
  if ( !s )
  {
    return QSizeF();
  }

  // setup temporary render context
  QgsRenderContext context;
  context.setScaleFactor( settings.dpi() / 25.4 );
  context.setRendererScale( settings.mapScale() );
  context.setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * context.scaleFactor() ) ) );
  context.setForceVectorOutput( true );
  context.setPainter( ctx ? ctx->painter : nullptr );

  if ( ctx && ctx->context )
  {
    context.setExpressionContext( ctx->context->expressionContext() );
  }
  else
  {
    // setup a minimal expression context
    QgsExpressionContext expContext;
    expContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) );
    context.setExpressionContext( expContext );
  }

  //Consider symbol size for point markers
  double height = settings.symbolSize().height();
  double width = settings.symbolSize().width();

  //Center small marker symbols
  double widthOffset = 0;
  double heightOffset = 0;

  if ( QgsMarkerSymbol *markerSymbol = dynamic_cast<QgsMarkerSymbol *>( s ) )
  {
    // allow marker symbol to occupy bigger area if necessary
    double size = markerSymbol->size( context ) / context.scaleFactor();
    height = size;
    width = size;
    if ( width < settings.symbolSize().width() )
    {
      widthOffset = ( settings.symbolSize().width() - width ) / 2.0;
    }
    if ( height < settings.symbolSize().height() )
    {
      heightOffset = ( settings.symbolSize().height() - height ) / 2.0;
    }
  }

  if ( ctx && ctx->painter )
  {
    double currentXPosition = ctx->point.x();
    double currentYCoord = ctx->point.y() + ( itemHeight - settings.symbolSize().height() ) / 2;
    QPainter *p = ctx->painter;

    //setup painter scaling to dots so that raster symbology is drawn to scale
    double dotsPerMM = context.scaleFactor();

    int opacity = 255;
    if ( QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layerNode()->layer() ) )
      opacity = ( 255 * vectorLayer->opacity() );

    p->save();
    p->setRenderHint( QPainter::Antialiasing );
    p->translate( currentXPosition + widthOffset, currentYCoord + heightOffset );
    p->scale( 1.0 / dotsPerMM, 1.0 / dotsPerMM );
    if ( opacity != 255 && settings.useAdvancedEffects() )
    {
      //semi transparent layer, so need to draw symbol to an image (to flatten it first)
      //create image which is same size as legend rect, in case symbol bleeds outside its alloted space
      QSize tempImageSize( width * dotsPerMM, height * dotsPerMM );
      QImage tempImage = QImage( tempImageSize, QImage::Format_ARGB32 );
      tempImage.fill( Qt::transparent );
      QPainter imagePainter( &tempImage );
      context.setPainter( &imagePainter );
      s->drawPreviewIcon( &imagePainter, tempImageSize, &context );
      context.setPainter( ctx->painter );
      //reduce opacity of image
      imagePainter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
      imagePainter.fillRect( tempImage.rect(), QColor( 0, 0, 0, opacity ) );
      imagePainter.end();
      //draw rendered symbol image
      p->drawImage( 0, 0, tempImage );
    }
    else
    {
      s->drawPreviewIcon( p, QSize( width * dotsPerMM, height * dotsPerMM ), &context );
    }

    if ( !mTextOnSymbolLabel.isEmpty() )
    {
      QFontMetricsF fm( mTextOnSymbolTextFormat.scaledFont( context ) );
      qreal yBaselineVCenter = ( height * dotsPerMM + fm.ascent() - fm.descent() ) / 2;
      QgsTextRenderer::drawText( QPointF( width * dotsPerMM / 2, yBaselineVCenter ), 0, QgsTextRenderer::AlignCenter,
                                 QStringList() << mTextOnSymbolLabel, context, mTextOnSymbolTextFormat );
    }

    p->restore();
  }

  return QSizeF( std::max( width + 2 * widthOffset, static_cast< double >( settings.symbolSize().width() ) ),
                 std::max( height + 2 * heightOffset, static_cast< double >( settings.symbolSize().height() ) ) );
}
void QgsUniqueValueRenderer::renderFeature( QgsRenderContext &renderContext, QgsFeature& f, QImage* img, bool selected, double opacity )
{
  QPainter *p = renderContext.painter();
  QgsSymbol* symbol = symbolForFeature( &f );
  if ( !symbol ) //no matching symbol
  {
    if ( img && mGeometryType == QGis::Point )
    {
      img->fill( 0 );
    }
    else if ( mGeometryType != QGis::Point )
    {
      p->setPen( Qt::NoPen );
      p->setBrush( Qt::NoBrush );
    }
    return;
  }

  // Point
  if ( img && mGeometryType == QGis::Point )
  {
    double fieldScale = 1.0;
    double rotation = 0.0;

    if ( symbol->scaleClassificationField() >= 0 )
    {
      //first find out the value for the scale classification attribute
      fieldScale = sqrt( qAbs( f.attribute( symbol->scaleClassificationField() ).toDouble() ) );
    }
    if ( symbol->rotationClassificationField() >= 0 )
    {
      rotation = f.attribute( symbol->rotationClassificationField() ).toDouble();
    }

    QString oldName;

    if ( symbol->symbolField() >= 0 )
    {
      QString name = f.attribute( symbol->symbolField() ).toString();
      oldName = symbol->pointSymbolName();
      symbol->setNamedPointSymbol( name );
    }

    double scale = renderContext.scaleFactor();

    if ( symbol->pointSizeUnits() )
    {
      scale = 1.0 / renderContext.mapToPixel().mapUnitsPerPixel();
    }

    *img = symbol->getPointSymbolAsImage( scale, selected, mSelectionColor,
                                          fieldScale, rotation, renderContext.rasterScaleFactor(),
                                          opacity );
    if ( !oldName.isNull() )
    {
      symbol->setNamedPointSymbol( oldName );
    }
  }
  // Line, polygon
  else if ( mGeometryType != QGis::Point )
  {
    if ( !selected )
    {
      QPen pen = symbol->pen();
      pen.setWidthF( renderContext.scaleFactor() * pen.widthF() );
      p->setPen( pen );
      if ( mGeometryType == QGis::Polygon )
      {
        QBrush brush = symbol->brush();
        scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout
        p->setBrush( brush );
      }
    }
    else
    {
      QPen pen = symbol->pen();
      pen.setWidthF( renderContext.scaleFactor() * pen.widthF() );
      if ( mGeometryType == QGis::Polygon )
      {
        QBrush brush = symbol->brush();
        scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout
        brush.setColor( mSelectionColor );
        p->setBrush( brush );
      }
      else //don't draw outlines of polygons in selection color otherwise they appear merged
      {
        pen.setColor( mSelectionColor );
      }
      p->setPen( pen );
    }
  }
}
QgsUniqueValueDialog::QgsUniqueValueDialog( QgsVectorLayer* vl ): QDialog(), mVectorLayer( vl ), sydialog( vl, true )
{
  setupUi( this );
  setOrientation( Qt::Vertical );

  //find out the fields of mVectorLayer
  if ( mVectorLayer )
  {
    //we cannot use unique values for not-commited fields because QgsVectorLayer has no 'unique values' method...
    QgsVectorDataProvider* provider = mVectorLayer->dataProvider();
    if ( provider )
    {
      const QgsFieldMap & fields = provider->fields();
      QString str;

      for ( QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); ++it )
      {
        str = ( *it ).name();
        str = mVectorLayer->attributeDisplayName( it.key() );
        mClassificationComboBox->addItem( str, it.key() );
      }
    }
  }


  mClassListWidget->setSelectionMode( QAbstractItemView::ExtendedSelection );
  mClassListWidget->setEditTriggers( QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed | QAbstractItemView::AnyKeyPressed );
  mClassListWidget->setSortingEnabled( true );

  if ( mVectorLayer )
  {
    const QgsUniqueValueRenderer* renderer = dynamic_cast<const QgsUniqueValueRenderer *>( mVectorLayer->renderer() );

    if ( renderer )
    {
      mClassListWidget->clear();
      QString field = mVectorLayer->attributeDisplayName( renderer->classificationField() );
      mOldClassificationAttribute = field;
      mClassificationComboBox->setCurrentIndex( mClassificationComboBox->findText( field ) );

      const QList<QgsSymbol*> list = renderer->symbols();
      //fill the items of the renderer into mValues
      for ( QList<QgsSymbol*>::const_iterator iter = list.begin(); iter != list.end(); ++iter )
      {
        QgsSymbol* symbol = *iter;
        QString symbolvalue = symbol->lowerValue();
        QgsSymbol* sym = new QgsSymbol( mVectorLayer->geometryType(), symbol->lowerValue(), symbol->upperValue(), symbol->label() );
        sym->setPen( symbol->pen() );
        sym->setCustomTexture( symbol->customTexture() );
        sym->setBrush( symbol->brush() );
        sym->setNamedPointSymbol( symbol->pointSymbolName() );
        sym->setPointSize( symbol->pointSize() );
        sym->setPointSizeUnits( symbol->pointSizeUnits() );
        sym->setScaleClassificationField( symbol->scaleClassificationField() );
        sym->setRotationClassificationField( symbol->rotationClassificationField() );
        mValues.insert( symbolvalue, sym );

        QListWidgetItem *item = new QListWidgetItem( symbolvalue );
        mClassListWidget->addItem( item );
        updateEntryIcon( symbol, item );
        item->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled );
        item->setData( Qt::UserRole, symbol->lowerValue() );
        item->setToolTip( symbol->label() );
      }
    }
  }

  mDeletePushButton->setEnabled( false );

  connect( mClassifyButton, SIGNAL( clicked() ), this, SLOT( changeClassificationAttribute() ) );
  connect( mAddButton, SIGNAL( clicked() ), this, SLOT( addClass() ) );
  connect( mDeletePushButton, SIGNAL( clicked() ), this, SLOT( deleteSelectedClasses() ) );
  connect( mRandomizeColors, SIGNAL( clicked() ), this, SLOT( randomizeColors() ) );
  connect( mResetColors, SIGNAL( clicked() ), this, SLOT( resetColors() ) );
  connect( mClassListWidget, SIGNAL( itemSelectionChanged() ), this, SLOT( selectionChanged() ) );
  connect( mCommonPropertyLock, SIGNAL( clicked() ), this, SLOT( selectionChanged() ) );
  connect( mClassListWidget, SIGNAL( itemChanged( QListWidgetItem * ) ), this, SLOT( itemChanged( QListWidgetItem * ) ) );
  connect( &sydialog, SIGNAL( settingsChanged() ), this, SLOT( applySymbologyChanges() ) );
  mSymbolWidgetStack->addWidget( &sydialog );
  mSymbolWidgetStack->setCurrentWidget( &sydialog );
}
void QgsUniqueValueDialog::apply()
{
  QgsDebugMsg( "called." );
  QgsUniqueValueRenderer *renderer = new QgsUniqueValueRenderer( mVectorLayer->geometryType() );

  //go through mValues and add the entries to the renderer
  for ( QMap<QString, QgsSymbol*>::iterator it = mValues.begin(); it != mValues.end(); ++it )
  {
    QgsSymbol* symbol = it.value();
    QgsSymbol* newsymbol = new QgsSymbol( mVectorLayer->geometryType(), symbol->lowerValue(), symbol->upperValue(), symbol->label() );
    newsymbol->setPen( symbol->pen() );
    newsymbol->setCustomTexture( symbol->customTexture() );
    newsymbol->setBrush( symbol->brush() );
    newsymbol->setNamedPointSymbol( symbol->pointSymbolName() );
    newsymbol->setPointSize( symbol->pointSize() );
    newsymbol->setPointSizeUnits( symbol->pointSizeUnits() );
    newsymbol->setScaleClassificationField( symbol->scaleClassificationField() );
    newsymbol->setRotationClassificationField( symbol->rotationClassificationField() );
    renderer->insertValue( it.key(), newsymbol );
  }
  renderer->updateSymbolAttributes();

  QgsVectorDataProvider *provider = dynamic_cast<QgsVectorDataProvider *>( mVectorLayer->dataProvider() );
  if ( provider )
  {
    int fieldIndex = mClassificationComboBox->itemData( mClassificationComboBox->currentIndex() ).toInt();
    if ( fieldIndex != -1 )
    {
      renderer->setClassificationField( fieldIndex );
      mVectorLayer->setRenderer( renderer );
      return;
    }
  }

  delete renderer; //something went wrong
}
Ejemplo n.º 28
0
void QgsVectorLayerRenderer::drawRendererLevels( QgsFeatureIterator &fit )
{
  QHash< QgsSymbol *, QList<QgsFeature> > features; // key = symbol, value = array of features

  QgsSingleSymbolRenderer *selRenderer = nullptr;
  if ( !mSelectedFeatureIds.isEmpty() )
  {
    selRenderer = new QgsSingleSymbolRenderer( QgsSymbol::defaultSymbol( mGeometryType ) );
    selRenderer->symbol()->setColor( mContext.selectionColor() );
    selRenderer->setVertexMarkerAppearance( mVertexMarkerStyle, mVertexMarkerSize );
    selRenderer->startRender( mContext, mFields );
  }

  QgsExpressionContextScope *symbolScope = QgsExpressionContextUtils::updateSymbolScope( nullptr, new QgsExpressionContextScope() );
  mContext.expressionContext().appendScope( symbolScope );

  // 1. fetch features
  QgsFeature fet;
  while ( fit.nextFeature( fet ) )
  {
    if ( mContext.renderingStopped() )
    {
      qDebug( "rendering stop!" );
      stopRenderer( selRenderer );
      delete mContext.expressionContext().popScope();
      return;
    }

    if ( !fet.hasGeometry() )
      continue; // skip features without geometry

    mContext.expressionContext().setFeature( fet );
    QgsSymbol *sym = mRenderer->symbolForFeature( fet, mContext );
    if ( !sym )
    {
      continue;
    }

    if ( !features.contains( sym ) )
    {
      features.insert( sym, QList<QgsFeature>() );
    }
    features[sym].append( fet );

    // new labeling engine
    if ( mContext.labelingEngine() )
    {
      QgsGeometry obstacleGeometry;
      QgsSymbolList symbols = mRenderer->originalSymbolsForFeature( fet, mContext );

      if ( !symbols.isEmpty() && fet.geometry().type() == QgsWkbTypes::PointGeometry )
      {
        obstacleGeometry = QgsVectorLayerLabelProvider::getPointObstacleGeometry( fet, mContext, symbols );
      }

      if ( !symbols.isEmpty() )
      {
        QgsExpressionContextUtils::updateSymbolScope( symbols.at( 0 ), symbolScope );
      }

      if ( mLabelProvider )
      {
        mLabelProvider->registerFeature( fet, mContext, obstacleGeometry );
      }
      if ( mDiagramProvider )
      {
        mDiagramProvider->registerFeature( fet, mContext, obstacleGeometry );
      }
    }
  }

  delete mContext.expressionContext().popScope();

  if ( features.empty() )
  {
    // nothing to draw
    stopRenderer( selRenderer );
    return;
  }

  // find out the order
  QgsSymbolLevelOrder levels;
  QgsSymbolList symbols = mRenderer->symbols( mContext );
  for ( int i = 0; i < symbols.count(); i++ )
  {
    QgsSymbol *sym = symbols[i];
    for ( int j = 0; j < sym->symbolLayerCount(); j++ )
    {
      int level = sym->symbolLayer( j )->renderingPass();
      if ( level < 0 || level >= 1000 ) // ignore invalid levels
        continue;
      QgsSymbolLevelItem item( sym, j );
      while ( level >= levels.count() ) // append new empty levels
        levels.append( QgsSymbolLevel() );
      levels[level].append( item );
    }
  }

  // 2. draw features in correct order
  for ( int l = 0; l < levels.count(); l++ )
  {
    QgsSymbolLevel &level = levels[l];
    for ( int i = 0; i < level.count(); i++ )
    {
      QgsSymbolLevelItem &item = level[i];
      if ( !features.contains( item.symbol() ) )
      {
        QgsDebugMsg( QStringLiteral( "level item's symbol not found!" ) );
        continue;
      }
      int layer = item.layer();
      QList<QgsFeature> &lst = features[item.symbol()];
      QList<QgsFeature>::iterator fit;
      for ( fit = lst.begin(); fit != lst.end(); ++fit )
      {
        if ( mContext.renderingStopped() )
        {
          stopRenderer( selRenderer );
          return;
        }

        bool sel = mContext.showSelection() && mSelectedFeatureIds.contains( fit->id() );
        // maybe vertex markers should be drawn only during the last pass...
        bool drawMarker = ( mDrawVertexMarkers && mContext.drawEditingInformation() && ( !mVertexMarkerOnlyForSelection || sel ) );

        mContext.expressionContext().setFeature( *fit );

        try
        {
          mRenderer->renderFeature( *fit, mContext, layer, sel, drawMarker );
        }
        catch ( const QgsCsException &cse )
        {
          Q_UNUSED( cse );
          QgsDebugMsg( QStringLiteral( "Failed to transform a point while drawing a feature with ID '%1'. Ignoring this feature. %2" )
                       .arg( fet.id() ).arg( cse.what() ) );
        }
      }
    }
  }

  stopRenderer( selRenderer );
}
Ejemplo n.º 29
0
void QgsQuickPrint::scalePointSymbols( int theScaleFactor, SymbolScalingType theDirection )
{
  if ( 0 >= theScaleFactor )
  {
    QgsDebugMsg( "invalid scale factor" );
    return;
  }
  QStringList myLayerSet = mpMapRenderer->layerSet();
  QStringListIterator myLayerIterator( myLayerSet );
  while ( myLayerIterator.hasNext() )
  {
    QString myLayerId = myLayerIterator.next();
    QgsDebugMsg( "Scaling point symbols for print for " + myLayerId );
    QgsMapLayer * mypLayer =
      QgsMapLayerRegistry::instance()->mapLayer( myLayerId );
    if ( mypLayer )
    {
      QgsVectorLayer *mypVectorLayer  =
        qobject_cast<QgsVectorLayer *>( mypLayer );
      if ( mypVectorLayer )
      {
        const QgsRenderer* mypRenderer = mypVectorLayer->renderer();
        const QList<QgsSymbol*> mySymbolList = mypRenderer->symbols();
        //
        // Single symbol
        //
        if ( 1 == mySymbolList.size() )
        {
          QgsSymbol * mypSymbol = mySymbolList.at( 0 );
          if ( mypSymbol->type() == QGis::Point )
          {
            if ( theDirection == ScaleUp )
            {
              mypSymbol->setPointSize( mypSymbol->pointSize() * theScaleFactor );
            }
            else //Scale Down
            {
              mypSymbol->setPointSize( mypSymbol->pointSize() / theScaleFactor );
            }
          }
        }
        else  //class breaks
        {
          QListIterator<QgsSymbol *> myIterator( mySymbolList );
          while ( myIterator.hasNext() )
          {
            QgsSymbol * mypSymbol = myIterator.next();
            if ( mypSymbol->type() == QGis::Point )
            {
              if ( theDirection == ScaleUp )
              {
                mypSymbol->setPointSize( mypSymbol->pointSize() * theScaleFactor );
              }
              else //Scale Down
              {
                mypSymbol->setPointSize( mypSymbol->pointSize() / theScaleFactor );
              }
            }
          } //symbol loop
        } //class breaks
      } //if vectorlayer
    } //if maplayer
  } //layer iterator
}
Ejemplo n.º 30
0
void QgsQuickPrint::printMap()
{
  if ( mOutputFileName.isEmpty() )
  {
    return;
  }
  if ( mpMapRenderer == NULL )
  {
    return;
  }
  //ensure the user never omitted the extension from the file name
  if ( !mOutputFileName.toUpper().endsWith( ".PDF" ) )
  {
    mOutputFileName += ".pdf";
  }

  // Initialising the printer this way lets us find out what
  // the screen resolution is which we store and then
  // reset the resolution of the printer after that...
  QPrinter myPrinter( QPrinter::ScreenResolution );

  // Try to force the printer resolution to 300dpi
  // to get past platform specific defaults in printer
  // resolution...
  //
  int myPrintResolutionDpi = 300;
  myPrinter.setResolution( myPrintResolutionDpi );
  myPrinter.setOutputFormat( QPrinter::PdfFormat );
  QgsDebugMsg( QString( "Printing to page size %1" ).arg( pageSizeToString( mPageSize ) ) );
  myPrinter.setPageSize( mPageSize );
  myPrinter.setOutputFileName( mOutputFileName );
  myPrinter.setOrientation( QPrinter::Landscape );
  myPrinter.setDocName( "quickprint Report" );
  QPainter myPrintPainter( &myPrinter );
  myPrintPainter.setPen( Qt::gray );
  myPrintPainter.setBrush( Qt::white );
  // This is what we are aiming for:
  // a
  // +-(1)------ Acme Maps (2) --------------------------------------+
  // |b         12/01/2007 (3)                                         |
  // |                           Earthquakes (4)                       |
  // | +--(5)--------------------------------------------------------+ |
  // | |c                                                            | |
  // | | +-(6)---------------------------------------+  +~(7)~~~~~~+ | |
  // | | |                                           |  |          | | |
  // | | |                                           |  |          | | |
  // | | |                                           |  |          | | |
  // | | |                                           |  |          | | |
  // | | |                                           |  |          | | |
  // | | |                                           |  |          | | |
  // | | |                                           |  |          | | |
  // | | |                                           |  |          | | |
  // | | |                                           |  |          | | |
  // | | |                                           |  |          | | |
  // | | |                                           |  |          | | |
  // | | +-------------------------------------------+  +~~~~~~~~~~+ | |
  // | |                                                             | |
  // | +-------------------------------------------------------------+ |
  // |                                                                 |
  // |   +-(8)-----+ +-(9-)----+ +-(10)----+                 /|\       |
  // |   |         | |Copyright| |         |                / | \      |
  // |   |         | |  2008   | |         |                  |(11)    |
  // |   +---------+ +---------+ +---------+                           |
  // |                                                  +~(12)~~~~~~+  |
  // +-----------------------------------------------------------------+
  //
  // 1) PageBorder              8) Logo1
  // 2) PageTitle               9) CopyrightText
  // 3) MapDate                 10) Logo2
  // 4) MapTitle                11) NorthArrow
  // 5) MapFrame                12) ScaleBar
  // 6) MapPixmap
  // 7) LegendPixmap
  // a OriginXY
  // b HorizontalSpacing
  // c VerticalSpacing

  //
  // Note: Different operating systems will use different
  // page resolutions for QPrinter::HighResolution so I'm
  // working all coordinates out as percentages of page
  // size so that we can hopefully get comarable print
  // results on all platforms.
  //

  //
  // Note #2: Im defining all measurements here as my plan
  // is to later support templates with different page
  // layouts and paper sizes etc.
  //


  //set the top left origin for the print layout
  int myOriginX = myPrinter.pageRect().left();
  int myOriginY = myPrinter.pageRect().top();
  int myDrawableWidth = myPrinter.pageRect().width() - myOriginX;
  int myDrawableHeight = myPrinter.pageRect().height() - myOriginY;

  //define the spacing between layout elements
  int myHorizontalSpacing = myDrawableWidth / 100; // 1%
  int myVerticalSpacing = myDrawableHeight / 100; // 1%

  //define the proportions for the page layout
  int myMapWidthPercent = 65;
  int myMapHeightPercent = 71;
  int myLegendWidthPercent = 25;
  int myLegendHeightPercent = 65;
  int myLogoWidthPercent = 23;
  int myLogoHeightPercent = 17;
  //
  // Remember the size and dpi of the maprender
  // so we can restore it properly
  //
  int myOriginalDpi = mpMapRenderer->outputDpi();
  //sensible default to prevent divide by zero
  if ( 0 == myOriginalDpi ) myOriginalDpi = 96;
  QSize myOriginalSize = mpMapRenderer->outputSize();

  //define the font sizes and family
  int myMapTitleFontSize = 24;
  int myMapDateFontSize = 16;
  int myMapNameFontSize = 32;
  int myLegendFontSize = 12;
#ifdef Q_OS_LINUX//this sucks...
  myLegendFontSize -= 2;
#endif

#ifdef WIN32 //this sucks too...
  myMapTitleFontSize /= 2;
  myMapDateFontSize /= 2;
  myMapNameFontSize /= 2;
  myLegendFontSize /= 2;
#endif
  QString myFontFamily = "Arial";

  //
  // Draw the PageBorder
  //
  myPrintPainter.drawRect(
    myOriginX, myOriginY, myDrawableWidth, myDrawableHeight );
  //
  // Draw the PageTitle
  //
  QFont myTitleFont( myFontFamily, myMapTitleFontSize );
  myPrintPainter.setFont( myTitleFont );
  QFontMetrics myTitleMetrics( myTitleFont, &myPrinter );
  int myPageTitleHeight = myTitleMetrics.height();
  int myPageTitleWidth = myTitleMetrics.width( mTitleText );
  myOriginX += myHorizontalSpacing;
  myOriginY -= ( myPageTitleHeight / 2 );
  QRect myPageTitleRect( myOriginX,
                         myOriginY,
                         myPageTitleWidth,
                         myPageTitleHeight );
  // make sure the title goes onto a white background
  myPrintPainter.setPen( Qt::white );
  myPrintPainter.drawRect( myPageTitleRect );
  myPrintPainter.setPen( Qt::black );
  myPrintPainter.drawText( myPageTitleRect, Qt::AlignCenter, mTitleText );

  //
  // Draw the MapDate
  //
  QFont myDateFont( myFontFamily, myMapDateFontSize );
  QString myDateText( QDate::currentDate().toString( Qt::LocalDate ) );
  myPrintPainter.setFont( myDateFont );
  QFontMetrics myDateMetrics( myDateFont, &myPrinter );
  int myDateHeight = myDateMetrics.height();
  //int myDateWidth = myDateMetrics.width(myDateText);
  myOriginX += myHorizontalSpacing;
  myOriginY += myPageTitleHeight  + myVerticalSpacing ;
  QRect myDateRect( myOriginX,
                    myOriginY,
                    myPageTitleWidth, //use same width as page title for centering
                    myDateHeight );
  // make sure the title goes onto a white background
  myPrintPainter.setPen( Qt::white );
  myPrintPainter.drawRect( myDateRect );
  myPrintPainter.setPen( Qt::black );
  myPrintPainter.drawText( myDateRect, Qt::AlignCenter, myDateText );

  //
  // Draw the MapName
  //
  QFont myNameFont( myFontFamily, myMapNameFontSize );
  myPrintPainter.setFont( myNameFont );
  QFontMetrics myNameMetrics( myNameFont, &myPrinter );
  int myNameHeight = myNameMetrics.height();
  int myNameWidth = myNameMetrics.width( mNameText );
  myOriginX = myPrinter.pageRect().left() + myDrawableWidth / 2; //page center
  myOriginX -= myNameWidth / 2;
  myOriginY = myPrinter.pageRect().top() + ( myPageTitleHeight / 2 )  + myVerticalSpacing ;
  QRect myNameRect( myOriginX,
                    myOriginY,
                    myNameWidth,
                    myNameHeight );
  // make sure the title goes onto a white background
  myPrintPainter.setPen( Qt::white );
  myPrintPainter.drawRect( myNameRect );
  myPrintPainter.setPen( Qt::black );
  myPrintPainter.drawText( myNameRect, Qt::AlignCenter, mNameText );

  //
  // Draw the MapFrame (top)
  //
  int myMapFrameWidth = myDrawableWidth ;
  myOriginX = myPrinter.pageRect().left() + myHorizontalSpacing;
  myOriginY += myNameHeight + myVerticalSpacing;
  QLine myMapFrameTopLine( myOriginX,
                           myOriginY,
                           myMapFrameWidth,
                           myOriginY );
  myPrintPainter.setPen( Qt::black );
  myPrintPainter.drawLine( myMapFrameTopLine );


  // Draw the map onto a pixmap
  // @TODO: we need to save teh extent of the screen map and
  // then set them again for the print map so that the map scales
  // properly in the print
  int myMapDimensionX = ( myDrawableWidth / 100 ) * myMapHeightPercent;
  int myMapDimensionY = ( myDrawableHeight / 100 ) * myMapWidthPercent;

  QImage myMapImage( QSize( myMapDimensionX, myMapDimensionY ), QImage::Format_ARGB32 );
  myMapImage.setDotsPerMeterX(( double )( myPrinter.logicalDpiX() ) / 25.4 * 1000.0 );
  myMapImage.setDotsPerMeterY(( double )( myPrinter.logicalDpiY() ) / 25.4 * 1000.0 );
  myMapImage.fill( 0 );
  QPainter myMapPainter;
  myMapPainter.begin( &myMapImage );
  // Now resize for print
  mpMapRenderer->setOutputSize( QSize( myMapDimensionX, myMapDimensionY ), ( myPrinter.logicalDpiX() + myPrinter.logicalDpiY() ) / 2 );
  mpMapRenderer->render( &myMapPainter );

  myMapPainter.end();
  //draw the map pixmap onto our pdf print device
  myOriginX = myPrinter.pageRect().left() + myHorizontalSpacing;
  myOriginY += myVerticalSpacing * 2;

  myPrintPainter.drawImage( myOriginX, myOriginY, myMapImage );

  //
  // Draw the legend
  //
  QFont myLegendFont( myFontFamily, myLegendFontSize );
  //myPrintPainter.setFont(myLegendFont);
  int myLegendDimensionX = ( myDrawableWidth / 100 ) * myLegendWidthPercent;
  int myLegendDimensionY = ( myDrawableHeight / 100 ) * myLegendHeightPercent;


  // Create a viewport to make coordinate conversions easier
  // The viewport has the same dimensions as the page(otherwise items
  // drawn into it will appear squashed), but a different origin.
  QRect myOriginalViewport = myPrintPainter.viewport(); //for restoring later
  myOriginX += myMapDimensionX + myHorizontalSpacing;
  myPrintPainter.setViewport( myOriginX,
                              myOriginY,
                              myOriginalViewport.width(),
                              myOriginalViewport.height() );
  //draw a rectangale around the legend frame
  //@TODO make this user settable
  if ( 0 == 1 ) //put some real logic here
  {
    myPrintPainter.drawRect( 0, 0, myLegendDimensionX, myLegendDimensionY );
  }
  //get font metric and other vars needed
  QFontMetrics myLegendFontMetrics( myLegendFont, &myPrinter );
  int myLegendFontHeight = myLegendFontMetrics.height();
  int myLegendXPos = 0;
  int myLegendYPos = 0;
  int myLegendSpacer = myLegendFontHeight / 2; //for vertical and horizontal spacing
  int myLegendVerticalSpacer = myLegendFontHeight / 3; //for vertical between rows
  int myIconWidth = myLegendFontHeight;
  myPrintPainter.setFont( myLegendFont );
  QStringList myLayerSet = mpMapRenderer->layerSet();
  QStringListIterator myLayerIterator( myLayerSet );
  //second clause below is to prevent legend spilling out the bottom
  while ( myLayerIterator.hasNext() &&
          myLegendYPos < myLegendDimensionY )
  {
    QString myLayerId = myLayerIterator.next();
    QgsMapLayer * mypLayer =
      QgsMapLayerRegistry::instance()->mapLayer( myLayerId );
    if ( mypLayer )
    {
      QgsVectorLayer *mypVectorLayer  =
        qobject_cast<QgsVectorLayer *>( mypLayer );
      // TODO: add support for symbology-ng renderers
      if ( mypVectorLayer && mypVectorLayer->renderer() )
      {
        QString myLayerName = mypVectorLayer->name();
        QIcon myIcon;
        QPixmap myPixmap( QSize( myIconWidth, myIconWidth ) );   //square
        //based on code from qgslegendlayer.cpp - see that file for more info
        const QgsRenderer* mypRenderer = mypVectorLayer->renderer();
        const QList<QgsSymbol*> mySymbolList = mypRenderer->symbols();
        //
        // Single symbol
        //
        double widthScale = ( myPrinter.logicalDpiX() + myPrinter.logicalDpiY() ) / 2.0 / 25.4;

        if ( 1 == mySymbolList.size() )
        {
          QgsSymbol * mypSymbol = mySymbolList.at( 0 );
          myPrintPainter.setPen( mypSymbol->pen() );
          myPrintPainter.setBrush( mypSymbol->brush() );
          myLegendXPos = 0 ;
          if ( mypSymbol->type() == QGis::Point )
          {
            QImage myImage;
            myImage = mypSymbol->getPointSymbolAsImage( widthScale );
            myPrintPainter.drawImage( myLegendXPos, myLegendYPos, myImage );
          }
          else if ( mypSymbol->type() == QGis::Line )
          {
            myPrintPainter.drawLine( myLegendXPos, myLegendYPos,
                                     myLegendXPos + myIconWidth,
                                     myLegendYPos + myIconWidth );
          }
          else //polygon
          {
            myPrintPainter.drawRect( myLegendXPos, myLegendYPos, myIconWidth, myIconWidth );
          }
          myLegendXPos += myIconWidth + myLegendSpacer;
          myPrintPainter.setPen( Qt::black );
          QStringList myWrappedLayerNameList = wordWrap( myLayerName,
                                               myLegendFontMetrics,
                                               myLegendDimensionX - myIconWidth );
          //
          // Loop through wrapped legend label lines
          //
          QStringListIterator myLineWrapIterator( myWrappedLayerNameList );
          while ( myLineWrapIterator.hasNext() )
          {
            QString myLine = myLineWrapIterator.next();
            QRect myLegendItemRect( myLegendXPos,
                                    myLegendYPos,
                                    myLegendDimensionX - myIconWidth,
                                    myLegendFontHeight );
            myPrintPainter.drawText( myLegendItemRect, Qt::AlignLeft, myLine );
            myLegendYPos += myLegendVerticalSpacer + myLegendFontHeight;
          }
        }
        else  //class breaks
        {
          // draw in the layer name first, after we loop for the class breaks
          QStringList myWrappedLayerNameList = wordWrap( myLayerName,
                                               myLegendFontMetrics,
                                               myLegendDimensionX - myIconWidth );
          // Check the wrapped layer name wont overrun the space we have
          // for the legend ...
          int myLabelHeight = myLegendFontHeight *
                              myWrappedLayerNameList.count();
          if ( myLegendYPos + myLabelHeight > myLegendDimensionY )
          {
            continue;
          }

          //
          // Loop through wrapped legend label lines
          //
          QStringListIterator myLineWrapIterator( myWrappedLayerNameList );
          while ( myLineWrapIterator.hasNext() )
          {
            QString myLine = myLineWrapIterator.next();
            myLegendXPos = myIconWidth;
            QRect myLegendItemRect( myLegendXPos,
                                    myLegendYPos,
                                    myLegendFontMetrics.width( myLine ),
                                    myLegendFontHeight );
            myPrintPainter.setPen( Qt::black );
            myPrintPainter.drawText( myLegendItemRect, Qt::AlignLeft, myLine );
            myLegendYPos += myLegendVerticalSpacer + myLegendFontHeight;
          }
          //
          // Loop through the class breaks
          //
          QListIterator<QgsSymbol *> myIterator( mySymbolList );
          while ( myIterator.hasNext() && myLegendYPos < myLegendDimensionY )
          {
            QgsSymbol * mypSymbol = myIterator.next();
            myPrintPainter.setPen( mypSymbol->pen() );
            myPrintPainter.setBrush( mypSymbol->brush() );
            myLegendXPos = myLegendSpacer * 3; //extra indent for class breaks
            if ( mypSymbol->type() == QGis::Point )
            {
              QImage myImage;
              myImage = mypSymbol->getPointSymbolAsImage( widthScale );
              myPrintPainter.drawImage( myLegendXPos, myLegendYPos, myImage );
            }
            else if ( mypSymbol->type() == QGis::Line )
            {
              myPrintPainter.drawLine( myLegendXPos, myLegendYPos,
                                       myLegendXPos + myIconWidth,
                                       myLegendYPos + myIconWidth );
            }
            else //polygon
            {
              myPrintPainter.drawRect(
                myLegendXPos, myLegendYPos, myIconWidth, myIconWidth );
            }
            //
            // Now work out the class break label
            //
            QString myLabel;
            QString myLower = mypSymbol->lowerValue();
            if ( !myLower.isEmpty() )
            {
              myLabel = myLower;
            }
            QString myUpper = mypSymbol->upperValue();
            if ( !myUpper.isEmpty() )
            {
              myLabel += " - ";
              myLabel += myUpper;
            }
            QString myText = mypSymbol->label();
            if ( !myText.isEmpty() )
            {
              myLabel += " ";
              myLabel += myText;
            }
            myLabel = myLabel.trimmed();
            myLegendXPos += myIconWidth + myLegendSpacer;
            myPrintPainter.setPen( Qt::black );

            QStringList myWrappedLayerNameList = wordWrap( myLabel,
                                                 myLegendFontMetrics,
                                                 myLegendDimensionX - myLegendXPos );
            //
            // Loop through wrapped legend label lines
            //
            QStringListIterator myLineWrapIterator( myWrappedLayerNameList );
            while ( myLineWrapIterator.hasNext() )
            {
              QString myLine = myLineWrapIterator.next();
              // check if the text will overflow the space we have
              QRect myLegendItemRect( myLegendXPos,
                                      myLegendYPos,
                                      myLegendDimensionX - myIconWidth,
                                      myLegendFontHeight );
              myPrintPainter.drawText( myLegendItemRect, Qt::AlignLeft, myLine );
              myLegendYPos += myLegendVerticalSpacer + myLegendFontHeight;
            } //wordwrap loop
          } //symbol loop
        } //class breaks
      } //if vectorlayer
    } //if maplayer
  } //layer iterator

  //reinstate the viewport
  myPrintPainter.setViewport( myOriginalViewport );


  //
  // Draw the MapFrame (bottom)
  //
  myOriginX = myPrinter.pageRect().left() + myHorizontalSpacing;
  myOriginY += myMapDimensionY + ( myVerticalSpacing * 2 );
  QLine myMapFrameBottomLine( myOriginX,
                              myOriginY,
                              myMapFrameWidth,
                              myOriginY );
  myPrintPainter.setPen( Qt::black );
  myPrintPainter.drawLine( myMapFrameBottomLine );


  //
  // Draw logo 1
  //
  int myLogoXDim = ( myDrawableWidth / 100 ) * myLogoWidthPercent;
  int myLogoYDim = ( myDrawableHeight / 100 ) * myLogoHeightPercent;
  QPixmap myLogo1;
  QgsDebugMsg( QString( "Logo1: %1" ).arg( mLogo1File ) );
  myLogo1.fill( Qt::white );
  myLogo1.load( mLogo1File );
  myLogo1 = myLogo1.scaled( myLogoXDim, myLogoYDim, Qt::KeepAspectRatio );
  myOriginX = myPrinter.pageRect().left() + myHorizontalSpacing;
  myOriginY += myVerticalSpacing ;
  myPrintPainter.drawPixmap( myOriginX,
                             myOriginY,
                             myLogo1 );

  //
  // Draw Copyright Text
  //
  myOriginX += myHorizontalSpacing + myLogoXDim;
  QRect myCopyrightRect( myOriginX, myOriginY, myLogoXDim, myLogoYDim );
  myPrintPainter.setPen( Qt::black );
  QFont myCopyrightFont( myFontFamily, myMapDateFontSize );
  myPrintPainter.setFont( myCopyrightFont );
  //myPrintPainter.drawRect( myCopyrightRect );
  myPrintPainter.drawText( myCopyrightRect, Qt::AlignCenter | Qt::TextWordWrap, mCopyrightText );

  //
  // Draw logo 2
  //
  QPixmap myLogo2;
  myLogo2.fill( Qt::white );
  myLogo2.load( mLogo2File );
  myLogo2 = myLogo2.scaled( myLogoXDim, myLogoYDim, Qt::KeepAspectRatio );
  myOriginX += myHorizontalSpacing + myLogoXDim;
  myPrintPainter.drawPixmap( myOriginX,
                             myOriginY,
                             myLogo2 );

  //
  // Draw the north arrow
  //
  myOriginX += myHorizontalSpacing + myLogoXDim;
  // use half the available space for the n.arrow
  // and the rest for the scale bar (see below)
  QPixmap myNorthArrow( myLogoYDim / 2, myLogoYDim / 2 );
  myNorthArrow.fill( Qt::white );
  QPainter myNorthPainter( &myNorthArrow );
  QSvgRenderer mySvgRenderer( mNorthArrowFile );
  mySvgRenderer.render( &myNorthPainter );
  myPrintPainter.drawPixmap( myOriginX + (( myLogoXDim / 2 ) ),
                             myOriginY,
                             myNorthArrow );

  //
  // Draw the scale bar
  //
  myOriginY += myLogoYDim / 2 + myVerticalSpacing;
  myPrintPainter.setViewport( myOriginX,
                              myOriginY,
                              myOriginalViewport.width(),
                              myOriginalViewport.height() );
  renderPrintScaleBar( &myPrintPainter, mpMapRenderer, myLogoXDim );
  myPrintPainter.setViewport( myOriginalViewport );

  //
  // Finish up
  //


  myPrintPainter.end();
#if 0
  mProgressDialog.setValue( 0 );
  mProgressDialog.setLabelText( tr( "Please wait while your report is generated", "COMMENTED OUT" ) );
  mProgressDialog.show();
  mProgressDialog.setWindowModality( Qt::WindowModal );
  mProgressDialog.setAutoClose( true );
#endif
  //
  // Restore the map render to its former glory
  //
  mpMapRenderer->setOutputSize( myOriginalSize, myOriginalDpi );
}