QGIS API Documentation  2.8.2-Wien
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups 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] < t ) 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 }