QGIS API Documentation  2.5.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties 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( "Label" );
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, 0 );
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, 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 );
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, 0 ), createIndex( mRenderer->categories().size(), 0 ) );
338  QgsDebugMsg( "Done" );
339 }
340 
341 // ------------------------------ View style --------------------------------
343  : QProxyStyle( style )
344 {}
345 
346 void QgsCategorizedSymbolRendererV2ViewStyle::drawPrimitive( PrimitiveElement element, const QStyleOption * option, QPainter * painter, const QWidget * widget ) const
347 {
348  if ( element == QStyle::PE_IndicatorItemViewItemDrop && !option->rect.isNull() )
349  {
350  QStyleOption opt( *option );
351  opt.rect.setLeft( 0 );
352  // draw always as line above, because we move item to that index
353  opt.rect.setHeight( 0 );
354  if ( widget ) opt.rect.setRight( widget->width() );
355  QProxyStyle::drawPrimitive( element, &opt, painter, widget );
356  return;
357  }
358  QProxyStyle::drawPrimitive( element, option, painter, widget );
359 }
360 
361 // ------------------------------ Widget ------------------------------------
363 {
364  return new QgsCategorizedSymbolRendererV2Widget( layer, style, renderer );
365 }
366 
368  : QgsRendererV2Widget( layer, style )
369  , mRenderer( 0 )
370  , mModel( 0 )
371 {
372 
373  // try to recognize the previous renderer
374  // (null renderer means "no previous renderer")
375  if ( !renderer || renderer->type() != "categorizedSymbol" )
376  {
377  // we're not going to use it - so let's delete the renderer
378  delete renderer;
379 
381  }
382  else
383  {
385  }
386 
387  QString attrName = mRenderer->classAttribute();
388  mOldClassificationAttribute = attrName;
389 
390  // setup user interface
391  setupUi( this );
392 
393  mExpressionWidget->setLayer( mLayer );
394 
395  cboCategorizedColorRamp->populate( mStyle );
396  int randomIndex = cboCategorizedColorRamp->findText( tr( "Random colors" ) );
397  if ( randomIndex != -1 )
398  {
399  cboCategorizedColorRamp->setCurrentIndex( randomIndex );
400  }
401 
402  // set project default color ramp
403  QString defaultColorRamp = QgsProject::instance()->readEntry( "DefaultStyles", "/ColorRamp", "" );
404  if ( defaultColorRamp != "" )
405  {
406  int index = cboCategorizedColorRamp->findText( defaultColorRamp, Qt::MatchCaseSensitive );
407  if ( index >= 0 )
408  cboCategorizedColorRamp->setCurrentIndex( index );
409  }
410 
413  viewCategories->setModel( mModel );
414  viewCategories->resizeColumnToContents( 0 );
415  viewCategories->resizeColumnToContents( 1 );
416  viewCategories->resizeColumnToContents( 2 );
417 
418  viewCategories->setStyle( new QgsCategorizedSymbolRendererV2ViewStyle( viewCategories->style() ) );
419 
421 
422  connect( mModel, SIGNAL( rowsMoved() ), this, SLOT( rowsMoved() ) );
423 
424  connect( mExpressionWidget, SIGNAL( fieldChanged( QString ) ), this, SLOT( categoryColumnChanged( QString ) ) );
425 
426  connect( viewCategories, SIGNAL( doubleClicked( const QModelIndex & ) ), this, SLOT( categoriesDoubleClicked( const QModelIndex & ) ) );
427  connect( viewCategories, SIGNAL( customContextMenuRequested( const QPoint& ) ), this, SLOT( contextMenuViewCategories( const QPoint& ) ) );
428 
429  connect( btnChangeCategorizedSymbol, SIGNAL( clicked() ), this, SLOT( changeCategorizedSymbol() ) );
430  connect( btnAddCategories, SIGNAL( clicked() ), this, SLOT( addCategories() ) );
431  connect( btnDeleteCategories, SIGNAL( clicked() ), this, SLOT( deleteCategories() ) );
432  connect( btnDeleteAllCategories, SIGNAL( clicked() ), this, SLOT( deleteAllCategories() ) );
433  connect( btnAddCategory, SIGNAL( clicked() ), this, SLOT( addCategory() ) );
434 
435  // update GUI from renderer
437 
438  // menus for data-defined rotation/size
439  QMenu* advMenu = new QMenu;
440 
441  advMenu->addAction( tr( "Symbol levels..." ), this, SLOT( showSymbolLevels() ) );
442 
445  connect( mDataDefinedMenus, SIGNAL( rotationFieldChanged( QString ) ), this, SLOT( rotationFieldChanged( QString ) ) );
446  connect( mDataDefinedMenus, SIGNAL( sizeScaleFieldChanged( QString ) ), this, SLOT( sizeScaleFieldChanged( QString ) ) );
448  btnAdvanced->setMenu( advMenu );
449 }
450 
452 {
453  if ( mRenderer ) delete mRenderer;
454  if ( mModel ) delete mModel;
455 }
456 
458 {
460 
461  //mModel->setRenderer ( mRenderer ); // necessary?
462 
463  // set column
464  disconnect( mExpressionWidget, SIGNAL( fieldChanged( QString ) ), this, SLOT( categoryColumnChanged( QString ) ) );
465  QString attrName = mRenderer->classAttribute();
466  mExpressionWidget->setField( attrName );
467  connect( mExpressionWidget, SIGNAL( fieldChanged( QString ) ), this, SLOT( categoryColumnChanged( QString ) ) );
468 
469 
470  // set source symbol
471  if ( mRenderer->sourceSymbol() )
472  {
473  delete mCategorizedSymbol;
476  }
477 
478  // set source color ramp
479  if ( mRenderer->sourceColorRamp() )
480  {
481  cboCategorizedColorRamp->setSourceColorRamp( mRenderer->sourceColorRamp() );
482  cbxInvertedColorRamp->setChecked( mRenderer->invertedColorRamp() );
483  }
484 
485 }
486 
488 {
489  return mRenderer;
490 }
491 
493 {
494  QList<int> selectedCats = selectedCategories();
495 
496  if ( selectedCats.size() > 0 )
497  {
498  QgsSymbolV2* newSymbol = mCategorizedSymbol->clone();
499  QgsSymbolV2SelectorDialog dlg( newSymbol, mStyle, mLayer, this );
500  if ( !dlg.exec() )
501  {
502  delete newSymbol;
503  return;
504  }
505 
506  foreach ( const int idx, selectedCats )
507  {
508  QgsRendererCategoryV2 category = mRenderer->categories().value( idx );
509 
510  QgsSymbolV2* newCatSymbol = newSymbol->clone();
511  newCatSymbol->setColor( mRenderer->categories()[idx].symbol()->color() );
512  mRenderer->updateCategorySymbol( idx, newCatSymbol );
513  }
514  }
515 }
516 
518 {
519  // When there is a slection, change the selected symbols alone
520  QItemSelectionModel* m = viewCategories->selectionModel();
521  QModelIndexList i = m->selectedRows();
522 
523  if ( m && i.size() > 0 )
524  {
526  return;
527  }
528 
529  // When there is no selection, change the base mCategorizedSymbol
530  QgsSymbolV2* newSymbol = mCategorizedSymbol->clone();
531 
532  QgsSymbolV2SelectorDialog dlg( newSymbol, mStyle, mLayer, this );
533  if ( !dlg.exec() )
534  {
535  delete newSymbol;
536  return;
537  }
538 
539  mCategorizedSymbol = newSymbol;
541 
543 }
544 
546 {
547  QIcon icon = QgsSymbolLayerV2Utils::symbolPreviewIcon( mCategorizedSymbol, btnChangeCategorizedSymbol->iconSize() );
548  btnChangeCategorizedSymbol->setIcon( icon );
549 }
550 
552 {
553 }
554 
556 {
557  mRenderer->setClassAttribute( field );
558 }
559 
561 {
562  if ( idx.isValid() && idx.column() == 0 )
564 }
565 
567 {
568  int catIdx = currentCategoryRow();
570 
571  QgsSymbolV2 *symbol = category.symbol();
572  if ( symbol )
573  {
574  symbol = symbol->clone();
575  }
576  else
577  {
579  }
580 
581  QgsSymbolV2SelectorDialog dlg( symbol, mStyle, mLayer, this );
582  if ( !dlg.exec() )
583  {
584  delete symbol;
585  return;
586  }
587 
588  mRenderer->updateCategorySymbol( catIdx, symbol );
589 }
590 
591 static void _createCategories( QgsCategoryList& cats, QList<QVariant>& values, QgsSymbolV2* symbol, QgsVectorColorRampV2* ramp, bool invert )
592 {
593  // sort the categories first
594  QgsSymbolLayerV2Utils::sortVariantList( values, Qt::AscendingOrder );
595 
596  int num = values.count();
597 
598  bool hasNull = false;
599 
600  for ( int i = 0; i < num; i++ )
601  {
602  QVariant value = values[i];
603  if ( value.toString().isNull() )
604  {
605  hasNull = true;
606  }
607  double x = ( invert ? num - i : i ) / ( double ) num;
608  QgsSymbolV2* newSymbol = symbol->clone();
609  newSymbol->setColor( ramp->color( x ) );
610 
611  cats.append( QgsRendererCategoryV2( value, newSymbol, value.toString(), true ) );
612  }
613 
614  // add null (default) value if not exists
615  if ( !hasNull )
616  {
617  QgsSymbolV2* newSymbol = symbol->clone();
618  newSymbol->setColor( ramp->color( invert ? 0 : 1 ) );
619  cats.append( QgsRendererCategoryV2( QVariant( "" ), newSymbol, QString(), true ) );
620  }
621 }
622 
624 {
625  QString attrName = mExpressionWidget->currentField();
626  int idx = mLayer->fieldNameIndex( attrName );
627  QList<QVariant> unique_vals;
628  if ( idx == -1 )
629  {
630  // Lets assume it's an expression
631  QgsExpression* expression = new QgsExpression( attrName );
632  expression->prepare( mLayer->pendingFields() );
634  QgsFeature feature;
635  while ( fit.nextFeature( feature ) )
636  {
637  QVariant value = expression->evaluate( feature ) ;
638  if ( unique_vals.contains( value ) )
639  continue;
640  unique_vals << value;
641  }
642  }
643  else
644  {
645  mLayer->uniqueValues( idx, unique_vals );
646  }
647 
648  // ask to abort if too many classes
649  if ( unique_vals.size() >= 1000 )
650  {
651  int res = QMessageBox::warning( 0, tr( "High number of classes!" ),
652  tr( "Classification would yield %1 entries which might not be expected. Continue?" ).arg( unique_vals.size() ),
653  QMessageBox::Ok | QMessageBox::Cancel,
654  QMessageBox::Cancel );
655  if ( res == QMessageBox::Cancel )
656  {
657  return;
658  }
659  }
660 
661 #if 0
662  DlgAddCategories dlg( mStyle, createDefaultSymbol(), unique_vals, this );
663  if ( !dlg.exec() )
664  return;
665 #endif
666 
667  QgsVectorColorRampV2* ramp = cboCategorizedColorRamp->currentColorRamp();
668 
669  if ( ramp == NULL )
670  {
671  if ( cboCategorizedColorRamp->count() == 0 )
672  QMessageBox::critical( this, tr( "Error" ), tr( "There are no available color ramps. You can add them in Style Manager." ) );
673  else
674  QMessageBox::critical( this, tr( "Error" ), tr( "The selected color ramp is not available." ) );
675  return;
676  }
677 
678  QgsCategoryList cats;
679  _createCategories( cats, unique_vals, mCategorizedSymbol, ramp, cbxInvertedColorRamp->isChecked() );
680 
681  bool deleteExisting = false;
682 
683  if ( !mOldClassificationAttribute.isEmpty() &&
684  attrName != mOldClassificationAttribute &&
685  mRenderer->categories().count() > 0 )
686  {
687  int res = QMessageBox::question( this,
688  tr( "Confirm Delete" ),
689  tr( "The classification field was changed from '%1' to '%2'.\n"
690  "Should the existing classes be deleted before classification?" )
691  .arg( mOldClassificationAttribute ).arg( attrName ),
692  QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel );
693  if ( res == QMessageBox::Cancel )
694  {
695  return;
696  }
697 
698  deleteExisting = ( res == QMessageBox::Yes );
699  }
700 
701  if ( !deleteExisting )
702  {
703  QgsCategoryList prevCats = mRenderer->categories();
704  for ( int i = 0; i < cats.size(); ++i )
705  {
706  bool contains = false;
707  QVariant value = cats.at( i ).value();
708  for ( int j = 0; j < prevCats.size() && !contains; ++j )
709  {
710  if ( prevCats.at( j ).value() == value )
711  {
712  contains = true;
713  break;
714  }
715  }
716 
717  if ( !contains )
718  prevCats.append( cats.at( i ) );
719  }
720  cats = prevCats;
721  }
722 
723  mOldClassificationAttribute = attrName;
724 
725  // TODO: if not all categories are desired, delete some!
726  /*
727  if (not dlg.readAllCats.isChecked())
728  {
729  cats2 = {}
730  for item in dlg.listCategories.selectedItems():
731  for k,c in cats.iteritems():
732  if item.text() == k.toString():
733  break
734  cats2[k] = c
735  cats = cats2
736  }
737  */
738 
739  // recreate renderer
742  r->setSourceColorRamp( ramp->clone() );
746  r->setInvertedColorRamp( cbxInvertedColorRamp->isChecked() );
747 
748  if ( mModel )
749  {
750  mModel->setRenderer( r );
751  }
752  delete mRenderer;
753  mRenderer = r;
754 }
755 
757 {
758  QModelIndex idx = viewCategories->selectionModel()->currentIndex();
759  if ( !idx.isValid() )
760  return -1;
761  return idx.row();
762 }
763 
765 {
766  QList<int> rows;
767  QModelIndexList selectedRows = viewCategories->selectionModel()->selectedRows();
768 
769  foreach ( QModelIndex r, selectedRows )
770  {
771  if ( r.isValid() )
772  {
773  rows.append( r.row() );
774  }
775  }
776  return rows;
777 }
778 
780 {
781  QList<int> categoryIndexes = selectedCategories();
782  mModel->deleteRows( categoryIndexes );
783 }
784 
786 {
788 }
789 
791 {
792  if ( !mModel ) return;
794  QgsRendererCategoryV2 cat( QString(), symbol, QString(), true );
795  mModel->addCategory( cat );
796 }
797 
799 {
800  mRenderer->setRotationField( fldName );
801 }
802 
804 {
805  mRenderer->setSizeScaleField( fldName );
806 }
807 
809 {
810  mRenderer->setScaleMethod( scaleMethod );
811 }
812 
814 {
815  QList<QgsSymbolV2*> selectedSymbols;
816 
817  QItemSelectionModel* m = viewCategories->selectionModel();
818  QModelIndexList selectedIndexes = m->selectedRows( 1 );
819 
820  if ( m && selectedIndexes.size() > 0 )
821  {
822  const QgsCategoryList& categories = mRenderer->categories();
823  QModelIndexList::const_iterator indexIt = selectedIndexes.constBegin();
824  for ( ; indexIt != selectedIndexes.constEnd(); ++indexIt )
825  {
826  int row = ( *indexIt ).row();
827  QgsSymbolV2* s = categories[row].symbol();
828  if ( s )
829  {
830  selectedSymbols.append( s );
831  }
832  }
833  }
834  return selectedSymbols;
835 }
836 
838 {
839  QgsCategoryList cl;
840 
841  QItemSelectionModel* m = viewCategories->selectionModel();
842  QModelIndexList selectedIndexes = m->selectedRows( 1 );
843 
844  if ( m && selectedIndexes.size() > 0 )
845  {
846  QModelIndexList::const_iterator indexIt = selectedIndexes.constBegin();
847  for ( ; indexIt != selectedIndexes.constEnd(); ++indexIt )
848  {
849  cl.append( mModel->category( *indexIt ) );
850  }
851  }
852  return cl;
853 }
854 
856 {
858 }
859 
861 {
862  viewCategories->selectionModel()->clear();
863 }
864 
866 {
867  if ( !event )
868  {
869  return;
870  }
871 
872  if ( event->key() == Qt::Key_C && event->modifiers() == Qt::ControlModifier )
873  {
874  mCopyBuffer.clear();
876  }
877  else if ( event->key() == Qt::Key_V && event->modifiers() == Qt::ControlModifier )
878  {
879  QgsCategoryList::const_iterator rIt = mCopyBuffer.constBegin();
880  for ( ; rIt != mCopyBuffer.constEnd(); ++rIt )
881  {
882  mModel->addCategory( *rIt );
883  }
884  }
885 }
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:89
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)
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:36
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)
QString type() const
Definition: qgsrendererv2.h:77
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)
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const
virtual QColor color(double value) const =0
QList< int > selectedCategories()
return a list of indexes for the categories unders selection
bool updateCategoryLabel(int catIndex, QString label)
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.
static void _createCategories(QgsCategoryList &cats, QList< QVariant > &values, QgsSymbolV2 *symbol, QgsVectorColorRampV2 *ramp, bool invert)
void sortByValue(Qt::SortOrder order=Qt::AscendingOrder)
#define tr(sourceText)
int rowCount(const QModelIndex &parent=QModelIndex()) const