QGIS API Documentation  3.21.0-Master (5b68dc587e)
qgscolorscheme.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscolorscheme.cpp
3  -------------------
4  begin : July 2014
5  copyright : (C) 2014 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgscolorscheme.h"
19 #include "qgscolorschemeregistry.h"
20 
21 #include "qgsproject.h"
22 #include "qgssymbollayerutils.h"
23 #include "qgsapplication.h"
24 #include "qgssettings.h"
25 
26 #include <QDir>
27 #include <QRegularExpression>
28 #include <QTextStream>
29 
30 bool QgsColorScheme::setColors( const QgsNamedColorList &colors, const QString &context, const QColor &baseColor )
31 {
32  //base implementation does nothing
33  Q_UNUSED( colors )
34  Q_UNUSED( context )
35  Q_UNUSED( baseColor )
36  return false;
37 }
38 
39 
40 //
41 // QgsRecentColorScheme
42 //
43 
44 QgsNamedColorList QgsRecentColorScheme::fetchColors( const QString &context, const QColor &baseColor )
45 {
46  Q_UNUSED( context )
47  Q_UNUSED( baseColor )
48 
49  //fetch recent colors
50  const QgsSettings settings;
51  const QList< QVariant > recentColorVariants = settings.value( QStringLiteral( "colors/recent" ) ).toList();
52 
53  //generate list from recent colors
54  QgsNamedColorList colorList;
55  const auto constRecentColorVariants = recentColorVariants;
56  for ( const QVariant &color : constRecentColorVariants )
57  {
58  colorList.append( qMakePair( color.value<QColor>(), QgsSymbolLayerUtils::colorToName( color.value<QColor>() ) ) );
59  }
60  return colorList;
61 }
62 
64 {
65  return new QgsRecentColorScheme();
66 }
67 
68 void QgsRecentColorScheme::addRecentColor( const QColor &color )
69 {
70  if ( !color.isValid() )
71  {
72  return;
73  }
74 
75  //strip alpha from color
76  QColor opaqueColor = color;
77  opaqueColor.setAlpha( 255 );
78 
79  QgsSettings settings;
80  QList< QVariant > recentColorVariants = settings.value( QStringLiteral( "colors/recent" ) ).toList();
81 
82  //remove colors by name
83  for ( int colorIdx = recentColorVariants.length() - 1; colorIdx >= 0; --colorIdx )
84  {
85  if ( ( recentColorVariants.at( colorIdx ).value<QColor>() ).name() == opaqueColor.name() )
86  {
87  recentColorVariants.removeAt( colorIdx );
88  }
89  }
90 
91  //add color
92  const QVariant colorVariant = QVariant( opaqueColor );
93  recentColorVariants.prepend( colorVariant );
94 
95  //trim to 20 colors
96  while ( recentColorVariants.count() > 20 )
97  {
98  recentColorVariants.pop_back();
99  }
100 
101  settings.setValue( QStringLiteral( "colors/recent" ), recentColorVariants );
102 }
103 
105 {
106  //fetch recent colors
107  const QgsSettings settings;
108  const QList< QVariant > recentColorVariants = settings.value( QStringLiteral( "colors/recent" ) ).toList();
109 
110  if ( recentColorVariants.isEmpty() )
111  return QColor();
112 
113  return recentColorVariants.at( 0 ).value<QColor>();
114 }
115 
116 QgsNamedColorList QgsCustomColorScheme::fetchColors( const QString &context, const QColor &baseColor )
117 {
118  Q_UNUSED( context )
119  Q_UNUSED( baseColor )
120 
121  //fetch predefined custom colors
122  QgsNamedColorList colorList;
123  const QgsSettings settings;
124 
125  //check if settings contains custom palette
126  if ( !settings.contains( QStringLiteral( "/colors/palettecolors" ) ) )
127  {
128  //no custom palette, return default colors
129  colorList.append( qMakePair( QColor( 0, 0, 0 ), QString() ) );
130  colorList.append( qMakePair( QColor( 255, 255, 255 ), QString() ) );
131  colorList.append( qMakePair( QColor( 166, 206, 227 ), QString() ) );
132  colorList.append( qMakePair( QColor( 31, 120, 180 ), QString() ) );
133  colorList.append( qMakePair( QColor( 178, 223, 138 ), QString() ) );
134  colorList.append( qMakePair( QColor( 51, 160, 44 ), QString() ) );
135  colorList.append( qMakePair( QColor( 251, 154, 153 ), QString() ) );
136  colorList.append( qMakePair( QColor( 227, 26, 28 ), QString() ) );
137  colorList.append( qMakePair( QColor( 253, 191, 111 ), QString() ) );
138  colorList.append( qMakePair( QColor( 255, 127, 0 ), QString() ) );
139 
140  return colorList;
141  }
142 
143  QList< QVariant > customColorVariants = settings.value( QStringLiteral( "colors/palettecolors" ) ).toList();
144  const QList< QVariant > customColorLabels = settings.value( QStringLiteral( "colors/palettelabels" ) ).toList();
145 
146  //generate list from custom colors
147  int colorIndex = 0;
148  for ( QList< QVariant >::iterator it = customColorVariants.begin();
149  it != customColorVariants.end(); ++it )
150  {
151  const QColor color = ( *it ).value<QColor>();
152  QString label;
153  if ( customColorLabels.length() > colorIndex )
154  {
155  label = customColorLabels.at( colorIndex ).toString();
156  }
157 
158  colorList.append( qMakePair( color, label ) );
159  colorIndex++;
160  }
161 
162  return colorList;
163 }
164 
165 bool QgsCustomColorScheme::setColors( const QgsNamedColorList &colors, const QString &context, const QColor &baseColor )
166 {
167  Q_UNUSED( context )
168  Q_UNUSED( baseColor )
169 
170  // save colors to settings
171  QgsSettings settings;
172  QList< QVariant > customColors;
173  QList< QVariant > customColorLabels;
174 
175  QgsNamedColorList::const_iterator colorIt = colors.constBegin();
176  for ( ; colorIt != colors.constEnd(); ++colorIt )
177  {
178  const QVariant color = ( *colorIt ).first;
179  const QVariant label = ( *colorIt ).second;
180  customColors.append( color );
181  customColorLabels.append( label );
182  }
183  settings.setValue( QStringLiteral( "colors/palettecolors" ), customColors );
184  settings.setValue( QStringLiteral( "colors/palettelabels" ), customColorLabels );
185  return true;
186 }
187 
189 {
190  return new QgsCustomColorScheme();
191 }
192 
193 
194 QgsNamedColorList QgsProjectColorScheme::fetchColors( const QString &context, const QColor &baseColor )
195 {
196  Q_UNUSED( context )
197  Q_UNUSED( baseColor )
198 
199  QgsNamedColorList colorList;
200 
201  QStringList colorStrings = QgsProject::instance()->readListEntry( QStringLiteral( "Palette" ), QStringLiteral( "/Colors" ) );
202  const QStringList colorLabels = QgsProject::instance()->readListEntry( QStringLiteral( "Palette" ), QStringLiteral( "/Labels" ) );
203 
204  //generate list from custom colors
205  int colorIndex = 0;
206  for ( QStringList::iterator it = colorStrings.begin();
207  it != colorStrings.end(); ++it )
208  {
209  const QColor color = QgsSymbolLayerUtils::decodeColor( *it );
210  QString label;
211  if ( colorLabels.length() > colorIndex )
212  {
213  label = colorLabels.at( colorIndex );
214  }
215 
216  colorList.append( qMakePair( color, label ) );
217  colorIndex++;
218  }
219 
220  return colorList;
221 }
222 
223 bool QgsProjectColorScheme::setColors( const QgsNamedColorList &colors, const QString &context, const QColor &baseColor )
224 {
225  Q_UNUSED( context )
226  Q_UNUSED( baseColor )
228  return true;
229 }
230 
232 {
233  return new QgsProjectColorScheme();
234 }
235 
236 
237 //
238 // QgsGplColorScheme
239 //
240 
241 QgsNamedColorList QgsGplColorScheme::fetchColors( const QString &context, const QColor &baseColor )
242 {
243  Q_UNUSED( context )
244  Q_UNUSED( baseColor )
245 
246  const QString sourceFilePath = gplFilePath();
247  if ( sourceFilePath.isEmpty() )
248  {
249  QgsNamedColorList noColors;
250  return noColors;
251  }
252 
253  bool ok;
254  QString name;
255  QFile sourceFile( sourceFilePath );
256  return QgsSymbolLayerUtils::importColorsFromGpl( sourceFile, ok, name );
257 }
258 
259 bool QgsGplColorScheme::setColors( const QgsNamedColorList &colors, const QString &context, const QColor &baseColor )
260 {
261  Q_UNUSED( context )
262  Q_UNUSED( baseColor )
263 
264  const QString destFilePath = gplFilePath();
265  if ( destFilePath.isEmpty() )
266  {
267  return false;
268  }
269 
270  QFile destFile( destFilePath );
271  if ( QgsSymbolLayerUtils::saveColorsToGpl( destFile, schemeName(), colors ) )
272  {
273  if ( QgsApplication::colorSchemeRegistry()->randomStyleColorScheme() == this )
274  {
275  // force a re-generation of the random style color list, since the color list has changed
277  }
278  return true;
279  }
280  else
281  {
282  return false;
283  }
284 }
285 
286 
287 //
288 // QgsUserColorScheme
289 //
290 
291 QgsUserColorScheme::QgsUserColorScheme( const QString &filename )
292  : mFilename( filename )
293 {
294  QFile sourceFile( gplFilePath() );
295 
296  //read in name
297  if ( sourceFile.open( QIODevice::ReadOnly ) )
298  {
299  QTextStream in( &sourceFile );
300 
301  //find name line
302  QString line;
303  while ( !in.atEnd() && !line.startsWith( QLatin1String( "Name:" ) ) )
304  {
305  line = in.readLine();
306  }
307  if ( !in.atEnd() )
308  {
309  const QRegularExpression rx( "Name:\\s*(\\S.*)$" );
310  const QRegularExpressionMatch match = rx.match( line );
311  if ( match.hasMatch() )
312  {
313  mName = match.captured( 1 );
314  }
315  }
316  }
317  if ( mName.isEmpty() )
318  {
319  mName = mFilename;
320  }
321 
322  // we consider this scheme writable if the user has permission, OR
323  // if it DOESN'T already exist (since new schemes are only created when
324  // first written to)
325  const QFileInfo sourceFileInfo( gplFilePath() );
326  mEditable = !sourceFileInfo.exists() || sourceFileInfo.isWritable();
327 }
328 
330 {
331  return mName;
332 }
333 
335 {
336  return new QgsUserColorScheme( mFilename );
337 }
338 
339 QgsColorScheme::SchemeFlags QgsUserColorScheme::flags() const
340 {
341  QgsColorScheme::SchemeFlags f = QgsGplColorScheme::flags();
342 
343  const QgsSettings s;
344  const QStringList showInMenuSchemes = s.value( QStringLiteral( "/colors/showInMenuList" ) ).toStringList();
345 
346  if ( showInMenuSchemes.contains( mName ) )
347  {
349  }
350 
351  return f;
352 }
353 
355 {
356  const QString filePath = gplFilePath();
357  if ( filePath.isEmpty() )
358  {
359  return false;
360  }
361 
362  // if file does not exist, nothing to do on the disk, so we can consider erasing done
363  if ( ! QFile::exists( filePath ) )
364  {
365  return true;
366  }
367 
368  //try to erase gpl file
369  return QFile::remove( filePath );
370 }
371 
373 {
374  QgsSettings s;
375  QStringList showInMenuSchemes = s.value( QStringLiteral( "/colors/showInMenuList" ) ).toStringList();
376 
377  if ( show && !showInMenuSchemes.contains( mName ) )
378  {
379  showInMenuSchemes << mName;
380  }
381  else if ( !show && showInMenuSchemes.contains( mName ) )
382  {
383  showInMenuSchemes.removeAll( mName );
384  }
385 
386  s.setValue( QStringLiteral( "/colors/showInMenuList" ), showInMenuSchemes );
387 }
388 
390 {
391  const QString palettesDir = QgsApplication::qgisSettingsDirPath() + "palettes";
392 
393  const QDir localDir;
394  if ( !localDir.mkpath( palettesDir ) )
395  {
396  return QString();
397  }
398 
399  return QDir( palettesDir ).filePath( mFilename );
400 }
static QgsColorSchemeRegistry * colorSchemeRegistry()
Returns the application's color scheme registry, used for managing color schemes.
static QString qgisSettingsDirPath()
Returns the path to the settings directory in user's home dir.
void setRandomStyleColorScheme(QgsColorScheme *scheme)
Sets the color scheme to use when fetching random colors to use for symbol styles.
@ ShowInColorButtonMenu
Show scheme in color button drop-down menu.
virtual QString schemeName() const =0
Gets the name for the color scheme.
virtual bool setColors(const QgsNamedColorList &colors, const QString &context=QString(), const QColor &baseColor=QColor())
Sets the colors for the scheme.
virtual SchemeFlags flags() const
Returns the current flags for the color scheme.
A color scheme which contains custom colors set through QGIS app options dialog.
QgsNamedColorList fetchColors(const QString &context=QString(), const QColor &baseColor=QColor()) override
Gets a list of colors from the scheme.
bool setColors(const QgsNamedColorList &colors, const QString &context=QString(), const QColor &baseColor=QColor()) override
Sets the colors for the scheme.
QgsCustomColorScheme * clone() const override
Clones a color scheme.
QgsCustomColorScheme()=default
Constructor for QgsCustomColorScheme.
virtual QString gplFilePath()=0
Returns the file path for the associated gpl palette file.
QgsNamedColorList fetchColors(const QString &context=QString(), const QColor &baseColor=QColor()) override
Gets a list of colors from the scheme.
bool setColors(const QgsNamedColorList &colors, const QString &context=QString(), const QColor &baseColor=QColor()) override
Sets the colors for the scheme.
A color scheme which contains project specific colors set through project properties dialog.
QgsProjectColorScheme * clone() const override
Clones a color scheme.
bool setColors(const QgsNamedColorList &colors, const QString &context=QString(), const QColor &baseColor=QColor()) override
Sets the colors for the scheme.
QgsProjectColorScheme()=default
Constructor for QgsProjectColorScheme.
QgsNamedColorList fetchColors(const QString &context=QString(), const QColor &baseColor=QColor()) override
Gets a list of colors from the scheme.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:467
void setProjectColors(const QgsNamedColorList &colors)
Sets the colors for the project's color scheme (see QgsProjectColorScheme).
QStringList readListEntry(const QString &scope, const QString &key, const QStringList &def=QStringList(), bool *ok=nullptr) const
Reads a string list from the specified scope and key.
A color scheme which contains the most recently used colors.
QgsRecentColorScheme()=default
Constructor for QgsRecentColorScheme.
QgsNamedColorList fetchColors(const QString &context=QString(), const QColor &baseColor=QColor()) override
Gets a list of colors from the scheme.
static QColor lastUsedColor()
Returns the most recently used color.
QgsRecentColorScheme * clone() const override
Clones a color scheme.
static void addRecentColor(const QColor &color)
Adds a color to the list of recent colors.
static QColor decodeColor(const QString &str)
static bool saveColorsToGpl(QFile &file, const QString &paletteName, const QgsNamedColorList &colors)
Exports colors to a gpl GIMP palette file.
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.
A color scheme which stores its colors in a gpl palette file within the "palettes" subfolder off the ...
QString schemeName() const override
Gets the name for the color scheme.
QgsUserColorScheme(const QString &filename)
Constructs a new user color scheme, using a specified gpl palette file.
QgsColorScheme::SchemeFlags flags() const override
Returns the current flags for the color scheme.
QString gplFilePath() override
Returns the file path for the associated gpl palette file.
bool erase()
Erases the associated gpl palette file from the users "palettes" folder.
void setShowSchemeInMenu(bool show)
Sets whether a this scheme should be shown in color button menus.
QgsUserColorScheme * clone() const override
Clones a color scheme.
QList< QPair< QColor, QString > > QgsNamedColorList
List of colors paired with a friendly display name identifying the color.