Quantum GIS API Documentation  1.7.5-Wroclaw
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
qgssymbollayerv2utils.cpp
Go to the documentation of this file.
1 
3 
4 #include "qgssymbollayerv2.h"
6 #include "qgssymbolv2.h"
7 #include "qgsvectorcolorrampv2.h"
8 
9 #include "qgslogger.h"
10 #include "qgsrendercontext.h"
11 
12 #include <QColor>
13 #include <QDomNode>
14 #include <QDomElement>
15 #include <QIcon>
16 #include <QPainter>
17 
18 QString QgsSymbolLayerV2Utils::encodeColor( QColor color )
19 {
20  return QString( "%1,%2,%3,%4" ).arg( color.red() ).arg( color.green() ).arg( color.blue() ).arg( color.alpha() );
21 }
22 
24 {
25  QStringList lst = str.split( "," );
26  if ( lst.count() < 3 )
27  {
28  return QColor();
29  }
30  int red, green, blue, alpha;
31  red = lst[0].toInt();
32  green = lst[1].toInt();
33  blue = lst[2].toInt();
34  alpha = 255;
35  if ( lst.count() > 3 )
36  {
37  alpha = lst[3].toInt();
38  }
39  return QColor( red, green, blue, alpha );
40 }
41 
42 QString QgsSymbolLayerV2Utils::encodePenStyle( Qt::PenStyle style )
43 {
44  switch ( style )
45  {
46  case Qt::NoPen: return "no";
47  case Qt::SolidLine: return "solid";
48  case Qt::DashLine: return "dash";
49  case Qt::DotLine: return "dot";
50  case Qt::DashDotLine: return "dash dot";
51  case Qt::DashDotDotLine: return "dash dot dot";
52  default: return "???";
53  }
54 }
55 
56 Qt::PenStyle QgsSymbolLayerV2Utils::decodePenStyle( QString str )
57 {
58  if ( str == "no" ) return Qt::NoPen;
59  if ( str == "solid" ) return Qt::SolidLine;
60  if ( str == "dash" ) return Qt::DashLine;
61  if ( str == "dot" ) return Qt::DotLine;
62  if ( str == "dash dot" ) return Qt::DashDotLine;
63  if ( str == "dash dot dot" ) return Qt::DashDotDotLine;
64  return Qt::SolidLine;
65 }
66 
67 QString QgsSymbolLayerV2Utils::encodePenJoinStyle( Qt::PenJoinStyle style )
68 {
69  switch ( style )
70  {
71  case Qt::BevelJoin: return "bevel";
72  case Qt::MiterJoin: return "miter";
73  case Qt::RoundJoin: return "round";
74  default: return "???";
75  }
76 }
77 
78 Qt::PenJoinStyle QgsSymbolLayerV2Utils::decodePenJoinStyle( QString str )
79 {
80  if ( str == "bevel" ) return Qt::BevelJoin;
81  if ( str == "miter" ) return Qt::MiterJoin;
82  if ( str == "round" ) return Qt::RoundJoin;
83  return Qt::BevelJoin;
84 }
85 
86 QString QgsSymbolLayerV2Utils::encodePenCapStyle( Qt::PenCapStyle style )
87 {
88  switch ( style )
89  {
90  case Qt::SquareCap: return "square";
91  case Qt::FlatCap: return "flat";
92  case Qt::RoundCap: return "round";
93  default: return "???";
94  }
95 }
96 
97 Qt::PenCapStyle QgsSymbolLayerV2Utils::decodePenCapStyle( QString str )
98 {
99  if ( str == "square" ) return Qt::SquareCap;
100  if ( str == "flat" ) return Qt::FlatCap;
101  if ( str == "round" ) return Qt::RoundCap;
102  return Qt::SquareCap;
103 }
104 
105 
106 QString QgsSymbolLayerV2Utils::encodeBrushStyle( Qt::BrushStyle style )
107 {
108  switch ( style )
109  {
110  case Qt::SolidPattern : return "solid";
111  case Qt::HorPattern : return "horizontal";
112  case Qt::VerPattern : return "vertical";
113  case Qt::CrossPattern : return "cross";
114  case Qt::BDiagPattern : return "b_diagonal";
115  case Qt::FDiagPattern : return "f_diagonal";
116  case Qt::DiagCrossPattern : return "diagonal_x";
117  case Qt::Dense1Pattern : return "dense1";
118  case Qt::Dense2Pattern : return "dense2";
119  case Qt::Dense3Pattern : return "dense3";
120  case Qt::Dense4Pattern : return "dense4";
121  case Qt::Dense5Pattern : return "dense5";
122  case Qt::Dense6Pattern : return "dense6";
123  case Qt::Dense7Pattern : return "dense7";
124  case Qt::NoBrush : return "no";
125  default: return "???";
126  }
127 }
128 
129 Qt::BrushStyle QgsSymbolLayerV2Utils::decodeBrushStyle( QString str )
130 {
131  if ( str == "solid" ) return Qt::SolidPattern;
132  if ( str == "horizontal" ) return Qt::HorPattern;
133  if ( str == "vertical" ) return Qt::VerPattern;
134  if ( str == "cross" ) return Qt::CrossPattern;
135  if ( str == "b_diagonal" ) return Qt::BDiagPattern;
136  if ( str == "f_diagonal" ) return Qt::FDiagPattern;
137  if ( str == "diagonal_x" ) return Qt::DiagCrossPattern;
138  if ( str == "dense1" ) return Qt::Dense1Pattern;
139  if ( str == "dense2" ) return Qt::Dense2Pattern;
140  if ( str == "dense3" ) return Qt::Dense3Pattern;
141  if ( str == "dense4" ) return Qt::Dense4Pattern;
142  if ( str == "dense5" ) return Qt::Dense5Pattern;
143  if ( str == "dense6" ) return Qt::Dense6Pattern;
144  if ( str == "dense7" ) return Qt::Dense7Pattern;
145  if ( str == "no" ) return Qt::NoBrush;
146  return Qt::SolidPattern;
147 }
148 
149 QString QgsSymbolLayerV2Utils::encodePoint( QPointF point )
150 {
151  return QString( "%1,%2" ).arg( point.x() ).arg( point.y() );
152 }
153 
155 {
156  QStringList lst = str.split( ',' );
157  if ( lst.count() != 2 )
158  return QPointF( 0, 0 );
159  return QPointF( lst[0].toDouble(), lst[1].toDouble() );
160 }
161 
163 {
164  switch ( unit )
165  {
166  case QgsSymbolV2::MM:
167  return "MM";
169  return "MapUnit";
170  default:
171  return "MM";
172  }
173 }
174 
176 {
177  if ( str == "MM" )
178  {
179  return QgsSymbolV2::MM;
180  }
181  else if ( str == "MapUnit" )
182  {
183  return QgsSymbolV2::MapUnit;
184  }
185 
186  // milimeters are default
187  return QgsSymbolV2::MM;
188 }
189 
190 QString QgsSymbolLayerV2Utils::encodeRealVector( const QVector<qreal>& v )
191 {
192  QString vectorString;
193  QVector<qreal>::const_iterator it = v.constBegin();
194  for ( ; it != v.constEnd(); ++it )
195  {
196  if ( it != v.constBegin() )
197  {
198  vectorString.append( ";" );
199  }
200  vectorString.append( QString::number( *it ) );
201  }
202  return vectorString;
203 }
204 
205 QVector<qreal> QgsSymbolLayerV2Utils::decodeRealVector( const QString& s )
206 {
207  QVector<qreal> resultVector;
208 
209  QStringList realList = s.split( ";" );
210  QStringList::const_iterator it = realList.constBegin();
211  for ( ; it != realList.constEnd(); ++it )
212  {
213  resultVector.append( it->toDouble() );
214  }
215 
216  return resultVector;
217 }
218 
220 {
221  return QIcon( symbolPreviewPixmap( symbol, size ) );
222 }
223 
225 {
226  Q_ASSERT( symbol );
227 
228  QPixmap pixmap( size );
229  pixmap.fill( Qt::transparent );
230  QPainter painter;
231  painter.begin( &pixmap );
232  painter.setRenderHint( QPainter::Antialiasing );
233  symbol->drawPreviewIcon( &painter, size );
234  painter.end();
235  return pixmap;
236 }
237 
238 
240 {
241  QPixmap pixmap( size );
242  pixmap.fill( Qt::transparent );
243  QPainter painter;
244  painter.begin( &pixmap );
245  painter.setRenderHint( QPainter::Antialiasing );
246  QgsRenderContext renderContext = createRenderContext( &painter );
247  QgsSymbolV2RenderContext symbolContext( renderContext, u );
248  layer->drawPreviewIcon( symbolContext, size );
249  painter.end();
250  return QIcon( pixmap );
251 }
252 
254 {
255  return QIcon( colorRampPreviewPixmap( ramp, size ) );
256 }
257 
259 {
260  QPixmap pixmap( size );
261  QPainter painter;
262  painter.begin( &pixmap );
263  painter.setRenderHint( QPainter::Antialiasing );
264  painter.eraseRect( QRect( QPoint( 0, 0 ), size ) );
265  for ( int i = 0; i < size.width(); i++ )
266  {
267  QPen pen( ramp->color(( double ) i / size.width() ) );
268  painter.setPen( pen );
269  painter.drawLine( i, 0, i, size.height() - 1 );
270  }
271  painter.end();
272  return pixmap;
273 }
274 
275 
276 #include <QPolygonF>
277 
278 #include <cmath>
279 #include <cfloat>
280 
281 
282 // calculate line's angle and tangent
283 static bool lineInfo( QPointF p1, QPointF p2, double& angle, double& t )
284 {
285  double x1 = p1.x(), y1 = p1.y(), x2 = p2.x(), y2 = p2.y();
286 
287  if ( x1 == x2 && y1 == y2 )
288  return false;
289 
290  // tangent
291  t = ( x1 == x2 ? DBL_MAX : ( y2 - y1 ) / ( x2 - x1 ) );
292 
293  // angle
294  if ( t == DBL_MAX )
295  angle = ( y2 > y1 ? M_PI / 2 : M_PI * 3 / 2 ); // angle is 90 or 270
296  else if ( t == 0 )
297  angle = ( x2 > x1 ? 0 : M_PI ); // angle is 0 or 180
298  else if ( t >= 0 )
299  angle = ( y2 > y1 ? atan( t ) : M_PI + atan( t ) );
300  else // t < 0
301  angle = ( y2 > y1 ? M_PI + atan( t ) : atan( t ) );
302 
303  return true;
304 }
305 
306 // offset a point with an angle and distance
307 static QPointF offsetPoint( QPointF pt, double angle, double dist )
308 {
309  return QPointF( pt.x() + dist * cos( angle ), pt.y() + dist * sin( angle ) );
310 }
311 
312 // calc intersection of two (infinite) lines defined by one point and tangent
313 static QPointF linesIntersection( QPointF p1, double t1, QPointF p2, double t2 )
314 {
315  // parallel lines? (or the difference between angles is less than cca 0.1 degree)
316  if (( t1 == DBL_MAX && t2 == DBL_MAX ) || qAbs( t1 - t2 ) < 0.001 )
317  return QPointF();
318 
319  double x, y;
320  if ( t1 == DBL_MAX || t2 == DBL_MAX )
321  {
322  // in case one line is with angle 90 resp. 270 degrees (tangent undefined)
323  // swap them so that line 2 is with undefined tangent
324  if ( t1 == DBL_MAX )
325  {
326  QPointF pSwp = p1; p1 = p2; p2 = pSwp;
327  double tSwp = t1; t1 = t2; t2 = tSwp;
328  }
329 
330  x = p2.x();
331  }
332  else
333  {
334  // usual case
335  x = (( p1.y() - p2.y() ) + t2 * p2.x() - t1 * p1.x() ) / ( t2 - t1 );
336  }
337 
338  y = p1.y() + t1 * ( x - p1.x() );
339  return QPointF( x, y );
340 }
341 
342 
343 QPolygonF offsetLine( QPolygonF polyline, double dist )
344 {
345  QPolygonF newLine;
346 
347  if ( polyline.count() < 2 )
348  return newLine;
349 
350  double angle = 0.0, t_new, t_old = 0;
351  QPointF pt_old, pt_new;
352  QPointF p1 = polyline[0], p2;
353  bool first_point = true;
354 
355  for ( int i = 1; i < polyline.count(); i++ )
356  {
357  p2 = polyline[i];
358 
359  if ( !lineInfo( p1, p2, angle, t_new ) )
360  continue; // not a line...
361 
362  pt_new = offsetPoint( p1, angle + M_PI / 2, dist );
363 
364  if ( ! first_point )
365  {
366  // if it's not the first line segment
367  // calc intersection with last line (with offset)
368  QPointF pt_tmp = linesIntersection( pt_old, t_old, pt_new, t_new );
369  if ( !pt_tmp.isNull() ) pt_new = pt_tmp;
370  }
371 
372  newLine.append( pt_new );
373 
374  pt_old = pt_new;
375  t_old = t_new;
376  p1 = p2;
377  first_point = false;
378  }
379 
380  // last line segment:
381  pt_new = offsetPoint( p2, angle + M_PI / 2, dist );
382  newLine.append( pt_new );
383  return newLine;
384 }
385 
387 
388 
390 {
391  QgsSymbolLayerV2List layers;
392  QDomNode layerNode = element.firstChild();
393 
394  while ( !layerNode.isNull() )
395  {
396  QDomElement e = layerNode.toElement();
397  if ( !e.isNull() )
398  {
399  if ( e.tagName() != "layer" )
400  {
401  QgsDebugMsg( "unknown tag " + e.tagName() );
402  }
403  else
404  {
405  QgsSymbolLayerV2* layer = loadSymbolLayer( e );
406  if ( layer != NULL )
407  layers.append( layer );
408  }
409  }
410  layerNode = layerNode.nextSibling();
411  }
412 
413  if ( layers.count() == 0 )
414  {
415  QgsDebugMsg( "no layers for symbol" );
416  return NULL;
417  }
418 
419  QString symbolType = element.attribute( "type" );
420 
421  QgsSymbolV2* symbol = 0;
422  if ( symbolType == "line" )
423  symbol = new QgsLineSymbolV2( layers );
424  else if ( symbolType == "fill" )
425  symbol = new QgsFillSymbolV2( layers );
426  else if ( symbolType == "marker" )
427  symbol = new QgsMarkerSymbolV2( layers );
428  else
429  {
430  QgsDebugMsg( "unknown symbol type " + symbolType );
431  return NULL;
432  }
433 
434  symbol->setOutputUnit( decodeOutputUnit( element.attribute( "outputUnit" ) ) );
435  symbol->setAlpha( element.attribute( "alpha", "1.0" ).toDouble() );
436 
437  return symbol;
438 }
439 
441 {
442  QString layerClass = element.attribute( "class" );
443  bool locked = element.attribute( "locked" ).toInt();
444  int pass = element.attribute( "pass" ).toInt();
445 
446  // parse properties
447  QgsStringMap props = parseProperties( element );
448 
449  QgsSymbolLayerV2* layer;
450  layer = QgsSymbolLayerV2Registry::instance()->createSymbolLayer( layerClass, props );
451  if ( layer )
452  {
453  layer->setLocked( locked );
454  layer->setRenderingPass( pass );
455  return layer;
456  }
457  else
458  {
459  QgsDebugMsg( "unknown class " + layerClass );
460  return NULL;
461  }
462 }
463 
465 {
466  switch ( type )
467  {
468  case QgsSymbolV2::Line: return "line";
469  case QgsSymbolV2::Marker: return "marker";
470  case QgsSymbolV2::Fill: return "fill";
471  default: return "";
472  }
473 }
474 
475 QDomElement QgsSymbolLayerV2Utils::saveSymbol( QString name, QgsSymbolV2* symbol, QDomDocument& doc, QgsSymbolV2Map* subSymbols )
476 {
477  Q_ASSERT( symbol );
478 
479  QDomElement symEl = doc.createElement( "symbol" );
480  symEl.setAttribute( "type", _nameForSymbolType( symbol->type() ) );
481  symEl.setAttribute( "name", name );
482  symEl.setAttribute( "outputUnit", encodeOutputUnit( symbol->outputUnit() ) );
483  symEl.setAttribute( "alpha", symbol->alpha() );
484  QgsDebugMsg( "num layers " + QString::number( symbol->symbolLayerCount() ) );
485  for ( int i = 0; i < symbol->symbolLayerCount(); i++ )
486  {
487  QgsSymbolLayerV2* layer = symbol->symbolLayer( i );
488 
489  QDomElement layerEl = doc.createElement( "layer" );
490  layerEl.setAttribute( "class", layer->layerType() );
491  layerEl.setAttribute( "locked", layer->isLocked() );
492  layerEl.setAttribute( "pass", layer->renderingPass() );
493 
494  if ( subSymbols != NULL && layer->subSymbol() != NULL )
495  {
496  QString subname = QString( "@%1@%2" ).arg( name ).arg( i );
497  subSymbols->insert( subname, layer->subSymbol() );
498  }
499 
500  saveProperties( layer->properties(), doc, layerEl );
501  symEl.appendChild( layerEl );
502  }
503 
504  return symEl;
505 }
506 
507 
509 {
510  QgsStringMap props;
511  QDomElement e = element.firstChildElement();
512  while ( !e.isNull() )
513  {
514  if ( e.tagName() != "prop" )
515  {
516  QgsDebugMsg( "unknown tag " + e.tagName() );
517  }
518  else
519  {
520  QString propKey = e.attribute( "k" );
521  QString propValue = e.attribute( "v" );
522  props[propKey] = propValue;
523  }
524  e = e.nextSiblingElement();
525  }
526  return props;
527 }
528 
529 
530 void QgsSymbolLayerV2Utils::saveProperties( QgsStringMap props, QDomDocument& doc, QDomElement& element )
531 {
532  for ( QgsStringMap::iterator it = props.begin(); it != props.end(); ++it )
533  {
534  QDomElement propEl = doc.createElement( "prop" );
535  propEl.setAttribute( "k", it.key() );
536  propEl.setAttribute( "v", it.value() );
537  element.appendChild( propEl );
538  }
539 }
540 
542 {
543  // go through symbols one-by-one and load them
544 
545  QgsSymbolV2Map symbols;
546  QDomElement e = element.firstChildElement();
547 
548  while ( !e.isNull() )
549  {
550  if ( e.tagName() == "symbol" )
551  {
553  if ( symbol != NULL )
554  symbols.insert( e.attribute( "name" ), symbol );
555  }
556  else
557  {
558  QgsDebugMsg( "unknown tag: " + e.tagName() );
559  }
560  e = e.nextSiblingElement();
561  }
562 
563 
564  // now walk through the list of symbols and find those prefixed with @
565  // these symbols are sub-symbols of some other symbol layers
566  // e.g. symbol named "@foo@1" is sub-symbol of layer 1 in symbol "foo"
567  QStringList subsymbols;
568 
569  for ( QMap<QString, QgsSymbolV2*>::iterator it = symbols.begin(); it != symbols.end(); ++it )
570  {
571  if ( it.key()[0] != '@' )
572  continue;
573 
574  // add to array (for deletion)
575  subsymbols.append( it.key() );
576 
577  QStringList parts = it.key().split( "@" );
578  if ( parts.count() < 3 )
579  {
580  QgsDebugMsg( "found subsymbol with invalid name: " + it.key() );
581  delete it.value(); // we must delete it
582  continue; // some invalid syntax
583  }
584  QString symname = parts[1];
585  int symlayer = parts[2].toInt();
586 
587  if ( !symbols.contains( symname ) )
588  {
589  QgsDebugMsg( "subsymbol references invalid symbol: " + symname );
590  delete it.value(); // we must delete it
591  continue;
592  }
593 
594  QgsSymbolV2* sym = symbols[symname];
595  if ( symlayer < 0 || symlayer >= sym->symbolLayerCount() )
596  {
597  QgsDebugMsg( "subsymbol references invalid symbol layer: " + QString::number( symlayer ) );
598  delete it.value(); // we must delete it
599  continue;
600  }
601 
602  // set subsymbol takes ownership
603  bool res = sym->symbolLayer( symlayer )->setSubSymbol( it.value() );
604  if ( !res )
605  {
606  QgsDebugMsg( "symbol layer refused subsymbol: " + it.key() );
607  }
608 
609 
610  }
611 
612  // now safely remove sub-symbol entries (they have been already deleted or the ownership was taken away)
613  for ( int i = 0; i < subsymbols.count(); i++ )
614  symbols.take( subsymbols[i] );
615 
616  return symbols;
617 }
618 
619 QDomElement QgsSymbolLayerV2Utils::saveSymbols( QgsSymbolV2Map& symbols, QString tagName, QDomDocument& doc )
620 {
621  QDomElement symbolsElem = doc.createElement( tagName );
622 
623  QMap<QString, QgsSymbolV2*> subSymbols;
624 
625  // save symbols
626  for ( QMap<QString, QgsSymbolV2*>::iterator its = symbols.begin(); its != symbols.end(); ++its )
627  {
628  QDomElement symEl = saveSymbol( its.key(), its.value(), doc, &subSymbols );
629  symbolsElem.appendChild( symEl );
630  }
631 
632  // add subsymbols, don't allow subsymbols for them (to keep things simple)
633  for ( QMap<QString, QgsSymbolV2*>::iterator itsub = subSymbols.begin(); itsub != subSymbols.end(); ++itsub )
634  {
635  QDomElement subsymEl = saveSymbol( itsub.key(), itsub.value(), doc );
636  symbolsElem.appendChild( subsymEl );
637  }
638 
639  return symbolsElem;
640 }
641 
643 {
644  foreach( QString name, symbols.keys() )
645  delete symbols.value( name );
646  symbols.clear();
647 }
648 
649 
651 {
652  QString rampType = element.attribute( "type" );
653 
654  // parse properties
656 
657  if ( rampType == "gradient" )
658  return QgsVectorGradientColorRampV2::create( props );
659  else if ( rampType == "random" )
660  return QgsVectorRandomColorRampV2::create( props );
661  else if ( rampType == "colorbrewer" )
663  else
664  {
665  QgsDebugMsg( "unknown colorramp type " + rampType );
666  return NULL;
667  }
668 }
669 
670 
671 QDomElement QgsSymbolLayerV2Utils::saveColorRamp( QString name, QgsVectorColorRampV2* ramp, QDomDocument& doc )
672 {
673  QDomElement rampEl = doc.createElement( "colorramp" );
674  rampEl.setAttribute( "type", ramp->type() );
675  rampEl.setAttribute( "name", name );
676 
677  QgsSymbolLayerV2Utils::saveProperties( ramp->properties(), doc, rampEl );
678  return rampEl;
679 }
680 
682 {
683 
684  if ( u == QgsSymbolV2::MM )
685  {
686  return c.scaleFactor();
687  }
688  else //QgsSymbol::MapUnit
689  {
690  double mup = c.mapToPixel().mapUnitsPerPixel();
691  if ( mup > 0 )
692  {
693  return 1.0 / mup;
694  }
695  else
696  {
697  return 1.0;
698  }
699  }
700 }
701 
703 {
704  if ( u == QgsSymbolV2::MM )
705  {
706  return ( c.scaleFactor() * c.rasterScaleFactor() );
707  }
708  else //QgsSymbol::MapUnit
709  {
710  double mup = c.mapToPixel().mapUnitsPerPixel();
711  if ( mup > 0 )
712  {
713  return c.rasterScaleFactor() / c.mapToPixel().mapUnitsPerPixel();
714  }
715  else
716  {
717  return 1.0;
718  }
719  }
720 }
721 
723 {
724  QgsRenderContext context;
725  context.setPainter( p );
726  context.setRasterScaleFactor( 1.0 );
727  if ( p && p->device() )
728  {
729  context.setScaleFactor( p->device()->logicalDpiX() / 25.4 );
730  }
731  else
732  {
733  context.setScaleFactor( 3.465 ); //assume 88 dpi as standard value
734  }
735  return context;
736 }
737 
738 void QgsSymbolLayerV2Utils::multiplyImageOpacity( QImage* image, qreal alpha )
739 {
740  if ( !image )
741  {
742  return;
743  }
744 
745  QRgb myRgb;
746  QImage::Format format = image->format();
747  if ( format != QImage::Format_ARGB32_Premultiplied && format != QImage::Format_ARGB32 )
748  {
749  QgsDebugMsg( "no alpha channel." );
750  return;
751  }
752 
753  //change the alpha component of every pixel
754  for ( int heightIndex = 0; heightIndex < image->height(); ++heightIndex )
755  {
756  QRgb* scanLine = ( QRgb* )image->scanLine( heightIndex );
757  for ( int widthIndex = 0; widthIndex < image->width(); ++widthIndex )
758  {
759  myRgb = scanLine[widthIndex];
760  if ( format == QImage::Format_ARGB32_Premultiplied )
761  scanLine[widthIndex] = qRgba( alpha * qRed( myRgb ), alpha * qGreen( myRgb ), alpha * qBlue( myRgb ), alpha * qAlpha( myRgb ) );
762  else
763  scanLine[widthIndex] = qRgba( qRed( myRgb ), qGreen( myRgb ), qBlue( myRgb ), alpha * qAlpha( myRgb ) );
764  }
765  }
766 }
767 
768 static bool _QVariantLessThan( const QVariant& lhs, const QVariant& rhs )
769 {
770  switch( lhs.type() )
771  {
772  case QVariant::Int:
773  return lhs.toInt() < rhs.toInt();
774  case QVariant::UInt:
775  return lhs.toUInt() < rhs.toUInt();
776  case QVariant::LongLong:
777  return lhs.toLongLong() < rhs.toLongLong();
778  case QVariant::ULongLong:
779  return lhs.toULongLong() < rhs.toULongLong();
780  case QVariant::Double:
781  return lhs.toDouble() < rhs.toDouble();
782  case QVariant::Char:
783  return lhs.toChar() < rhs.toChar();
784  case QVariant::Date:
785  return lhs.toDate() < rhs.toDate();
786  case QVariant::Time:
787  return lhs.toTime() < rhs.toTime();
788  case QVariant::DateTime:
789  return lhs.toDateTime() < rhs.toDateTime();
790  default:
791  return QString::localeAwareCompare( lhs.toString(), rhs.toString() ) < 0;
792  }
793 }
794 
795 static bool _QVariantGreaterThan( const QVariant& lhs, const QVariant& rhs )
796 {
797  return ! _QVariantLessThan( lhs, rhs);
798 }
799 
800 void QgsSymbolLayerV2Utils::sortVariantList( QList<QVariant>& list, Qt::SortOrder order )
801 {
802  if (order == Qt::AscendingOrder)
803  {
804  qSort( list.begin(), list.end(), _QVariantLessThan );
805  }
806  else // Qt::DescendingOrder
807  {
808  qSort( list.begin(), list.end(), _QVariantGreaterThan );
809  }
810 }