QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
qgsstylev2managerdialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsstylev2managerdialog.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 
18 #include "qgsstylev2.h"
19 #include "qgssymbolv2.h"
20 #include "qgssymbollayerv2utils.h"
21 #include "qgsvectorcolorrampv2.h"
22 
30 
31 #include <QFile>
32 #include <QFileDialog>
33 #include <QInputDialog>
34 #include <QMessageBox>
35 #include <QSettings>
36 #include <QStandardItemModel>
37 #include <QAction>
38 #include <QMenu>
39 
40 #include "qgsapplication.h"
41 #include "qgslogger.h"
42 
44  : QDialog( parent )
45  , mStyle( style )
46  , mModified( false )
47 {
48  setupUi( this );
49 #ifdef Q_OS_MAC
50  setWindowModality( Qt::WindowModal );
51 #endif
52 
53  QSettings settings;
54 
55  restoreGeometry( settings.value( "/Windows/StyleV2Manager/geometry" ).toByteArray() );
56  mSplitter->setSizes( QList<int>() << 170 << 540 );
57  mSplitter->restoreState( settings.value( "/Windows/StyleV2Manager/splitter" ).toByteArray() );
58 
59  tabItemType->setDocumentMode( true );
60  searchBox->setPlaceholderText( tr( "Type here to filter symbols..." ) );
61 
62  connect( this, SIGNAL( finished( int ) ), this, SLOT( onFinished() ) );
63 
64  connect( listItems, SIGNAL( doubleClicked( const QModelIndex & ) ), this, SLOT( editItem() ) );
65 
66  connect( btnAddItem, SIGNAL( clicked() ), this, SLOT( addItem() ) );
67  connect( actnEditItem, SIGNAL( triggered( bool ) ), this, SLOT( editItem() ) );
68  connect( actnRemoveItem, SIGNAL( triggered( bool ) ), this, SLOT( removeItem() ) );
69 
70  btnRemoveItem->setDefaultAction( actnRemoveItem );
71  btnEditItem->setDefaultAction( actnEditItem );
72 
73  QMenu *shareMenu = new QMenu( tr( "Share menu" ), this );
74  shareMenu->addAction( actnExportAsPNG );
75  shareMenu->addAction( actnExportAsSVG );
76  QAction *exportAction = new QAction( tr( "Export..." ), this );
77  shareMenu->addAction( exportAction );
78  QAction *importAction = new QAction( tr( "Import..." ), this );
79  shareMenu->addAction( importAction );
80  exportAction->setIcon( QIcon( QgsApplication::iconPath( "mActionFileSave.svg" ) ) );
81  importAction->setIcon( QIcon( QgsApplication::iconPath( "mActionFileOpen.svg" ) ) );
82  connect( actnExportAsPNG, SIGNAL( triggered() ), this, SLOT( exportItemsPNG() ) );
83  connect( actnExportAsSVG, SIGNAL( triggered() ), this, SLOT( exportItemsSVG() ) );
84  connect( exportAction, SIGNAL( triggered() ), this, SLOT( exportItems() ) );
85  connect( importAction, SIGNAL( triggered() ), this, SLOT( importItems() ) );
86  btnShare->setMenu( shareMenu );
87 
88  // Set editing mode off by default
89  mGrouppingMode = false;
90 
91  QStandardItemModel* model = new QStandardItemModel( listItems );
92  listItems->setModel( model );
93  listItems->setSelectionMode( QAbstractItemView::ExtendedSelection );
94 
95  connect( model, SIGNAL( itemChanged( QStandardItem* ) ), this, SLOT( itemChanged( QStandardItem* ) ) );
96  connect( listItems->selectionModel(), SIGNAL( currentChanged( const QModelIndex&, const QModelIndex& ) ),
97  this, SLOT( symbolSelected( const QModelIndex& ) ) );
98  connect( listItems->selectionModel(), SIGNAL( selectionChanged( const QItemSelection, const QItemSelection ) ),
99  this, SLOT( selectedSymbolsChanged( const QItemSelection&, const QItemSelection& ) ) );
100 
101  populateTypes();
102 
103  QStandardItemModel* groupModel = new QStandardItemModel( groupTree );
104  groupTree->setModel( groupModel );
105  groupTree->setHeaderHidden( true );
106  populateGroups();
107  connect( groupTree->selectionModel(), SIGNAL( currentChanged( const QModelIndex&, const QModelIndex& ) ),
108  this, SLOT( groupChanged( const QModelIndex& ) ) );
109  connect( groupModel, SIGNAL( itemChanged( QStandardItem* ) ),
110  this, SLOT( groupRenamed( QStandardItem* ) ) );
111 
112  QMenu *groupMenu = new QMenu( tr( "Group actions" ), this );
113  connect( actnGroupSymbols, SIGNAL( triggered() ), this, SLOT( groupSymbolsAction() ) );
114  groupMenu->addAction( actnGroupSymbols );
115  connect( actnFinishGrouping, SIGNAL( triggered() ), this, SLOT( groupSymbolsAction() ) );
116  actnFinishGrouping->setVisible( false );
117  groupMenu->addAction( actnFinishGrouping );
118  groupMenu->addAction( actnEditSmartGroup );
119  btnManageGroups->setMenu( groupMenu );
120 
121  connect( searchBox, SIGNAL( textChanged( QString ) ), this, SLOT( filterSymbols( QString ) ) );
122  tagsLineEdit->installEventFilter( this );
123 
124  // Context menu for groupTree
125  groupTree->setContextMenuPolicy( Qt::CustomContextMenu );
126  connect( groupTree, SIGNAL( customContextMenuRequested( const QPoint& ) ),
127  this, SLOT( grouptreeContextMenu( const QPoint& ) ) );
128 
129  // Context menu for listItems
130  listItems->setContextMenuPolicy( Qt::CustomContextMenu );
131  connect( listItems, SIGNAL( customContextMenuRequested( const QPoint& ) ),
132  this, SLOT( listitemsContextMenu( const QPoint& ) ) );
133 
134  // Menu for the "Add item" toolbutton when in colorramp mode
135  QStringList rampTypes;
136  rampTypes << tr( "Gradient" ) << tr( "Random" ) << tr( "ColorBrewer" );
137  rampTypes << tr( "cpt-city" ); // todo, only for rasters?
138  mMenuBtnAddItemColorRamp = new QMenu( this );
139  Q_FOREACH ( const QString& rampType, rampTypes )
140  mMenuBtnAddItemColorRamp->addAction( new QAction( rampType, this ) );
141  connect( mMenuBtnAddItemColorRamp, SIGNAL( triggered( QAction* ) ),
142  this, SLOT( addColorRamp( QAction* ) ) );
143 
144  // Context menu for symbols/colorramps. The menu entries for every group are created when displaying the menu.
145  mGroupMenu = new QMenu( this );
147  mGroupListMenu->setTitle( tr( "Add to group" ) );
148  mGroupListMenu->setEnabled( false );
150  actnUngroup->setData( 0 );
151  connect( actnUngroup, SIGNAL( triggered( bool ) ), this, SLOT( groupSelectedSymbols() ) );
152  mGroupMenu->addAction( actnUngroup );
153  mGroupMenu->addSeparator()->setParent( this );
154  mGroupMenu->addAction( actnRemoveItem );
155  mGroupMenu->addAction( actnEditItem );
156  mGroupMenu->addSeparator()->setParent( this );
157  mGroupMenu->addAction( actnExportAsPNG );
158  mGroupMenu->addAction( actnExportAsSVG );
159 
160  // Context menu for the group tree
161  mGroupTreeContextMenu = new QMenu( this );
162  connect( actnEditSmartGroup, SIGNAL( triggered( bool ) ), this, SLOT( editSmartgroupAction() ) );
163  mGroupTreeContextMenu->addAction( actnEditSmartGroup );
164  connect( actnAddGroup, SIGNAL( triggered( bool ) ), this, SLOT( addGroup() ) );
165  mGroupTreeContextMenu->addAction( actnAddGroup );
166  connect( actnRemoveGroup, SIGNAL( triggered( bool ) ), this, SLOT( removeGroup() ) );
167  mGroupTreeContextMenu->addAction( actnRemoveGroup );
168 
170 }
171 
173 {
174  if ( mModified )
175  {
176  mStyle->save();
177  }
178 
179  QSettings settings;
180  settings.setValue( "/Windows/StyleV2Manager/geometry", saveGeometry() );
181  settings.setValue( "/Windows/StyleV2Manager/splitter", mSplitter->saveState() );
182 }
183 
185 {
186 #if 0
187  // save current selection index in types combo
188  int current = ( tabItemType->count() > 0 ? tabItemType->currentIndex() : 0 );
189 
190 // no counting of style items
191  int markerCount = 0, lineCount = 0, fillCount = 0;
192 
193  QStringList symbolNames = mStyle->symbolNames();
194  for ( int i = 0; i < symbolNames.count(); ++i )
195  {
196  switch ( mStyle->symbolRef( symbolNames[i] )->type() )
197  {
198  case QgsSymbolV2::Marker:
199  markerCount++;
200  break;
201  case QgsSymbolV2::Line:
202  lineCount++;
203  break;
204  case QgsSymbolV2::Fill:
205  fillCount++;
206  break;
207  default:
208  Q_ASSERT( 0 && "unknown symbol type" );
209  break;
210  }
211  }
212 
213  cboItemType->clear();
214  cboItemType->addItem( tr( "Marker symbol (%1)" ).arg( markerCount ), QVariant( QgsSymbolV2::Marker ) );
215  cboItemType->addItem( tr( "Line symbol (%1)" ).arg( lineCount ), QVariant( QgsSymbolV2::Line ) );
216  cboItemType->addItem( tr( "Fill symbol (%1)" ).arg( fillCount ), QVariant( QgsSymbolV2::Fill ) );
217 
218  cboItemType->addItem( tr( "Color ramp (%1)" ).arg( mStyle->colorRampCount() ), QVariant( 3 ) );
219 
220  // update current index to previous selection
221  cboItemType->setCurrentIndex( current );
222 #endif
223 }
224 
226 {
227  // when in Color Ramp tab, add menu to add item button and hide "Export symbols as PNG/SVG"
228  bool flag = currentItemType() != 3;
229  btnAddItem->setMenu( flag ? nullptr : mMenuBtnAddItemColorRamp );
230  actnExportAsPNG->setVisible( flag );
231  actnExportAsSVG->setVisible( flag );
232 
233  // set icon and grid size, depending on type
234  if ( currentItemType() == 1 || currentItemType() == 3 )
235  {
236  listItems->setIconSize( QSize( 75, 50 ) );
237  listItems->setGridSize( QSize( 100, 80 ) );
238  }
239  else
240  {
241  listItems->setIconSize( QSize( 50, 50 ) );
242  listItems->setGridSize( QSize( 75, 80 ) );
243  }
244 
245  populateList();
246 }
247 
249 {
250  if ( currentItemType() > 3 )
251  {
252  Q_ASSERT( 0 && "not implemented" );
253  return;
254  }
255  groupChanged( groupTree->selectionModel()->currentIndex() );
256 }
257 
258 void QgsStyleV2ManagerDialog::populateSymbols( const QStringList& symbolNames, bool check )
259 {
260  QStandardItemModel* model = qobject_cast<QStandardItemModel*>( listItems->model() );
261  model->clear();
262 
263  int type = currentItemType();
264 
265  for ( int i = 0; i < symbolNames.count(); ++i )
266  {
267  QString name = symbolNames[i];
268  QgsSymbolV2* symbol = mStyle->symbol( name );
269  if ( symbol && symbol->type() == type )
270  {
271  QStandardItem* item = new QStandardItem( name );
272  QIcon icon = QgsSymbolLayerV2Utils::symbolPreviewIcon( symbol, listItems->iconSize() );
273  item->setIcon( icon );
274  item->setData( name ); // used to find out original name when user edited the name
275  item->setCheckable( check );
276  item->setToolTip( name );
277  // add to model
278  model->appendRow( item );
279  }
280  delete symbol;
281  }
283  symbolSelected( listItems->currentIndex() );
284 }
285 
286 
287 void QgsStyleV2ManagerDialog::populateColorRamps( const QStringList& colorRamps, bool check )
288 {
289  QStandardItemModel* model = qobject_cast<QStandardItemModel*>( listItems->model() );
290  model->clear();
291 
292  for ( int i = 0; i < colorRamps.count(); ++i )
293  {
294  QString name = colorRamps[i];
295  QgsVectorColorRampV2* ramp = mStyle->colorRamp( name );
296 
297  QStandardItem* item = new QStandardItem( name );
298  QIcon icon = QgsSymbolLayerV2Utils::colorRampPreviewIcon( ramp, listItems->iconSize() );
299  item->setIcon( icon );
300  item->setData( name ); // used to find out original name when user edited the name
301  item->setCheckable( check );
302  item->setToolTip( name );
303  model->appendRow( item );
304  delete ramp;
305  }
307  symbolSelected( listItems->currentIndex() );
308 }
309 
311 {
312  switch ( tabItemType->currentIndex() )
313  {
314  case 0:
315  return QgsSymbolV2::Marker;
316  case 1:
317  return QgsSymbolV2::Line;
318  case 2:
319  return QgsSymbolV2::Fill;
320  case 3:
321  return 3;
322  default:
323  return 0;
324  }
325 }
326 
328 {
329  QModelIndex index = listItems->selectionModel()->currentIndex();
330  if ( !index.isValid() )
331  return QString();
332  return index.model()->data( index, 0 ).toString();
333 }
334 
336 {
337  bool changed = false;
338  if ( currentItemType() < 3 )
339  {
340  changed = addSymbol();
341  }
342  else if ( currentItemType() == 3 )
343  {
344  changed = addColorRamp();
345  }
346  else
347  {
348  Q_ASSERT( 0 && "not implemented" );
349  }
350 
351  if ( changed )
352  {
353  populateList();
354  populateTypes();
355  }
356 }
357 
359 {
360  // create new symbol with current type
361  QgsSymbolV2* symbol;
362  QString name = tr( "new symbol" );
363  switch ( currentItemType() )
364  {
365  case QgsSymbolV2::Marker:
366  symbol = new QgsMarkerSymbolV2();
367  name = tr( "new marker" );
368  break;
369  case QgsSymbolV2::Line:
370  symbol = new QgsLineSymbolV2();
371  name = tr( "new line" );
372  break;
373  case QgsSymbolV2::Fill:
374  symbol = new QgsFillSymbolV2();
375  name = tr( "new fill symbol" );
376  break;
377  default:
378  Q_ASSERT( 0 && "unknown symbol type" );
379  return false;
380  }
381 
382  // get symbol design
383  // NOTE : Set the parent widget as "this" to notify the Symbol selector
384  // that, it is being called by Style Manager, so recursive calling
385  // of style manager and symbol selector can be arrested
386  // See also: editSymbol()
387  QgsSymbolV2SelectorDialog dlg( symbol, mStyle, nullptr, this );
388  if ( dlg.exec() == 0 )
389  {
390  delete symbol;
391  return false;
392  }
393 
394  // get unique name
395  bool nameInvalid = true;
396 
397  while ( nameInvalid )
398  {
399  bool ok;
400  name = QInputDialog::getText( this, tr( "Symbol Name" ),
401  tr( "Please enter a name for new symbol:" ),
402  QLineEdit::Normal, name, &ok );
403  if ( !ok )
404  {
405  delete symbol;
406  return false;
407  }
408  // validate name
409  if ( name.isEmpty() )
410  {
411  QMessageBox::warning( this, tr( "Save symbol" ),
412  tr( "Cannot save symbol without name. Enter a name." ) );
413  }
414  else if ( mStyle->symbolNames().contains( name ) )
415  {
416  int res = QMessageBox::warning( this, tr( "Save symbol" ),
417  tr( "Symbol with name '%1' already exists. Overwrite?" )
418  .arg( name ),
419  QMessageBox::Yes | QMessageBox::No );
420  if ( res == QMessageBox::Yes )
421  {
422  nameInvalid = false;
423  }
424  }
425  else
426  {
427  // valid name
428  nameInvalid = false;
429  }
430  }
431 
432  // add new symbol to style and re-populate the list
433  mStyle->addSymbol( name, symbol, true );
434  // TODO groups and tags
435  mModified = true;
436  return true;
437 }
438 
439 
441 {
442  // let the user choose the color ramp type if rampType is not given
443  bool ok = true;
444  if ( rampType.isEmpty() )
445  {
446  QStringList rampTypes;
447  rampTypes << tr( "Gradient" ) << tr( "Random" ) << tr( "ColorBrewer" );
448  rampTypes << tr( "cpt-city" ); // todo, only for rasters?
449  rampType = QInputDialog::getItem( parent, tr( "Color ramp type" ),
450  tr( "Please select color ramp type:" ), rampTypes, 0, false, &ok );
451  }
452  if ( !ok || rampType.isEmpty() )
453  return QString();
454 
455  QString name = tr( "new ramp" );
456 
457  QgsVectorColorRampV2 *ramp = nullptr;
458  if ( rampType == tr( "Gradient" ) )
459  {
461  QgsVectorGradientColorRampV2Dialog dlg( gradRamp, parent );
462  if ( !dlg.exec() )
463  {
464  delete gradRamp;
465  return QString();
466  }
467  ramp = gradRamp;
468  name = tr( "new gradient ramp" );
469  }
470  else if ( rampType == tr( "Random" ) )
471  {
473  QgsVectorRandomColorRampV2Dialog dlg( randRamp, parent );
474  if ( !dlg.exec() )
475  {
476  delete randRamp;
477  return QString();
478  }
479  ramp = randRamp;
480  name = tr( "new random ramp" );
481  }
482  else if ( rampType == tr( "ColorBrewer" ) )
483  {
485  QgsVectorColorBrewerColorRampV2Dialog dlg( brewerRamp, parent );
486  if ( !dlg.exec() )
487  {
488  delete brewerRamp;
489  return QString();
490  }
491  ramp = brewerRamp;
492  name = brewerRamp->schemeName() + QString::number( brewerRamp->colors() );
493  }
494  else if ( rampType == tr( "cpt-city" ) )
495  {
496  QgsCptCityColorRampV2* cptCityRamp = new QgsCptCityColorRampV2( "", "" );
497  QgsCptCityColorRampV2Dialog dlg( cptCityRamp, parent );
498  if ( !dlg.exec() )
499  {
500  delete cptCityRamp;
501  return QString();
502  }
503  // name = dlg.selectedName();
504  name = QFileInfo( cptCityRamp->schemeName() ).baseName() + cptCityRamp->variantName();
505  if ( dlg.saveAsGradientRamp() )
506  {
507  ramp = cptCityRamp->cloneGradientRamp();
508  delete cptCityRamp;
509  }
510  else
511  {
512  ramp = cptCityRamp;
513  }
514  }
515  else
516  {
517  // Q_ASSERT( 0 && "invalid ramp type" );
518  // bailing out is rather harsh!
519  QgsDebugMsg( "invalid ramp type " + rampType );
520  return QString();
521  }
522 
523  // get unique name
524  bool nameInvalid = true;
525 
526  while ( nameInvalid )
527  {
528  bool ok;
529  name = QInputDialog::getText( parent, tr( "Color Ramp Name" ),
530  tr( "Please enter a name for new color ramp:" ),
531  QLineEdit::Normal, name, &ok );
532  if ( !ok )
533  {
534  delete ramp;
535  return QString();
536  }
537  // validate name
538  if ( name.isEmpty() )
539  {
540  QMessageBox::warning( parent, tr( "Save Color Ramp" ),
541  tr( "Cannot save color ramp without name. Enter a name." ) );
542  }
543  else if ( style->colorRampNames().contains( name ) )
544  {
545  int res = QMessageBox::warning( parent, tr( "Save color ramp" ),
546  tr( "Color ramp with name '%1' already exists. Overwrite?" )
547  .arg( name ),
548  QMessageBox::Yes | QMessageBox::No );
549  if ( res == QMessageBox::Yes )
550  {
551  nameInvalid = false;
552  }
553  }
554  else
555  {
556  // valid name
557  nameInvalid = false;
558  }
559  }
560 
561  // add new symbol to style and re-populate the list
562  style->addColorRamp( name, ramp, true );
563  // TODO groups and tags, using saveColorRamp
564  return name;
565 }
566 
567 
569 {
570  return addColorRamp( nullptr );
571 }
572 
574 {
575  // pass the action text, which is the color ramp type
576  QString rampName = addColorRampStatic( this, mStyle,
577  action ? action->text() : QString() );
578  if ( !rampName.isEmpty() )
579  {
580  mModified = true;
581  populateList();
582  return true;
583  }
584 
585  return false;
586 }
587 
589 {
590  bool changed = false;
591  if ( currentItemType() < 3 )
592  {
593  changed = editSymbol();
594  }
595  else if ( currentItemType() == 3 )
596  {
597  changed = editColorRamp();
598  }
599  else
600  {
601  Q_ASSERT( 0 && "not implemented" );
602  }
603 
604  if ( changed )
605  populateList();
606 }
607 
609 {
610  QString symbolName = currentItemName();
611  if ( symbolName.isEmpty() )
612  return false;
613 
614  QgsSymbolV2* symbol = mStyle->symbol( symbolName );
615 
616  // let the user edit the symbol and update list when done
617  QgsSymbolV2SelectorDialog dlg( symbol, mStyle, nullptr, this );
618  if ( dlg.exec() == 0 )
619  {
620  delete symbol;
621  return false;
622  }
623 
624  // by adding symbol to style with the same name the old effectively gets overwritten
625  mStyle->addSymbol( symbolName, symbol, true );
626  mModified = true;
627  return true;
628 }
629 
631 {
633  if ( name.isEmpty() )
634  return false;
635 
636  QgsVectorColorRampV2* ramp = mStyle->colorRamp( name );
637 
638  if ( ramp->type() == "gradient" )
639  {
640  QgsVectorGradientColorRampV2* gradRamp = static_cast<QgsVectorGradientColorRampV2*>( ramp );
641  QgsVectorGradientColorRampV2Dialog dlg( gradRamp, this );
642  if ( !dlg.exec() )
643  {
644  delete ramp;
645  return false;
646  }
647  }
648  else if ( ramp->type() == "random" )
649  {
650  QgsVectorRandomColorRampV2* randRamp = static_cast<QgsVectorRandomColorRampV2*>( ramp );
651  QgsVectorRandomColorRampV2Dialog dlg( randRamp, this );
652  if ( !dlg.exec() )
653  {
654  delete ramp;
655  return false;
656  }
657  }
658  else if ( ramp->type() == "colorbrewer" )
659  {
660  QgsVectorColorBrewerColorRampV2* brewerRamp = static_cast<QgsVectorColorBrewerColorRampV2*>( ramp );
661  QgsVectorColorBrewerColorRampV2Dialog dlg( brewerRamp, this );
662  if ( !dlg.exec() )
663  {
664  delete ramp;
665  return false;
666  }
667  }
668  else if ( ramp->type() == "cpt-city" )
669  {
670  QgsCptCityColorRampV2* cptCityRamp = static_cast<QgsCptCityColorRampV2*>( ramp );
671  QgsCptCityColorRampV2Dialog dlg( cptCityRamp, this );
672  if ( !dlg.exec() )
673  {
674  delete ramp;
675  return false;
676  }
677  if ( dlg.saveAsGradientRamp() )
678  {
679  ramp = cptCityRamp->cloneGradientRamp();
680  delete cptCityRamp;
681  }
682  }
683  else
684  {
685  Q_ASSERT( 0 && "invalid ramp type" );
686  }
687 
688  mStyle->addColorRamp( name, ramp, true );
689  mModified = true;
690  return true;
691 }
692 
693 
695 {
696  bool changed = false;
697  if ( currentItemType() < 3 )
698  {
699  changed = removeSymbol();
700  }
701  else if ( currentItemType() == 3 )
702  {
703  changed = removeColorRamp();
704  }
705  else
706  {
707  Q_ASSERT( 0 && "not implemented" );
708  }
709 
710  if ( changed )
711  {
712  populateList();
713  populateTypes();
714  }
715 }
716 
718 {
719  QModelIndexList indexes = listItems->selectionModel()->selectedIndexes();
720  if ( QMessageBox::Yes != QMessageBox::question( this, tr( "Confirm removal" ),
721  QString( tr( "Do you really want to remove %n symbol(s)?", nullptr, indexes.count() ) ),
722  QMessageBox::Yes,
723  QMessageBox::No ) )
724  return false;
725 
726  Q_FOREACH ( const QModelIndex& index, indexes )
727  {
728  QString symbolName = index.data().toString();
729  // delete from style and update list
730  if ( !symbolName.isEmpty() )
731  mStyle->removeSymbol( symbolName );
732  }
733  mModified = true;
734  return true;
735 }
736 
738 {
739  QModelIndexList indexes = listItems->selectionModel()->selectedIndexes();
740  if ( QMessageBox::Yes != QMessageBox::question( this, tr( "Confirm removal" ),
741  QString( tr( "Do you really want to remove %n ramps(s)?", nullptr, indexes.count() ) ),
742  QMessageBox::Yes,
743  QMessageBox::No ) )
744  return false;
745 
746  Q_FOREACH ( const QModelIndex& index, indexes )
747  {
748  QString rampName = index.data().toString();
749  // delete from style and update list
750  if ( !rampName.isEmpty() )
751  mStyle->removeColorRamp( rampName );
752  }
753  mModified = true;
754  return true;
755 }
756 
758 {
759  // an item has been edited
760  QString oldName = item->data().toString();
761 
762  bool changed = false;
763  if ( currentItemType() < 3 )
764  {
765  changed = mStyle->renameSymbol( oldName, item->text() );
766  }
767  else if ( currentItemType() == 3 )
768  {
769  changed = mStyle->renameColorRamp( oldName, item->text() );
770  }
771 
772  if ( changed )
773  {
774  populateList();
775  mModified = true;
776  }
777  else
778  {
779  QMessageBox::critical( this, tr( "Cannot rename item" ),
780  tr( "Name is already taken by another item. Choose a different name." ) );
781  item->setText( oldName );
782  }
783 }
784 
786 {
787  QString dir = QFileDialog::getExistingDirectory( this, tr( "Exported selected symbols as PNG" ),
788  QDir::home().absolutePath(),
789  QFileDialog::ShowDirsOnly
790  | QFileDialog::DontResolveSymlinks );
791  exportSelectedItemsImages( dir, "png", QSize( 32, 32 ) );
792 }
793 
795 {
796  QString dir = QFileDialog::getExistingDirectory( this, tr( "Exported selected symbols as SVG" ),
797  QDir::home().absolutePath(),
798  QFileDialog::ShowDirsOnly
799  | QFileDialog::DontResolveSymlinks );
800  exportSelectedItemsImages( dir, "svg", QSize( 32, 32 ) );
801 }
802 
803 
805 {
806  if ( dir.isEmpty() )
807  return;
808 
809  QModelIndexList indexes = listItems->selectionModel()->selection().indexes();
810  Q_FOREACH ( const QModelIndex& index, indexes )
811  {
812  QString name = index.data().toString();
813  QString path = dir + '/' + name + '.' + format;
814  QgsSymbolV2 *sym = mStyle->symbol( name );
815  sym->exportImage( path, format, size );
816  }
817 }
818 
820 {
822  dlg.exec();
823 }
824 
826 {
828  dlg.exec();
829  populateList();
830  populateGroups();
831 }
832 
834 {
835  QFont font = item->font();
836  font.setBold( true );
837  item->setFont( font );
838 }
839 
841 {
842  QStandardItemModel *model = qobject_cast<QStandardItemModel*>( groupTree->model() );
843  model->clear();
844 
845  QStandardItem *allSymbols = new QStandardItem( tr( "All Symbols" ) );
846  allSymbols->setData( "all" );
847  allSymbols->setEditable( false );
848  setBold( allSymbols );
849  model->appendRow( allSymbols );
850 
851  QStandardItem *group = new QStandardItem( "" ); //require empty name to get first order groups
852  group->setData( "groups" );
853  group->setEditable( false );
854  buildGroupTree( group );
855  group->setText( tr( "Groups" ) );//set title later
856  QStandardItem *ungrouped = new QStandardItem( tr( "Ungrouped" ) );
857  ungrouped->setData( 0 );
858  setBold( ungrouped );
859  setBold( group );
860  group->appendRow( ungrouped );
861  model->appendRow( group );
862 
863  QStandardItem *tag = new QStandardItem( tr( "Smart Groups" ) );
864  tag->setData( "smartgroups" );
865  tag->setEditable( false );
866  setBold( tag );
869  while ( i != sgMap.constEnd() )
870  {
871  QStandardItem *item = new QStandardItem( i.value() );
872  item->setData( i.key() );
873  tag->appendRow( item );
874  ++i;
875  }
876  model->appendRow( tag );
877 
878  // expand things in the grouo tree
879  int rows = model->rowCount( model->indexFromItem( model->invisibleRootItem() ) );
880  for ( int i = 0; i < rows; i++ )
881  {
882  groupTree->setExpanded( model->indexFromItem( model->item( i ) ), true );
883  }
884 }
885 
887 {
888  QgsSymbolGroupMap groups = mStyle->childGroupNames( parent->text() );
890  while ( i != groups.constEnd() )
891  {
892  QStandardItem *item = new QStandardItem( i.value() );
893  item->setData( i.key() );
894  parent->appendRow( item );
895  buildGroupTree( item );
896  ++i;
897  }
898 }
899 
901 {
902  QStringList symbolNames;
903  QStringList groupSymbols;
904 
906  if ( currentItemType() > 3 )
907  {
908  QgsDebugMsg( "Entity not implemented" );
909  return;
910  }
911 
912  QString category = index.data( Qt::UserRole + 1 ).toString();
913  if ( category == "all" || category == "groups" || category == "smartgroups" )
914  {
915  enableGroupInputs( false );
916  if ( category == "groups" || category == "smartgroups" )
917  {
918  btnAddGroup->setEnabled( true );
919  actnAddGroup->setEnabled( true );
920  }
921  symbolNames = currentItemType() < 3 ? mStyle->symbolNames() : mStyle->colorRampNames();
922  }
923  else
924  {
925  //determine groups and tags
926  if ( index.parent().data( Qt::UserRole + 1 ) == "smartgroups" )
927  {
928  btnAddGroup->setEnabled( false );
929  actnAddGroup->setEnabled( false );
930  btnRemoveGroup->setEnabled( true );
931  actnRemoveGroup->setEnabled( true );
932  btnManageGroups->setEnabled( true );
933  int groupId = index.data( Qt::UserRole + 1 ).toInt();
934  symbolNames = mStyle->symbolsOfSmartgroup( type, groupId );
935  }
936  else // then it must be a group
937  {
938  if (( !index.data( Qt::UserRole + 1 ).toInt() && ( index.data() == "Ungrouped" ) ) || mGrouppingMode )
939  enableGroupInputs( false );
940  else
941  enableGroupInputs( true );
942  int groupId = index.data( Qt::UserRole + 1 ).toInt();
943  symbolNames = mStyle->symbolsOfGroup( type, groupId );
944  if ( mGrouppingMode && groupId )
945  {
946  groupSymbols = symbolNames;
947  symbolNames += mStyle->symbolsOfGroup( type, 0 );
948  }
949  }
950  }
951 
952  if ( currentItemType() < 3 )
953  {
954  populateSymbols( symbolNames, mGrouppingMode );
955  }
956  else if ( currentItemType() == 3 )
957  {
958  populateColorRamps( symbolNames, mGrouppingMode );
959  }
960  if ( mGrouppingMode )
961  setSymbolsChecked( groupSymbols );
962 
963  actnEditSmartGroup->setVisible( false );
964  actnAddGroup->setVisible( false );
965  actnRemoveGroup->setVisible( false );
966  actnGroupSymbols->setVisible( false );
967  actnFinishGrouping->setVisible( false );
968 
969  if ( index.parent().isValid() && ( index.data().toString() != "Ungrouped" ) )
970  {
971  if ( index.parent().data( Qt::UserRole + 1 ).toString() == "smartgroups" )
972  {
973  actnEditSmartGroup->setVisible( !mGrouppingMode );
974  }
975  else
976  {
977  actnAddGroup->setVisible( !mGrouppingMode );
978  actnGroupSymbols->setVisible( !mGrouppingMode );
979  actnFinishGrouping->setVisible( mGrouppingMode );
980  }
981  actnRemoveGroup->setVisible( true );
982  }
983  else if ( index.data( Qt::UserRole + 1 ) == "groups" || index.data( Qt::UserRole + 1 ) == "smartgroups" )
984  {
985  actnAddGroup->setVisible( !mGrouppingMode );
986  }
987 }
988 
990 {
991  QStandardItemModel *model = qobject_cast<QStandardItemModel*>( groupTree->model() );
992  QModelIndex parentIndex = groupTree->currentIndex();
993 
994  // Violation 1: Creating sub-groups of system defined groups
995  QString parentData = parentIndex.data( Qt::UserRole + 1 ).toString();
996  if ( parentData == "all" || ( parentIndex.data() == "Ungrouped" && parentData == "0" ) )
997  {
998  int err = QMessageBox::critical( this, tr( "Invalid Selection" ),
999  tr( "The parent group you have selected is not user editable.\n"
1000  "Kindly select a user defined group." ) );
1001  if ( err )
1002  return;
1003  }
1004 
1005  // Violation 2: Creating a nested tag
1006  if ( parentIndex.parent().data( Qt::UserRole + 1 ).toString() == "smartgroups" )
1007  {
1008  int err = QMessageBox::critical( this, tr( "Operation Not Allowed" ),
1009  tr( "Creation of nested smart groups are not allowed\n"
1010  "Select the 'Smart Group' to create a new group." ) );
1011  if ( err )
1012  return;
1013  }
1014 
1015  QString itemName;
1016  bool isGroup = true;
1017 
1018  int id;
1019  if ( parentData == "smartgroups" )
1020  {
1021  // create a smart group
1022 
1023  QgsSmartGroupEditorDialog dlg( mStyle, this );
1024  if ( dlg.exec() == QDialog::Rejected )
1025  return;
1026  id = mStyle->addSmartgroup( dlg.smartgroupName(), dlg.conditionOperator(), dlg.conditionMap() );
1027  if ( !id )
1028  return;
1029  itemName = dlg.smartgroupName();
1030  isGroup = false;
1031  }
1032  else
1033  {
1034  // create a simple child-group to the selected
1035 
1036  itemName = QString( tr( "New Group" ) );
1037  int parentid = ( parentData == "groups" ) ? 0 : parentData.toInt(); // parentid is 0 for top-level groups
1038  id = mStyle->addGroup( itemName, parentid );
1039  if ( !id )
1040  {
1041  QMessageBox::critical( this, tr( "Error!" ),
1042  tr( "New group could not be created.\n"
1043  "There was a problem with your symbol database." ) );
1044  return;
1045  }
1046  }
1047 
1048  QStandardItem *parentItem = model->itemFromIndex( parentIndex );
1049  QStandardItem *childItem = new QStandardItem( itemName );
1050  childItem->setData( id );
1051  parentItem->appendRow( childItem );
1052 
1053  groupTree->setCurrentIndex( childItem->index() );
1054  if ( isGroup )
1055  {
1056  groupTree->edit( childItem->index() );
1057  }
1058 }
1059 
1061 {
1062  QStandardItemModel *model = qobject_cast<QStandardItemModel*>( groupTree->model() );
1063  QModelIndex index = groupTree->currentIndex();
1064 
1065  // Violation: removing system groups
1066  QString data = index.data( Qt::UserRole + 1 ).toString();
1067  if ( data == "all" || data == "groups" || data == "smartgroups" || index.data() == "Ungrouped" )
1068  {
1069  int err = QMessageBox::critical( this, tr( "Invalid selection" ),
1070  tr( "Cannot delete system defined categories.\n"
1071  "Kindly select a group or smart group you might want to delete." ) );
1072  if ( err )
1073  return;
1074  }
1075 
1076  QStandardItem *parentItem = model->itemFromIndex( index.parent() );
1077  if ( parentItem->data( Qt::UserRole + 1 ).toString() == "smartgroups" )
1078  {
1079  mStyle->remove( QgsStyleV2::SmartgroupEntity, index.data( Qt::UserRole + 1 ).toInt() );
1080  }
1081  else
1082  {
1083  mStyle->remove( QgsStyleV2::GroupEntity, index.data( Qt::UserRole + 1 ).toInt() );
1084  QStandardItem *item = model->itemFromIndex( index );
1085  if ( item->hasChildren() )
1086  {
1087  QStandardItem *parent = item->parent();
1088  for ( int i = 0; i < item->rowCount(); i++ )
1089  {
1090  parent->appendRow( item->takeChild( i ) );
1091  }
1092  }
1093  }
1094  parentItem->removeRow( index.row() );
1095 }
1096 
1098 {
1099  QgsDebugMsg( "Symbol group edited: data=" + item->data( Qt::UserRole + 1 ).toString() + " text=" + item->text() );
1100  int id = item->data( Qt::UserRole + 1 ).toInt();
1101  QString name = item->text();
1102  if ( item->parent()->data( Qt::UserRole + 1 ) == "smartgroups" )
1103  {
1105  }
1106  else
1107  {
1108  mStyle->rename( QgsStyleV2::GroupEntity, id, name );
1109  }
1110 }
1111 
1113 {
1114 
1115  QStandardItemModel *treeModel = qobject_cast<QStandardItemModel*>( groupTree->model() );
1116  QStandardItemModel *model = qobject_cast<QStandardItemModel*>( listItems->model() );
1117 
1118  if ( mGrouppingMode )
1119  {
1120  mGrouppingMode = false;
1121  actnGroupSymbols->setVisible( true );
1122  actnFinishGrouping->setVisible( false );
1123  // disconnect slot which handles regrouping
1124  disconnect( model, SIGNAL( itemChanged( QStandardItem* ) ),
1125  this, SLOT( regrouped( QStandardItem* ) ) );
1126 
1127  // disabel all items except groups in groupTree
1129  groupChanged( groupTree->currentIndex() );
1130 
1131  // Finally: Reconnect all Symbol editing functionalities
1132  connect( treeModel, SIGNAL( itemChanged( QStandardItem* ) ),
1133  this, SLOT( groupRenamed( QStandardItem* ) ) );
1134  connect( model, SIGNAL( itemChanged( QStandardItem* ) ),
1135  this, SLOT( itemChanged( QStandardItem* ) ) );
1136  // Reset the selection mode
1137  listItems->setSelectionMode( QAbstractItemView::ExtendedSelection );
1138  }
1139  else
1140  {
1141  bool validGroup = false;
1142  // determine whether it is a valid group
1143  QModelIndex present = groupTree->currentIndex();
1144  while ( present.parent().isValid() )
1145  {
1146  if ( present.parent().data() == "Groups" )
1147  {
1148  validGroup = true;
1149  break;
1150  }
1151  else
1152  present = present.parent();
1153  }
1154  if ( !validGroup )
1155  return;
1156 
1157  mGrouppingMode = true;
1158  // Change visibility of actions
1159  actnGroupSymbols->setVisible( false );
1160  actnFinishGrouping->setVisible( true );
1161  // Remove all Symbol editing functionalities
1162  disconnect( treeModel, SIGNAL( itemChanged( QStandardItem* ) ),
1163  this, SLOT( groupRenamed( QStandardItem* ) ) );
1164  disconnect( model, SIGNAL( itemChanged( QStandardItem* ) ),
1165  this, SLOT( itemChanged( QStandardItem* ) ) );
1166 
1167  // disabel all items except groups in groupTree
1168  enableItemsForGroupingMode( false );
1169  groupChanged( groupTree->currentIndex() );
1170  btnManageGroups->setEnabled( true );
1171 
1172 
1173  // Connect to slot which handles regrouping
1174  connect( model, SIGNAL( itemChanged( QStandardItem* ) ),
1175  this, SLOT( regrouped( QStandardItem* ) ) );
1176 
1177  // No selection should be possible
1178  listItems->setSelectionMode( QAbstractItemView::NoSelection );
1179  }
1180 }
1181 
1183 {
1185  if ( currentItemType() > 3 )
1186  {
1187  QgsDebugMsg( "Unknown style entity" );
1188  return;
1189  }
1190  int groupid = groupTree->currentIndex().data( Qt::UserRole + 1 ).toInt();
1191  QString symbolName = item->text();
1192  bool regrouped;
1193  if ( item->checkState() == Qt::Checked )
1194  regrouped = mStyle->group( type, symbolName, groupid );
1195  else
1196  regrouped = mStyle->group( type, symbolName, 0 );
1197  if ( !regrouped )
1198  {
1199  int er = QMessageBox::critical( this, tr( "Database Error" ),
1200  tr( "There was a problem with the Symbols database while regrouping." ) );
1201  // call the slot again to get back to normal
1202  if ( er )
1204  }
1205 }
1206 
1208 {
1209  QStandardItemModel *model = qobject_cast<QStandardItemModel*>( listItems->model() );
1210  Q_FOREACH ( const QString& symbol, symbols )
1211  {
1212  QList<QStandardItem*> items = model->findItems( symbol );
1213  Q_FOREACH ( QStandardItem* item, items )
1214  item->setCheckState( Qt::Checked );
1215  }
1216 }
1217 
1219 {
1220  QStringList items;
1221  if ( currentItemType() == 3 )
1222  {
1223  items = mStyle->findSymbols( QgsStyleV2::ColorrampEntity, qword );
1224  populateColorRamps( items );
1225  }
1226  else
1227  {
1228  items = mStyle->findSymbols( QgsStyleV2::SymbolEntity, qword );
1229  populateSymbols( items );
1230  }
1231 }
1232 
1234 {
1235  QModelIndexList indexes = listItems->selectionModel()->selection().indexes();
1236  QStringList addtags;
1237  QStringList removetags;
1238 
1239  QStringList oldtags = mTagList;
1240  QStringList newtags = tagsLineEdit->text().split( ',', QString::SkipEmptyParts );
1241 
1243  if ( currentItemType() < 3 )
1244  {
1245  type = QgsStyleV2::SymbolEntity;
1246  }
1247  else if ( currentItemType() == 3 )
1248  {
1250  }
1251  else
1252  {
1253  QgsDebugMsg( "Unknown Style Entity!" );
1254  return;
1255  }
1256  // compare old with new to find removed tags
1257  Q_FOREACH ( const QString &tag, oldtags )
1258  {
1259  if ( !newtags.contains( tag ) )
1260  removetags.append( tag );
1261  }
1262  if ( !removetags.isEmpty() )
1263  {
1264  Q_FOREACH ( const QModelIndex& index, indexes )
1265  {
1266  mStyle->detagSymbol( type, index.data().toString(), removetags );
1267  }
1268  }
1269  // compare new with old to find added tags
1270  Q_FOREACH ( const QString &tag, newtags )
1271  {
1272  if ( !oldtags.contains( tag ) )
1273  addtags.append( tag );
1274  }
1275  if ( !addtags.isEmpty() )
1276  {
1277  Q_FOREACH ( const QModelIndex& index, indexes )
1278  {
1279  mStyle->tagSymbol( type, index.data().toString(), addtags );
1280  }
1281  }
1282 }
1283 
1285 {
1286  // Populate the tags for the symbol
1287  tagsLineEdit->clear();
1288  if ( index.isValid() )
1289  {
1290  QStandardItem *item = static_cast<QStandardItemModel*>( listItems->model() )->itemFromIndex( index );
1292  mTagList = mStyle->tagsOfSymbol( type, item->data().toString() );
1293  tagsLineEdit->setText( mTagList.join( "," ) );
1294  }
1295 
1296  actnEditItem->setEnabled( index.isValid() && !mGrouppingMode );
1297 }
1298 
1300 {
1301  Q_UNUSED( selected );
1302  Q_UNUSED( deselected );
1303  bool nothingSelected = listItems->selectionModel()->selectedIndexes().empty();
1304  actnRemoveItem->setDisabled( nothingSelected );
1305  mGroupListMenu->setDisabled( nothingSelected );
1306  actnUngroup->setDisabled( nothingSelected );
1307  actnExportAsPNG->setDisabled( nothingSelected );
1308  actnExportAsSVG->setDisabled( nothingSelected );
1309  actnEditItem->setDisabled( nothingSelected );
1310 }
1311 
1313 {
1314  groupTree->setEnabled( enable );
1315  btnAddGroup->setEnabled( enable );
1316  actnAddGroup->setEnabled( enable );
1317  btnRemoveGroup->setEnabled( enable );
1318  actnRemoveGroup->setEnabled( enable );
1319  btnManageGroups->setEnabled( enable || mGrouppingMode ); // always enabled in grouping mode, as it is the only way to leave grouping mode
1320  searchBox->setEnabled( enable );
1321  tagsLineEdit->setEnabled( enable );
1322 }
1323 
1325 {
1326  btnAddGroup->setEnabled( enable );
1327  btnRemoveGroup->setEnabled( enable );
1328  actnRemoveGroup->setEnabled( enable );
1329  btnManageGroups->setEnabled( enable || mGrouppingMode ); // always enabled in grouping mode, as it is the only way to leave grouping mode
1330 }
1331 
1333 {
1334  QStandardItemModel *treeModel = qobject_cast<QStandardItemModel*>( groupTree->model() );
1335  for ( int i = 0; i < treeModel->rowCount(); i++ )
1336  {
1337  if ( treeModel->item( i )->data() != "groups" )
1338  {
1339  treeModel->item( i )->setEnabled( enable );
1340  }
1341  if ( treeModel->item( i )->data() == "groups" )
1342  {
1343  treeModel->item( i )->setEnabled( enable );
1344  for ( int k = 0; k < treeModel->item( i )->rowCount(); k++ )
1345  {
1346  if ( !treeModel->item( i )->child( k )->data().toInt() )
1347  treeModel->item( i )->child( k )->setEnabled( enable );
1348  }
1349  }
1350  if ( treeModel->item( i )->data() == "smartgroups" )
1351  {
1352  for ( int j = 0; j < treeModel->item( i )->rowCount(); j++ )
1353  {
1354  treeModel->item( i )->child( j )->setEnabled( enable );
1355  }
1356  }
1357  }
1358 
1359  // The buttons
1360  // NOTE: if you ever change the layout name in the .ui file edit here too
1361  for ( int i = 0; i < symbolBtnsLayout->count(); i++ )
1362  {
1363  QWidget *w = qobject_cast<QWidget*>( symbolBtnsLayout->itemAt( i )->widget() );
1364  if ( w )
1365  w->setEnabled( enable );
1366  }
1367 
1368  // The actions
1369  actnRemoveItem->setEnabled( enable );
1370  actnEditItem->setEnabled( enable );
1371 }
1372 
1374 {
1375  QPoint globalPos = groupTree->viewport()->mapToGlobal( point );
1376 
1377  QModelIndex index = groupTree->indexAt( point );
1378  QgsDebugMsg( "Now you clicked: " + index.data().toString() );
1379 
1380  if ( index.isValid() && !mGrouppingMode )
1381  mGroupTreeContextMenu->popup( globalPos );
1382 }
1383 
1385 {
1386  QPoint globalPos = listItems->viewport()->mapToGlobal( point );
1387 
1388  // Clear all actions and create new actions for every group
1389  mGroupListMenu->clear();
1390 
1391  QAction* a;
1392  QList<int> groupIds = mStyle->groupIds();
1393  Q_FOREACH ( int groupId, groupIds )
1394  {
1395  a = new QAction( mStyle->groupName( groupId ), mGroupListMenu );
1396  a->setData( groupId );
1397  connect( a, SIGNAL( triggered( bool ) ), this, SLOT( groupSelectedSymbols() ) );
1398  mGroupListMenu->addAction( a );
1399  }
1400 
1401  mGroupMenu->popup( globalPos );
1402 }
1403 
1405 {
1406  QAction* selectedItem = qobject_cast<QAction*>( sender() );
1407 
1408  if ( selectedItem )
1409  {
1411  if ( currentItemType() > 3 )
1412  {
1413  QgsDebugMsg( "unknown entity type" );
1414  return;
1415  }
1416  int groupId = selectedItem->data().toInt();
1417  QModelIndexList indexes = listItems->selectionModel()->selectedIndexes();
1418  Q_FOREACH ( const QModelIndex& index, indexes )
1419  {
1420  mStyle->group( type, index.data().toString(), groupId );
1421  }
1422  populateList();
1423 
1424  QgsDebugMsg( "Selected Action: " + selectedItem->text() );
1425  }
1426 }
1427 
1429 {
1430  QStandardItemModel *treeModel = qobject_cast<QStandardItemModel*>( groupTree->model() );
1431 
1432  // determine whether it is a valid group
1433  QModelIndex present = groupTree->currentIndex();
1434  if ( present.parent().data( Qt::UserRole + 1 ) != "smartgroups" )
1435  {
1436  QMessageBox::critical( this, tr( "Invalid Selection" ),
1437  tr( "You have not selected a Smart Group. Kindly select a Smart Group to edit." ) );
1438  return;
1439  }
1440  QStandardItem* item = treeModel->itemFromIndex( present );
1441 
1442  QgsSmartGroupEditorDialog dlg( mStyle, this );
1443  QgsSmartConditionMap map = mStyle->smartgroup( present.data( Qt::UserRole + 1 ).toInt() );
1444  dlg.setSmartgroupName( item->text() );
1445  dlg.setOperator( mStyle->smartgroupOperator( item->data().toInt() ) );
1446  dlg.setConditionMap( map );
1447 
1448  if ( dlg.exec() == QDialog::Rejected )
1449  return;
1450 
1452  int id = mStyle->addSmartgroup( dlg.smartgroupName(), dlg.conditionOperator(), dlg.conditionMap() );
1453  if ( !id )
1454  {
1455  QMessageBox::critical( this, tr( "Database Error!" ),
1456  tr( "There was some error while editing the smart group." ) );
1457  return;
1458  }
1459  item->setText( dlg.smartgroupName() );
1460  item->setData( id );
1461 
1462  groupChanged( present );
1463 }
1464 
1466 {
1467 
1468  if (( obj == tagsLineEdit ) && ( event->type() == QEvent::FocusOut ) )
1469  {
1470  tagsChanged();
1471  return true;
1472  }
1473  return false;
1474 }
1475 
void customContextMenuRequested(const QPoint &pos)
QStringList tagsOfSymbol(StyleEntity type, const QString &symbol)
return the tags associated with the symbol
Definition: qgsstylev2.cpp:980
QString smartgroupOperator(int id)
returns the operator for the smartgroup
void setToolTip(const QString &toolTip)
QByteArray toByteArray() const
static unsigned index
virtual bool event(QEvent *e)
void remove(StyleEntity type, int id)
remove the specified entity from the db
Definition: qgsstylev2.cpp:723
QgsVectorColorRampV2 * colorRamp(const QString &name)
return a NEW copy of color ramp
Definition: qgsstylev2.cpp:257
QString getExistingDirectory(QWidget *parent, const QString &caption, const QString &dir, QFlags< QFileDialog::Option > options)
Type type() const
void setupUi(QWidget *widget)
QMenu * mMenuBtnAddItemColorRamp
Menu for the "Add item" toolbutton when in colorramp mode.
void setIcon(const QIcon &icon)
static QIcon colorRampPreviewIcon(QgsVectorColorRampV2 *ramp, QSize size)
virtual QString type() const =0
Returns a string representing the color ramp type.
QString getItem(QWidget *parent, const QString &title, const QString &label, const QStringList &items, int current, bool editable, bool *ok, QFlags< Qt::WindowType > flags, QFlags< Qt::InputMethodHint > inputMethodHints)
bool tagSymbol(StyleEntity type, const QString &symbol, const QStringList &tags)
tags the symbol with the tags in the list
Definition: qgsstylev2.cpp:870
bool group(StyleEntity type, const QString &name, int groupid)
applies the specified group to the symbol or colorramp specified by StyleEntity
Definition: qgsstylev2.cpp:775
void selectedSymbolsChanged(const QItemSelection &selected, const QItemSelection &deselected)
Perform tasks when the selected symbols change.
QStandardItem * invisibleRootItem() const
bool addSymbol(const QString &name, QgsSymbolV2 *symbol, bool update=false)
add symbol to style. takes symbol&#39;s ownership
Definition: qgsstylev2.cpp:81
QgsSmartConditionMap conditionMap()
returns the condition map
void setWindowModality(Qt::WindowModality windowModality)
void itemChanged(QStandardItem *item)
void groupChanged(const QModelIndex &)
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void enableItemsForGroupingMode(bool)
Enables or diables the groupTree items for grouping mode.
QObject * sender() const
QVariant data() const
QStyle * style() const
void tagsChanged()
Listen to tag changes.
const_iterator constBegin() const
void setIcon(const QIcon &icon)
QStringList symbolsOfGroup(StyleEntity type, int groupid)
returns the symbolnames of a given groupid
Definition: qgsstylev2.cpp:538
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
void addAction(QAction *action)
bool contains(const QString &str, Qt::CaseSensitivity cs) const
void removeRow(int row)
int exec()
SymbolType type() const
Definition: qgssymbolv2.h:107
Line symbol.
Definition: qgssymbolv2.h:82
bool addColorRamp(const QString &name, QgsVectorColorRampV2 *colorRamp, bool update=false)
add color ramp to style. takes ramp&#39;s ownership
Definition: qgsstylev2.cpp:186
QgsVectorGradientColorRampV2 * cloneGradientRamp() const
const QPixmap * icon() const
bool detagSymbol(StyleEntity type, const QString &symbol, const QStringList &tags)
detags the symbol with the given list
Definition: qgsstylev2.cpp:922
QString join(const QString &separator) const
QString smartgroupName()
returns the value from mNameLineEdit
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QStringList colorRampNames()
return a list of names of color ramps
Definition: qgsstylev2.cpp:273
QString tr(const char *sourceText, const char *disambiguation, int n)
QString text() const
Qt::CheckState checkState() const
const QgsSymbolV2 * symbolRef(const QString &name) const
return a const pointer to a symbol (doesn&#39;t create new instance)
Definition: qgsstylev2.cpp:170
Marker symbol.
Definition: qgssymbolv2.h:81
virtual void setData(const QVariant &value, int role)
void finished(int result)
bool save(QString filename=QString())
save style into a file (will use current filename if empty string is passed)
Definition: qgsstylev2.cpp:357
QList< int > groupIds() const
return the ids of all the groups in the style
Definition: qgsstylev2.cpp:477
void setBold(bool enable)
void setValue(const QString &key, const QVariant &value)
QSize size() const
void clear()
const char * name() const
bool isValid() const
void setEnabled(bool)
QString number(int n, int base)
static QIcon symbolPreviewIcon(QgsSymbolV2 *symbol, QSize size)
QgsSymbolGroupMap childGroupNames(const QString &parent="")
return a map of groupid and names for the given parent group
Definition: qgsstylev2.cpp:491
int count(const T &value) const
bool addSymbol()
add a new symbol to style
void append(const T &value)
bool renameColorRamp(const QString &oldName, const QString &newName)
change ramp&#39;s name
Definition: qgsstylev2.cpp:435
void popup(const QPoint &p, QAction *atAction)
int toInt(bool *ok) const
int colorRampCount()
return count of color ramps
Definition: qgsstylev2.cpp:268
QModelIndex indexFromItem(const QStandardItem *item) const
const Key & key() const
void filterSymbols(const QString &)
filter the symbols based on input search term
StandardButton question(QWidget *parent, const QString &title, const QString &text, QFlags< QMessageBox::StandardButton > buttons, StandardButton defaultButton)
void populateSymbols(const QStringList &symbolNames, bool checkable=false)
populate list view with symbols of the current type with the given names
bool restoreGeometry(const QByteArray &geometry)
void populateGroups()
populate the groups
void appendRow(const QList< QStandardItem * > &items)
bool hasChildren() const
int toInt(bool *ok, int base) const
bool isEmpty() const
QStringList mTagList
space to store symbol tags
bool isEmpty() const
QStandardItem * parent() const
const_iterator constEnd() const
QMenu * mGroupMenu
Context menu for the symbols/colorramps.
void groupRenamed(QStandardItem *)
void rename(StyleEntity type, int id, const QString &newName)
rename the given entity with the specified id
Definition: qgsstylev2.cpp:677
void populateColorRamps(const QStringList &colorRamps, bool checkable=false)
populate list view with color ramps
QList< QStandardItem * > findItems(const QString &text, QFlags< Qt::MatchFlag > flags, int column) const
const T & value() const
void buildGroupTree(QStandardItem *&parent)
build the groups tree
QStringList symbolsOfSmartgroup(StyleEntity type, int id)
returns the symbols for the smartgroup
void exportSelectedItemsImages(const QString &dir, const QString &format, QSize size)
virtual QVariant data(const QModelIndex &index, int role) const=0
void setTitle(const QString &title)
QAction * addSeparator()
void setSymbolsChecked(const QStringList &)
to set symbols checked when in editing mode
QMenu * mGroupTreeContextMenu
Context menu for the group tree.
void populateTypes()
populate combo box with known style items (symbols, color ramps)
QModelIndex parent() const
QgsStyleV2ManagerDialog(QgsStyleV2 *style, QWidget *parent=nullptr)
QStringList symbolNames()
return a list of names of symbols
Definition: qgsstylev2.cpp:180
QgsSymbolGroupMap smartgroupsListMap()
returns the smart groups map with id as key and name as value
QStandardItem * child(int row, int column) const
void setFont(const QFont &font)
QString getText(QWidget *parent, const QString &title, const QString &label, QLineEdit::EchoMode mode, const QString &text, bool *ok, QFlags< Qt::WindowType > flags, QFlags< Qt::InputMethodHint > inputMethodHints)
void setData(const QVariant &userData)
void setEnabled(bool enabled)
QgsSymbolV2 * symbol(const QString &name)
return a NEW copy of symbol
Definition: qgsstylev2.cpp:164
QStandardItem * item(int row, int column) const
void setParent(QObject *parent)
const QFont & font() const
void exportImage(const QString &path, const QString &format, QSize size)
export symbol as image format. PNG and SVG supported
bool eventFilter(QObject *, QEvent *) override
Event filter to capture tagsLineEdit out of focus.
bool mGrouppingMode
Mode to display the symbol list.
void setBold(QStandardItem *)
sets the text of the item with bold font
void setText(const QString &text)
Random color ramp, which returns random colors based on preset parameters.
QFont font() const
QVariant value(const QString &key, const QVariant &defaultValue) const
void symbolSelected(const QModelIndex &)
Perform symbol specific tasks when selected.
const QAbstractItemModel * model() const
void listitemsContextMenu(QPoint)
Context menu for the listItems ( symbols list )
void groupSymbolsAction()
carryout symbol grouping using check boxes
QString groupName(int groupId) const
return the group name for the given DB id
bool renameSymbol(const QString &oldName, const QString &newName)
change symbol&#39;s name
Definition: qgsstylev2.cpp:403
QVariant data(int role) const
QByteArray saveGeometry() const
void setOperator(const QString &)
sets the operator AND/OR
QStandardItem * itemFromIndex(const QModelIndex &index) const
QAction * addMenu(QMenu *menu)
void grouptreeContextMenu(QPoint)
Context menu for the groupTree.
Fill symbol.
Definition: qgssymbolv2.h:83
StandardButton critical(QWidget *parent, const QString &title, const QString &text, QFlags< QMessageBox::StandardButton > buttons, StandardButton defaultButton)
virtual int rowCount(const QModelIndex &parent) const
QStringList split(const QString &sep, const QString &str, bool allowEmptyEntries)
QModelIndex index() const
int rowCount() const
void setSmartgroupName(const QString &)
sets the smart group Name
StandardButton warning(QWidget *parent, const QString &title, const QString &text, QFlags< QMessageBox::StandardButton > buttons, StandardButton defaultButton)
void editSmartgroupAction()
edit the selected smart group
bool removeColorRamp(const QString &name)
remove color ramp from style (and delete it)
Definition: qgsstylev2.cpp:239
static QString addColorRampStatic(QWidget *parent, QgsStyleV2 *style, QString RampType=QString())
open add color ramp dialog, return color ramp&#39;s name if the ramp has been added
void setCheckState(Qt::CheckState state)
void enableGroupInputs(bool)
Enables or disables the groupTree specific inputs.
void enableSymbolInputs(bool)
Enables or disbables the symbol specific inputs.
void onFinished()
called when the dialog is going to be closed
QStandardItem * takeChild(int row, int column)
void setDisabled(bool disable)
StyleEntity
Enum for Entities involved in a style.
Definition: qgsstylev2.h:83
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const
Abstract base class for color ramps.
QChar * data()
bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:34
QString toString() const
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
QDir home()
void setCheckable(bool checkable)
void setConditionMap(const QgsSmartConditionMap &)
sets up the GUI for the given conditionmap
void appendRow(const QList< QStandardItem * > &items)
virtual QVariant data(int role) const
QStringList findSymbols(StyleEntity type, const QString &qword)
return the names of the symbols which have a matching &#39;substring&#39; in its defintion ...
Definition: qgsstylev2.cpp:796
void setEditable(bool editable)
void regrouped(QStandardItem *)
symbol changed from one group
int addGroup(const QString &groupName, int parent=0)
adds a new group and returns the group&#39;s id
Definition: qgsstylev2.cpp:624
QgsSmartConditionMap smartgroup(int id)
returns the QgsSmartConditionMap for the given id
bool removeSymbol(const QString &name)
remove symbol from style (and delete it)
Definition: qgsstylev2.cpp:136
int addSmartgroup(const QString &name, const QString &op, const QgsSmartConditionMap &conditions)
adds new smartgroup to the database and returns the id
QMenu * mGroupListMenu
Sub-menu of mGroupMenu, dynamically filled to show one entry for every group.
QString conditionOperator()
returns the AND/OR condition
bool addColorRamp()
add a new color ramp to style
void populateList()
adds symbols of some type to list