QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
qgscategorizedsymbolrendererv2widget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscategorizedsymbolrendererv2widget.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 
19 
20 #include "qgssymbolv2.h"
21 #include "qgssymbollayerv2utils.h"
22 #include "qgsvectorcolorrampv2.h"
23 #include "qgsstylev2.h"
24 
27 
28 #include "qgsvectorlayer.h"
29 
30 #include "qgsproject.h"
31 #include "qgsexpression.h"
32 
33 #include <QKeyEvent>
34 #include <QMenu>
35 #include <QMessageBox>
36 #include <QStandardItemModel>
37 #include <QStandardItem>
38 #include <QPen>
39 #include <QPainter>
40 
41 QgsCategorizedSymbolRendererV2Model::QgsCategorizedSymbolRendererV2Model( QObject * parent ) : QAbstractItemModel( parent )
42  , mRenderer( 0 )
43  , mMimeFormat( "application/x-qgscategorizedsymbolrendererv2model" )
44 {
45 }
46 
48 {
49  if ( mRenderer )
50  {
51  beginRemoveRows( QModelIndex(), 0, mRenderer->categories().size() - 1 );
52  mRenderer = 0;
53  endRemoveRows();
54  }
55  if ( renderer )
56  {
57  beginInsertRows( QModelIndex(), 0, renderer->categories().size() - 1 );
58  mRenderer = renderer;
59  endInsertRows();
60  }
61 }
62 
64 {
65  if ( !mRenderer ) return;
66  int idx = mRenderer->categories().size();
67  beginInsertRows( QModelIndex(), idx, idx );
68  mRenderer->addCategory( cat );
69  endInsertRows();
70 }
71 
73 {
74  if ( !mRenderer )
75  {
76  return QgsRendererCategoryV2();
77  }
78  const QgsCategoryList& catList = mRenderer->categories();
79  int row = index.row();
80  if ( row >= catList.size() )
81  {
82  return QgsRendererCategoryV2();
83  }
84  return catList.at( row );
85 }
86 
87 
88 Qt::ItemFlags QgsCategorizedSymbolRendererV2Model::flags( const QModelIndex & index ) const
89 {
90  if ( !index.isValid() )
91  {
92  return Qt::ItemIsDropEnabled;
93  }
94 
95  Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable;
96  if ( index.column() == 1 || index.column() == 2 )
97  {
98  flags |= Qt::ItemIsEditable;
99  }
100  return flags;
101 }
102 
104 {
105  return Qt::MoveAction;
106 }
107 
108 QVariant QgsCategorizedSymbolRendererV2Model::data( const QModelIndex &index, int role ) const
109 {
110  if ( !index.isValid() || !mRenderer )
111  return QVariant();
112 
113  const QgsRendererCategoryV2 category = mRenderer->categories().value( index.row() );
114 
115  if ( role == Qt::CheckStateRole && index.column() == 0 )
116  {
117  return category.renderState() ? Qt::Checked : Qt::Unchecked;
118  }
119  else if ( role == Qt::DisplayRole || role == Qt::ToolTipRole )
120  {
121  switch ( index.column() )
122  {
123  case 1: return category.value().toString();
124  case 2: return category.label();
125  default: return QVariant();
126  }
127  }
128  else if ( role == Qt::DecorationRole && index.column() == 0 && category.symbol() )
129  {
130  return QgsSymbolLayerV2Utils::symbolPreviewIcon( category.symbol(), QSize( 16, 16 ) );
131  }
132  else if ( role == Qt::TextAlignmentRole )
133  {
134  return ( index.column() == 0 ) ? Qt::AlignHCenter : Qt::AlignLeft;
135  }
136  else if ( role == Qt::EditRole )
137  {
138  switch ( index.column() )
139  {
140  case 1: return category.value();
141  case 2: return category.label();
142  default: return QVariant();
143  }
144  }
145 
146  return QVariant();
147 }
148 
149 bool QgsCategorizedSymbolRendererV2Model::setData( const QModelIndex & index, const QVariant & value, int role )
150 {
151  if ( !index.isValid() )
152  return false;
153 
154  if ( index.column() == 0 && role == Qt::CheckStateRole )
155  {
156  mRenderer->updateCategoryRenderState( index.row(), value == Qt::Checked );
157  emit dataChanged( index, index );
158  return true;
159  }
160 
161  if ( role != Qt::EditRole )
162  return false;
163 
164  switch ( index.column() )
165  {
166  case 1: // value
167  {
168  // try to preserve variant type for this value
169  QVariant val;
170  switch ( mRenderer->categories().value( index.row() ).value().type() )
171  {
172  case QVariant::Int:
173  val = value.toInt();
174  break;
175  case QVariant::Double:
176  val = value.toDouble();
177  break;
178  default:
179  val = value.toString();
180  break;
181  }
182  mRenderer->updateCategoryValue( index.row(), val );
183  break;
184  }
185  case 2: // label
186  mRenderer->updateCategoryLabel( index.row(), value.toString() );
187  break;
188  default:
189  return false;
190  }
191 
192  emit dataChanged( index, index );
193  return true;
194 }
195 
196 QVariant QgsCategorizedSymbolRendererV2Model::headerData( int section, Qt::Orientation orientation, int role ) const
197 {
198  if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section < 3 )
199  {
200  QStringList lst; lst << tr( "Symbol" ) << tr( "Value" ) << tr( "Legend" );
201  return lst.value( section );
202  }
203  return QVariant();
204 }
205 
206 int QgsCategorizedSymbolRendererV2Model::rowCount( const QModelIndex &parent ) const
207 {
208  if ( parent.isValid() || !mRenderer )
209  {
210  return 0;
211  }
212  return mRenderer->categories().size();
213 }
214 
216 {
217  Q_UNUSED( index );
218  return 3;
219 }
220 
221 QModelIndex QgsCategorizedSymbolRendererV2Model::index( int row, int column, const QModelIndex &parent ) const
222 {
223  if ( hasIndex( row, column, parent ) )
224  {
225  return createIndex( row, column );
226  }
227  return QModelIndex();
228 }
229 
230 QModelIndex QgsCategorizedSymbolRendererV2Model::parent( const QModelIndex &index ) const
231 {
232  Q_UNUSED( index );
233  return QModelIndex();
234 }
235 
237 {
238  QStringList types;
239  types << mMimeFormat;
240  return types;
241 }
242 
243 QMimeData *QgsCategorizedSymbolRendererV2Model::mimeData( const QModelIndexList &indexes ) const
244 {
245  QMimeData *mimeData = new QMimeData();
246  QByteArray encodedData;
247 
248  QDataStream stream( &encodedData, QIODevice::WriteOnly );
249 
250  // Create list of rows
251  foreach ( const QModelIndex &index, indexes )
252  {
253  if ( !index.isValid() || index.column() != 0 )
254  continue;
255 
256  stream << index.row();
257  }
258  mimeData->setData( mMimeFormat, encodedData );
259  return mimeData;
260 }
261 
262 bool QgsCategorizedSymbolRendererV2Model::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
263 {
264  Q_UNUSED( row );
265  Q_UNUSED( column );
266  if ( action != Qt::MoveAction ) return true;
267 
268  if ( !data->hasFormat( mMimeFormat ) ) return false;
269 
270  QByteArray encodedData = data->data( mMimeFormat );
271  QDataStream stream( &encodedData, QIODevice::ReadOnly );
272 
273  QVector<int> rows;
274  while ( !stream.atEnd() )
275  {
276  int r;
277  stream >> r;
278  rows.append( r );
279  }
280 
281  int to = parent.row();
282  // to is -1 if dragged outside items, i.e. below any item,
283  // then move to the last position
284  if ( to == -1 ) to = mRenderer->categories().size(); // out of rang ok, will be decreased
285  for ( int i = rows.size() - 1; i >= 0; i-- )
286  {
287  QgsDebugMsg( QString( "move %1 to %2" ).arg( rows[i] ).arg( to ) );
288  int t = to;
289  // moveCategory first removes and then inserts
290  if ( rows[i] < to ) t--;
291  mRenderer->moveCategory( rows[i], t );
292  // current moved under another, shift its index up
293  for ( int j = 0; j < i; j++ )
294  {
295  if ( to < rows[j] && rows[i] > rows[j] ) rows[j] += 1;
296  }
297  // removed under 'to' so the target shifted down
298  if ( rows[i] < to ) to--;
299  }
300  emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
301  emit rowsMoved();
302  return false;
303 }
304 
306 {
307  for ( int i = rows.size() - 1; i >= 0; i-- )
308  {
309  beginRemoveRows( QModelIndex(), rows[i], rows[i] );
310  mRenderer->deleteCategory( rows[i] );
311  endRemoveRows();
312  }
313 }
314 
316 {
317  beginRemoveRows( QModelIndex(), 0, mRenderer->categories().size() - 1 );
318  mRenderer->deleteAllCategories();
319  endRemoveRows();
320 }
321 
322 void QgsCategorizedSymbolRendererV2Model::sort( int column, Qt::SortOrder order )
323 {
324  QgsDebugMsg( "Entered" );
325  if ( column == 0 )
326  {
327  return;
328  }
329  if ( column == 1 )
330  {
331  mRenderer->sortByValue( order );
332  }
333  else if ( column == 2 )
334  {
335  mRenderer->sortByLabel( order );
336  }
337  emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
338  QgsDebugMsg( "Done" );
339 }
340 
342 {
343  emit dataChanged( createIndex( 0, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
344 }
345 
346 // ------------------------------ View style --------------------------------
348  : QProxyStyle( style )
349 {}
350 
351 void QgsCategorizedSymbolRendererV2ViewStyle::drawPrimitive( PrimitiveElement element, const QStyleOption * option, QPainter * painter, const QWidget * widget ) const
352 {
353  if ( element == QStyle::PE_IndicatorItemViewItemDrop && !option->rect.isNull() )
354  {
355  QStyleOption opt( *option );
356  opt.rect.setLeft( 0 );
357  // draw always as line above, because we move item to that index
358  opt.rect.setHeight( 0 );
359  if ( widget ) opt.rect.setRight( widget->width() );
360  QProxyStyle::drawPrimitive( element, &opt, painter, widget );
361  return;
362  }
363  QProxyStyle::drawPrimitive( element, option, painter, widget );
364 }
365 
366 // ------------------------------ Widget ------------------------------------
368 {
369  return new QgsCategorizedSymbolRendererV2Widget( layer, style, renderer );
370 }
371 
373  : QgsRendererV2Widget( layer, style )
374  , mRenderer( 0 )
375  , mModel( 0 )
376 {
377 
378  // try to recognize the previous renderer
379  // (null renderer means "no previous renderer")
380  if ( renderer )
381  {
383  }
384  if ( !mRenderer )
385  {
387  }
388 
389  QString attrName = mRenderer->classAttribute();
390  mOldClassificationAttribute = attrName;
391 
392  // setup user interface
393  setupUi( this );
394 
395  mExpressionWidget->setLayer( mLayer );
396 
397  cboCategorizedColorRamp->populate( mStyle );
398  int randomIndex = cboCategorizedColorRamp->findText( tr( "Random colors" ) );
399  if ( randomIndex != -1 )
400  {
401  cboCategorizedColorRamp->setCurrentIndex( randomIndex );
402  }
403 
404  // set project default color ramp
405  QString defaultColorRamp = QgsProject::instance()->readEntry( "DefaultStyles", "/ColorRamp", "" );
406  if ( defaultColorRamp != "" )
407  {
408  int index = cboCategorizedColorRamp->findText( defaultColorRamp, Qt::MatchCaseSensitive );
409  if ( index >= 0 )
410  cboCategorizedColorRamp->setCurrentIndex( index );
411  }
412 
414 
416  mModel->setRenderer( mRenderer );
417 
418  // update GUI from renderer
420 
421  viewCategories->setModel( mModel );
422  viewCategories->resizeColumnToContents( 0 );
423  viewCategories->resizeColumnToContents( 1 );
424  viewCategories->resizeColumnToContents( 2 );
425 
426  viewCategories->setStyle( new QgsCategorizedSymbolRendererV2ViewStyle( viewCategories->style() ) );
427 
428  connect( mModel, SIGNAL( rowsMoved() ), this, SLOT( rowsMoved() ) );
429 
430  connect( mExpressionWidget, SIGNAL( fieldChanged( QString ) ), this, SLOT( categoryColumnChanged( QString ) ) );
431 
432  connect( viewCategories, SIGNAL( doubleClicked( const QModelIndex & ) ), this, SLOT( categoriesDoubleClicked( const QModelIndex & ) ) );
433  connect( viewCategories, SIGNAL( customContextMenuRequested( const QPoint& ) ), this, SLOT( contextMenuViewCategories( const QPoint& ) ) );
434 
435  connect( btnChangeCategorizedSymbol, SIGNAL( clicked() ), this, SLOT( changeCategorizedSymbol() ) );
436  connect( btnAddCategories, SIGNAL( clicked() ), this, SLOT( addCategories() ) );
437  connect( btnDeleteCategories, SIGNAL( clicked() ), this, SLOT( deleteCategories() ) );
438  connect( btnDeleteAllCategories, SIGNAL( clicked() ), this, SLOT( deleteAllCategories() ) );
439  connect( btnAddCategory, SIGNAL( clicked() ), this, SLOT( addCategory() ) );
440  connect( cbxInvertedColorRamp, SIGNAL( toggled( bool ) ), this, SLOT( applyColorRamp() ) );
441  connect( cboCategorizedColorRamp, SIGNAL( currentIndexChanged( int ) ), this, SLOT( applyColorRamp() ) );
442 
443  // menus for data-defined rotation/size
444  QMenu* advMenu = new QMenu;
445 
446  advMenu->addAction( tr( "Symbol levels..." ), this, SLOT( showSymbolLevels() ) );
447 
450  connect( mDataDefinedMenus, SIGNAL( rotationFieldChanged( QString ) ), this, SLOT( rotationFieldChanged( QString ) ) );
451  connect( mDataDefinedMenus, SIGNAL( sizeScaleFieldChanged( QString ) ), this, SLOT( sizeScaleFieldChanged( QString ) ) );
453  btnAdvanced->setMenu( advMenu );
454 }
455 
457 {
458  if ( mRenderer ) delete mRenderer;
459  if ( mModel ) delete mModel;
460 }
461 
463 {
464  // Note: This assumes that the signals for UI element changes have not
465  // yet been connected, so that the updates to color ramp, symbol, etc
466  // don't override existing customisations.
467 
469 
470  //mModel->setRenderer ( mRenderer ); // necessary?
471 
472  // set column
473  QString attrName = mRenderer->classAttribute();
474  mExpressionWidget->setField( attrName );
475 
476  // set source symbol
477  if ( mRenderer->sourceSymbol() )
478  {
479  delete mCategorizedSymbol;
482  }
483 
484  // set source color ramp
485  if ( mRenderer->sourceColorRamp() )
486  {
487  cboCategorizedColorRamp->setSourceColorRamp( mRenderer->sourceColorRamp() );
488  cbxInvertedColorRamp->setChecked( mRenderer->invertedColorRamp() );
489  }
490 
491 }
492 
494 {
495  return mRenderer;
496 }
497 
499 {
500  QList<int> selectedCats = selectedCategories();
501 
502  if ( selectedCats.size() > 0 )
503  {
504  QgsSymbolV2* newSymbol = mCategorizedSymbol->clone();
505  QgsSymbolV2SelectorDialog dlg( newSymbol, mStyle, mLayer, this );
506  if ( !dlg.exec() )
507  {
508  delete newSymbol;
509  return;
510  }
511 
512  foreach ( const int idx, selectedCats )
513  {
514  QgsRendererCategoryV2 category = mRenderer->categories().value( idx );
515 
516  QgsSymbolV2* newCatSymbol = newSymbol->clone();
517  newCatSymbol->setColor( mRenderer->categories()[idx].symbol()->color() );
518  mRenderer->updateCategorySymbol( idx, newCatSymbol );
519  }
520  }
521 }
522 
524 {
525  // When there is a slection, change the selected symbols alone
526  QItemSelectionModel* m = viewCategories->selectionModel();
527  QModelIndexList i = m->selectedRows();
528 
529  if ( m && i.size() > 0 )
530  {
532  return;
533  }
534 
535  // When there is no selection, change the base mCategorizedSymbol
536  QgsSymbolV2* newSymbol = mCategorizedSymbol->clone();
537 
538  QgsSymbolV2SelectorDialog dlg( newSymbol, mStyle, mLayer, this );
539  if ( !dlg.exec() )
540  {
541  delete newSymbol;
542  return;
543  }
544 
545  mCategorizedSymbol = newSymbol;
547 
549 }
550 
552 {
553  QIcon icon = QgsSymbolLayerV2Utils::symbolPreviewIcon( mCategorizedSymbol, btnChangeCategorizedSymbol->iconSize() );
554  btnChangeCategorizedSymbol->setIcon( icon );
555 }
556 
558 {
559 }
560 
562 {
563  mRenderer->setClassAttribute( field );
564 }
565 
567 {
568  if ( idx.isValid() && idx.column() == 0 )
570 }
571 
573 {
574  int catIdx = currentCategoryRow();
576 
577  QgsSymbolV2 *symbol = category.symbol();
578  if ( symbol )
579  {
580  symbol = symbol->clone();
581  }
582  else
583  {
585  }
586 
587  QgsSymbolV2SelectorDialog dlg( symbol, mStyle, mLayer, this );
588  if ( !dlg.exec() )
589  {
590  delete symbol;
591  return;
592  }
593 
594  mRenderer->updateCategorySymbol( catIdx, symbol );
595 }
596 
597 static void _createCategories( QgsCategoryList& cats, QList<QVariant>& values, QgsSymbolV2* symbol )
598 {
599  // sort the categories first
600  QgsSymbolLayerV2Utils::sortVariantList( values, Qt::AscendingOrder );
601 
602  int num = values.count();
603 
604  bool hasNull = false;
605 
606  for ( int i = 0; i < num; i++ )
607  {
608  QVariant value = values[i];
609  if ( value.toString().isNull() )
610  {
611  hasNull = true;
612  }
613  QgsSymbolV2* newSymbol = symbol->clone();
614 
615  cats.append( QgsRendererCategoryV2( value, newSymbol, value.toString(), true ) );
616  }
617 
618  // add null (default) value if not exists
619  if ( !hasNull )
620  {
621  QgsSymbolV2* newSymbol = symbol->clone();
622  cats.append( QgsRendererCategoryV2( QVariant( "" ), newSymbol, QString(), true ) );
623  }
624 }
625 
627 {
628  QgsVectorColorRampV2* ramp = cboCategorizedColorRamp->currentColorRamp();
629  if ( ramp == NULL )
630  {
631  if ( cboCategorizedColorRamp->count() == 0 )
632  QMessageBox::critical( this, tr( "Error" ), tr( "There are no available color ramps. You can add them in Style Manager." ) );
633  else if ( !cboCategorizedColorRamp->createNewColorRampSelected() )
634  QMessageBox::critical( this, tr( "Error" ), tr( "The selected color ramp is not available." ) );
635  }
636  return ramp;
637 }
638 
639 
641 {
642  QString attrName = mExpressionWidget->currentField();
643  int idx = mLayer->fieldNameIndex( attrName );
644  QList<QVariant> unique_vals;
645  if ( idx == -1 )
646  {
647  // Lets assume it's an expression
648  QgsExpression* expression = new QgsExpression( attrName );
649  expression->prepare( mLayer->pendingFields() );
651  QgsFeature feature;
652  while ( fit.nextFeature( feature ) )
653  {
654  QVariant value = expression->evaluate( feature );
655  if ( unique_vals.contains( value ) )
656  continue;
657  unique_vals << value;
658  }
659  }
660  else
661  {
662  mLayer->uniqueValues( idx, unique_vals );
663  }
664 
665  // ask to abort if too many classes
666  if ( unique_vals.size() >= 1000 )
667  {
668  int res = QMessageBox::warning( 0, tr( "High number of classes!" ),
669  tr( "Classification would yield %1 entries which might not be expected. Continue?" ).arg( unique_vals.size() ),
670  QMessageBox::Ok | QMessageBox::Cancel,
671  QMessageBox::Cancel );
672  if ( res == QMessageBox::Cancel )
673  {
674  return;
675  }
676  }
677 
678 #if 0
679  DlgAddCategories dlg( mStyle, createDefaultSymbol(), unique_vals, this );
680  if ( !dlg.exec() )
681  return;
682 #endif
683 
684  QgsCategoryList cats;
685  _createCategories( cats, unique_vals, mCategorizedSymbol );
686  bool deleteExisting = false;
687 
688  if ( !mOldClassificationAttribute.isEmpty() &&
689  attrName != mOldClassificationAttribute &&
690  mRenderer->categories().count() > 0 )
691  {
692  int res = QMessageBox::question( this,
693  tr( "Confirm Delete" ),
694  tr( "The classification field was changed from '%1' to '%2'.\n"
695  "Should the existing classes be deleted before classification?" )
696  .arg( mOldClassificationAttribute ).arg( attrName ),
697  QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel );
698  if ( res == QMessageBox::Cancel )
699  {
700  return;
701  }
702 
703  deleteExisting = ( res == QMessageBox::Yes );
704  }
705 
706  // First element to apply coloring to
707  bool keepExistingColors = false;
708  if ( !deleteExisting )
709  {
710  QgsCategoryList prevCats = mRenderer->categories();
711  keepExistingColors = prevCats.size() > 0;
712  for ( int i = 0; i < cats.size(); ++i )
713  {
714  bool contains = false;
715  QVariant value = cats.at( i ).value();
716  for ( int j = 0; j < prevCats.size() && !contains; ++j )
717  {
718  if ( prevCats.at( j ).value() == value )
719  {
720  contains = true;
721  break;
722  }
723  }
724 
725  if ( !contains )
726  prevCats.append( cats.at( i ) );
727  }
728  cats = prevCats;
729  }
730 
731  mOldClassificationAttribute = attrName;
732 
733  // TODO: if not all categories are desired, delete some!
734  /*
735  if (not dlg.readAllCats.isChecked())
736  {
737  cats2 = {}
738  for item in dlg.listCategories.selectedItems():
739  for k,c in cats.iteritems():
740  if item.text() == k.toString():
741  break
742  cats2[k] = c
743  cats = cats2
744  }
745  */
746 
747  // recreate renderer
753  r->setInvertedColorRamp( cbxInvertedColorRamp->isChecked() );
755  if ( ramp ) r->setSourceColorRamp( ramp->clone() );
756 
757  if ( mModel )
758  {
759  mModel->setRenderer( r );
760  }
761  delete mRenderer;
762  mRenderer = r;
763  if ( ! keepExistingColors && ramp ) applyColorRamp();
764 }
765 
767 {
769  if ( ramp )
770  {
771  mRenderer->updateColorRamp( ramp->clone(), cbxInvertedColorRamp->isChecked() );
772  }
774 }
775 
777 {
778  QModelIndex idx = viewCategories->selectionModel()->currentIndex();
779  if ( !idx.isValid() )
780  return -1;
781  return idx.row();
782 }
783 
785 {
786  QList<int> rows;
787  QModelIndexList selectedRows = viewCategories->selectionModel()->selectedRows();
788 
789  foreach ( QModelIndex r, selectedRows )
790  {
791  if ( r.isValid() )
792  {
793  rows.append( r.row() );
794  }
795  }
796  return rows;
797 }
798 
800 {
801  QList<int> categoryIndexes = selectedCategories();
802  mModel->deleteRows( categoryIndexes );
803 }
804 
806 {
808 }
809 
811 {
812  if ( !mModel ) return;
814  QgsRendererCategoryV2 cat( QString(), symbol, QString(), true );
815  mModel->addCategory( cat );
816 }
817 
819 {
820  mRenderer->setRotationField( fldName );
821 }
822 
824 {
825  mRenderer->setSizeScaleField( fldName );
826 }
827 
829 {
830  mRenderer->setScaleMethod( scaleMethod );
831 }
832 
834 {
835  QList<QgsSymbolV2*> selectedSymbols;
836 
837  QItemSelectionModel* m = viewCategories->selectionModel();
838  QModelIndexList selectedIndexes = m->selectedRows( 1 );
839 
840  if ( m && selectedIndexes.size() > 0 )
841  {
842  const QgsCategoryList& categories = mRenderer->categories();
843  QModelIndexList::const_iterator indexIt = selectedIndexes.constBegin();
844  for ( ; indexIt != selectedIndexes.constEnd(); ++indexIt )
845  {
846  int row = ( *indexIt ).row();
847  QgsSymbolV2* s = categories[row].symbol();
848  if ( s )
849  {
850  selectedSymbols.append( s );
851  }
852  }
853  }
854  return selectedSymbols;
855 }
856 
858 {
859  QgsCategoryList cl;
860 
861  QItemSelectionModel* m = viewCategories->selectionModel();
862  QModelIndexList selectedIndexes = m->selectedRows( 1 );
863 
864  if ( m && selectedIndexes.size() > 0 )
865  {
866  QModelIndexList::const_iterator indexIt = selectedIndexes.constBegin();
867  for ( ; indexIt != selectedIndexes.constEnd(); ++indexIt )
868  {
869  cl.append( mModel->category( *indexIt ) );
870  }
871  }
872  return cl;
873 }
874 
876 {
878 }
879 
881 {
882  viewCategories->selectionModel()->clear();
883 }
884 
886 {
887  if ( !event )
888  {
889  return;
890  }
891 
892  if ( event->key() == Qt::Key_C && event->modifiers() == Qt::ControlModifier )
893  {
894  mCopyBuffer.clear();
895  mCopyBuffer = selectedCategoryList();
896  }
897  else if ( event->key() == Qt::Key_V && event->modifiers() == Qt::ControlModifier )
898  {
899  QgsCategoryList::const_iterator rIt = mCopyBuffer.constBegin();
900  for ( ; rIt != mCopyBuffer.constEnd(); ++rIt )
901  {
902  mModel->addCategory( *rIt );
903  }
904  }
905 }
static void sortVariantList(QList< QVariant > &list, Qt::SortOrder order)
Sorts the passed list in requested order.
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:87
void showSymbolLevelsDialog(QgsFeatureRendererV2 *r)
show a dialog with renderer's symbol level settings
Wrapper for iterator of features from vector data provider or vector layer.
static unsigned index
QgsRendererCategoryV2 category(const QModelIndex &index)
QList< QgsSymbolV2 * > selectedSymbols()
Subclasses may provide the capability of changing multiple symbols at once by implementing the follow...
const QgsCategoryList & categories() const
virtual QgsFeatureRendererV2 * renderer()
return pointer to the renderer (no transfer of ownership)
void contextMenuViewCategories(const QPoint &p)
void setRotationField(QString fieldOrExpression)
sets rotation field of renderer (if supported by the renderer)
QVariant evaluate(const QgsFeature *f=NULL)
Evaluate the feature and return the result.
bool prepare(const QgsFields &fields)
Get the expression ready for evaluation - find out column indexes.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void uniqueValues(int index, QList< QVariant > &uniqueValues, int limit=-1)
Returns unique values for column.
virtual QgsSymbolV2 * clone() const =0
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
static QgsRendererV2Widget * create(QgsVectorLayer *layer, QgsStyleV2 *style, QgsFeatureRendererV2 *renderer)
bool updateCategoryRenderState(int catIndex, bool render)
void addCategory(const QgsRendererCategoryV2 &cat)
void moveCategory(int from, int to)
Moves the category at index position from to index position to.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:113
QModelIndex parent(const QModelIndex &index) const
void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget=0) const
static QIcon icon(QString icon)
void setSizeScaleField(QString fieldOrExpression)
void setSourceColorRamp(QgsVectorColorRampV2 *ramp)
void sort(int column, Qt::SortOrder order=Qt::AscendingOrder)
void sortByLabel(Qt::SortOrder order=Qt::AscendingOrder)
void setColor(const QColor &color)
Utility class for providing GUI for data-defined rendering.
QList< QgsRendererCategoryV2 > QgsCategoryList
static QIcon symbolPreviewIcon(QgsSymbolV2 *symbol, QSize size)
QgsVectorLayer * mLayer
virtual QgsVectorColorRampV2 * clone() const =0
void changeSelectedSymbols()
change the selected symbols alone for the change button, if there is a selection
int columnCount(const QModelIndex &=QModelIndex()) const
QMimeData * mimeData(const QModelIndexList &indexes) const
bool setData(const QModelIndex &index, const QVariant &value, int role)
QGis::GeometryType geometryType() const
Returns point, line or polygon.
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
QgsCategorizedSymbolRendererV2Widget(QgsVectorLayer *layer, QgsStyleV2 *style, QgsFeatureRendererV2 *renderer)
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
static QgsCategorizedSymbolRendererV2 * convertFromRenderer(const QgsFeatureRendererV2 *renderer)
creates a QgsCategorizedSymbolRendererV2 from an existing renderer.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const
void updateColorRamp(QgsVectorColorRampV2 *ramp, bool inverted=false)
static void _createCategories(QgsCategoryList &cats, QList< QVariant > &values, QgsSymbolV2 *symbol)
QList< int > selectedCategories()
return a list of indexes for the categories unders selection
bool updateCategoryLabel(int catIndex, QString label)
QString rotationField() const
return rotation field name (or empty string if not set or not supported by renderer) ...
QString readEntry(const QString &scope, const QString &key, const QString &def=QString::null, bool *ok=0) const
static QgsSymbolV2 * defaultSymbol(QGis::GeometryType geomType)
return new default symbol for specified geometry type
Qt::ItemFlags flags(const QModelIndex &index) const
void scaleMethodChanged(QgsSymbolV2::ScaleMethod scaleMethod)
void setRenderer(QgsCategorizedSymbolRendererV2 *renderer)
bool updateCategoryValue(int catIndex, const QVariant &value)
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:362
bool updateCategorySymbol(int catIndex, QgsSymbolV2 *symbol)
Base class for renderer settings widgets.
QVariant headerData(int section, Qt::Orientation orientation, int role) const
int currentCategoryRow()
return row index for the currently selected category (-1 if on no selection)
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
QgsSymbolV2::ScaleMethod scaleMethod() const
bool nextFeature(QgsFeature &f)
QVariant data(const QModelIndex &index, int role) const
void addCategory(const QgsRendererCategoryV2 &category)
Represents a vector layer which manages a vector based data sets.
int fieldNameIndex(const QString &fieldName) const
Returns the index of a field name or -1 if the field does not exist.
void sortByValue(Qt::SortOrder order=Qt::AscendingOrder)
#define tr(sourceText)
int rowCount(const QModelIndex &parent=QModelIndex()) const