QGIS API Documentation  2.11.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgscolordialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscolordialog.cpp - color selection dialog
3 
4  ---------------------
5  begin : March 19, 2013
6  copyright : (C) 2013 by Larry Shaffer
7  email : larrys at dakcarto dot com
8  ***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include "qgscolordialog.h"
18 #include "qgscolorscheme.h"
19 #include "qgscolorschemeregistry.h"
20 #include "qgssymbollayerv2utils.h"
21 #include "qgscursors.h"
22 #include "qgsapplication.h"
23 #include <QSettings>
24 #include <QPushButton>
25 #include <QMenu>
26 #include <QToolButton>
27 #include <QFileDialog>
28 #include <QMessageBox>
29 #include <QDesktopWidget>
30 #include <QMouseEvent>
31 #include <QInputDialog>
32 
34 {
35 }
36 
38 {
39 }
40 
41 QColor QgsColorDialog::getLiveColor( const QColor& initialColor, QObject* updateObject, const char* updateSlot,
42  QWidget* parent,
43  const QString& title,
45 {
46  QColor returnColor( initialColor );
47  QColorDialog* liveDialog = new QColorDialog( initialColor, parent );
48  liveDialog->setWindowTitle( title.isEmpty() ? tr( "Select Color" ) : title );
49  liveDialog->setOptions( options );
50 
51  connect( liveDialog, SIGNAL( currentColorChanged( const QColor& ) ),
52  updateObject, updateSlot );
53 
54  if ( liveDialog->exec() )
55  {
56  returnColor = liveDialog->currentColor();
57  }
58  delete liveDialog;
59  liveDialog = 0;
60 
61  return returnColor;
62 }
63 
64 
65 //
66 // QgsColorDialogV2
67 //
68 
70  : QDialog( parent, fl )
71  , mPreviousColor( color )
72  , mAllowAlpha( true )
73  , mLastCustomColorIndex( 0 )
74  , mPickingColor( false )
75 {
76  setupUi( this );
77 
78  QSettings settings;
79  restoreGeometry( settings.value( "/Windows/ColorDialog/geometry" ).toByteArray() );
80 
81  mSchemeList->header()->hide();
82  mSchemeList->setColumnWidth( 0, 44 );
83 
84  //get schemes with ShowInColorDialog set
85  refreshSchemeComboBox();
87 
88  //choose a reasonable starting scheme
89  int activeScheme = settings.value( "/Windows/ColorDialog/activeScheme", 0 ).toInt();
90  activeScheme = activeScheme >= mSchemeComboBox->count() ? 0 : activeScheme;
91 
92  mSchemeList->setScheme( schemeList.at( activeScheme ) );
93  mSchemeComboBox->setCurrentIndex( activeScheme );
94  mActionImportColors->setEnabled( schemeList.at( activeScheme )->isEditable() );
95  mActionPasteColors->setEnabled( schemeList.at( activeScheme )->isEditable() );
96  mAddColorToSchemeButton->setEnabled( schemeList.at( activeScheme )->isEditable() );
97  mRemoveColorsFromSchemeButton->setEnabled( schemeList.at( activeScheme )->isEditable() );
98  QgsUserColorScheme* userScheme = dynamic_cast<QgsUserColorScheme*>( schemeList.at( activeScheme ) );
99  mActionRemovePalette->setEnabled( userScheme ? true : false );
100 
101  //listen out for selection changes in list, so we can enable/disable the copy colors option
102  connect( mSchemeList->selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), this, SLOT( listSelectionChanged( QItemSelection, QItemSelection ) ) );
103  //copy action defaults to disabled
104  mActionCopyColors->setEnabled( false );
105 
106  connect( mActionCopyColors, SIGNAL( triggered() ), mSchemeList, SLOT( copyColors() ) );
107  connect( mActionPasteColors, SIGNAL( triggered() ), mSchemeList, SLOT( pasteColors() ) );
108  connect( mActionExportColors, SIGNAL( triggered() ), this, SLOT( exportColors() ) );
109  connect( mActionImportColors, SIGNAL( triggered() ), this, SLOT( importColors() ) );
110  connect( mActionImportPalette, SIGNAL( triggered() ), this, SLOT( importPalette() ) );
111  connect( mActionRemovePalette, SIGNAL( triggered() ), this, SLOT( removePalette() ) );
112  connect( mActionNewPalette, SIGNAL( triggered() ), this, SLOT( newPalette() ) );
113  connect( mRemoveColorsFromSchemeButton, SIGNAL( clicked() ), mSchemeList, SLOT( removeSelection() ) );
114 
115  QMenu* schemeMenu = new QMenu( mSchemeToolButton );
116  schemeMenu->addAction( mActionCopyColors );
117  schemeMenu->addAction( mActionPasteColors );
118  schemeMenu->addSeparator();
119  schemeMenu->addAction( mActionImportColors );
120  schemeMenu->addAction( mActionExportColors );
121  schemeMenu->addSeparator();
122  schemeMenu->addAction( mActionNewPalette );
123  schemeMenu->addAction( mActionImportPalette );
124  schemeMenu->addAction( mActionRemovePalette );
125  mSchemeToolButton->setMenu( schemeMenu );
126 
127  connect( mSchemeComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( schemeIndexChanged( int ) ) );
128  connect( mSchemeList, SIGNAL( colorSelected( QColor ) ), this, SLOT( setColor( QColor ) ) );
129 
130  if ( mPreviousColor.isValid() )
131  {
132  QPushButton* resetButton = new QPushButton( tr( "Reset" ) );
133  mButtonBox->addButton( resetButton, QDialogButtonBox::ResetRole );
134  }
135  else
136  {
137  mOldColorLabel->hide();
138  }
139 
140  mVerticalRamp->setOrientation( QgsColorRampWidget::Vertical );
141  mVerticalRamp->setInteriorMargin( 2 );
142  mVerticalRamp->setShowFrame( true );
143 
144  mRedSlider->setComponent( QgsColorWidget::Red );
145  mGreenSlider->setComponent( QgsColorWidget::Green );
146  mBlueSlider->setComponent( QgsColorWidget::Blue );
147  mHueSlider->setComponent( QgsColorWidget::Hue );
148  mSaturationSlider->setComponent( QgsColorWidget::Saturation );
149  mValueSlider->setComponent( QgsColorWidget::Value );
150  mAlphaSlider->setComponent( QgsColorWidget::Alpha );
151 
152  mSwatchButton1->setShowMenu( false );
153  mSwatchButton1->setBehaviour( QgsColorButtonV2::SignalOnly );
154  mSwatchButton2->setShowMenu( false );
155  mSwatchButton2->setBehaviour( QgsColorButtonV2::SignalOnly );
156  mSwatchButton3->setShowMenu( false );
157  mSwatchButton3->setBehaviour( QgsColorButtonV2::SignalOnly );
158  mSwatchButton4->setShowMenu( false );
159  mSwatchButton4->setBehaviour( QgsColorButtonV2::SignalOnly );
160  mSwatchButton5->setShowMenu( false );
161  mSwatchButton5->setBehaviour( QgsColorButtonV2::SignalOnly );
162  mSwatchButton6->setShowMenu( false );
163  mSwatchButton6->setBehaviour( QgsColorButtonV2::SignalOnly );
164  mSwatchButton7->setShowMenu( false );
165  mSwatchButton7->setBehaviour( QgsColorButtonV2::SignalOnly );
166  mSwatchButton8->setShowMenu( false );
167  mSwatchButton8->setBehaviour( QgsColorButtonV2::SignalOnly );
168  mSwatchButton9->setShowMenu( false );
169  mSwatchButton9->setBehaviour( QgsColorButtonV2::SignalOnly );
170  mSwatchButton10->setShowMenu( false );
171  mSwatchButton10->setBehaviour( QgsColorButtonV2::SignalOnly );
172  mSwatchButton11->setShowMenu( false );
173  mSwatchButton11->setBehaviour( QgsColorButtonV2::SignalOnly );
174  mSwatchButton12->setShowMenu( false );
175  mSwatchButton12->setBehaviour( QgsColorButtonV2::SignalOnly );
176  mSwatchButton13->setShowMenu( false );
177  mSwatchButton13->setBehaviour( QgsColorButtonV2::SignalOnly );
178  mSwatchButton14->setShowMenu( false );
179  mSwatchButton14->setBehaviour( QgsColorButtonV2::SignalOnly );
180  mSwatchButton15->setShowMenu( false );
181  mSwatchButton15->setBehaviour( QgsColorButtonV2::SignalOnly );
182  mSwatchButton16->setShowMenu( false );
183  mSwatchButton16->setBehaviour( QgsColorButtonV2::SignalOnly );
184  //restore custom colors
185  mSwatchButton1->setColor( settings.value( "/Windows/ColorDialog/customColor1", QVariant( QColor() ) ).value<QColor>() );
186  mSwatchButton2->setColor( settings.value( "/Windows/ColorDialog/customColor2", QVariant( QColor() ) ).value<QColor>() );
187  mSwatchButton3->setColor( settings.value( "/Windows/ColorDialog/customColor3", QVariant( QColor() ) ).value<QColor>() );
188  mSwatchButton4->setColor( settings.value( "/Windows/ColorDialog/customColor4", QVariant( QColor() ) ).value<QColor>() );
189  mSwatchButton5->setColor( settings.value( "/Windows/ColorDialog/customColor5", QVariant( QColor() ) ).value<QColor>() );
190  mSwatchButton6->setColor( settings.value( "/Windows/ColorDialog/customColor6", QVariant( QColor() ) ).value<QColor>() );
191  mSwatchButton7->setColor( settings.value( "/Windows/ColorDialog/customColor7", QVariant( QColor() ) ).value<QColor>() );
192  mSwatchButton8->setColor( settings.value( "/Windows/ColorDialog/customColor8", QVariant( QColor() ) ).value<QColor>() );
193  mSwatchButton9->setColor( settings.value( "/Windows/ColorDialog/customColor9", QVariant( QColor() ) ).value<QColor>() );
194  mSwatchButton10->setColor( settings.value( "/Windows/ColorDialog/customColor10", QVariant( QColor() ) ).value<QColor>() );
195  mSwatchButton11->setColor( settings.value( "/Windows/ColorDialog/customColor11", QVariant( QColor() ) ).value<QColor>() );
196  mSwatchButton12->setColor( settings.value( "/Windows/ColorDialog/customColor12", QVariant( QColor() ) ).value<QColor>() );
197  mSwatchButton13->setColor( settings.value( "/Windows/ColorDialog/customColor13", QVariant( QColor() ) ).value<QColor>() );
198  mSwatchButton14->setColor( settings.value( "/Windows/ColorDialog/customColor14", QVariant( QColor() ) ).value<QColor>() );
199  mSwatchButton15->setColor( settings.value( "/Windows/ColorDialog/customColor15", QVariant( QColor() ) ).value<QColor>() );
200  mSwatchButton16->setColor( settings.value( "/Windows/ColorDialog/customColor16", QVariant( QColor() ) ).value<QColor>() );
201 
202  //restore sample radius
203  mSpinBoxRadius->setValue( settings.value( "/Windows/ColorDialog/sampleRadius", 1 ).toInt() );
204  mSamplePreview->setColor( QColor() );
205 
206  if ( color.isValid() )
207  {
208  setColor( color );
209  mColorPreview->setColor2( color );
210  }
211 
212  //restore active component radio button
213  int activeRadio = settings.value( "/Windows/ColorDialog/activeComponent", 2 ).toInt();
214  switch ( activeRadio )
215  {
216  case 0:
217  mHueRadio->setChecked( true );
218  break;
219  case 1:
220  mSaturationRadio->setChecked( true );
221  break;
222  case 2:
223  mValueRadio->setChecked( true );
224  break;
225  case 3:
226  mRedRadio->setChecked( true );
227  break;
228  case 4:
229  mGreenRadio->setChecked( true );
230  break;
231  case 5:
232  mBlueRadio->setChecked( true );
233  break;
234  }
235  int currentTab = settings.value( "/Windows/ColorDialog/activeTab", 0 ).toInt();
236  mTabWidget->setCurrentIndex( currentTab );
237 
238 #ifdef Q_OS_MAC
239  //disable color picker tab for OSX, as it is impossible to grab the mouse under OSX
240  //see note for QWidget::grabMouse() re OSX Cocoa
241  //http://qt-project.org/doc/qt-4.8/qwidget.html#grabMouse
242  mTabWidget->removeTab( 3 );
243 #endif
244 
245  //setup connections
246  connect( mColorBox, SIGNAL( colorChanged( QColor ) ), this, SLOT( setColor( QColor ) ) );
247  connect( mColorWheel, SIGNAL( colorChanged( QColor ) ), this, SLOT( setColor( QColor ) ) );
248  connect( mColorText, SIGNAL( colorChanged( QColor ) ), this, SLOT( setColor( QColor ) ) );
249  connect( mVerticalRamp, SIGNAL( colorChanged( QColor ) ), this, SLOT( setColor( QColor ) ) );
250  connect( mRedSlider, SIGNAL( colorChanged( QColor ) ), this, SLOT( setColor( QColor ) ) );
251  connect( mGreenSlider, SIGNAL( colorChanged( QColor ) ), this, SLOT( setColor( QColor ) ) );
252  connect( mBlueSlider, SIGNAL( colorChanged( QColor ) ), this, SLOT( setColor( QColor ) ) );
253  connect( mHueSlider, SIGNAL( colorChanged( QColor ) ), this, SLOT( setColor( QColor ) ) );
254  connect( mValueSlider, SIGNAL( colorChanged( QColor ) ), this, SLOT( setColor( QColor ) ) );
255  connect( mSaturationSlider, SIGNAL( colorChanged( QColor ) ), this, SLOT( setColor( QColor ) ) );
256  connect( mAlphaSlider, SIGNAL( colorChanged( QColor ) ), this, SLOT( setColor( QColor ) ) );
257  connect( mColorPreview, SIGNAL( colorChanged( QColor ) ), this, SLOT( setColor( QColor ) ) );
258  connect( mSwatchButton1, SIGNAL( colorClicked( QColor ) ), this, SLOT( setColor( QColor ) ) );
259  connect( mSwatchButton2, SIGNAL( colorClicked( QColor ) ), this, SLOT( setColor( QColor ) ) );
260  connect( mSwatchButton3, SIGNAL( colorClicked( QColor ) ), this, SLOT( setColor( QColor ) ) );
261  connect( mSwatchButton4, SIGNAL( colorClicked( QColor ) ), this, SLOT( setColor( QColor ) ) );
262  connect( mSwatchButton5, SIGNAL( colorClicked( QColor ) ), this, SLOT( setColor( QColor ) ) );
263  connect( mSwatchButton6, SIGNAL( colorClicked( QColor ) ), this, SLOT( setColor( QColor ) ) );
264  connect( mSwatchButton7, SIGNAL( colorClicked( QColor ) ), this, SLOT( setColor( QColor ) ) );
265  connect( mSwatchButton8, SIGNAL( colorClicked( QColor ) ), this, SLOT( setColor( QColor ) ) );
266  connect( mSwatchButton9, SIGNAL( colorClicked( QColor ) ), this, SLOT( setColor( QColor ) ) );
267  connect( mSwatchButton10, SIGNAL( colorClicked( QColor ) ), this, SLOT( setColor( QColor ) ) );
268  connect( mSwatchButton11, SIGNAL( colorClicked( QColor ) ), this, SLOT( setColor( QColor ) ) );
269  connect( mSwatchButton12, SIGNAL( colorClicked( QColor ) ), this, SLOT( setColor( QColor ) ) );
270  connect( mSwatchButton13, SIGNAL( colorClicked( QColor ) ), this, SLOT( setColor( QColor ) ) );
271  connect( mSwatchButton14, SIGNAL( colorClicked( QColor ) ), this, SLOT( setColor( QColor ) ) );
272  connect( mSwatchButton15, SIGNAL( colorClicked( QColor ) ), this, SLOT( setColor( QColor ) ) );
273  connect( mSwatchButton16, SIGNAL( colorClicked( QColor ) ), this, SLOT( setColor( QColor ) ) );
274 }
275 
277 {
278 
279 }
280 
282 {
283  //all widgets should have the same color, so it shouldn't matter
284  //which we fetch it from
285  return mColorPreview->color();
286 }
287 
289 {
290  setWindowTitle( title.isEmpty() ? tr( "Select Color" ) : title );
291 }
292 
293 void QgsColorDialogV2::setAllowAlpha( const bool allowAlpha )
294 {
295  mAllowAlpha = allowAlpha;
296  mAlphaLabel->setVisible( allowAlpha );
297  mAlphaSlider->setVisible( allowAlpha );
298  if ( !allowAlpha )
299  {
300  mAlphaLayout->setContentsMargins( 0, 0, 0, 0 );
301  mAlphaLayout->setSpacing( 0 );
302  }
303 }
304 
305 QColor QgsColorDialogV2::getLiveColor( const QColor &initialColor, QObject *updateObject, const char *updateSlot, QWidget *parent, const QString &title, const bool allowAlpha )
306 {
307  QColor returnColor( initialColor );
308  QgsColorDialogV2* liveDialog = new QgsColorDialogV2( parent, 0, initialColor );
309  liveDialog->setWindowTitle( title.isEmpty() ? tr( "Select Color" ) : title );
310  if ( !allowAlpha )
311  {
312  liveDialog->setAllowAlpha( false );
313  }
314 
315  connect( liveDialog, SIGNAL( currentColorChanged( const QColor& ) ),
316  updateObject, updateSlot );
317 
318  if ( liveDialog->exec() )
319  {
320  returnColor = liveDialog->color();
321  }
322  delete liveDialog;
323  liveDialog = 0;
324 
325  return returnColor;
326 }
327 
328 QColor QgsColorDialogV2::getColor( const QColor &initialColor, QWidget *parent, const QString &title, const bool allowAlpha )
329 {
330  QString dialogTitle = title.isEmpty() ? tr( "Select Color" ) : title;
331 
332  QSettings settings;
333  //using native color dialogs?
334  bool useNative = settings.value( "/qgis/native_color_dialogs", false ).toBool();
335  if ( useNative )
336  {
337  return QColorDialog::getColor( initialColor, parent, dialogTitle, allowAlpha ? QColorDialog::ShowAlphaChannel : ( QColorDialog::ColorDialogOption )0 );
338  }
339  else
340  {
341  QgsColorDialogV2* dialog = new QgsColorDialogV2( parent, 0, initialColor );
342  dialog->setWindowTitle( dialogTitle );
343  dialog->setAllowAlpha( allowAlpha );
344 
345  QColor result;
346  if ( dialog->exec() )
347  {
348  result = dialog->color();
349  }
350 
351  if ( !parent )
352  {
353  delete dialog;
354  }
355  return result;
356  }
357 }
358 
359 void QgsColorDialogV2::on_mButtonBox_accepted()
360 {
361  saveSettings();
362  accept();
363 }
364 
365 void QgsColorDialogV2::on_mButtonBox_rejected()
366 {
367  saveSettings();
368  reject();
369 }
370 
371 void QgsColorDialogV2::on_mButtonBox_clicked( QAbstractButton * button )
372 {
373  if ( mButtonBox->buttonRole( button ) == QDialogButtonBox::ResetRole && mPreviousColor.isValid() )
374  {
375  setColor( mPreviousColor );
376  }
377 }
378 
379 void QgsColorDialogV2::importColors()
380 {
381  QSettings s;
382  QString lastDir = s.value( "/UI/lastGplPaletteDir", "" ).toString();
383  QString filePath = QFileDialog::getOpenFileName( this, tr( "Select palette file" ), lastDir, "GPL (*.gpl);;All files (*.*)" );
384  activateWindow();
385  if ( filePath.isEmpty() )
386  {
387  return;
388  }
389 
390  //check if file exists
391  QFileInfo fileInfo( filePath );
392  if ( !fileInfo.exists() || !fileInfo.isReadable() )
393  {
394  QMessageBox::critical( 0, tr( "Invalid file" ), tr( "Error, file does not exist or is not readable" ) );
395  return;
396  }
397 
398  s.setValue( "/UI/lastGplPaletteDir", fileInfo.absolutePath() );
399  QFile file( filePath );
400  bool importOk = mSchemeList->importColorsFromGpl( file );
401  if ( !importOk )
402  {
403  QMessageBox::critical( 0, tr( "Invalid file" ), tr( "Error, no colors found in palette file" ) );
404  return;
405  }
406 }
407 
408 void QgsColorDialogV2::refreshSchemeComboBox()
409 {
410  mSchemeComboBox->blockSignals( true );
411  mSchemeComboBox->clear();
413  QList<QgsColorScheme *>::const_iterator schemeIt = schemeList.constBegin();
414  for ( ; schemeIt != schemeList.constEnd(); ++schemeIt )
415  {
416  mSchemeComboBox->addItem(( *schemeIt )->schemeName() );
417  }
418  mSchemeComboBox->blockSignals( false );
419 }
420 
421 void QgsColorDialogV2::importPalette()
422 {
423  QSettings s;
424  QString lastDir = s.value( "/UI/lastGplPaletteDir", "" ).toString();
425  QString filePath = QFileDialog::getOpenFileName( this, tr( "Select palette file" ), lastDir, "GPL (*.gpl);;All files (*.*)" );
426  activateWindow();
427  if ( filePath.isEmpty() )
428  {
429  return;
430  }
431 
432  //check if file exists
433  QFileInfo fileInfo( filePath );
434  if ( !fileInfo.exists() || !fileInfo.isReadable() )
435  {
436  QMessageBox::critical( 0, tr( "Invalid file" ), tr( "Error, file does not exist or is not readable" ) );
437  return;
438  }
439 
440  s.setValue( "/UI/lastGplPaletteDir", fileInfo.absolutePath() );
441  QFile file( filePath );
442 
443  QgsNamedColorList importedColors;
444  bool ok = false;
445  QString paletteName;
446  importedColors = QgsSymbolLayerV2Utils::importColorsFromGpl( file, ok, paletteName );
447  if ( !ok )
448  {
449  QMessageBox::critical( 0, tr( "Invalid file" ), tr( "Palette file is not readable" ) );
450  return;
451  }
452 
453  if ( importedColors.length() == 0 )
454  {
455  //no imported colors
456  QMessageBox::critical( 0, tr( "Invalid file" ), tr( "No colors found in palette file" ) );
457  return;
458  }
459 
460  //TODO - handle conflicting file names, name for new palette
461  QgsUserColorScheme* importedScheme = new QgsUserColorScheme( fileInfo.fileName() );
462  importedScheme->setName( paletteName );
463  importedScheme->setColors( importedColors );
464 
466 
467  //refresh combobox
468  refreshSchemeComboBox();
469  mSchemeComboBox->setCurrentIndex( mSchemeComboBox->count() - 1 );
470 }
471 
472 void QgsColorDialogV2::removePalette()
473 {
474  //get current scheme
476  int prevIndex = mSchemeComboBox->currentIndex();
477  if ( prevIndex >= schemeList.length() )
478  {
479  return;
480  }
481 
482  //make user scheme is a user removable scheme
483  QgsUserColorScheme* userScheme = dynamic_cast<QgsUserColorScheme*>( schemeList.at( prevIndex ) );
484  if ( !userScheme )
485  {
486  return;
487  }
488 
489  if ( QMessageBox::question( this, tr( "Remove Color Palette" ),
490  QString( tr( "Are you sure you want to remove %1?" ) ).arg( userScheme->schemeName() ),
491  QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
492  {
493  //user cancelled
494  return;
495  }
496 
497  //remove palette and associated gpl file
498  if ( !userScheme->erase() )
499  {
500  //something went wrong
501  return;
502  }
503 
504  //remove scheme from registry
506  refreshSchemeComboBox();
507  prevIndex = qMax( qMin( prevIndex, mSchemeComboBox->count() - 1 ), 0 );
508  mSchemeComboBox->setCurrentIndex( prevIndex );
509 }
510 
511 void QgsColorDialogV2::newPalette()
512 {
513  bool ok = false;
514  QString name = QInputDialog::getText( this, tr( "Create New Palette" ), tr( "Enter a name for the new palette:" ),
515  QLineEdit::Normal, tr( "New palette" ), &ok );
516 
517  if ( !ok || name.isEmpty() )
518  {
519  //user cancelled
520  return;
521  }
522 
523  //generate file name for new palette
524  QDir palettePath( gplFilePath() );
525  QRegExp badChars( "[,^@={}\\[\\]~!?:&*\"|#%<>$\"'();`' /\\\\]" );
526  QString filename = name.simplified().toLower().replace( badChars, QString( "_" ) );
527  if ( filename.isEmpty() )
528  {
529  filename = tr( "new_palette" );
530  }
531  QFileInfo destFileInfo( palettePath.filePath( filename + ".gpl" ) );
532  int fileNumber = 1;
533  while ( destFileInfo.exists() )
534  {
535  //try to generate a unique file name
536  destFileInfo = QFileInfo( palettePath.filePath( filename + QString( "%1.gpl" ).arg( fileNumber ) ) );
537  fileNumber++;
538  }
539 
540  QgsUserColorScheme* newScheme = new QgsUserColorScheme( destFileInfo.fileName() );
541  newScheme->setName( name );
542 
544 
545  //refresh combobox and set new scheme as active
546  refreshSchemeComboBox();
547  mSchemeComboBox->setCurrentIndex( mSchemeComboBox->count() - 1 );
548 }
549 
550 QString QgsColorDialogV2::gplFilePath()
551 {
552  QString palettesDir = QgsApplication::qgisSettingsDirPath() + "/palettes";
553 
554  QDir localDir;
555  if ( !localDir.mkpath( palettesDir ) )
556  {
557  return QString();
558  }
559 
560  return palettesDir;
561 }
562 
563 void QgsColorDialogV2::exportColors()
564 {
565  QSettings s;
566  QString lastDir = s.value( "/UI/lastGplPaletteDir", "" ).toString();
567  QString fileName = QFileDialog::getSaveFileName( this, tr( "Palette file" ), lastDir, "GPL (*.gpl)" );
568  activateWindow();
569  if ( fileName.isEmpty() )
570  {
571  return;
572  }
573 
574  // ensure filename contains extension
575  if ( !fileName.toLower().endsWith( ".gpl" ) )
576  {
577  fileName += ".gpl";
578  }
579 
580  QFileInfo fileInfo( fileName );
581  s.setValue( "/UI/lastGplPaletteDir", fileInfo.absolutePath() );
582 
583  QFile file( fileName );
584  bool exportOk = mSchemeList->exportColorsToGpl( file );
585  if ( !exportOk )
586  {
587  QMessageBox::critical( 0, tr( "Error exporting" ), tr( "Error writing palette file" ) );
588  return;
589  }
590 }
591 
592 void QgsColorDialogV2::schemeIndexChanged( int index )
593 {
594  //save changes to scheme
595  if ( mSchemeList->isDirty() )
596  {
597  mSchemeList->saveColorsToScheme();
598  }
599 
600  //get schemes with ShowInColorDialog set
602  if ( index >= schemeList.length() )
603  {
604  return;
605  }
606 
607  QgsColorScheme* scheme = schemeList.at( index );
608  mSchemeList->setScheme( scheme );
609  mActionImportColors->setEnabled( scheme->isEditable() );
610  mActionPasteColors->setEnabled( scheme->isEditable() );
611  mAddColorToSchemeButton->setEnabled( scheme->isEditable() );
612  mRemoveColorsFromSchemeButton->setEnabled( scheme->isEditable() );
613  QgsUserColorScheme* userScheme = dynamic_cast<QgsUserColorScheme*>( scheme );
614  mActionRemovePalette->setEnabled( userScheme ? true : false );
615 
616  //copy action defaults to disabled
617  mActionCopyColors->setEnabled( false );
618 }
619 
620 void QgsColorDialogV2::listSelectionChanged( const QItemSelection &selected, const QItemSelection &deselected )
621 {
622  Q_UNUSED( deselected );
623  mActionCopyColors->setEnabled( selected.length() > 0 );
624 }
625 
626 void QgsColorDialogV2::on_mAddCustomColorButton_clicked()
627 {
628  switch ( mLastCustomColorIndex )
629  {
630  case 0:
631  mSwatchButton1->setColor( mColorPreview->color() );
632  break;
633  case 1:
634  mSwatchButton2->setColor( mColorPreview->color() );
635  break;
636  case 2:
637  mSwatchButton3->setColor( mColorPreview->color() );
638  break;
639  case 3:
640  mSwatchButton4->setColor( mColorPreview->color() );
641  break;
642  case 4:
643  mSwatchButton5->setColor( mColorPreview->color() );
644  break;
645  case 5:
646  mSwatchButton6->setColor( mColorPreview->color() );
647  break;
648  case 6:
649  mSwatchButton7->setColor( mColorPreview->color() );
650  break;
651  case 7:
652  mSwatchButton8->setColor( mColorPreview->color() );
653  break;
654  case 8:
655  mSwatchButton9->setColor( mColorPreview->color() );
656  break;
657  case 9:
658  mSwatchButton10->setColor( mColorPreview->color() );
659  break;
660  case 10:
661  mSwatchButton11->setColor( mColorPreview->color() );
662  break;
663  case 11:
664  mSwatchButton12->setColor( mColorPreview->color() );
665  break;
666  case 12:
667  mSwatchButton13->setColor( mColorPreview->color() );
668  break;
669  case 13:
670  mSwatchButton14->setColor( mColorPreview->color() );
671  break;
672  case 14:
673  mSwatchButton15->setColor( mColorPreview->color() );
674  break;
675  case 15:
676  mSwatchButton16->setColor( mColorPreview->color() );
677  break;
678  }
679  mLastCustomColorIndex++;
680  if ( mLastCustomColorIndex >= 16 )
681  {
682  mLastCustomColorIndex = 0;
683  }
684 }
685 
686 void QgsColorDialogV2::on_mSampleButton_clicked()
687 {
688  //activate picker color
689  QPixmap samplerPixmap = QPixmap(( const char ** ) sampler_cursor );
690  setCursor( QCursor( samplerPixmap, 0, 0 ) );
691  grabMouse();
692  grabKeyboard();
693  mPickingColor = true;
694  setMouseTracking( true );
695 }
696 
697 void QgsColorDialogV2::on_mTabWidget_currentChanged( int index )
698 {
699  //disable radio buttons if not using the first tab, as they have no meaning for other tabs
700  bool enabled = index == 0;
701  mRedRadio->setEnabled( enabled );
702  mBlueRadio->setEnabled( enabled );
703  mGreenRadio->setEnabled( enabled );
704  mHueRadio->setEnabled( enabled );
705  mSaturationRadio->setEnabled( enabled );
706  mValueRadio->setEnabled( enabled );
707 }
708 
709 void QgsColorDialogV2::saveSettings()
710 {
711  //save changes to scheme
712  if ( mSchemeList->isDirty() )
713  {
714  mSchemeList->saveColorsToScheme();
715  }
716 
717  QSettings settings;
718  settings.setValue( "/Windows/ColorDialog/geometry", saveGeometry() );
719 
720  //record active component
721  int activeRadio = 0;
722  if ( mHueRadio->isChecked() )
723  activeRadio = 0;
724  if ( mSaturationRadio->isChecked() )
725  activeRadio = 1;
726  if ( mValueRadio->isChecked() )
727  activeRadio = 2;
728  if ( mRedRadio->isChecked() )
729  activeRadio = 3;
730  if ( mGreenRadio->isChecked() )
731  activeRadio = 4;
732  if ( mBlueRadio->isChecked() )
733  activeRadio = 5;
734  settings.setValue( "/Windows/ColorDialog/activeComponent", activeRadio );
735 
736  //record current scheme
737  settings.setValue( "/Windows/ColorDialog/activeScheme", mSchemeComboBox->currentIndex() );
738 
739  //record current tab
740  settings.setValue( "/Windows/ColorDialog/activeTab", mTabWidget->currentIndex() );
741 
742  //record custom colors
743  settings.setValue( "/Windows/ColorDialog/customColor1", QVariant( mSwatchButton1->color() ) );
744  settings.setValue( "/Windows/ColorDialog/customColor2", QVariant( mSwatchButton2->color() ) );
745  settings.setValue( "/Windows/ColorDialog/customColor3", QVariant( mSwatchButton3->color() ) );
746  settings.setValue( "/Windows/ColorDialog/customColor4", QVariant( mSwatchButton4->color() ) );
747  settings.setValue( "/Windows/ColorDialog/customColor5", QVariant( mSwatchButton5->color() ) );
748  settings.setValue( "/Windows/ColorDialog/customColor6", QVariant( mSwatchButton6->color() ) );
749  settings.setValue( "/Windows/ColorDialog/customColor7", QVariant( mSwatchButton7->color() ) );
750  settings.setValue( "/Windows/ColorDialog/customColor8", QVariant( mSwatchButton8->color() ) );
751  settings.setValue( "/Windows/ColorDialog/customColor9", QVariant( mSwatchButton9->color() ) );
752  settings.setValue( "/Windows/ColorDialog/customColor10", QVariant( mSwatchButton10->color() ) );
753  settings.setValue( "/Windows/ColorDialog/customColor11", QVariant( mSwatchButton11->color() ) );
754  settings.setValue( "/Windows/ColorDialog/customColor12", QVariant( mSwatchButton12->color() ) );
755  settings.setValue( "/Windows/ColorDialog/customColor13", QVariant( mSwatchButton13->color() ) );
756  settings.setValue( "/Windows/ColorDialog/customColor14", QVariant( mSwatchButton14->color() ) );
757  settings.setValue( "/Windows/ColorDialog/customColor15", QVariant( mSwatchButton15->color() ) );
758  settings.setValue( "/Windows/ColorDialog/customColor16", QVariant( mSwatchButton16->color() ) );
759 
760  //sample radius
761  settings.setValue( "/Windows/ColorDialog/sampleRadius", mSpinBoxRadius->value() );
762 }
763 
764 void QgsColorDialogV2::stopPicking( const QPoint &eventPos, const bool takeSample )
765 {
766  //release mouse and keyboard, and reset cursor
767  releaseMouse();
768  releaseKeyboard();
769  unsetCursor();
770  setMouseTracking( false );
771  mPickingColor = false;
772 
773  if ( !takeSample )
774  {
775  //not sampling color, nothing more to do
776  return;
777  }
778 
779  //grab snapshot of pixel under mouse cursor
780  QColor snappedColor = sampleColor( eventPos );
781  mSamplePreview->setColor( snappedColor );
782  mColorPreview->setColor( snappedColor, true );
783 }
784 
785 void QgsColorDialogV2::setColor( const QColor &color )
786 {
787  if ( !color.isValid() )
788  {
789  return;
790  }
791 
792  QColor fixedColor = QColor( color );
793  if ( !mAllowAlpha )
794  {
795  //alpha disallowed, so don't permit transparent colors
796  fixedColor.setAlpha( 255 );
797  }
798  QList<QgsColorWidget*> colorWidgets = this->findChildren<QgsColorWidget *>();
799  foreach ( QgsColorWidget* widget, colorWidgets )
800  {
801  if ( widget == mSamplePreview )
802  {
803  continue;
804  }
805  widget->blockSignals( true );
806  widget->setColor( fixedColor );
807  widget->blockSignals( false );
808  }
809  emit currentColorChanged( fixedColor );
810 }
811 
813 {
814  saveSettings();
815  QDialog::closeEvent( e );
816 }
817 
819 {
820  if ( mPickingColor )
821  {
822  //don't show dialog if in color picker mode
823  e->accept();
824  return;
825  }
826 
828 }
829 
830 QColor QgsColorDialogV2::averageColor( const QImage &image ) const
831 {
832  QRgb tmpRgb;
833  int colorCount = 0;
834  int sumRed = 0;
835  int sumBlue = 0;
836  int sumGreen = 0;
837  //scan through image and sum rgb components
838  for ( int heightIndex = 0; heightIndex < image.height(); ++heightIndex )
839  {
840  QRgb* scanLine = ( QRgb* )image.constScanLine( heightIndex );
841  for ( int widthIndex = 0; widthIndex < image.width(); ++widthIndex )
842  {
843  tmpRgb = scanLine[widthIndex];
844  sumRed += qRed( tmpRgb );
845  sumBlue += qBlue( tmpRgb );
846  sumGreen += qGreen( tmpRgb );
847  colorCount++;
848  }
849  }
850  //calculate average components as floats
851  double avgRed = ( double )sumRed / ( 255.0 * colorCount );
852  double avgGreen = ( double )sumGreen / ( 255.0 * colorCount );
853  double avgBlue = ( double )sumBlue / ( 255.0 * colorCount );
854 
855  //create a new color representing the average
856  return QColor::fromRgbF( avgRed, avgGreen, avgBlue );
857 }
858 
859 QColor QgsColorDialogV2::sampleColor( const QPoint &point ) const
860 {
861  int sampleRadius = mSpinBoxRadius->value() - 1;
862  QPixmap snappedPixmap = QPixmap::grabWindow( QApplication::desktop()->winId(), point.x() - sampleRadius, point.y() - sampleRadius,
863  1 + sampleRadius * 2, 1 + sampleRadius * 2 );
864  QImage snappedImage = snappedPixmap.toImage();
865  //scan all pixels and take average color
866  return averageColor( snappedImage );
867 }
868 
870 {
871  if ( mPickingColor )
872  {
873  //currently in color picker mode
874  //sample color under cursor update preview widget to give feedback to user
875  QColor hoverColor = sampleColor( e->globalPos() );
876  mSamplePreview->setColor( hoverColor );
877 
878  e->accept();
879  return;
880  }
881 
883 }
884 
886 {
887  if ( mPickingColor )
888  {
889  //end color picking operation by sampling the color under cursor
890  stopPicking( e->globalPos() );
891  e->accept();
892  return;
893  }
894 
896 }
897 
899 {
900  if ( !mPickingColor )
901  {
902  //if not picking a color, use default tool button behaviour
904  return;
905  }
906 
907  //cancel picking, sampling the color if space was pressed
908  stopPicking( QCursor::pos(), e->key() == Qt::Key_Space );
909 }
910 
911 void QgsColorDialogV2::on_mHueRadio_toggled( bool checked )
912 {
913  if ( checked )
914  {
915  mColorBox->setComponent( QgsColorWidget::Hue );
916  mVerticalRamp->setComponent( QgsColorWidget::Hue );
917  }
918 }
919 
920 void QgsColorDialogV2::on_mSaturationRadio_toggled( bool checked )
921 {
922  if ( checked )
923  {
924  mColorBox->setComponent( QgsColorWidget::Saturation );
925  mVerticalRamp->setComponent( QgsColorWidget::Saturation );
926  }
927 }
928 
929 void QgsColorDialogV2::on_mValueRadio_toggled( bool checked )
930 {
931  if ( checked )
932  {
933  mColorBox->setComponent( QgsColorWidget::Value );
934  mVerticalRamp->setComponent( QgsColorWidget::Value );
935  }
936 }
937 
938 void QgsColorDialogV2::on_mRedRadio_toggled( bool checked )
939 {
940  if ( checked )
941  {
942  mColorBox->setComponent( QgsColorWidget::Red );
943  mVerticalRamp->setComponent( QgsColorWidget::Red );
944  }
945 }
946 
947 void QgsColorDialogV2::on_mGreenRadio_toggled( bool checked )
948 {
949  if ( checked )
950  {
951  mColorBox->setComponent( QgsColorWidget::Green );
952  mVerticalRamp->setComponent( QgsColorWidget::Green );
953  }
954 }
955 
956 void QgsColorDialogV2::on_mBlueRadio_toggled( bool checked )
957 {
958  if ( checked )
959  {
960  mColorBox->setComponent( QgsColorWidget::Blue );
961  mVerticalRamp->setComponent( QgsColorWidget::Blue );
962  }
963 }
964 
965 void QgsColorDialogV2::on_mAddColorToSchemeButton_clicked()
966 {
967  mSchemeList->addColor( mColorPreview->color(), QgsSymbolLayerV2Utils::colorToName( mColorPreview->color() ) );
968 }
A color scheme which stores its colors in a gpl palette file within the "palettes" subfolder off th...
void setOptions(QFlags< QColorDialog::ColorDialogOption > options)
void setName(const QString &name)
Sets the name for the scheme.
void releaseMouse()
QByteArray toByteArray() const
int colorCount() const
static unsigned index
A base class for interactive color widgets.
virtual void closeEvent(QCloseEvent *e)
void setupUi(QWidget *widget)
virtual void reject()
void setCursor(const QCursor &)
bool erase()
Erases the associated gpl palette file from the users "palettes" folder.
void keyPressEvent(QKeyEvent *e) override
const uchar * constScanLine(int i) const
A custom QGIS dialog for selecting a color.
int length() const
QgsColorDialogV2(QWidget *parent=0, Qt::WindowFlags fl=QgisGui::ModalDialogFlags, const QColor &color=QColor())
Create a new color picker dialog.
Abstract base class for color schemes.
virtual bool setColors(const QgsNamedColorList &colors, const QString &context=QString(), const QColor &baseColor=QColor()) override
Sets the colors for the scheme.
int value() const
void currentColorChanged(const QColor &color)
Emitted when the dialog's color changes.
const T & at(int i) const
void addAction(QAction *action)
QString simplified() const
T value() const
int exec()
void setAlpha(int alpha)
QPixmap grabWindow(WId window, int x, int y, int width, int height)
void mousePressEvent(QMouseEvent *e) override
static QString colorToName(const QColor &color)
Returns a friendly display name for a color.
bool removeColorScheme(QgsColorScheme *scheme)
Removes all matching color schemes from the registry.
virtual void mouseReleaseEvent(QMouseEvent *event)
void mouseReleaseEvent(QMouseEvent *e) override
static const QString qgisSettingsDirPath()
Returns the path to the settings directory in user's home dir.
QString tr(const char *sourceText, const char *disambiguation, int n)
int x() const
int y() const
void setValue(const QString &key, const QVariant &value)
void setAllowAlpha(const bool allowAlpha)
Sets whether alpha modification (transparency) is permitted for the color dialog. ...
const char * name() const
const QPoint & globalPos() const
virtual bool isEditable() const
Returns whether the color scheme is editable.
virtual void mousePressEvent(QMouseEvent *event)
int toInt(bool *ok) const
StandardButton question(QWidget *parent, const QString &title, const QString &text, QFlags< QMessageBox::StandardButton > buttons, StandardButton defaultButton)
bool restoreGeometry(const QByteArray &geometry)
QColor color() const
Returns the current color for the dialog.
static QgsNamedColorList importColorsFromGpl(QFile &file, bool &ok, QString &name)
Imports colors from a gpl GIMP palette file.
int width() const
typedef ColorDialogOptions
virtual void mouseMoveEvent(QMouseEvent *event)
bool isEmpty() const
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
int result() const
WId winId() const
QAction * addSeparator()
virtual void accept()
void addColorScheme(QgsColorScheme *scheme)
Adds a color scheme to the registry.
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)
QString toLower() const
int key() const
void accept()
bool blockSignals(bool block)
QColor fromRgbF(qreal r, qreal g, qreal b, qreal a)
QColor getColor(const QColor &initial, QWidget *parent, const QString &title, QFlags< QColorDialog::ColorDialogOption > options)
void closeEvent(QCloseEvent *e) override
static QgsColorSchemeRegistry * instance()
Returns the global instance pointer, creating the object on the first call.
virtual void keyPressEvent(QKeyEvent *e)
const char * sampler_cursor[]
Definition: qgscursors.cpp:183
QString & replace(int position, int n, QChar after)
QVariant value(const QString &key, const QVariant &defaultValue) const
static QColor getColor(const QColor &initialColor, QWidget *parent, const QString &title=QString(), const bool allowAlpha=false)
Return a color selection from a color dialog.
QPoint pos()
void activateWindow()
QByteArray saveGeometry() const
QDesktopWidget * desktop()
virtual QString schemeName() const override
Gets the name for the color scheme.
void grabMouse()
void setWindowTitle(const QString &)
void releaseKeyboard()
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFlags< QFileDialog::Option > options)
StandardButton critical(QWidget *parent, const QString &title, const QString &text, QFlags< QMessageBox::StandardButton > buttons, StandardButton defaultButton)
void mouseMoveEvent(QMouseEvent *e) override
bool toBool() const
void setMouseTracking(bool enable)
int height() const
typedef WindowFlags
static QColor getLiveColor(const QColor &initialColor, QObject *updateObject, const char *updateSlot, QWidget *parent=0, const QString &title=QString(), const bool allowAlpha=true)
Return a color selection from a color dialog, with live updating of interim selections.
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFlags< QFileDialog::Option > options)
QImage toImage() const
const_iterator constEnd() const
const_iterator constBegin() const
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
static QColor getLiveColor(const QColor &initialColor, QObject *updateObject, const char *updateSlot, QWidget *parent=0, const QString &title="", QColorDialog::ColorDialogOptions options=0)
Return a color selection from a QColorDialog, with live updating of interim selections.
void setColor(const QColor &color)
Sets the current color for the dialog.
void grabKeyboard()
QString toString() const
QList< QgsColorScheme * > schemes() const
Returns all color schemes in the registry.
bool mkpath(const QString &dirPath) const
virtual void setColor(const QColor &color, const bool emitSignals=false)
Sets the color for the widget.
bool isValid() const
void setTitle(const QString title)
Sets the title for the color dialog.