Skip to content

Commit a326224

Browse files
committed
Flip symbology from alpha/transparency to opacity
1 parent 233a95e commit a326224

27 files changed

+324
-252
lines changed

doc/api_break.dox

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1837,6 +1837,12 @@ QProgressDialog argument will need to be updated using manually created connecti
18371837
signals and the updates to the progress dialog.
18381838

18391839

1840+
QgsRasterFillSymbolLayer {#qgis_api_break_3_0_QgsRasterFillSymbolLayer}
1841+
-----------------
1842+
1843+
- alpha() and setAlpha() were removed. Use opacity() and setOpacity() instead.
1844+
1845+
18401846
QgsRasterInterface {#qgis_api_break_3_0_QgsRasterInterface}
18411847
------------------
18421848

@@ -2108,6 +2114,7 @@ than an integer value
21082114
- usedAttributes() now requires a QgsRenderContext argument.
21092115
- setDataDefinedAngle(), dataDefinedAngle(), setDataDefinedSize(), dataDefinedSize(), setDataDefinedWidth() and dataDefinedWidth()
21102116
now work with QgsProperty objects instead of QgsDataDefined.
2117+
- alpha() and setAlpha() were removed. Use opacity() and setOpacity() instead.
21112118

21122119

21132120
QgsSymbolLayer (renamed from QgsSymbolLayerV2) {#qgis_api_break_3_0_QgsSymbolLayer}
@@ -2146,6 +2153,7 @@ QgsSymbolRenderContext (renamed from QgsSymbolV2RenderContext) {#qgis_api
21462153
- The constructor, setRenderHints() and renderHints() now accept and return a QgsSymbol::RenderHints flag rather
21472154
than an integer value
21482155
- fields() now returns a QgsFields value, not a pointer.
2156+
- alpha() and setAlpha() were removed. Use opacity() and setOpacity() instead.
21492157

21502158

21512159
QgsSymbolLayerUtils (renamed from QgsSymbolLayerUtilsV2) {#qgis_api_break_3_0_QgsSymbolLayerUtils}

python/core/symbology-ng/qgsfillsymbollayer.sip

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -550,16 +550,8 @@ class QgsRasterFillSymbolLayer: QgsImageFillSymbolLayer
550550
*/
551551
FillCoordinateMode coordinateMode() const;
552552

553-
/** Sets the opacity for the raster image used in the fill.
554-
* @param alpha opacity value between 0 (fully transparent) and 1 (fully opaque)
555-
* @see alpha
556-
*/
557-
void setAlpha( const double alpha );
558-
/** The opacity for the raster image used in the fill.
559-
* @returns opacity value between 0 (fully transparent) and 1 (fully opaque)
560-
* @see setAlpha
561-
*/
562-
double alpha() const;
553+
void setOpacity( const double opacity );
554+
double opacity() const;
563555

564556
/** Sets the offset for the fill.
565557
* @param offset offset for fill

python/core/symbology-ng/qgssymbol.sip

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,8 @@ class QgsSymbol
175175
QgsMapUnitScale mapUnitScale() const;
176176
void setMapUnitScale( const QgsMapUnitScale &scale );
177177

178-
//! Get alpha transparency 1 for opaque, 0 for invisible
179-
qreal alpha() const;
180-
//! Set alpha transparency 1 for opaque, 0 for invisible
181-
void setAlpha( qreal alpha );
178+
qreal opacity() const;
179+
void setOpacity( qreal opacity );
182180

183181
/** Sets rendering hint flags for the symbol.
184182
* @see renderHints()
@@ -303,17 +301,7 @@ class QgsSymbolRenderContext
303301

304302
public:
305303

306-
/** Constructor for QgsSymbolRenderContext
307-
* @param c
308-
* @param u
309-
* @param alpha
310-
* @param selected set to true if symbol should be drawn in a "selected" state
311-
* @param renderHints flags controlling rendering behavior
312-
* @param f
313-
* @param fields
314-
* @param mapUnitScale
315-
*/
316-
QgsSymbolRenderContext( QgsRenderContext &c, QgsUnitTypes::RenderUnit u, qreal alpha = 1.0, bool selected = false, QgsSymbol::RenderHints renderHints = 0, const QgsFeature *f = 0, const QgsFields &fields = QgsFields(), const QgsMapUnitScale &mapUnitScale = QgsMapUnitScale() );
304+
QgsSymbolRenderContext( QgsRenderContext &c, QgsUnitTypes::RenderUnit u, qreal opacity = 1.0, bool selected = false, QgsSymbol::RenderHints renderHints = 0, const QgsFeature *f = 0, const QgsFields &fields = QgsFields(), const QgsMapUnitScale &mapUnitScale = QgsMapUnitScale() );
317305
~QgsSymbolRenderContext();
318306

319307
QgsRenderContext &renderContext();
@@ -335,10 +323,8 @@ class QgsSymbolRenderContext
335323
QgsMapUnitScale mapUnitScale() const;
336324
void setMapUnitScale( const QgsMapUnitScale &scale );
337325

338-
//! Get alpha transparency 1 for opaque, 0 for invisible
339-
qreal alpha() const;
340-
//! Set alpha transparency 1 for opaque, 0 for invisible
341-
void setAlpha( qreal alpha );
326+
qreal opacity() const;
327+
void setOpacity( qreal opacity );
342328

343329
bool selected() const;
344330
void setSelected( bool selected );

python/gui/symbology-ng/qgssymbolslistwidget.sip

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ class QgsSymbolsListWidget : QWidget
3535
void saveSymbol();
3636
void symbolAddedToStyle( const QString &name, QgsSymbol *symbol );
3737
void on_mSymbolUnitWidget_changed();
38-
void on_mTransparencySlider_valueChanged( int value );
3938

4039
//! Pupulates the groups combo box with available tags and smartgroups
4140
void populateGroups();

src/app/qgsprojectproperties.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,7 +1133,7 @@ void QgsProjectProperties::apply()
11331133
QgsProject::instance()->writeEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Line" ), cboStyleLine->currentText() );
11341134
QgsProject::instance()->writeEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Fill" ), cboStyleFill->currentText() );
11351135
QgsProject::instance()->writeEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/ColorRamp" ), cboStyleColorRamp->currentText() );
1136-
QgsProject::instance()->writeEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/AlphaInt" ), ( int )( 255 - ( mTransparencySlider->value() * 2.55 ) ) );
1136+
QgsProject::instance()->writeEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Opacity" ), 1.0 - mTransparencySlider->value() / 100.0 );
11371137
QgsProject::instance()->writeEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/RandomColors" ), cbxStyleRandomColors->isChecked() );
11381138
if ( mTreeProjectColors->isDirty() )
11391139
{
@@ -1687,7 +1687,15 @@ void QgsProjectProperties::populateStyles()
16871687
cbxStyleRandomColors->setChecked( QgsProject::instance()->readBoolEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/RandomColors" ), true ) );
16881688

16891689
// alpha transparency
1690-
int transparencyInt = ( 255 - QgsProject::instance()->readNumEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/AlphaInt" ), 255 ) ) / 2.55;
1690+
int transparencyInt = 255;
1691+
bool ok = false;
1692+
double alpha = QgsProject::instance()->readDoubleEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/AlphaInt" ), 255, &ok );
1693+
if ( ok )
1694+
transparencyInt = alpha;
1695+
double newOpacity = QgsProject::instance()->readDoubleEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Opacity" ), 1.0, &ok );
1696+
if ( ok )
1697+
transparencyInt = 255 - newOpacity * 255.0;
1698+
16911699
mTransparencySlider->setValue( transparencyInt );
16921700
}
16931701

src/core/composer/qgscomposermapoverview.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ void QgsComposerMapOverview::createDefaultFrameSymbol()
5858
properties.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) );
5959
properties.insert( QStringLiteral( "style_border" ), QStringLiteral( "no" ) );
6060
mFrameSymbol = QgsFillSymbol::createSimple( properties );
61-
mFrameSymbol->setAlpha( 0.3 );
61+
mFrameSymbol->setOpacity( 0.3 );
6262
}
6363

6464
QgsComposerMapOverview::~QgsComposerMapOverview()

src/core/dxf/qgsdxfexport.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -897,7 +897,7 @@ void QgsDxfExport::writeBlocks()
897897
continue;
898898

899899
// if point symbol layer and no data defined properties: write block
900-
QgsSymbolRenderContext ctx( ct, QgsUnitTypes::RenderMapUnits, slIt->second->alpha(), false, slIt->second->renderHints(), nullptr );
900+
QgsSymbolRenderContext ctx( ct, QgsUnitTypes::RenderMapUnits, slIt->second->opacity(), false, slIt->second->renderHints(), nullptr );
901901
ml->startRender( ctx );
902902

903903
// markers with data defined properties are inserted inline

src/core/symbology-ng/qgsfillsymbollayer.cpp

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -232,20 +232,20 @@ QString QgsSimpleFillSymbolLayer::layerType() const
232232
void QgsSimpleFillSymbolLayer::startRender( QgsSymbolRenderContext &context )
233233
{
234234
QColor fillColor = mColor;
235-
fillColor.setAlphaF( context.alpha() * mColor.alphaF() );
235+
fillColor.setAlphaF( context.opacity() * mColor.alphaF() );
236236
mBrush = QBrush( fillColor, mBrushStyle );
237237

238238
QColor selColor = context.renderContext().selectionColor();
239239
QColor selPenColor = selColor == mColor ? selColor : mStrokeColor;
240-
if ( ! SELECTION_IS_OPAQUE ) selColor.setAlphaF( context.alpha() );
240+
if ( ! SELECTION_IS_OPAQUE ) selColor.setAlphaF( context.opacity() );
241241
mSelBrush = QBrush( selColor );
242242
// N.B. unless a "selection line color" is implemented in addition to the "selection color" option
243243
// this would mean symbols with "no fill" look the same whether or not they are selected
244244
if ( SELECT_FILL_STYLE )
245245
mSelBrush.setStyle( mBrushStyle );
246246

247247
QColor strokeColor = mStrokeColor;
248-
strokeColor.setAlphaF( context.alpha() * mStrokeColor.alphaF() );
248+
strokeColor.setAlphaF( context.opacity() * mStrokeColor.alphaF() );
249249
mPen = QPen( strokeColor );
250250
mSelPen = QPen( selPenColor );
251251
mPen.setStyle( mStrokeStyle );
@@ -767,9 +767,9 @@ void QgsGradientFillSymbolLayer::applyGradient( const QgsSymbolRenderContext &co
767767
{
768768
//update alpha of gradient colors
769769
QColor fillColor = color;
770-
fillColor.setAlphaF( context.alpha() * fillColor.alphaF() );
770+
fillColor.setAlphaF( context.opacity() * fillColor.alphaF() );
771771
QColor fillColor2 = color2;
772-
fillColor2.setAlphaF( context.alpha() * fillColor2.alphaF() );
772+
fillColor2.setAlphaF( context.opacity() * fillColor2.alphaF() );
773773

774774
//rotate reference points
775775
QPointF rotatedReferencePoint1 = !qgsDoubleNear( angle, 0.0 ) ? rotateReferencePoint( referencePoint1, angle ) : referencePoint1;
@@ -817,7 +817,7 @@ void QgsGradientFillSymbolLayer::applyGradient( const QgsSymbolRenderContext &co
817817
{
818818
//color ramp gradient
819819
QgsGradientColorRamp *gradRamp = static_cast<QgsGradientColorRamp *>( gradientRamp );
820-
gradRamp->addStopsToGradient( &gradient, context.alpha() );
820+
gradRamp->addStopsToGradient( &gradient, context.opacity() );
821821
}
822822
else
823823
{
@@ -833,7 +833,8 @@ void QgsGradientFillSymbolLayer::applyGradient( const QgsSymbolRenderContext &co
833833
void QgsGradientFillSymbolLayer::startRender( QgsSymbolRenderContext &context )
834834
{
835835
QColor selColor = context.renderContext().selectionColor();
836-
if ( ! SELECTION_IS_OPAQUE ) selColor.setAlphaF( context.alpha() );
836+
if ( ! SELECTION_IS_OPAQUE )
837+
selColor.setAlphaF( context.opacity() );
837838
mSelBrush = QBrush( selColor );
838839
}
839840

@@ -1125,7 +1126,8 @@ void QgsShapeburstFillSymbolLayer::startRender( QgsSymbolRenderContext &context
11251126
{
11261127
//TODO - check this
11271128
QColor selColor = context.renderContext().selectionColor();
1128-
if ( ! SELECTION_IS_OPAQUE ) selColor.setAlphaF( context.alpha() );
1129+
if ( ! SELECTION_IS_OPAQUE )
1130+
selColor.setAlphaF( context.opacity() );
11291131
mSelBrush = QBrush( selColor );
11301132
}
11311133

@@ -1237,7 +1239,7 @@ void QgsShapeburstFillSymbolLayer::renderPolygon( const QPolygonF &points, QList
12371239

12381240
//copy distance transform values back to QImage, shading by appropriate color ramp
12391241
dtArrayToQImage( dtArray, fillImage, mColorType == QgsShapeburstFillSymbolLayer::SimpleTwoColor ? mTwoColorGradientRamp : mGradientRamp,
1240-
context.alpha(), useWholeShape, outputPixelMaxDist );
1242+
context.opacity(), useWholeShape, outputPixelMaxDist );
12411243

12421244
//clean up some variables
12431245
delete [] dtArray;
@@ -1962,10 +1964,10 @@ void QgsSVGFillSymbolLayer::applyPattern( QBrush &brush, const QString &svgFileP
19621964
}
19631965

19641966
QTransform brushTransform;
1965-
if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
1967+
if ( !qgsDoubleNear( context.opacity(), 1.0 ) )
19661968
{
19671969
QImage transparentImage = fitsInCache ? patternImage.copy() : mSvgPattern->copy();
1968-
QgsSymbolLayerUtils::multiplyImageOpacity( &transparentImage, context.alpha() );
1970+
QgsSymbolLayerUtils::multiplyImageOpacity( &transparentImage, context.opacity() );
19691971
brush.setTextureImage( transparentImage );
19701972
}
19711973
else
@@ -2771,10 +2773,10 @@ void QgsLinePatternFillSymbolLayer::applyPattern( const QgsSymbolRenderContext &
27712773
patternImage = patternImage.copy( xBuffer, yBuffer, patternImage.width() - 2 * xBuffer, patternImage.height() - 2 * yBuffer );
27722774

27732775
//set image to mBrush
2774-
if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
2776+
if ( !qgsDoubleNear( context.opacity(), 1.0 ) )
27752777
{
27762778
QImage transparentImage = patternImage.copy();
2777-
QgsSymbolLayerUtils::multiplyImageOpacity( &transparentImage, context.alpha() );
2779+
QgsSymbolLayerUtils::multiplyImageOpacity( &transparentImage, context.opacity() );
27782780
brush.setTextureImage( transparentImage );
27792781
}
27802782
else
@@ -3185,10 +3187,10 @@ void QgsPointPatternFillSymbolLayer::applyPattern( const QgsSymbolRenderContext
31853187
mMarkerSymbol->stopRender( pointRenderContext );
31863188
}
31873189

3188-
if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
3190+
if ( !qgsDoubleNear( context.opacity(), 1.0 ) )
31893191
{
31903192
QImage transparentImage = patternImage.copy();
3191-
QgsSymbolLayerUtils::multiplyImageOpacity( &transparentImage, context.alpha() );
3193+
QgsSymbolLayerUtils::multiplyImageOpacity( &transparentImage, context.opacity() );
31923194
brush.setTextureImage( transparentImage );
31933195
}
31943196
else
@@ -3418,7 +3420,7 @@ QColor QgsCentroidFillSymbolLayer::color() const
34183420

34193421
void QgsCentroidFillSymbolLayer::startRender( QgsSymbolRenderContext &context )
34203422
{
3421-
mMarker->setAlpha( context.alpha() );
3423+
mMarker->setOpacity( context.opacity() );
34223424
mMarker->startRender( context.renderContext(), context.fields() );
34233425

34243426
mCurrentFeatureId = -1;
@@ -3590,7 +3592,6 @@ QgsRasterFillSymbolLayer::QgsRasterFillSymbolLayer( const QString &imageFilePath
35903592
: QgsImageFillSymbolLayer()
35913593
, mImageFilePath( imageFilePath )
35923594
, mCoordinateMode( QgsRasterFillSymbolLayer::Feature )
3593-
, mAlpha( 1.0 )
35943595
, mOffsetUnit( QgsUnitTypes::RenderMillimeters )
35953596
, mWidth( 0.0 )
35963597
, mWidthUnit( QgsUnitTypes::RenderPixels )
@@ -3633,7 +3634,7 @@ QgsSymbolLayer *QgsRasterFillSymbolLayer::create( const QgsStringMap &properties
36333634
}
36343635
QgsRasterFillSymbolLayer *symbolLayer = new QgsRasterFillSymbolLayer( imagePath );
36353636
symbolLayer->setCoordinateMode( mode );
3636-
symbolLayer->setAlpha( alpha );
3637+
symbolLayer->setOpacity( alpha );
36373638
symbolLayer->setOffset( offset );
36383639
symbolLayer->setAngle( angle );
36393640
symbolLayer->setWidth( width );
@@ -3701,7 +3702,7 @@ void QgsRasterFillSymbolLayer::renderPolygon( const QPolygonF &points, QList<QPo
37013702

37023703
void QgsRasterFillSymbolLayer::startRender( QgsSymbolRenderContext &context )
37033704
{
3704-
applyPattern( mBrush, mImageFilePath, mWidth, mAlpha, context );
3705+
applyPattern( mBrush, mImageFilePath, mWidth, mOpacity, context );
37053706
}
37063707

37073708
void QgsRasterFillSymbolLayer::stopRender( QgsSymbolRenderContext &context )
@@ -3714,7 +3715,7 @@ QgsStringMap QgsRasterFillSymbolLayer::properties() const
37143715
QgsStringMap map;
37153716
map[QStringLiteral( "imageFile" )] = mImageFilePath;
37163717
map[QStringLiteral( "coordinate_mode" )] = QString::number( mCoordinateMode );
3717-
map[QStringLiteral( "alpha" )] = QString::number( mAlpha );
3718+
map[QStringLiteral( "alpha" )] = QString::number( mOpacity );
37183719
map[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
37193720
map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
37203721
map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
@@ -3729,7 +3730,7 @@ QgsRasterFillSymbolLayer *QgsRasterFillSymbolLayer::clone() const
37293730
{
37303731
QgsRasterFillSymbolLayer *sl = new QgsRasterFillSymbolLayer( mImageFilePath );
37313732
sl->setCoordinateMode( mCoordinateMode );
3732-
sl->setAlpha( mAlpha );
3733+
sl->setOpacity( mOpacity );
37333734
sl->setOffset( mOffset );
37343735
sl->setOffsetUnit( mOffsetUnit );
37353736
sl->setOffsetMapUnitScale( mOffsetMapUnitScale );
@@ -3757,9 +3758,9 @@ void QgsRasterFillSymbolLayer::setCoordinateMode( const QgsRasterFillSymbolLayer
37573758
mCoordinateMode = mode;
37583759
}
37593760

3760-
void QgsRasterFillSymbolLayer::setAlpha( const double alpha )
3761+
void QgsRasterFillSymbolLayer::setOpacity( const double opacity )
37613762
{
3762-
mAlpha = alpha;
3763+
mOpacity = opacity;
37633764
}
37643765

37653766
void QgsRasterFillSymbolLayer::applyDataDefinedSettings( QgsSymbolRenderContext &context )
@@ -3769,10 +3770,10 @@ void QgsRasterFillSymbolLayer::applyDataDefinedSettings( QgsSymbolRenderContext
37693770

37703771
bool hasWidthExpression = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth );
37713772
bool hasFileExpression = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFile );
3772-
bool hasAlphaExpression = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyAlpha );
3773+
bool hasOpacityExpression = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyOpacity );
37733774
bool hasAngleExpression = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyAngle );
37743775

3775-
if ( !hasWidthExpression && !hasAngleExpression && !hasAlphaExpression && !hasFileExpression )
3776+
if ( !hasWidthExpression && !hasAngleExpression && !hasOpacityExpression && !hasFileExpression )
37763777
{
37773778
return; //no data defined settings
37783779
}
@@ -3786,7 +3787,7 @@ void QgsRasterFillSymbolLayer::applyDataDefinedSettings( QgsSymbolRenderContext
37863787
mNextAngle = nextAngle;
37873788
}
37883789

3789-
if ( !hasWidthExpression && !hasAlphaExpression && !hasFileExpression )
3790+
if ( !hasWidthExpression && !hasOpacityExpression && !hasFileExpression )
37903791
{
37913792
return; //nothing further to do
37923793
}
@@ -3797,19 +3798,19 @@ void QgsRasterFillSymbolLayer::applyDataDefinedSettings( QgsSymbolRenderContext
37973798
context.setOriginalValueVariable( mWidth );
37983799
width = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyWidth, context.renderContext().expressionContext(), width );
37993800
}
3800-
double alpha = mAlpha;
3801-
if ( hasAlphaExpression )
3801+
double opacity = mOpacity;
3802+
if ( hasOpacityExpression )
38023803
{
3803-
context.setOriginalValueVariable( mAlpha );
3804-
alpha = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyAlpha, context.renderContext().expressionContext(), alpha );
3804+
context.setOriginalValueVariable( mOpacity );
3805+
opacity = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyOpacity, context.renderContext().expressionContext(), opacity * 100 ) / 100.0;
38053806
}
38063807
QString file = mImageFilePath;
38073808
if ( hasFileExpression )
38083809
{
38093810
context.setOriginalValueVariable( mImageFilePath );
38103811
file = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyFile, context.renderContext().expressionContext(), file );
38113812
}
3812-
applyPattern( mBrush, file, width, alpha, context );
3813+
applyPattern( mBrush, file, width, opacity, context );
38133814
}
38143815

38153816
void QgsRasterFillSymbolLayer::applyPattern( QBrush &brush, const QString &imageFilePath, const double width, const double alpha, const QgsSymbolRenderContext &context )

0 commit comments

Comments
 (0)