29 #include <QDomDocument>
30 #include <QDomElement>
35 , mTitle(
tr(
"Legend" ) )
36 , mFontColor( QColor( 0, 0, 0 ) )
41 , mSplitLayer( false )
42 , mEqualColumnWidth( false )
78 Q_UNUSED( itemStyle );
86 QStandardItem* rootItem =
mLegendModel.invisibleRootItem();
87 if ( !rootItem )
return size;
93 painter->setPen( QPen( QColor( 0, 0, 0 ) ) );
100 qreal maxColumnWidth = 0;
103 foreach (
Atom atom, atomList )
105 maxColumnWidth = qMax( atom.
size.width(), maxColumnWidth );
113 bool firstInColumn =
true;
114 double columnMaxHeight = 0;
115 qreal columnWidth = 0;
117 foreach (
Atom atom, atomList )
119 if ( atom.
column > column )
130 point.ry() = columnTop;
133 firstInColumn =
true;
135 if ( !firstInColumn )
140 QSizeF atomSize =
drawAtom( atom, painter, point );
141 columnWidth = qMax( atomSize.width(), columnWidth );
143 point.ry() += atom.
size.height();
144 columnMaxHeight = qMax( point.y() - columnTop, columnMaxHeight );
146 firstInColumn =
false;
150 size.rheight() = columnTop + columnMaxHeight +
mBoxSpace;
151 size.rwidth() = point.x();
159 Qt::AlignmentFlag halignment;
160 if (
mColumnCount > 1 && titleSize.width() + 2 * mBoxSpace < size.width() )
162 halignment = Qt::AlignHCenter;
163 point.rx() = mBoxSpace + size.rwidth() / 2;
167 halignment = Qt::AlignLeft;
169 size.rwidth() = qMax( titleSize.width() + 2 *
mBoxSpace, size.width() );
176 if ( painter && size.height() > rect().height() )
178 setSceneRect( QRectF( pos().x(), pos().y(), rect().width(), size.height() ) );
180 if ( painter && size.width() > rect().width() )
182 setSceneRect( QRectF( pos().x(), pos().y(), size.width(), rect().height() ) );
203 if (
mTitle.isEmpty() )
return size;
207 double y = point.y();
211 for ( QStringList::Iterator titlePart = lines.begin(); titlePart != lines.end(); ++titlePart )
217 double left = halignment == Qt::AlignLeft ? point.x() : point.x() - width / 2;
219 QRectF rect( left, y, width, height );
223 size.rwidth() = qMax( width, size.width() );
226 if ( titlePart != lines.end() )
231 size.rheight() = y - point.y();
240 if ( !groupItem )
return size;
242 double y = point.y();
247 for ( QStringList::Iterator groupPart = lines.begin(); groupPart != lines.end(); ++groupPart )
252 size.rwidth() = qMax( width, size.width() );
253 if ( groupPart != lines.end() )
258 size.rheight() = y - point.y();
265 if ( !layerItem )
return size;
268 if ( layerItem->text().isEmpty() )
return size;
270 double y = point.y();
275 for ( QStringList::Iterator layerItemPart = lines.begin(); layerItemPart != lines.end(); ++layerItemPart )
280 size.rwidth() = qMax( width, size.width() );
281 if ( layerItemPart != lines.end() )
286 size.rheight() = y - point.y();
294 QgsDebugMsg( QString(
"width = %1 height = %2" ).arg( size.width() ).arg( size.height() ) );
295 if ( size.isValid() )
297 setSceneRect( QRectF( pos().x(), pos().y(), size.width(), size.height() ) );
303 QSizeF symbolSize( 0, 0 );
304 QSizeF labelSize( 0, 0 );
305 if ( !symbolItem )
return Nucleon();
314 double realSymbolHeight;
325 opacity = currentLayer->getTransparency();
330 QString text = symbolItem->text();
338 symbolNg = symbolV2Item->
symbolV2();
342 double x = point.x();
347 symbolSize.rwidth() = qMax( x - point.x(),
mSymbolWidth );
348 symbolSize.rheight() = qMax( realSymbolHeight,
mSymbolHeight );
350 else if ( rasterItem )
354 QIcon symbolIcon = symbolItem->icon();
355 if ( !symbolIcon.isNull() && symbolItem->text().isEmpty() )
358 QList<QSize> sizes = symbolIcon.availableSizes();
360 double maxHeight = 0;
361 foreach ( QSize
size, sizes )
363 if ( maxWidth < size.width() ) maxWidth = size.width();
364 if ( maxHeight < size.height() ) maxHeight = size.height();
366 QSize maxSize( maxWidth, maxHeight );
369 QImage legend = symbolIcon.pixmap( maxWidth, maxHeight ).toImage();
381 painter->setBrush( rasterItem->
color() );
390 QIcon symbolIcon = symbolItem->icon();
391 if ( !symbolIcon.isNull() )
402 double labelX = point.x() + qMax((
double ) symbolSize.width(), labelXOffset );
408 labelSize.rheight() = lines.count() * textHeight + ( lines.count() - 1 ) *
mlineSpacing;
411 if ( labelSize.height() < symbolSize.height() )
413 labelY = point.y() + symbolSize.height() / 2 + textHeight / 2;
417 labelY = point.y() + textHeight;
420 for ( QStringList::Iterator itemPart = lines.begin(); itemPart != lines.end(); ++itemPart )
424 if ( itemPart != lines.end() )
431 nucleon.
item = symbolItem;
435 double width = qMax((
double ) symbolSize.width(), labelXOffset ) + labelSize.width();
436 double height = qMax( symbolSize.height(), labelSize.height() );
437 nucleon.
size = QSizeF( width, height );
452 QPaintDevice* paintDevice = p->device();
457 rasterScaleFactor = ( paintDevice->logicalDpiX() + paintDevice->logicalDpiY() ) / 2.0 / 25.4;
462 double mmPerMapUnit = 1;
474 double widthOffset = 0;
475 double heightOffset = 0;
479 size = markerSymbol->
size();
484 height *= mmPerMapUnit;
485 width *= mmPerMapUnit;
486 markerSymbol->
setSize( width );
501 p->translate( currentXPosition + widthOffset, currentYCoord + heightOffset );
502 p->scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor );
504 if ( markerSymbol && sizeInMapUnits )
509 s->
drawPreviewIcon( p, QSize( width * rasterScaleFactor, height * rasterScaleFactor ) );
511 if ( markerSymbol && sizeInMapUnits )
518 currentXPosition += width;
519 currentXPosition += 2 * widthOffset;
520 symbolHeight = height + 2 * heightOffset;
535 return QStringList();
574 QDomElement composerLegendElem = doc.createElement(
"ComposerLegend" );
575 elem.appendChild( composerLegendElem );
578 composerLegendElem.setAttribute(
"title",
mTitle );
579 composerLegendElem.setAttribute(
"columnCount", QString::number(
mColumnCount ) );
580 composerLegendElem.setAttribute(
"splitLayer", QString::number(
mSplitLayer ) );
581 composerLegendElem.setAttribute(
"equalColumnWidth", QString::number(
mEqualColumnWidth ) );
583 composerLegendElem.setAttribute(
"boxSpace", QString::number(
mBoxSpace ) );
584 composerLegendElem.setAttribute(
"columnSpace", QString::number(
mColumnSpace ) );
586 composerLegendElem.setAttribute(
"symbolWidth", QString::number(
mSymbolWidth ) );
587 composerLegendElem.setAttribute(
"symbolHeight", QString::number(
mSymbolHeight ) );
588 composerLegendElem.setAttribute(
"wmsLegendWidth", QString::number(
mWmsLegendWidth ) );
589 composerLegendElem.setAttribute(
"wmsLegendHeight", QString::number(
mWmsLegendHeight ) );
590 composerLegendElem.setAttribute(
"wrapChar",
mWrapChar );
591 composerLegendElem.setAttribute(
"fontColor",
mFontColor.name() );
598 QDomElement composerLegendStyles = doc.createElement(
"styles" );
599 composerLegendElem.appendChild( composerLegendStyles );
610 return _writeXML( composerLegendElem, doc );
615 if ( itemElem.isNull() )
621 mTitle = itemElem.attribute(
"title" );
622 mColumnCount = itemElem.attribute(
"columnCount",
"1" ).toInt();
624 mSplitLayer = itemElem.attribute(
"splitLayer",
"0" ).toInt() == 1;
627 QDomNodeList stylesNodeList = itemElem.elementsByTagName(
"styles" );
628 if ( stylesNodeList.size() > 0 )
630 QDomNode stylesNode = stylesNodeList.at( 0 );
631 for (
int i = 0; i < stylesNode.childNodes().size(); i++ )
633 QDomElement styleElem = stylesNode.childNodes().at( i ).toElement();
635 style.
readXML( styleElem, doc );
636 QString name = styleElem.attribute(
"name" );
649 mFontColor.setNamedColor( itemElem.attribute(
"fontColor",
"#000000" ) );
652 mBoxSpace = itemElem.attribute(
"boxSpace",
"2.0" ).toDouble();
653 mColumnSpace = itemElem.attribute(
"columnSpace",
"2.0" ).toDouble();
655 mSymbolWidth = itemElem.attribute(
"symbolWidth",
"7.0" ).toDouble();
656 mSymbolHeight = itemElem.attribute(
"symbolHeight",
"14.0" ).toDouble();
657 mWmsLegendWidth = itemElem.attribute(
"wmsLegendWidth",
"50" ).toDouble();
658 mWmsLegendHeight = itemElem.attribute(
"wmsLegendHeight",
"25" ).toDouble();
660 mWrapChar = itemElem.attribute(
"wrapChar" );
663 if ( !itemElem.attribute(
"map" ).isEmpty() )
669 QDomNodeList modelNodeList = itemElem.elementsByTagName(
"Model" );
670 if ( modelNodeList.size() > 0 )
672 QDomElement modelElem = modelNodeList.at( 0 ).toElement();
677 QDomNodeList composerItemList = itemElem.elementsByTagName(
"ComposerItem" );
678 if ( composerItemList.size() > 0 )
680 QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
686 QString titleFontString = itemElem.attribute(
"titleFont" );
687 if ( !titleFontString.isEmpty() )
692 QString groupFontString = itemElem.attribute(
"groupFont" );
693 if ( !groupFontString.isEmpty() )
699 QString layerFontString = itemElem.attribute(
"layerFont" );
700 if ( !layerFontString.isEmpty() )
705 QString itemFontString = itemElem.attribute(
"itemFont" );
706 if ( !itemFontString.isEmpty() )
711 if ( !itemElem.attribute(
"groupSpace" ).isEmpty() )
715 if ( !itemElem.attribute(
"layerSpace" ).isEmpty() )
719 if ( !itemElem.attribute(
"symbolSpace" ).isEmpty() )
753 list << stringToSplt;
763 if ( !rootItem )
return atoms;
767 for (
int i = 0; i < rootItem->rowCount(); i++ )
769 QStandardItem* currentLayerItem = rootItem->child( i );
771 if ( !currentLegendItem )
continue;
777 QList<Atom> groupAtoms =
createAtomList( currentLayerItem, splitLayer );
780 nucleon.
item = currentLegendItem;
783 if ( groupAtoms.size() > 0 )
788 groupAtoms[0].nucleons.prepend( nucleon );
789 groupAtoms[0].size.rheight() += nucleon.
size.height();
790 groupAtoms[0].size.rwidth() = qMax( nucleon.
size.width(), groupAtoms[0].size.width() );
797 atom.
size.rwidth() += nucleon.
size.width();
798 atom.
size.rheight() += nucleon.
size.height();
799 atom.
size.rwidth() = qMax( nucleon.
size.width(), atom.
size.width() );
800 groupAtoms.append( atom );
802 atoms.append( groupAtoms );
811 nucleon.
item = currentLegendItem;
814 atom.
size.rwidth() = nucleon.
size.width();
815 atom.
size.rheight() = nucleon.
size.height();
818 QList<Atom> layerAtoms;
820 for (
int j = 0; j < currentLegendItem->rowCount(); j++ )
823 if ( !symbolItem )
continue;
831 atom.
size.rwidth() = qMax( symbolNucleon.
size.width(), atom.
size.width() );
838 atom.
size.rheight() += symbolNucleon.
size.height();
839 atom.
nucleons.append( symbolNucleon );
844 symbolAtom.
nucleons.append( symbolNucleon );
845 symbolAtom.
size.rwidth() = symbolNucleon.
size.width();
846 symbolAtom.
size.rheight() = symbolNucleon.
size.height();
847 layerAtoms.append( symbolAtom );
850 layerAtoms.prepend( atom );
851 atoms.append( layerAtoms );
867 if ( !item )
continue;
872 if ( !groupItem )
continue;
885 if ( !layerItem )
continue;
905 size.rwidth() = qMax( symbolNucleon.
size.width(), size.width() );
907 point.ry() += nucleon.
size.height();
915 if ( atom.
nucleons.size() == 0 )
return 0;
920 if ( !item )
return 0;
947 double totalHeight = 0;
949 qreal maxAtomHeight = 0;
950 foreach (
Atom atom, atomList )
956 totalHeight += atom.
size.height();
957 maxAtomHeight = qMax( atom.
size.height(), maxAtomHeight );
968 int currentColumn = 0;
969 int currentColumnAtomCount = 0;
970 double currentColumnHeight = 0;
971 double maxColumnHeight = 0;
972 double closedColumnsHeight = 0;
974 for (
int i = 0; i < atomList.size(); i++ )
976 Atom atom = atomList[i];
977 double currentHeight = currentColumnHeight;
982 currentHeight += atom.
size.height();
985 avgColumnHeight = ( totalHeight - closedColumnsHeight ) / (
mColumnCount - currentColumn );
986 if (( currentHeight - avgColumnHeight ) > atom.
size.height() / 2
987 && currentColumnAtomCount > 0
988 && currentHeight > maxAtomHeight
989 && currentHeight > maxColumnHeight
994 currentColumnAtomCount = 0;
995 closedColumnsHeight += currentColumnHeight;
996 currentColumnHeight = atom.
size.height();
1000 currentColumnHeight = currentHeight;
1002 atomList[i].column = currentColumn;
1003 currentColumnAtomCount++;
1004 maxColumnHeight = qMax( currentColumnHeight, maxColumnHeight );
1010 QMap<QString, qreal> maxSymbolWidth;
1011 for (
int i = 0; i < atomList.size(); i++ )
1013 for (
int j = 0; j < atomList[i].nucleons.size(); j++ )
1016 if ( !item )
continue;
1021 QString key = QString(
"%1-%2" ).arg(( qulonglong )item->parent() ).arg( atomList[i].column );
1022 maxSymbolWidth[key] = qMax( atomList[i].nucleons[j].symbolSize.width(), maxSymbolWidth[key] );
1026 for (
int i = 0; i < atomList.size(); i++ )
1028 for (
int j = 0; j < atomList[i].nucleons.size(); j++ )
1031 if ( !item )
continue;
1036 QString key = QString(
"%1-%2" ).arg(( qulonglong )item->parent() ).arg( atomList[i].column );
1039 atomList[i].nucleons[j].labelXOffset = maxSymbolWidth[key] + space;
1040 atomList[i].nucleons[j].size.rwidth() = maxSymbolWidth[key] + space + atomList[i].nucleons[j].labelSize.width();
Base class for all map layer types.
QgsComposerLegendStyle style(QgsComposerLegendStyle::Style s) const
Returns style.
double mWmsLegendWidth
Width of WMS legendGraphic pixmap.
double fontHeightCharacterMM(const QFont &font, const QChar &c) const
Returns the font height of a character in millimeters.
double mColumnSpace
Space between columns.
void readXML(const QDomElement &elem, const QDomDocument &doc)
double mapUnitsToMM() const
Returns the conversion factor map units -> mm.
void setMargin(Side side, double margin)
double mWmsLegendHeight
Height of WMS legendGraphic pixmap.
bool writeXML(QDomElement &elem, QDomDocument &doc) const
stores state in Dom node
void drawPreviewIcon(QPainter *painter, QSize size)
Nucleon is either group title, layer title or layer child item.
A item that forms part of a map composition.
QgsMapRenderer * mapRenderer()
Returns pointer to map renderer of qgis map canvas.
QgsLegendModel mLegendModel
virtual void drawFrame(QPainter *p)
Draw black frame around item.
A non GUI class for rendering a map layer set onto a QPainter.
int mColumnCount
Number of legend columns.
void updateLegend()
Updates the model and all legend entries.
double mlineSpacing
Spacing between lines when wrapped.
QStringList splitStringForWrapping(QString stringToSplt)
Splits a string using the wrap char taking into account handling empty wrap char which means no wrapp...
void adjustBoxSize()
Sets item box to the whole content.
QSizeF drawLayerItemTitle(QgsComposerLayerItem *layerItem, QPainter *painter=0, QPointF point=QPointF())
Draws a layer item and all subitems.
void itemChanged()
Used e.g.
bool _readXML(const QDomElement &itemElem, const QDomDocument &doc)
Reads parameter that are not subclass specific in document.
double fontDescentMillimeters(const QFont &font) const
Returns the font ascent in Millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCAL...
QSizeF drawGroupItemTitle(QgsComposerGroupItem *groupItem, QPainter *painter=0, QPointF point=QPointF())
Draws a group item and all subitems Returns list of sizes of layers and groups including this group...
QList< Atom > createAtomList(QStandardItem *rootItem, bool splitLayer)
Create list of atoms according to current layer splitting mode.
double mSymbolHeight
Height of symbol icon.
const QgsComposerMap * mComposerMap
Reference to map (because symbols are sometimes in map units)
void setLayerSet(const QStringList &layerIds, double scaleDenominator=-1, QString rule="")
virtual void drawSelectionBoxes(QPainter *p)
Draw selection boxes around item.
double textWidthMillimeters(const QFont &font, const QString &text) const
Returns the font width in millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCALE...
QStringList layerIdList() const
Helper function that lists ids of layers contained in map canvas.
void setComposerMap(const QgsComposerMap *map)
void synchronizeWithModel()
Data changed.
void setStyleFont(QgsComposerLegendStyle::Style s, const QFont &f)
Set style font.
void setSize(double size)
void drawText(QPainter *p, double x, double y, const QString &text, const QFont &font) const
Draws Text.
QSizeF drawTitle(QPainter *painter=0, QPointF point=QPointF(), Qt::AlignmentFlag halignment=Qt::AlignLeft)
bool writeXML(QDomElement &composerLegendElem, QDomDocument &doc) const
QgsComposition * mComposition
void setColumns(QList< Atom > &atomList)
Divide atoms to columns and set columns on atoms.
Graphics scene for map printing.
QFont styleFont(QgsComposerLegendStyle::Style s) const
Abstract base class for the legend item types.
Object representing map window.
QSizeF paintAndDetermineSize(QPainter *painter)
Paints the legend and calculates its size.
void invalidateCurrentMap()
Sets mCompositionMap to 0 if the map is deleted.
bool readXML(const QDomElement &legendModelElem, const QDomDocument &doc)
QgsComposerLegendStyle & rstyle(QgsComposerLegendStyle::Style s)
Returns reference to modifiable style.
void writeXML(QString name, QDomElement &elem, QDomDocument &doc) const
int id() const
Get identification number.
Composer legend components style.
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
bool _writeXML(QDomElement &itemElem, QDomDocument &doc) const
Writes parameter that are not subclass specific in document.
void setStyleMargin(QgsComposerLegendStyle::Style s, double margin)
Set style margin.
qreal mBoxSpace
Space between item box and contents.
Nucleon drawSymbolItem(QgsComposerLegendItem *symbolItem, QPainter *painter=0, QPointF point=QPointF(), double labelXOffset=0.)
virtual void drawBackground(QPainter *p)
Draw background.
double spaceAboveAtom(Atom atom)
QgsComposerLegendStyle::Style style() const
virtual void setSceneRect(const QRectF &rectangle)
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
virtual ItemType itemType() const =0
QgsSymbolV2::OutputUnit outputUnit() const
void setStyle(QgsComposerLegendStyle::Style s, const QgsComposerLegendStyle style)
bool mEqualColumnWidth
Use the same width (maximum) for all columns.
QSizeF drawAtom(Atom atom, QPainter *painter=0, QPointF point=QPointF())
Draw atom and return its actual size, the atom is drawn with the space above it so that first atoms i...
QgsMapLayer * mapLayer(QString theLayerId)
Retrieve a pointer to a loaded layer by id.
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget)
Reimplementation of QCanvasItem::paint.
Atom is indivisible set (indivisible into more columns).
QgsComposerLegendItem * item
bool mSplitLayer
Allow splitting layers into multiple columns.
const QgsComposerMap * getComposerMapById(int id) const
Returns the composer map with specified id.
virtual int type() const
return correct graphics item type.
double mSymbolWidth
Width of symbol icon.
QStringList & layerSet()
returns current layer set
QList< Nucleon > nucleons
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
sets state from Dom document
void setOutputUnit(QgsSymbolV2::OutputUnit u)
double fontAscentMillimeters(const QFont &font) const
Returns the font ascent in Millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCAL...
void drawSymbolV2(QPainter *p, QgsSymbolV2 *s, double currentYCoord, double ¤tXPosition, double &symbolHeight) const
Draws a symbol at the current y position and returns the new x position.
void setFont(const QFont &font)