QGIS API Documentation  3.13.0-Master (5a3b1ced84)
qgscolorschemelist.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscolorschemelist.cpp
3  ----------------------
4  Date : August 2014
5  Copyright : (C) 2014 by Nyall Dawson
6  Email : nyall dot dawson 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 
16 #include "qgscolorschemelist.h"
17 #include "qgsapplication.h"
18 #include "qgslogger.h"
19 #include "qgssymbollayerutils.h"
20 #include "qgscolordialog.h"
21 #include "qgssettings.h"
22 
23 #include <QPainter>
24 #include <QColorDialog>
25 #include <QMimeData>
26 #include <QClipboard>
27 #include <QKeyEvent>
28 #include <QFileDialog>
29 #include <QMessageBox>
30 
31 #ifdef ENABLE_MODELTEST
32 #include "modeltest.h"
33 #endif
34 
35 QgsColorSchemeList::QgsColorSchemeList( QWidget *parent, QgsColorScheme *scheme, const QString &context, const QColor &baseColor )
36  : QTreeView( parent )
37  , mScheme( scheme )
38 {
39  mModel = new QgsColorSchemeModel( scheme, context, baseColor, this );
40 #ifdef ENABLE_MODELTEST
41  new ModelTest( mModel, this );
42 #endif
43  setModel( mModel );
44 
45  mSwatchDelegate = new QgsColorSwatchDelegate( this );
46  setItemDelegateForColumn( 0, mSwatchDelegate );
47 
48  setRootIsDecorated( false );
49  setSelectionMode( QAbstractItemView::ExtendedSelection );
50  setSelectionBehavior( QAbstractItemView::SelectRows );
51  setDragEnabled( true );
52  setAcceptDrops( true );
53  setDragDropMode( QTreeView::DragDrop );
54  setDropIndicatorShown( true );
55  setDefaultDropAction( Qt::CopyAction );
56 }
57 
58 void QgsColorSchemeList::setScheme( QgsColorScheme *scheme, const QString &context, const QColor &baseColor )
59 {
60  mScheme = scheme;
61  mModel->setScheme( scheme, context, baseColor );
62 }
63 
65 {
66  if ( !mScheme || !mScheme->isEditable() )
67  {
68  return false;
69  }
70 
71  mScheme->setColors( mModel->colors(), mModel->context(), mModel->baseColor() );
72  return true;
73 }
74 
76 {
77  QList<int> rows;
78  const auto constSelectedIndexes = selectedIndexes();
79  for ( const QModelIndex &index : constSelectedIndexes )
80  {
81  rows << index.row();
82  }
83  //remove duplicates
84  QList<int> rowsToRemove = QList<int>::fromSet( rows.toSet() );
85 
86  //remove rows in descending order
87  std::sort( rowsToRemove.begin(), rowsToRemove.end(), std::greater<int>() );
88  const auto constRowsToRemove = rowsToRemove;
89  for ( int row : constRowsToRemove )
90  {
91  mModel->removeRow( row );
92  }
93 }
94 
95 void QgsColorSchemeList::addColor( const QColor &color, const QString &label, bool allowDuplicate )
96 {
97  mModel->addColor( color, label, allowDuplicate );
98 }
99 
101 {
102  QgsNamedColorList pastedColors = QgsSymbolLayerUtils::colorListFromMimeData( QApplication::clipboard()->mimeData() );
103 
104  if ( pastedColors.length() == 0 )
105  {
106  //no pasted colors
107  return;
108  }
109 
110  //insert pasted colors
111  QgsNamedColorList::const_iterator colorIt = pastedColors.constBegin();
112  for ( ; colorIt != pastedColors.constEnd(); ++colorIt )
113  {
114  mModel->addColor( ( *colorIt ).first, !( *colorIt ).second.isEmpty() ? ( *colorIt ).second : QgsSymbolLayerUtils::colorToName( ( *colorIt ).first ) );
115  }
116 }
117 
119 {
120  QList<int> rows;
121  const auto constSelectedIndexes = selectedIndexes();
122  for ( const QModelIndex &index : constSelectedIndexes )
123  {
124  rows << index.row();
125  }
126  //remove duplicates
127  QList<int> rowsToCopy = QList<int>::fromSet( rows.toSet() );
128 
129  QgsNamedColorList colorsToCopy;
130  const auto constRowsToCopy = rowsToCopy;
131  for ( int row : constRowsToCopy )
132  {
133  colorsToCopy << mModel->colors().at( row );
134  }
135 
136  //copy colors
137  QMimeData *mimeData = QgsSymbolLayerUtils::colorListToMimeData( colorsToCopy );
138  QApplication::clipboard()->setMimeData( mimeData );
139 }
140 
142 {
143  QgsSettings s;
144  QString lastDir = s.value( QStringLiteral( "/UI/lastGplPaletteDir" ), QDir::homePath() ).toString();
145  QString filePath = QFileDialog::getOpenFileName( this, tr( "Select Palette File" ), lastDir, QStringLiteral( "GPL (*.gpl);;All files (*.*)" ) );
146  activateWindow();
147  if ( filePath.isEmpty() )
148  {
149  return;
150  }
151 
152  //check if file exists
153  QFileInfo fileInfo( filePath );
154  if ( !fileInfo.exists() || !fileInfo.isReadable() )
155  {
156  QMessageBox::critical( nullptr, tr( "Import Colors" ), tr( "Error, file does not exist or is not readable." ) );
157  return;
158  }
159 
160  s.setValue( QStringLiteral( "/UI/lastGplPaletteDir" ), fileInfo.absolutePath() );
161  QFile file( filePath );
162  bool importOk = importColorsFromGpl( file );
163  if ( !importOk )
164  {
165  QMessageBox::critical( nullptr, tr( "Import Colors" ), tr( "Error, no colors found in palette file." ) );
166  return;
167  }
168 }
169 
171 {
172  QgsSettings s;
173  QString lastDir = s.value( QStringLiteral( "/UI/lastGplPaletteDir" ), QDir::homePath() ).toString();
174  QString fileName = QFileDialog::getSaveFileName( this, tr( "Palette file" ), lastDir, QStringLiteral( "GPL (*.gpl)" ) );
175  activateWindow();
176  if ( fileName.isEmpty() )
177  {
178  return;
179  }
180 
181  // ensure filename contains extension
182  if ( !fileName.endsWith( QLatin1String( ".gpl" ), Qt::CaseInsensitive ) )
183  {
184  fileName += QLatin1String( ".gpl" );
185  }
186 
187  QFileInfo fileInfo( fileName );
188  s.setValue( QStringLiteral( "/UI/lastGplPaletteDir" ), fileInfo.absolutePath() );
189 
190  QFile file( fileName );
191  bool exportOk = exportColorsToGpl( file );
192  if ( !exportOk )
193  {
194  QMessageBox::critical( nullptr, tr( "Export Colors" ), tr( "Error writing palette file." ) );
195  return;
196  }
197 }
198 
199 void QgsColorSchemeList::keyPressEvent( QKeyEvent *event )
200 {
201  //listen out for delete/backspace presses and remove selected colors
202  if ( ( event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete ) )
203  {
204  QList<int> rows;
205  const auto constSelectedIndexes = selectedIndexes();
206  for ( const QModelIndex &index : constSelectedIndexes )
207  {
208  rows << index.row();
209  }
210  //remove duplicates
211  QList<int> rowsToRemove = QList<int>::fromSet( rows.toSet() );
212 
213  //remove rows in descending order
214  std::sort( rowsToRemove.begin(), rowsToRemove.end(), std::greater<int>() );
215  const auto constRowsToRemove = rowsToRemove;
216  for ( int row : constRowsToRemove )
217  {
218  mModel->removeRow( row );
219  }
220  return;
221  }
222 
223  QTreeView::keyPressEvent( event );
224 }
225 
226 void QgsColorSchemeList::mousePressEvent( QMouseEvent *event )
227 {
228  if ( event->button() == Qt::LeftButton )
229  {
230  //record press start position
231  mDragStartPosition = event->pos();
232  }
233  QTreeView::mousePressEvent( event );
234 }
235 
236 void QgsColorSchemeList::mouseReleaseEvent( QMouseEvent *event )
237 {
238  if ( ( event->button() == Qt::LeftButton ) &&
239  ( event->pos() - mDragStartPosition ).manhattanLength() <= QApplication::startDragDistance() )
240  {
241  //just a click, not a drag
242 
243  //if only one item is selected, emit color changed signal
244  //(if multiple are selected, user probably was interacting with color list rather than trying to pick a color)
245  if ( selectedIndexes().length() == mModel->columnCount() )
246  {
247  QModelIndex selectedColor = selectedIndexes().at( 0 );
248  emit colorSelected( mModel->colors().at( selectedColor.row() ).first );
249  }
250  }
251 
252  QTreeView::mouseReleaseEvent( event );
253 }
254 
256 {
257  QgsNamedColorList importedColors;
258  bool ok = false;
259  QString name;
260  importedColors = QgsSymbolLayerUtils::importColorsFromGpl( file, ok, name );
261  if ( !ok )
262  {
263  return false;
264  }
265 
266  if ( importedColors.length() == 0 )
267  {
268  //no imported colors
269  return false;
270  }
271 
272  //insert imported colors
273  QgsNamedColorList::const_iterator colorIt = importedColors.constBegin();
274  for ( ; colorIt != importedColors.constEnd(); ++colorIt )
275  {
276  mModel->addColor( ( *colorIt ).first, !( *colorIt ).second.isEmpty() ? ( *colorIt ).second : QgsSymbolLayerUtils::colorToName( ( *colorIt ).first ) );
277  }
278 
279  return true;
280 }
281 
283 {
284  return QgsSymbolLayerUtils::saveColorsToGpl( file, QString(), mModel->colors() );
285 }
286 
288 {
289  if ( !mModel )
290  {
291  return false;
292  }
293 
294  return mModel->isDirty();
295 }
296 
298 {
299  return mScheme;
300 }
301 
302 //
303 // QgsColorSchemeModel
304 //
305 
306 QgsColorSchemeModel::QgsColorSchemeModel( QgsColorScheme *scheme, const QString &context, const QColor &baseColor, QObject *parent )
307  : QAbstractItemModel( parent )
308  , mScheme( scheme )
309  , mContext( context )
310  , mBaseColor( baseColor )
311  , mIsDirty( false )
312 {
313  if ( scheme )
314  {
315  mColors = scheme->fetchColors( context, baseColor );
316  }
317 }
318 
319 QModelIndex QgsColorSchemeModel::index( int row, int column, const QModelIndex &parent ) const
320 {
321  if ( column < 0 || column >= columnCount() )
322  {
323  //column out of bounds
324  return QModelIndex();
325  }
326 
327  if ( !parent.isValid() && row >= 0 && row < mColors.size() )
328  {
329  //return an index for the color item at this position
330  return createIndex( row, column );
331  }
332 
333  //only top level supported
334  return QModelIndex();
335 }
336 
337 QModelIndex QgsColorSchemeModel::parent( const QModelIndex &index ) const
338 {
339  Q_UNUSED( index )
340 
341  //all items are top level
342  return QModelIndex();
343 }
344 
345 int QgsColorSchemeModel::rowCount( const QModelIndex &parent ) const
346 {
347  if ( !parent.isValid() )
348  {
349  return mColors.size();
350  }
351  else
352  {
353  //no children
354  return 0;
355  }
356 }
357 
358 int QgsColorSchemeModel::columnCount( const QModelIndex &parent ) const
359 {
360  Q_UNUSED( parent )
361  return 2;
362 }
363 
364 QVariant QgsColorSchemeModel::data( const QModelIndex &index, int role ) const
365 {
366  if ( !index.isValid() )
367  return QVariant();
368 
369  QPair< QColor, QString > namedColor = mColors.at( index.row() );
370  switch ( role )
371  {
372  case Qt::DisplayRole:
373  case Qt::EditRole:
374  switch ( index.column() )
375  {
376  case ColorSwatch:
377  return namedColor.first;
378  case ColorLabel:
379  return namedColor.second;
380  default:
381  return QVariant();
382  }
383 
384  case Qt::TextAlignmentRole:
385  return QVariant( Qt::AlignLeft | Qt::AlignVCenter );
386 
387  default:
388  return QVariant();
389  }
390 }
391 
392 Qt::ItemFlags QgsColorSchemeModel::flags( const QModelIndex &index ) const
393 {
394  Qt::ItemFlags flags = QAbstractItemModel::flags( index );
395 
396  if ( ! index.isValid() )
397  {
398  return flags | Qt::ItemIsDropEnabled;
399  }
400 
401  switch ( index.column() )
402  {
403  case ColorSwatch:
404  case ColorLabel:
405  if ( mScheme && mScheme->isEditable() )
406  {
407  flags = flags | Qt::ItemIsEditable;
408  }
409  return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
410  default:
411  return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
412  }
413 }
414 
415 bool QgsColorSchemeModel::setData( const QModelIndex &index, const QVariant &value, int role )
416 {
417  Q_UNUSED( role )
418 
419  if ( !mScheme || !mScheme->isEditable() )
420  return false;
421 
422  if ( !index.isValid() )
423  return false;
424 
425  if ( index.row() >= mColors.length() )
426  return false;
427 
428  switch ( index.column() )
429  {
430  case ColorSwatch:
431  mColors[ index.row()].first = value.value<QColor>();
432  emit dataChanged( index, index );
433  mIsDirty = true;
434  return true;
435 
436  case ColorLabel:
437  mColors[ index.row()].second = value.toString();
438  emit dataChanged( index, index );
439  mIsDirty = true;
440  return true;
441 
442  default:
443  return false;
444  }
445 }
446 
447 QVariant QgsColorSchemeModel::headerData( int section, Qt::Orientation orientation, int role ) const
448 {
449  switch ( role )
450  {
451  case Qt::DisplayRole:
452  {
453  switch ( section )
454  {
455  case ColorSwatch:
456  return tr( "Color" );
457  case ColorLabel:
458  return tr( "Label" );
459  default:
460  return QVariant();
461  }
462  }
463 
464  case Qt::TextAlignmentRole:
465  switch ( section )
466  {
467  case ColorSwatch:
468  return QVariant( Qt::AlignHCenter | Qt::AlignVCenter );
469  case ColorLabel:
470  return QVariant( Qt::AlignLeft | Qt::AlignVCenter );
471  default:
472  return QVariant();
473  }
474  default:
475  return QAbstractItemModel::headerData( section, orientation, role );
476  }
477 }
478 
480 {
481  if ( mScheme && mScheme->isEditable() )
482  {
483  return Qt::CopyAction | Qt::MoveAction;
484  }
485  else
486  {
487  return Qt::CopyAction;
488  }
489 }
490 
492 {
493  if ( !mScheme || !mScheme->isEditable() )
494  {
495  return QStringList();
496  }
497 
498  QStringList types;
499  types << QStringLiteral( "text/xml" );
500  types << QStringLiteral( "text/plain" );
501  types << QStringLiteral( "application/x-color" );
502  types << QStringLiteral( "application/x-colorobject-list" );
503  return types;
504 }
505 
506 QMimeData *QgsColorSchemeModel::mimeData( const QModelIndexList &indexes ) const
507 {
508  QgsNamedColorList colorList;
509 
510  QModelIndexList::const_iterator indexIt = indexes.constBegin();
511  for ( ; indexIt != indexes.constEnd(); ++indexIt )
512  {
513  if ( ( *indexIt ).column() > 0 )
514  continue;
515 
516  colorList << qMakePair( mColors[( *indexIt ).row()].first, mColors[( *indexIt ).row()].second );
517  }
518 
519  QMimeData *mimeData = QgsSymbolLayerUtils::colorListToMimeData( colorList );
520  return mimeData;
521 }
522 
523 bool QgsColorSchemeModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
524 {
525  Q_UNUSED( column )
526 
527  if ( !mScheme || !mScheme->isEditable() )
528  {
529  return false;
530  }
531 
532  if ( action == Qt::IgnoreAction )
533  {
534  return true;
535  }
536 
537  if ( parent.isValid() )
538  {
539  return false;
540  }
541 
542  int beginRow = row != -1 ? row : rowCount( QModelIndex() );
544 
545  if ( droppedColors.length() == 0 )
546  {
547  //no dropped colors
548  return false;
549  }
550 
551  //any existing colors? if so, remove them first
552  QgsNamedColorList::const_iterator colorIt = droppedColors.constBegin();
553  for ( ; colorIt != droppedColors.constEnd(); ++colorIt )
554  {
555  //dest color
556  QPair< QColor, QString > color = qMakePair( ( *colorIt ).first, !( *colorIt ).second.isEmpty() ? ( *colorIt ).second : QgsSymbolLayerUtils::colorToName( ( *colorIt ).first ) );
557  //if color already exists, remove it
558  int existingIndex = mColors.indexOf( color );
559  if ( existingIndex >= 0 )
560  {
561  if ( existingIndex < beginRow )
562  {
563  //color is before destination row, so decrease destination row to account for removal
564  beginRow--;
565  }
566 
567  beginRemoveRows( parent, existingIndex, existingIndex );
568  mColors.removeAt( existingIndex );
569  endRemoveRows();
570  }
571  }
572 
573  //insert dropped colors
574  insertRows( beginRow, droppedColors.length(), QModelIndex() );
575  colorIt = droppedColors.constBegin();
576  for ( ; colorIt != droppedColors.constEnd(); ++colorIt )
577  {
578  QModelIndex colorIdx = index( beginRow, 0, QModelIndex() );
579  setData( colorIdx, QVariant( ( *colorIt ).first ) );
580  QModelIndex labelIdx = index( beginRow, 1, QModelIndex() );
581  setData( labelIdx, !( *colorIt ).second.isEmpty() ? ( *colorIt ).second : QgsSymbolLayerUtils::colorToName( ( *colorIt ).first ) );
582  beginRow++;
583  }
584  mIsDirty = true;
585 
586  return true;
587 }
588 
589 void QgsColorSchemeModel::setScheme( QgsColorScheme *scheme, const QString &context, const QColor &baseColor )
590 {
591  mScheme = scheme;
592  mContext = context;
593  mBaseColor = baseColor;
594  mIsDirty = false;
595  beginResetModel();
596  mColors = scheme->fetchColors( mContext, mBaseColor );
597  endResetModel();
598 }
599 
600 bool QgsColorSchemeModel::removeRows( int row, int count, const QModelIndex &parent )
601 {
602  if ( !mScheme || !mScheme->isEditable() )
603  {
604  return false;
605  }
606 
607  if ( parent.isValid() )
608  {
609  return false;
610  }
611 
612  if ( row >= mColors.count() )
613  {
614  return false;
615  }
616 
617  for ( int i = row + count - 1; i >= row; --i )
618  {
619  beginRemoveRows( parent, i, i );
620  mColors.removeAt( i );
621  endRemoveRows();
622  }
623 
624  mIsDirty = true;
625  return true;
626 }
627 
628 bool QgsColorSchemeModel::insertRows( int row, int count, const QModelIndex &parent )
629 {
630  Q_UNUSED( parent )
631 
632  if ( !mScheme || !mScheme->isEditable() )
633  {
634  return false;
635  }
636 
637  beginInsertRows( QModelIndex(), row, row + count - 1 );
638  for ( int i = row; i < row + count; ++i )
639  {
640  QPair< QColor, QString > newColor;
641  mColors.insert( i, newColor );
642  }
643  endInsertRows();
644  mIsDirty = true;
645  return true;
646 }
647 
648 void QgsColorSchemeModel::addColor( const QColor &color, const QString &label, bool allowDuplicate )
649 {
650  if ( !mScheme || !mScheme->isEditable() )
651  {
652  return;
653  }
654 
655  if ( !allowDuplicate )
656  {
657  //matches existing color? if so, remove it first
658  QPair< QColor, QString > newColor = qMakePair( color, !label.isEmpty() ? label : QgsSymbolLayerUtils::colorToName( color ) );
659  //if color already exists, remove it
660  int existingIndex = mColors.indexOf( newColor );
661  if ( existingIndex >= 0 )
662  {
663  beginRemoveRows( QModelIndex(), existingIndex, existingIndex );
664  mColors.removeAt( existingIndex );
665  endRemoveRows();
666  }
667  }
668 
669  int row = rowCount();
670  insertRow( row );
671  QModelIndex colorIdx = index( row, 0, QModelIndex() );
672  setData( colorIdx, QVariant( color ) );
673  QModelIndex labelIdx = index( row, 1, QModelIndex() );
674  setData( labelIdx, QVariant( label ) );
675  mIsDirty = true;
676 }
677 
678 
679 //
680 // QgsColorSwatchDelegate
681 //
683  : QAbstractItemDelegate( parent )
684  , mParent( parent )
685 {
686 
687 }
688 
689 void QgsColorSwatchDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
690 {
691  if ( option.state & QStyle::State_Selected )
692  {
693  painter->setPen( QPen( Qt::NoPen ) );
694  if ( option.state & QStyle::State_Active )
695  {
696  painter->setBrush( QBrush( option.widget->palette().highlight() ) );
697  }
698  else
699  {
700  painter->setBrush( QBrush( option.widget->palette().color( QPalette::Inactive,
701  QPalette::Highlight ) ) );
702  }
703  painter->drawRect( option.rect );
704  }
705 
706  QColor color = index.model()->data( index, Qt::DisplayRole ).value<QColor>();
707  if ( !color.isValid() )
708  {
709  return;
710  }
711 
712  QRect rect = option.rect;
713 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
714  const int iconSize = Qgis::UI_SCALE_FACTOR * option.fontMetrics.width( 'X' ) * 4;
715 #else
716  const int iconSize = Qgis::UI_SCALE_FACTOR * option.fontMetrics.horizontalAdvance( 'X' ) * 4;
717 #endif
718 
719  const int cornerSize = iconSize / 6;
720  //center it
721  rect.setLeft( option.rect.center().x() - iconSize / 2 );
722 
723  rect.setSize( QSize( iconSize, iconSize ) );
724  rect.adjust( 0, 1, 0, 1 );
725  //create an icon pixmap
726  painter->save();
727  painter->setRenderHint( QPainter::Antialiasing );
728  painter->setPen( Qt::NoPen );
729  if ( color.alpha() < 255 )
730  {
731  //start with checkboard pattern
732  QBrush checkBrush = QBrush( transparentBackground() );
733  painter->setBrush( checkBrush );
734  painter->drawRoundedRect( rect, cornerSize, cornerSize );
735  }
736 
737  //draw semi-transparent color on top
738  painter->setBrush( color );
739  painter->drawRoundedRect( rect, cornerSize, cornerSize );
740  painter->restore();
741 }
742 
743 QPixmap QgsColorSwatchDelegate::transparentBackground() const
744 {
745  static QPixmap sTranspBkgrd;
746 
747  if ( sTranspBkgrd.isNull() )
748  sTranspBkgrd = QgsApplication::getThemePixmap( QStringLiteral( "/transp-background_8x8.png" ) );
749 
750  return sTranspBkgrd;
751 }
752 
753 QSize QgsColorSwatchDelegate::sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const
754 {
755  Q_UNUSED( index )
756 
757 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
758  const int iconSize = Qgis::UI_SCALE_FACTOR * option.fontMetrics.width( 'X' ) * 4;
759 #else
760  const int iconSize = Qgis::UI_SCALE_FACTOR * option.fontMetrics.horizontalAdvance( 'X' ) * 4;
761 #endif
762  return QSize( iconSize, iconSize * 32 / 30.0 );
763 }
764 
765 bool QgsColorSwatchDelegate::editorEvent( QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index )
766 {
767  Q_UNUSED( option )
768  if ( event->type() == QEvent::MouseButtonDblClick )
769  {
770  if ( !index.model()->flags( index ).testFlag( Qt::ItemIsEditable ) )
771  {
772  //item not editable
773  return false;
774  }
775 
776  QColor color = index.model()->data( index, Qt::DisplayRole ).value<QColor>();
777 
778  QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( qobject_cast< QWidget * >( parent() ) );
779  if ( panel && panel->dockMode() )
780  {
782  colorWidget->setPanelTitle( tr( "Select Color" ) );
783  colorWidget->setAllowOpacity( true );
784  colorWidget->setProperty( "index", index );
785  connect( colorWidget, &QgsCompoundColorWidget::currentColorChanged, this, &QgsColorSwatchDelegate::colorChanged );
786  panel->openPanel( colorWidget );
787  return true;
788  }
789 
790  QColor newColor = QgsColorDialog::getColor( color, mParent, tr( "Select color" ), true );
791  if ( !newColor.isValid() )
792  {
793  return false;
794  }
795 
796  return model->setData( index, newColor, Qt::EditRole );
797  }
798 
799  return false;
800 }
801 
802 void QgsColorSwatchDelegate::colorChanged()
803 {
804  if ( QgsCompoundColorWidget *colorWidget = qobject_cast< QgsCompoundColorWidget * >( sender() ) )
805  {
806  QModelIndex index = colorWidget->property( "index" ).toModelIndex();
807  const_cast< QAbstractItemModel * >( index.model() )->setData( index, colorWidget->color(), Qt::EditRole );
808  }
809 }
Qt::DropActions supportedDropActions() const override
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
static QColor getColor(const QColor &initialColor, QWidget *parent, const QString &title=QString(), bool allowOpacity=false)
Returns a color selection from a color dialog.
bool exportColorsToGpl(QFile &file)
Export colors to a GPL palette file from the list.
void colorSelected(const QColor &color)
Emitted when a color is selected from the list.
QgsNamedColorList colors() const
Returns a list of colors shown in the widget.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
void removeSelection()
Removes any selected colors from the list.
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:182
This class is a composition of two QSettings instances:
Definition: qgssettings.h:61
QColor baseColor() const
Gets the base color for the color scheme used by the model.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Abstract base class for color schemes.
QString context() const
Gets the current color scheme context for the model.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
static QgsNamedColorList colorListFromMimeData(const QMimeData *data)
Attempts to parse mime data as a list of named colors.
QModelIndex parent(const QModelIndex &index) const override
void setScheme(QgsColorScheme *scheme, const QString &context=QString(), const QColor &baseColor=QColor())
Sets the color scheme to show in the widget.
Qt::ItemFlags flags(const QModelIndex &index) const override
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
void setScheme(QgsColorScheme *scheme, const QString &context=QString(), const QColor &baseColor=QColor())
Sets the color scheme to show in the list.
Base class for any widget that can be shown as a inline panel.
void addColor(const QColor &color, const QString &label=QString(), bool allowDuplicate=false)
Adds a color to the list.
void pasteColors()
Pastes colors from clipboard to the list.
QgsColorSchemeModel(QgsColorScheme *scheme, const QString &context=QString(), const QColor &baseColor=QColor(), QObject *parent=nullptr)
Constructor.
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
static QPixmap getThemePixmap(const QString &name)
Helper to get a theme icon as a pixmap.
bool importColorsFromGpl(QFile &file)
Import colors from a GPL palette file to the list.
void mouseReleaseEvent(QMouseEvent *event) override
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override
QgsColorScheme * scheme()
Returns the scheme currently selected in the list.
void showExportColorsDialog()
Displays a file picker dialog allowing users to export colors from the list into a file...
static QgsNamedColorList importColorsFromGpl(QFile &file, bool &ok, QString &name)
Imports colors from a gpl GIMP palette file.
void mousePressEvent(QMouseEvent *event) override
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget...
void showImportColorsDialog()
Displays a file picker dialog allowing users to import colors into the list from a file...
A custom QGIS widget for selecting a color, including options for selecting colors via hue wheel...
static QString colorToName(const QColor &color)
Returns a friendly display name for a color.
QList< QPair< QColor, QString > > QgsNamedColorList
List of colors paired with a friendly display name identifying the color.
bool isDirty() const
Returns whether the color scheme list has been modified.
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window&#39;s toolbar icons.
QgsColorSwatchDelegate(QWidget *parent=nullptr)
bool saveColorsToScheme()
Saves the current colors shown in the list back to a color scheme, if supported by the color scheme...
void setAllowOpacity(bool allowOpacity)
Sets whether opacity modification (transparency) is permitted for the color dialog.
virtual bool isEditable() const
Returns whether the color scheme is editable.
static bool saveColorsToGpl(QFile &file, const QString &paletteName, const QgsNamedColorList &colors)
Exports colors to a gpl GIMP palette file.
bool isDirty() const
Returns whether the color scheme model has been modified.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
void copyColors()
Copies colors from the list to the clipboard.
void currentColorChanged(const QColor &color)
Emitted when the dialog&#39;s color changes.
virtual QgsNamedColorList fetchColors(const QString &context=QString(), const QColor &baseColor=QColor())=0
Gets a list of colors from the scheme.
QStringList mimeTypes() const override
QgsColorSchemeList(QWidget *parent=nullptr, QgsColorScheme *scheme=nullptr, const QString &context=QString(), const QColor &baseColor=QColor())
Construct a new color swatch grid.
static QMimeData * colorListToMimeData(const QgsNamedColorList &colorList, bool allFormats=true)
Creates mime data from a list of named colors.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void keyPressEvent(QKeyEvent *event) override
int columnCount(const QModelIndex &parent=QModelIndex()) const override
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
void addColor(const QColor &color, const QString &label=QString(), bool allowDuplicate=false)
Add a color to the list.
Use a narrower, vertically stacked layout.
virtual bool setColors(const QgsNamedColorList &colors, const QString &context=QString(), const QColor &baseColor=QColor())
Sets the colors for the scheme.
A delegate for showing a color swatch in a list.
QMimeData * mimeData(const QModelIndexList &indexes) const override
A model for colors in a color scheme.