QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
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 = qgis::setToList( qgis::listToSet( rows ) );
85 
86  //remove rows in descending order
87  std::sort( rowsToRemove.begin(), rowsToRemove.end(), std::greater<int>() );
88  const auto constRowsToRemove = rowsToRemove;
89  for ( const 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  const 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  const QList<int> rowsToCopy = qgis::setToList( qgis::listToSet( rows ) );
128 
129  QgsNamedColorList colorsToCopy;
130  const auto constRowsToCopy = rowsToCopy;
131  for ( const 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  const QString lastDir = s.value( QStringLiteral( "/UI/lastGplPaletteDir" ), QDir::homePath() ).toString();
145  const 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  const 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  const 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  const 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  const QFileInfo fileInfo( fileName );
188  s.setValue( QStringLiteral( "/UI/lastGplPaletteDir" ), fileInfo.absolutePath() );
189 
190  QFile file( fileName );
191  const 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 = qgis::setToList( qgis::listToSet( rows ) );
212 
213  //remove rows in descending order
214  std::sort( rowsToRemove.begin(), rowsToRemove.end(), std::greater<int>() );
215  const auto constRowsToRemove = rowsToRemove;
216  for ( const 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  const 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  const 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 static_cast<Qt::Alignment::Int>( 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 static_cast<Qt::Alignment::Int>( Qt::AlignHCenter | Qt::AlignVCenter );
469  case ColorLabel:
470  return static_cast<Qt::Alignment::Int>( 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  const QPair< QColor, QString > color = qMakePair( ( *colorIt ).first, !( *colorIt ).second.isEmpty() ? ( *colorIt ).second : QgsSymbolLayerUtils::colorToName( ( *colorIt ).first ) );
557  //if color already exists, remove it
558  const 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  const QModelIndex colorIdx = index( beginRow, 0, QModelIndex() );
579  setData( colorIdx, QVariant( ( *colorIt ).first ) );
580  const 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  const 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  const QPair< QColor, QString > newColor = qMakePair( color, !label.isEmpty() ? label : QgsSymbolLayerUtils::colorToName( color ) );
659  //if color already exists, remove it
660  const 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  const int row = rowCount();
670  insertRow( row );
671  const QModelIndex colorIdx = index( row, 0, QModelIndex() );
672  setData( colorIdx, QVariant( color ) );
673  const 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  const 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  const int iconSize = Qgis::UI_SCALE_FACTOR * option.fontMetrics.horizontalAdvance( 'X' ) * 4;
714 
715  const int cornerSize = iconSize / 6;
716  //center it
717  rect.setLeft( option.rect.center().x() - iconSize / 2 );
718 
719  rect.setSize( QSize( iconSize, iconSize ) );
720  rect.adjust( 0, 1, 0, 1 );
721  //create an icon pixmap
722  const QgsScopedQPainterState painterState( painter );
723  painter->setRenderHint( QPainter::Antialiasing );
724  painter->setPen( Qt::NoPen );
725  if ( color.alpha() < 255 )
726  {
727  //start with checkboard pattern
728  const QBrush checkBrush = QBrush( transparentBackground() );
729  painter->setBrush( checkBrush );
730  painter->drawRoundedRect( rect, cornerSize, cornerSize );
731  }
732 
733  //draw semi-transparent color on top
734  painter->setBrush( color );
735  painter->drawRoundedRect( rect, cornerSize, cornerSize );
736 }
737 
738 QPixmap QgsColorSwatchDelegate::transparentBackground() const
739 {
740  static QPixmap sTranspBkgrd;
741 
742  if ( sTranspBkgrd.isNull() )
743  sTranspBkgrd = QgsApplication::getThemePixmap( QStringLiteral( "/transp-background_8x8.png" ) );
744 
745  return sTranspBkgrd;
746 }
747 
748 QSize QgsColorSwatchDelegate::sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const
749 {
750  Q_UNUSED( index )
751 
752  const int iconSize = Qgis::UI_SCALE_FACTOR * option.fontMetrics.horizontalAdvance( 'X' ) * 4;
753  return QSize( iconSize, iconSize * 32 / 30.0 );
754 }
755 
756 bool QgsColorSwatchDelegate::editorEvent( QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index )
757 {
758  Q_UNUSED( option )
759  if ( event->type() == QEvent::MouseButtonDblClick )
760  {
761  if ( !index.model()->flags( index ).testFlag( Qt::ItemIsEditable ) )
762  {
763  //item not editable
764  return false;
765  }
766 
767  const QColor color = index.model()->data( index, Qt::DisplayRole ).value<QColor>();
768 
769  QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( qobject_cast< QWidget * >( parent() ) );
770  if ( panel && panel->dockMode() )
771  {
773  colorWidget->setPanelTitle( tr( "Select Color" ) );
774  colorWidget->setAllowOpacity( true );
775  colorWidget->setProperty( "index", index );
776  connect( colorWidget, &QgsCompoundColorWidget::currentColorChanged, this, &QgsColorSwatchDelegate::colorChanged );
777  panel->openPanel( colorWidget );
778  return true;
779  }
780 
781  const QColor newColor = QgsColorDialog::getColor( color, mParent, tr( "Select color" ), true );
782  if ( !newColor.isValid() )
783  {
784  return false;
785  }
786 
787  return model->setData( index, newColor, Qt::EditRole );
788  }
789 
790  return false;
791 }
792 
793 void QgsColorSwatchDelegate::colorChanged()
794 {
795  if ( QgsCompoundColorWidget *colorWidget = qobject_cast< QgsCompoundColorWidget * >( sender() ) )
796  {
797  const QModelIndex index = colorWidget->property( "index" ).toModelIndex();
798  const_cast< QAbstractItemModel * >( index.model() )->setData( index, colorWidget->color(), Qt::EditRole );
799  }
800 }
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:1052
static QPixmap getThemePixmap(const QString &name, const QColor &foreColor=QColor(), const QColor &backColor=QColor(), int size=16)
Helper to get a theme icon as a pixmap.
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 setScheme(QgsColorScheme *scheme, const QString &context=QString(), const QColor &baseColor=QColor())
Sets the color scheme to show in the list.
void pasteColors()
Pastes colors from clipboard to the list.
void removeSelection()
Removes any selected colors from the list.
bool importColorsFromGpl(QFile &file)
Import colors from a GPL palette file to the list.
void copyColors()
Copies colors from the list to the clipboard.
bool isDirty() const
Returns whether the color scheme list has been modified.
void mouseReleaseEvent(QMouseEvent *event) override
void mousePressEvent(QMouseEvent *event) override
QgsColorScheme * scheme()
Returns the scheme currently selected in the list.
void addColor(const QColor &color, const QString &label=QString(), bool allowDuplicate=false)
Adds a color to the list.
void showExportColorsDialog()
Displays a file picker dialog allowing users to export colors from the list into a file.
void colorSelected(const QColor &color)
Emitted when a color is selected from the list.
void keyPressEvent(QKeyEvent *event) override
QgsColorSchemeList(QWidget *parent=nullptr, QgsColorScheme *scheme=nullptr, const QString &context=QString(), const QColor &baseColor=QColor())
Construct a new color swatch grid.
bool saveColorsToScheme()
Saves the current colors shown in the list back to a color scheme, if supported by the color scheme.
void showImportColorsDialog()
Displays a file picker dialog allowing users to import colors into the list from a file.
A model for colors in a color scheme.
QgsNamedColorList colors() const
Returns a list of colors shown in the widget.
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
void addColor(const QColor &color, const QString &label=QString(), bool allowDuplicate=false)
Add a color to the list.
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
QColor baseColor() const
Gets the base color for the color scheme used by the model.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Qt::DropActions supportedDropActions() const override
QModelIndex parent(const QModelIndex &index) const override
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
Qt::ItemFlags flags(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.
bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
QMimeData * mimeData(const QModelIndexList &indexes) const override
bool isDirty() const
Returns whether the color scheme model has been modified.
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
QgsColorSchemeModel(QgsColorScheme *scheme, const QString &context=QString(), const QColor &baseColor=QColor(), QObject *parent=nullptr)
Constructor.
QStringList mimeTypes() const override
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
QString context() const
Gets the current color scheme context for the model.
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Abstract base class for color schemes.
virtual bool setColors(const QgsNamedColorList &colors, const QString &context=QString(), const QColor &baseColor=QColor())
Sets the colors for the scheme.
virtual QgsNamedColorList fetchColors(const QString &context=QString(), const QColor &baseColor=QColor())=0
Gets a list of colors from the scheme.
virtual bool isEditable() const
Returns whether the color scheme is editable.
A delegate for showing a color swatch in a list.
QgsColorSwatchDelegate(QWidget *parent=nullptr)
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
A custom QGIS widget for selecting a color, including options for selecting colors via hue wheel,...
@ LayoutVertical
Use a narrower, vertically stacked layout.
void currentColorChanged(const QColor &color)
Emitted when the dialog's color changes.
void setAllowOpacity(bool allowOpacity)
Sets whether opacity modification (transparency) is permitted for the color dialog.
Base class for any widget that can be shown as a inline panel.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget.
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
Scoped object for saving and restoring a QPainter object's state.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
static bool saveColorsToGpl(QFile &file, const QString &paletteName, const QgsNamedColorList &colors)
Exports colors to a gpl GIMP palette file.
static QgsNamedColorList colorListFromMimeData(const QMimeData *data)
Attempts to parse mime data as a list of named colors.
static QMimeData * colorListToMimeData(const QgsNamedColorList &colorList, bool allFormats=true)
Creates mime data from a list of named colors.
static QgsNamedColorList importColorsFromGpl(QFile &file, bool &ok, QString &name)
Imports colors from a gpl GIMP palette file.
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.
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.