📄 qgscomposervectorlegend.cpp
字号:
/*************************************************************************** qgscomposervectorlegend.cpp ------------------- begin : January 2005 copyright : (C) 2005 by Radim Blazek email : blazek@itc.it ***************************************************************************//*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/#include "qgscomposervectorlegend.h"#include "qgscomposermap.h"#include "qgscontinuouscolorrenderer.h"#include "qgsmapcanvas.h"#include "qgsmaplayer.h"#include "qgsproject.h"#include "qgsrenderer.h"#include "qgssymbol.h"#include "qgsvectorlayer.h"#include <QFontDialog>#include <QPainter>#include <Q3PopupMenu>#include <QGraphicsScene>#include <iostream>#include <vector>QgsComposerVectorLegend::QgsComposerVectorLegend ( QgsComposition *composition, int id, int x, int y, int fontSize ) : QWidget(composition), QGraphicsRectItem(x,y,10,10,0){ setupUi(this); //std::cout << "QgsComposerVectorLegend::QgsComposerVectorLegend()" << std::endl; mComposition = composition; mId = id; mMapCanvas = mComposition->mapCanvas(); init(); // Font and pen if(fontSize < 10){ fontSize = 10; } mFont.setPointSize ( fontSize ); // Set map to the first available if any std::vector<QgsComposerMap*> maps = mComposition->maps(); if ( maps.size() > 0 ) { mMap = maps[0]->id(); } // Calc size and cache recalculate(); // Add to scene mComposition->canvas()->addItem(this); QGraphicsRectItem::show(); QGraphicsRectItem::update(); writeSettings();}QgsComposerVectorLegend::QgsComposerVectorLegend ( QgsComposition *composition, int id ) : QGraphicsRectItem(0,0,10,10,0){ //std::cout << "QgsComposerVectorLegend::QgsComposerVectorLegend()" << std::endl; setupUi(this); mComposition = composition; mId = id; mMapCanvas = mComposition->mapCanvas(); init(); readSettings(); // Calc size and cache recalculate(); // Add to scene mComposition->canvas()->addItem(this); QGraphicsRectItem::show(); QGraphicsRectItem::update();}void QgsComposerVectorLegend::init ( void ) { mSelected = false; mNumCachedLayers = 0; mTitle = tr("Legend"); mMap = 0; mNextLayerGroup = 1; mFrame = true; // Cache mCacheUpdated = false; // Rectangle QGraphicsRectItem::setZValue(50);// setActive(true); // Layers list view mLayersListView->setColumnText(0,tr("Layers")); mLayersListView->addColumn(tr("Group")); mLayersListView->setSorting(-1); mLayersListView->setResizeMode(Q3ListView::AllColumns); mLayersListView->setSelectionMode(Q3ListView::Extended); mLayersPopupMenu = new Q3PopupMenu( ); mLayersPopupMenu->insertItem( tr("Combine selected layers"), this, SLOT(groupLayers()) ); connect ( mLayersListView, SIGNAL(clicked(Q3ListViewItem *)), this, SLOT(layerChanged(Q3ListViewItem *))); connect ( mLayersListView, SIGNAL(rightButtonClicked(Q3ListViewItem *, const QPoint &, int)), this, SLOT( showLayersPopupMenu(Q3ListViewItem *, const QPoint &, int)) ); // Plot style setPlotStyle ( QgsComposition::Preview ); // Preview style mPreviewMode = Render; mPreviewModeComboBox->insertItem ( tr("Cache"), Cache ); mPreviewModeComboBox->insertItem ( tr("Render"), Render ); mPreviewModeComboBox->insertItem ( tr("Rectangle"), Rectangle ); mPreviewModeComboBox->setCurrentItem ( mPreviewMode ); connect ( mComposition, SIGNAL(mapChanged(int)), this, SLOT(mapChanged(int)) ); }QgsComposerVectorLegend::~QgsComposerVectorLegend(){ //std::cerr << "QgsComposerVectorLegend::~QgsComposerVectorLegend()" << std::endl;}#define FONT_WORKAROUND_SCALE 10QRectF QgsComposerVectorLegend::render ( QPainter *p ){ //std::cout << "QgsComposerVectorLegend::render p = " << p << std::endl; // Painter can be 0, create dummy to avoid many if below QPainter *painter = NULL; QPixmap *pixmap = NULL; if ( p ) { painter = p; } else { pixmap = new QPixmap(1,1); painter = new QPainter( pixmap ); } //std::cout << "mComposition->scale() = " << mComposition->scale() << std::endl; // Font size in canvas units float titleSize = 25.4 * mComposition->scale() * mTitleFont.pointSizeFloat() / 72; float sectionSize = 25.4 * mComposition->scale() * mSectionFont.pointSizeFloat() / 72; float size = 25.4 * mComposition->scale() * mFont.pointSizeFloat() / 72; //std::cout << "font sizes = " << titleSize << " " << sectionSize << " " << size << std::endl; // Create fonts QFont titleFont ( mTitleFont ); QFont sectionFont ( mSectionFont ); QFont font ( mFont ); titleFont.setPointSizeFloat ( titleSize ); sectionFont.setPointSizeFloat ( sectionSize ); font.setPointSizeFloat ( size ); // Not sure about Style Strategy, QFont::PreferMatch? titleFont.setStyleStrategy ( (QFont::StyleStrategy) (QFont::PreferOutline | QFont::PreferAntialias) ); sectionFont.setStyleStrategy ( (QFont::StyleStrategy) (QFont::PreferOutline | QFont::PreferAntialias) ); font.setStyleStrategy ( (QFont::StyleStrategy) (QFont::PreferOutline | QFont::PreferAntialias) ); QFontMetricsF titleMetrics ( titleFont ); QFontMetricsF sectionMetrics ( sectionFont ); QFontMetricsF metrics ( font ); if ( plotStyle() == QgsComposition::Postscript) //do we need seperate PostScript rendering settings? { // Fonts sizes for Postscript rendering double psTitleSize = titleMetrics.ascent() * 72.0 / mComposition->resolution(); //What?? double psSectionSize = sectionMetrics.ascent() * 72.0 / mComposition->resolution(); double psSize = metrics.ascent() * 72.0 / mComposition->resolution(); titleFont.setPointSizeFloat ( psTitleSize * FONT_WORKAROUND_SCALE ); sectionFont.setPointSizeFloat ( psSectionSize * FONT_WORKAROUND_SCALE ); font.setPointSizeFloat ( psSize * FONT_WORKAROUND_SCALE ); } else { titleFont.setPointSizeFloat ( titleSize * FONT_WORKAROUND_SCALE ); sectionFont.setPointSizeFloat ( sectionSize * FONT_WORKAROUND_SCALE ); font.setPointSizeFloat ( size * FONT_WORKAROUND_SCALE ); } double x, y; // Legend title -if we do this later, we can center it y = mMargin + titleMetrics.height(); painter->setPen ( mPen ); painter->setFont ( titleFont ); painter->save(); //Save the painter state so we can undo the scaling later painter->scale(1./FONT_WORKAROUND_SCALE, 1./FONT_WORKAROUND_SCALE); //scale the painter to work around the font bug painter->drawText( QPointF(2 * mMargin * FONT_WORKAROUND_SCALE, y * FONT_WORKAROUND_SCALE), mTitle ); painter->restore(); //used to keep track of total width and height double width = 4 * mMargin + titleMetrics.width ( mTitle ); double height = mMargin + mSymbolSpace + titleMetrics.height(); // mSymbolSpace? // Layers QgsComposerMap *map = mComposition->map ( mMap ); //Get the map from the composition by ID number if ( map ) { std::map<int,int> doneGroups; int nlayers = mMapCanvas->layerCount(); for ( int i = nlayers - 1; i >= 0; i-- ) { QgsMapLayer *layer = mMapCanvas->getZpos(i);// if ( !layer->visible() ) continue; // skip non-visible layers if ( layer->type() != QgsMapLayer::VECTOR ) continue; //skip raster layers QString layerId = layer->getLayerID();// if( ! layerOn(layerId) ) continue; //does this need to go away? int group = layerGroup ( layerId ); if ( group > 0 ) { if ( doneGroups.find(group) != doneGroups.end() ) { continue; } else { doneGroups.insert(std::make_pair(group,1)); } } // Make list of all layers in the group and count section items std::vector<int> groupLayers; // vector of layers std::vector<double> itemHeights; // maximum item sizes std::vector<QString> itemLabels; // item labels int sectionItemsCount = 0; QString sectionTitle; for ( int j = nlayers - 1; j >= 0; j-- ) { QgsMapLayer *layer2 = mMapCanvas->getZpos(j);// if ( !layer2->visible() ) continue; if ( layer2->type() != QgsMapLayer::VECTOR ) continue; QString layerId2 = layer2->getLayerID(); if( ! layerOn(layerId2) ) continue; int group2 = layerGroup ( layerId2 ); QgsVectorLayer *vector = dynamic_cast <QgsVectorLayer*> (layer2); const QgsRenderer *renderer = vector->renderer(); if ( (group > 0 && group2 == group) || ( group == 0 && j == i ) ) { groupLayers.push_back(j); QList<QgsSymbol*> symbols = renderer->symbols(); if ( sectionTitle.length() == 0 ) { sectionTitle = layer2->name(); } if ( symbols.size() > sectionItemsCount ) { sectionItemsCount = symbols.size(); itemHeights.resize(sectionItemsCount); itemLabels.resize(sectionItemsCount); } double widthScale = map->widthScale() * mComposition->scale(); if ( plotStyle() == QgsComposition::Preview && mPreviewMode == Render ) { widthScale *= mComposition->viewScale(); } double scale = map->symbolScale() * mComposition->scale(); int icnt = 0; for ( QList<QgsSymbol*>::iterator it = symbols.begin(); it != symbols.end(); ++it ) { QgsSymbol* sym = (*it); // height if ( itemHeights[icnt] < mSymbolHeight ) { // init first itemHeights[icnt] = mSymbolHeight; } QPixmap pic = QPixmap::fromImage(sym->getPointSymbolAsImage(widthScale, false)); double h = scale * pic.height(); if ( h > itemHeights[icnt] ) { itemHeights[icnt] = h; } if ( itemLabels[icnt].length() == 0 ) { if ( sym->label().length() > 0 ) { itemLabels[icnt] = sym->label(); } else { itemLabels[icnt] = sym->lowerValue(); if (sym->upperValue().length() > 0) itemLabels[icnt] += " - " + sym->upperValue(); } } icnt++; } } } //std::cout << "group size = " << groupLayers.size() << std::endl; //std::cout << "sectionItemsCount = " << sectionItemsCount << std::endl; // Section title if ( sectionItemsCount > 1 ) { height += mSymbolSpace; x = 2*mMargin; y = height + sectionMetrics.height(); painter->setPen ( mPen ); painter->setFont ( sectionFont ); painter->save(); //Save the painter state so we can undo the scaling later painter->scale(1./FONT_WORKAROUND_SCALE, 1./FONT_WORKAROUND_SCALE); //scale the painter to work around the font bug painter->drawText(QPointF(x * FONT_WORKAROUND_SCALE, y * FONT_WORKAROUND_SCALE), sectionTitle ); painter->restore(); double w = 3*mMargin + sectionMetrics.width( sectionTitle ); if ( w > width ) width = w; height += sectionMetrics.height(); height += (1.5*mSymbolSpace); } // Draw all layers in group double groupStartHeight = height; for ( int j = groupLayers.size()-1; j >= 0; j-- ) { std::cout << "layer = " << groupLayers[j] << std::endl; double localHeight = groupStartHeight; layer = mMapCanvas->getZpos(groupLayers[j]); QgsVectorLayer *vector = dynamic_cast <QgsVectorLayer*> (layer); const QgsRenderer *renderer = vector->renderer(); // Get a list of the symbols from the renderer - some renderers can have several symbols QList<QgsSymbol*> symbols = renderer->symbols(); int icnt = 0; for ( QList<QgsSymbol*>::iterator it = symbols.begin(); it != symbols.end(); ++it ) { localHeight += mSymbolSpace; double symbolHeight = itemHeights[icnt]; QgsSymbol* sym = (*it); QPen pen = sym->pen(); double widthScale = map->widthScale(); pen.setWidthF( ( widthScale * pen.widthF() ) ); pen.setCapStyle(Qt::FlatCap); //make sure that the line doesn't extend past its endpoints painter->setPen ( pen ); painter->setBrush ( sym->brush() ); if ( vector->vectorType() == QGis::Point ) { double scale = map->symbolScale(); // Get the picture of appropriate size directly from catalogue QPixmap pic = QPixmap::fromImage(sym->getPointSymbolAsImage(widthScale,false,sym->color())); painter->save(); painter->scale(scale,scale); painter->drawPixmap ( static_cast<int>( (1.*mMargin+mSymbolWidth/2)/scale-pic.width()/2), static_cast<int>( (1.*localHeight+symbolHeight/2)/scale-1.*pic.height()/2), pic ); painter->restore(); } else if ( vector->vectorType() == QGis::Line ) { painter->drawLine (QPointF(mMargin, localHeight+mSymbolHeight/2), QPointF(mMargin+mSymbolWidth, localHeight+mSymbolHeight/2)); } else if ( vector->vectorType() == QGis::Polygon ) { pen.setCapStyle(Qt::FlatCap); painter->setPen ( pen ); painter->drawRect (QRectF(mMargin, localHeight, mSymbolWidth, mSymbolHeight)); } // Label painter->setPen ( mPen ); painter->setFont ( font ); QString lab; if ( sectionItemsCount == 1 ) { lab = sectionTitle; } else { lab = itemLabels[icnt]; } // drawText (x, y w, h, ...) was cutting last letter (the box was too small) QRectF br = metrics.boundingRect ( lab ); x = 2*mMargin + mSymbolWidth; y = localHeight + symbolHeight/2 + ( metrics.height()/2 - metrics.descent()); painter->save(); //Save the painter state so we can undo the scaling later painter->scale(1./FONT_WORKAROUND_SCALE, 1./FONT_WORKAROUND_SCALE);//scale the painter to work around the font bug painter->drawText(QPointF(x * FONT_WORKAROUND_SCALE, y * FONT_WORKAROUND_SCALE), lab ); painter->restore(); double w = 3*mMargin + mSymbolWidth + metrics.width(lab); if ( w > width ) width = w; localHeight += symbolHeight; icnt++; }//End of iterating through the symbols in the renderer } // add height of section items to the total height height = groupStartHeight; for ( int j = 0; j < (int)itemHeights.size(); j++ ) { height += mSymbolSpace + itemHeights[j]; } if ( sectionItemsCount > 1 ) { // add more space to separate section from next item height += mSymbolSpace; } }//End of iterating through the layers }//END if(map) height += mMargin; if(mFrame) { QPen pen(QColor(0,0,0), 0.5); painter->setPen( pen ); painter->setBrush( QBrush( QColor(255,255,255), Qt::NoBrush)); painter->setRenderHint(QPainter::Antialiasing, true);//turn on antialiasing painter->drawRect(QRectF(0, 0, width, height)); } // QGraphicsRectItem::setRect(0, 0, width, height); //BUG! - calling this causes a re-draw, which means we are continuously re-drawing. if ( !p ) { delete painter; delete pixmap;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -