QGIS API Documentation 3.99.0-Master (8e76e220402)
Loading...
Searching...
No Matches
qgsprojectstylesettings.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsprojectstylesettings.cpp
3 ---------------------------
4 begin : May 2022
5 copyright : (C) 2022 by Mathieu Pellerin
6 email : nirvn dot asia at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include "qgis.h"
19#include "qgscolorramp.h"
20#include "qgscolorutils.h"
22#include "qgsfillsymbol.h"
23#include "qgslinesymbol.h"
24#include "qgsmarkersymbol.h"
25#include "qgsproject.h"
26#include "qgsstyle.h"
27#include "qgssymbol.h"
28#include "qgssymbollayerutils.h"
29#include "qgstextformat.h"
30#include "qgsxmlutils.h"
31
32#include <QDomElement>
33#include <QString>
34
35#include "moc_qgsprojectstylesettings.cpp"
36
37using namespace Qt::StringLiterals;
38
40 : QObject( project )
41 , mProject( project )
42{
43 mCombinedStyleModel = new QgsCombinedStyleModel( this );
44}
45
47{
48 if ( mProjectStyle )
49 {
50 mProjectStyle->deleteLater();
51 mProjectStyle = nullptr;
52 }
53}
54
56{
57 switch ( symbolType )
58 {
60 return mDefaultMarkerSymbol ? mDefaultMarkerSymbol->clone() : nullptr;
61
63 return mDefaultLineSymbol ? mDefaultLineSymbol->clone() : nullptr;
64
66 return mDefaultFillSymbol ? mDefaultFillSymbol->clone() : nullptr;
67
69 break;
70 }
71
72 return nullptr;
73}
74
76{
77 switch ( symbolType )
78 {
80 if ( mDefaultMarkerSymbol.get() == symbol )
81 return;
82
83 mDefaultMarkerSymbol.reset( symbol ? symbol->clone() : nullptr );
84
85 makeDirty();
86 break;
87
89 if ( mDefaultLineSymbol.get() == symbol )
90 return;
91
92 mDefaultLineSymbol.reset( symbol ? symbol->clone() : nullptr );
93
94 makeDirty();
95 break;
96
98 if ( mDefaultFillSymbol.get() == symbol )
99 return;
100
101 mDefaultFillSymbol.reset( symbol ? symbol->clone() : nullptr );
102
103 makeDirty();
104 break;
105
107 break;
108 }
109}
110
112{
113 return mDefaultColorRamp ? mDefaultColorRamp->clone() : nullptr;
114}
115
117{
118 if ( mDefaultColorRamp.get() == colorRamp )
119 return;
120
121 mDefaultColorRamp.reset( colorRamp ? colorRamp->clone() : nullptr );
122
123 makeDirty();
124}
125
127{
128 return mDefaultTextFormat;
129}
130
132{
133 if ( mDefaultTextFormat == textFormat )
134 return;
135
136 mDefaultTextFormat = textFormat;
137
138 makeDirty();
139}
140
142{
143 if ( qgsDoubleNear( mDefaultSymbolOpacity, opacity ) )
144 return;
145
146 mDefaultSymbolOpacity = opacity;
147
148 makeDirty();
149}
150
152{
153 if ( mRandomizeDefaultSymbolColor == randomized )
154 return;
155
156 mRandomizeDefaultSymbolColor = randomized;
157
158 makeDirty();
159}
160
162{
163 mDefaultMarkerSymbol.reset();
164 mDefaultLineSymbol.reset();
165 mDefaultFillSymbol.reset();
166 mDefaultColorRamp.reset();
167 mDefaultTextFormat = QgsTextFormat();
168 mRandomizeDefaultSymbolColor = true;
169 mDefaultSymbolOpacity = 1.0;
170
171 clearStyles();
172
173 if ( mProject && ( mProject->capabilities() & Qgis::ProjectCapability::ProjectStyles ) )
174 {
175 const QString stylePath = mProject->createAttachedFile( u"styles.db"_s );
176 QgsStyle *style = new QgsStyle();
177 style->createDatabase( stylePath );
178 style->setName( tr( "Project Style" ) );
179 style->setFileName( stylePath );
180 setProjectStyle( style );
181 }
182
184}
185
187{
188 if ( mProjectStyle )
189 {
190 mCombinedStyleModel->removeStyle( mProjectStyle );
191 delete mProjectStyle;
192 mProjectStyle = nullptr;
193 }
194}
195
197{
198 if ( mProjectStyle )
199 {
200 mCombinedStyleModel->removeStyle( mProjectStyle );
201 mProjectStyle->deleteLater();
202 }
203 mProjectStyle = style;
204 mProjectStyle->setName( tr( "Project Styles" ) );
205
206 // if project color scheme changes, we need to redraw symbols - they may use project colors and accordingly
207 // need updating to reflect the new colors
208 if ( mProject )
209 {
210 connect( mProject, &QgsProject::projectColorsChanged, mProjectStyle, &QgsStyle::triggerIconRebuild );
211 }
212 mCombinedStyleModel->addStyle( mProjectStyle );
213
214 emit projectStyleChanged();
215}
216
218{
219 return mProjectStyle;
220}
221
222bool QgsProjectStyleSettings::readXml( const QDomElement &element, const QgsReadWriteContext &context, Qgis::ProjectReadFlags )
223{
224 mRandomizeDefaultSymbolColor = element.attribute( u"RandomizeDefaultSymbolColor"_s, u"0"_s ).toInt();
225 mDefaultSymbolOpacity = element.attribute( u"DefaultSymbolOpacity"_s, u"1.0"_s ).toDouble();
226 mColorModel = qgsEnumKeyToValue( element.attribute( u"colorModel"_s ), Qgis::ColorModel::Rgb );
227
228 QDomElement elem = element.firstChildElement( u"markerSymbol"_s );
229 if ( !elem.isNull() )
230 {
231 QDomElement symbolElem = elem.firstChildElement( u"symbol"_s );
232 mDefaultMarkerSymbol = !symbolElem.isNull() ? QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( symbolElem, context ) : nullptr;
233 }
234 else
235 {
236 mDefaultMarkerSymbol.reset();
237 }
238
239 elem = element.firstChildElement( u"lineSymbol"_s );
240 if ( !elem.isNull() )
241 {
242 QDomElement symbolElem = elem.firstChildElement( u"symbol"_s );
243 mDefaultLineSymbol = !symbolElem.isNull() ? QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( symbolElem, context ) : nullptr;
244 }
245 else
246 {
247 mDefaultLineSymbol.reset();
248 }
249
250 elem = element.firstChildElement( u"fillSymbol"_s );
251 if ( !elem.isNull() )
252 {
253 QDomElement symbolElem = elem.firstChildElement( u"symbol"_s );
254 mDefaultFillSymbol = !symbolElem.isNull() ? QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElem, context ) : nullptr;
255 }
256 else
257 {
258 mDefaultFillSymbol.reset();
259 }
260
261 elem = element.firstChildElement( u"colorramp"_s );
262 mDefaultColorRamp = !elem.isNull() ? QgsSymbolLayerUtils::loadColorRamp( elem ) : nullptr;
263
264 elem = element.firstChildElement( u"text-style"_s );
265 if ( !elem.isNull() )
266 {
267 mDefaultTextFormat.readXml( elem, context );
268 }
269 else
270 {
271 mDefaultTextFormat = QgsTextFormat();
272 }
273
274 {
275 clearStyles();
276 if ( !mProject || ( mProject->capabilities() & Qgis::ProjectCapability::ProjectStyles ) )
277 {
278 const QDomElement styleDatabases = element.firstChildElement( u"databases"_s );
279 if ( !styleDatabases.isNull() )
280 {
281 const QDomNodeList styleEntries = styleDatabases.childNodes();
282 for ( int i = 0; i < styleEntries.count(); ++i )
283 {
284 const QDomElement styleElement = styleEntries.at( i ).toElement();
285 const QString path = styleElement.attribute( u"path"_s );
286 const QString fullPath = context.pathResolver().readPath( path );
287 emit styleDatabaseAboutToBeAdded( fullPath );
288 mStyleDatabases.append( fullPath );
289 loadStyleAtPath( fullPath );
290 emit styleDatabaseAdded( fullPath );
291 }
292 }
293
294 if ( mProject && ( mProject->capabilities() & Qgis::ProjectCapability::ProjectStyles ) )
295 {
296 const QString projectStyleId = element.attribute( u"projectStyleId"_s );
297 const QString projectStyleFile = mProject->resolveAttachmentIdentifier( projectStyleId );
298 QgsStyle *style = new QgsStyle();
299 if ( !projectStyleFile.isEmpty() && QFile::exists( projectStyleFile ) )
300 {
301 style->load( projectStyleFile );
302 style->setFileName( projectStyleFile );
303 }
304 else
305 {
306 const QString stylePath = mProject->createAttachedFile( u"styles.db"_s );
307 style->createDatabase( stylePath );
308 style->setFileName( stylePath );
309 }
310 style->setName( tr( "Project Style" ) );
311 setProjectStyle( style );
312 }
313 }
314 }
315
316 const QString iccProfileId = element.attribute( u"iccProfileId"_s );
317 mIccProfileFilePath = mProject ? mProject->resolveAttachmentIdentifier( iccProfileId ) : QString();
318 if ( !mIccProfileFilePath.isEmpty() )
319 {
320 QString errorMsg;
321 QColorSpace colorSpace = QgsColorUtils::iccProfile( mIccProfileFilePath, errorMsg );
322 if ( !errorMsg.isEmpty() )
323 context.pushMessage( errorMsg );
324
326 }
327
329
330 return true;
331}
332
333QDomElement QgsProjectStyleSettings::writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const
334{
335 QDomElement element = doc.createElement( u"ProjectStyleSettings"_s );
336
337 element.setAttribute( u"RandomizeDefaultSymbolColor"_s, mRandomizeDefaultSymbolColor ? u"1"_s : u"0"_s );
338 element.setAttribute( u"DefaultSymbolOpacity"_s, QString::number( mDefaultSymbolOpacity ) );
339
340 element.setAttribute( u"colorModel"_s, qgsEnumValueToKey( mColorModel ) );
341
342 if ( mDefaultMarkerSymbol )
343 {
344 QDomElement markerSymbolElem = doc.createElement( u"markerSymbol"_s );
345 markerSymbolElem.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mDefaultMarkerSymbol.get(), doc, context ) );
346 element.appendChild( markerSymbolElem );
347 }
348
349 if ( mDefaultLineSymbol )
350 {
351 QDomElement lineSymbolElem = doc.createElement( u"lineSymbol"_s );
352 lineSymbolElem.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mDefaultLineSymbol.get(), doc, context ) );
353 element.appendChild( lineSymbolElem );
354 }
355
356 if ( mDefaultFillSymbol )
357 {
358 QDomElement fillSymbolElem = doc.createElement( u"fillSymbol"_s );
359 fillSymbolElem.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mDefaultFillSymbol.get(), doc, context ) );
360 element.appendChild( fillSymbolElem );
361 }
362
363 if ( mDefaultColorRamp )
364 {
365 QDomElement colorRampElem = QgsSymbolLayerUtils::saveColorRamp( QString(), mDefaultColorRamp.get(), doc );
366 element.appendChild( colorRampElem );
367 }
368
369 if ( mDefaultTextFormat.isValid() )
370 {
371 QDomElement textFormatElem = mDefaultTextFormat.writeXml( doc, context );
372 element.appendChild( textFormatElem );
373 }
374
375 {
376 QDomElement styleDatabases = doc.createElement( u"databases"_s );
377 for ( const QString &db : mStyleDatabases )
378 {
379 QDomElement dbElement = doc.createElement( u"db"_s );
380 dbElement.setAttribute( u"path"_s, context.pathResolver().writePath( db ) );
381 styleDatabases.appendChild( dbElement );
382 }
383 element.appendChild( styleDatabases );
384 }
385
386 if ( mProject && mProjectStyle )
387 {
388 element.setAttribute( u"projectStyleId"_s, mProject->attachmentIdentifier( mProjectStyle->fileName() ) );
389 }
390
391 if ( mProject )
392 {
393 element.setAttribute( u"iccProfileId"_s, mProject->attachmentIdentifier( mIccProfileFilePath ) );
394 }
395
396 return element;
397}
398
399QList<QgsStyle *> QgsProjectStyleSettings::styles() const
400{
401 QList< QgsStyle * > res;
402 res.reserve( mStyles.size() );
403 for ( QgsStyle *style : mStyles )
404 {
405 if ( style )
406 res.append( style );
407 }
408 return res;
409}
410
412{
413 if ( path == QgsStyle::defaultStyle()->fileName() )
414 return QgsStyle::defaultStyle();
415
416 if ( mProjectStyle && path == mProjectStyle->fileName() )
417 return mProjectStyle;
418
419 for ( QgsStyle *style : std::as_const( mStyles ) )
420 {
421 if ( style->fileName() == path )
422 return style;
423 }
424
425 return nullptr;
426}
427
429{
430 if ( mStyleDatabases.contains( path ) )
431 return;
432
433 emit styleDatabaseAboutToBeAdded( path );
434 mStyleDatabases.append( path );
435 loadStyleAtPath( path );
436 emit styleDatabaseAdded( path );
437
439}
440
442{
443 if ( paths == mStyleDatabases )
444 return;
445
446 clearStyles();
447
448 for ( const QString &path : paths )
449 {
450 emit styleDatabaseAboutToBeAdded( path );
451 mStyleDatabases.append( path );
452 loadStyleAtPath( path );
453 emit styleDatabaseAdded( path );
454 }
456}
457
458void QgsProjectStyleSettings::loadStyleAtPath( const QString &path )
459{
460 QgsStyle *style = new QgsStyle( this );
461
462 const QFileInfo fileInfo( path );
463 if ( fileInfo.suffix().compare( "xml"_L1, Qt::CaseInsensitive ) == 0 )
464 {
465 style->createMemoryDatabase();
466 ( void )style->importXml( path );
467 style->setFileName( path );
468 style->setReadOnly( true );
469 }
470 else
471 {
472 style->load( path );
473 }
474 style->setName( fileInfo.completeBaseName() );
475 mStyles.append( style );
476 mCombinedStyleModel->addStyle( style );
477
478 if ( mProject )
479 {
480 // if project color scheme changes, we need to redraw symbols - they may use project colors and accordingly
481 // need updating to reflect the new colors
483 }
484}
485
486void QgsProjectStyleSettings::clearStyles()
487{
488 const QStringList pathsToRemove = mStyleDatabases;
489 for ( const QString &path : pathsToRemove )
490 {
492 mStyleDatabases.removeAll( path );
493 if ( QgsStyle *style = styleAtPath( path ) )
494 {
495 mCombinedStyleModel->removeStyle( style );
496 style->deleteLater();
497 mStyles.removeAll( style );
498 }
499 emit styleDatabaseRemoved( path );
500 }
501
502 // should already be empty, but play it safe..!
503 for ( QgsStyle *style : std::as_const( mStyles ) )
504 {
505 mCombinedStyleModel->removeStyle( style );
506 }
507 qDeleteAll( mStyles );
508 mStyles.clear();
509}
510
512{
513 return mCombinedStyleModel;
514}
515
517{
518 if ( mColorModel == colorModel )
519 return;
520
521 mColorModel = colorModel;
522
523 makeDirty();
524
525#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
526 if ( mColorSpace.isValid() && QgsColorUtils::toColorModel( mColorSpace.colorModel() ) != colorModel )
527 {
528 setColorSpace( QColorSpace() );
529 }
530#endif
531}
532
534{
535 return mColorModel;
536}
537
539{
540 if ( mColorSpace == colorSpace )
541 return;
542
543 if ( !mProject )
544 {
545 QgsDebugError( "Impossible to attach ICC profile, no project defined" );
546 return;
547 }
548
549 auto clearIccProfile = [this]()
550 {
551 mProject->removeAttachedFile( mIccProfileFilePath );
552 mIccProfileFilePath.clear();
553 mColorSpace = QColorSpace();
554 };
555
556 if ( !mIccProfileFilePath.isEmpty() )
557 clearIccProfile();
558
559#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
560 bool ok;
562 mColorSpace = ok ? colorSpace : QColorSpace();
563#else
564 mColorSpace = colorSpace;
565#endif
566
567 makeDirty();
568
569 if ( !mColorSpace.isValid() )
570 return;
571
572#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
573 if ( colorModel != mColorModel )
574 mColorModel = colorModel;
575#endif
576
577 mIccProfileFilePath = mProject->createAttachedFile( u"profile.icc"_s );
578 QFile file( mIccProfileFilePath );
579 if ( !file.open( QIODevice::WriteOnly ) || file.write( colorSpace.iccProfile() ) < 0 )
580 clearIccProfile();
581}
582
584{
585 return mColorSpace;
586}
587
588void QgsProjectStyleSettings::makeDirty()
589{
590 if ( mProject )
591 mProject->setDirty( true );
592}
593
594//
595// QgsProjectStyleDatabaseModel
596//
597
599 : QAbstractListModel( parent )
600 , mSettings( settings )
601{
602 connect( mSettings, &QgsProjectStyleSettings::styleDatabaseAboutToBeAdded, this, &QgsProjectStyleDatabaseModel::styleDatabaseAboutToBeAdded );
603 connect( mSettings, &QgsProjectStyleSettings::styleDatabaseAdded, this, &QgsProjectStyleDatabaseModel::styleDatabaseAdded );
604 connect( mSettings, &QgsProjectStyleSettings::styleDatabaseAboutToBeRemoved, this, &QgsProjectStyleDatabaseModel::styleDatabaseAboutToBeRemoved );
605 connect( mSettings, &QgsProjectStyleSettings::styleDatabaseRemoved, this, &QgsProjectStyleDatabaseModel::styleDatabaseRemoved );
606
607 if ( mSettings->projectStyle() )
608 setProjectStyle( mSettings->projectStyle() );
609 connect( mSettings, &QgsProjectStyleSettings::projectStyleChanged, this, &QgsProjectStyleDatabaseModel::projectStyleChanged );
610}
611
612int QgsProjectStyleDatabaseModel::rowCount( const QModelIndex &parent ) const
613{
614 Q_UNUSED( parent )
615 return ( mSettings ? mSettings->styleDatabasePaths().count() : 0 ) + ( mProjectStyle ? 1 : 0 ) + ( mShowDefault ? 1 : 0 );
616}
617
618QVariant QgsProjectStyleDatabaseModel::data( const QModelIndex &index, int role ) const
619{
620 if ( index.row() < 0 || index.row() >= rowCount( QModelIndex() ) )
621 return QVariant();
622
623 const bool isProjectStyle = index.row() == 0 && mProjectStyle;
624 const bool isDefault = mShowDefault && ( ( index.row() == 0 && !mProjectStyle ) || ( index.row() == 1 && mProjectStyle ) );
625 const int styleRow = index.row() - ( mShowDefault ? 1 : 0 ) - ( mProjectStyle ? 1 : 0 );
626
627 switch ( role )
628 {
629 case Qt::DisplayRole:
630 case Qt::EditRole:
631 if ( isDefault )
632 return QgsStyle::defaultStyle()->name();
633 else if ( isProjectStyle )
634 return mProjectStyle->name();
635 else
636 return mSettings ? mSettings->styles().at( styleRow )->name() : QVariant();
637
638 case Qt::ToolTipRole:
639 if ( isDefault )
640 return QDir::toNativeSeparators( QgsStyle::defaultStyle()->fileName() );
641 else if ( isProjectStyle )
642 return mProjectStyle->name();
643 else
644 return mSettings ? QDir::toNativeSeparators( mSettings->styles().at( styleRow )->fileName() ) : QVariant();
645
646 case static_cast< int >( CustomRole::Style ):
647 {
648 if ( isDefault )
649 return QVariant::fromValue( QgsStyle::defaultStyle() );
650 else if ( isProjectStyle )
651 return QVariant::fromValue( mProjectStyle.data() );
652 else if ( QgsStyle *style = mSettings->styles().value( styleRow ) )
653 return QVariant::fromValue( style );
654 else
655 return QVariant();
656 }
657
658 case static_cast< int >( CustomRole::Path ):
659 if ( isDefault )
661 else if ( isProjectStyle )
662 return mProjectStyle->fileName();
663 else
664 return mSettings ? mSettings->styles().at( styleRow )->fileName() : QVariant();
665
666 default:
667 return QVariant();
668 }
669}
670
672{
673 if ( index.row() == 0 && mProjectStyle )
674 return mProjectStyle;
675 else if ( mShowDefault && ( ( index.row() == 0 && !mProjectStyle ) || ( index.row() == 1 && mProjectStyle ) ) )
676 return QgsStyle::defaultStyle();
677 else if ( QgsStyle *style = qobject_cast< QgsStyle * >( qvariant_cast<QObject *>( data( index, static_cast< int >( CustomRole::Style ) ) ) ) )
678 return style;
679 else
680 return nullptr;
681}
682
684{
685 if ( style == mProjectStyle )
686 return index( 0, 0, QModelIndex() );
687 else if ( style == QgsStyle::defaultStyle() && mShowDefault )
688 return index( mProjectStyle ? 1 : 0, 0, QModelIndex() );
689
690 if ( !mSettings )
691 {
692 return QModelIndex();
693 }
694
695 const int r = mSettings->styles().indexOf( style );
696 if ( r < 0 )
697 return QModelIndex();
698
699 QModelIndex idx = index( r + ( mShowDefault ? 1 : 0 ) + ( mProjectStyle ? 1 : 0 ), 0, QModelIndex() );
700 if ( idx.isValid() )
701 {
702 return idx;
703 }
704
705 return QModelIndex();
706}
707
709{
710 if ( show == mShowDefault )
711 return;
712
713 const int row = mProjectStyle ? 1 : 0;
714 if ( show )
715 {
716 beginInsertRows( QModelIndex(), row, row );
717 mShowDefault = true;
718 endInsertRows();
719 }
720 else
721 {
722 beginRemoveRows( QModelIndex(), row, row );
723 mShowDefault = false;
724 endRemoveRows();
725 }
726}
727
728void QgsProjectStyleDatabaseModel::setProjectStyle( QgsStyle *style )
729{
730 if ( style == mProjectStyle )
731 return;
732
733 if ( mProjectStyle )
734 {
735 disconnect( mProjectStyle, &QgsStyle::aboutToBeDestroyed, this, &QgsProjectStyleDatabaseModel::projectStyleAboutToBeDestroyed );
736 disconnect( mProjectStyle, &QgsStyle::destroyed, this, &QgsProjectStyleDatabaseModel::projectStyleDestroyed );
737 beginRemoveRows( QModelIndex(), 0, 0 );
738 mProjectStyle = nullptr;
739 endRemoveRows();
740 }
741
742 if ( style )
743 {
744 beginInsertRows( QModelIndex(), 0, 0 );
745 mProjectStyle = style;
746 endInsertRows();
747
748 connect( mProjectStyle, &QgsStyle::aboutToBeDestroyed, this, &QgsProjectStyleDatabaseModel::projectStyleAboutToBeDestroyed );
749 connect( mProjectStyle, &QgsStyle::destroyed, this, &QgsProjectStyleDatabaseModel::projectStyleDestroyed );
750 }
751}
752
753void QgsProjectStyleDatabaseModel::styleDatabaseAboutToBeAdded( const QString & )
754{
755 int row = mSettings->styles().count() + ( mShowDefault ? 1 : 0 ) + ( mProjectStyle ? 1 : 0 );
756 beginInsertRows( QModelIndex(), row, row );
757}
758
759void QgsProjectStyleDatabaseModel::styleDatabaseAboutToBeRemoved( const QString &path )
760{
761 QgsStyle *style = mSettings->styleAtPath( path );
762 int row = mSettings->styles().indexOf( style ) + ( mShowDefault ? 1 : 0 ) + ( mProjectStyle ? 1 : 0 );
763 if ( row >= 0 )
764 beginRemoveRows( QModelIndex(), row, row );
765}
766
767void QgsProjectStyleDatabaseModel::styleDatabaseAdded( const QString & )
768{
769 endInsertRows();
770}
771
772void QgsProjectStyleDatabaseModel::styleDatabaseRemoved( const QString & )
773{
774 endRemoveRows();
775}
776
777void QgsProjectStyleDatabaseModel::projectStyleAboutToBeDestroyed()
778{
779 beginRemoveRows( QModelIndex(), 0, 0 );
780}
781
782void QgsProjectStyleDatabaseModel::projectStyleDestroyed()
783{
784 endRemoveRows();
785}
786
787void QgsProjectStyleDatabaseModel::projectStyleChanged()
788{
789 setProjectStyle( mSettings->projectStyle() );
790}
791
792//
793// QgsProjectStyleDatabaseProxyModel
794//
795
797 : QSortFilterProxyModel( parent )
798{
799 setSourceModel( model );
800 setDynamicSortFilter( true );
801}
802
803bool QgsProjectStyleDatabaseProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
804{
805 if ( mFilters & Filter::FilterHideReadOnly )
806 {
807 if ( const QgsStyle *style = qobject_cast< QgsStyle * >( sourceModel()->data( sourceModel()->index( sourceRow, 0, sourceParent ), static_cast< int >( QgsProjectStyleDatabaseModel::CustomRole::Style ) ).value< QObject * >() ) )
808 {
809 if ( style->isReadOnly() )
810 return false;
811 }
812 }
813
814 return true;
815}
816
821
QFlags< ProjectReadFlag > ProjectReadFlags
Project load flags.
Definition qgis.h:4415
@ ProjectStyles
Enable the project embedded style library. Enabling this flag can increase the time required to clear...
Definition qgis.h:4428
SymbolType
Symbol types.
Definition qgis.h:629
@ Marker
Marker symbol.
Definition qgis.h:630
@ Line
Line symbol.
Definition qgis.h:631
@ Fill
Fill symbol.
Definition qgis.h:632
@ Hybrid
Hybrid symbol.
Definition qgis.h:633
ColorModel
Color model types.
Definition qgis.h:6287
@ Rgb
RGB color model.
Definition qgis.h:6288
Abstract base class for color ramps.
virtual QgsColorRamp * clone() const =0
Creates a clone of the color ramp.
static Qgis::ColorModel toColorModel(QColorSpace::ColorModel colorModel, bool *ok=nullptr)
Convert and returns Qt colorModel to Qgis::ColorModel.
static QColorSpace iccProfile(const QString &iccProfileFilePath, QString &errorMsg)
Loads an ICC profile from iccProfileFilePath and returns associated color space.
A model which contains entities from multiple QgsStyle databases.
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
List model representing the style databases associated with a QgsProject.
QVariant data(const QModelIndex &index, int role) const override
void setShowDefaultStyle(bool show)
Sets whether the default style should also be included in the model.
QModelIndex indexFromStyle(QgsStyle *style) const
Returns the model index corresponding to a style.
QgsProjectStyleDatabaseModel(QgsProjectStyleSettings *settings, QObject *parent=nullptr)
Constructor for QgsProjectStyleDatabaseModel, showing the styles from the specified settings.
QgsStyle * styleFromIndex(const QModelIndex &index) const
Returns the style at the corresponding index.
int rowCount(const QModelIndex &parent) const override
@ FilterHideReadOnly
Hide read-only style databases.
QgsProjectStyleDatabaseProxyModel::Filters filters() const
Returns the current filters used for filtering available style.
QFlags< Filter > Filters
Available filter flags for filtering the model.
void setFilters(QgsProjectStyleDatabaseProxyModel::Filters filters)
Sets the current filters used for filtering available styles.
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
QgsProjectStyleDatabaseProxyModel(QgsProjectStyleDatabaseModel *model, QObject *parent=nullptr)
Constructor for QgsProjectStyleDatabaseProxyModel, for the specified style database model.
Contains settings and properties relating to how a QgsProject should handle styling.
QColorSpace colorSpace() const
Returns the project's color space.
void setDefaultTextFormat(const QgsTextFormat &textFormat)
Sets the project default text format.
QList< QgsStyle * > styles() const
Returns a list of all the styles associated with the project.
void setStyleDatabasePaths(const QStringList &paths)
Sets the paths to all style databases associated with the project.
QgsStyle * styleAtPath(const QString &path)
Returns a reference to the style database associated with the project with matching file path.
QgsTextFormat defaultTextFormat() const
Returns the project default text format.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Returns a DOM element representing the settings.
void setProjectStyle(QgsStyle *style)
Sets the style database to use for the project style.
Qgis::ColorModel colorModel() const
Returns the project's color model.
void projectStyleChanged()
Emitted when the style returned by projectStyle() is changed.
QgsColorRamp * defaultColorRamp() const
Returns the project default color ramp.
QgsSymbol * defaultSymbol(Qgis::SymbolType symbolType) const
Returns the project default symbol for a given type.
void setDefaultSymbol(Qgis::SymbolType symbolType, QgsSymbol *symbol)
Sets the project default symbol for a given type.
void reset()
Resets the settings to a default state.
QgsProjectStyleSettings(QgsProject *project=nullptr)
Constructor for QgsProjectStyleSettings for the specified project.
void styleDatabaseAdded(const QString &path)
Emitted when a style database path is added.
void styleDatabaseAboutToBeRemoved(const QString &path)
Emitted when a style database path is about to be removed.
void removeProjectStyle()
Removes and deletes the project style database.
void setRandomizeDefaultSymbolColor(bool randomized)
Sets whether the default symbol fill color is randomized.
void setColorModel(Qgis::ColorModel colorModel)
Set the project's color model to colorModel.
void setColorSpace(const QColorSpace &colorSpace)
Set the project's current color space to colorSpace.
void setDefaultColorRamp(QgsColorRamp *colorRamp)
Sets the project default color ramp.
void addStyleDatabasePath(const QString &path)
Adds a style database path to the project.
void styleDatabaseRemoved(const QString &path)
Emitted when a style database path is removed.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context, Qgis::ProjectReadFlags flags=Qgis::ProjectReadFlags())
Reads the settings's state from a DOM element.
QgsStyle * projectStyle()
Returns the style database to use for project specific styles.
QgsCombinedStyleModel * combinedStyleModel()
Returns the combined style model which includes all style databases associated with the project.
void setDefaultSymbolOpacity(double opacity)
Sets the default symbol opacity.
void styleDatabaseAboutToBeAdded(const QString &path)
Emitted when a style database path is about to be added.
void styleDatabasesChanged()
Emitted whenever the set of style databases associated with the project is changed.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:113
void projectColorsChanged()
Emitted whenever the project's color scheme has been changed.
void setDirty(bool b=true)
Flag the project as dirty (modified).
A container for the context for various read/write operations on objects.
void pushMessage(const QString &message, Qgis::MessageLevel level=Qgis::MessageLevel::Warning) const
Append a message to the context.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
A database of saved style entities, including symbols, color ramps, text formats and others.
Definition qgsstyle.h:89
void setFileName(const QString &filename)
Sets the current file name of the style database.
Definition qgsstyle.cpp:898
void aboutToBeDestroyed()
Emitted just before the style object is destroyed.
bool createDatabase(const QString &filename)
Creates an on-disk database.
Definition qgsstyle.cpp:553
void triggerIconRebuild()
Triggers emission of the rebuildIconPreviews() signal.
void setName(const QString &name)
Sets the name of the style.
Definition qgsstyle.cpp:106
QString fileName() const
Returns the current file name of the style database.
Definition qgsstyle.h:927
bool isReadOnly() const
Returns true if the style is considered a read-only library.
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
Definition qgsstyle.cpp:150
bool createMemoryDatabase()
Creates a temporary memory database.
Definition qgsstyle.cpp:568
bool load(const QString &filename)
Loads a file into the style.
Definition qgsstyle.cpp:643
QString name() const
Returns the name of the style.
Definition qgsstyle.cpp:111
void setReadOnly(bool readOnly)
Sets whether the style is considered a read-only library.
bool importXml(const QString &filename)
Imports the symbols and colorramps into the default style database from the given XML file.
static std::unique_ptr< QgsColorRamp > loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
static std::unique_ptr< QgsSymbol > loadSymbol(const QDomElement &element, const QgsReadWriteContext &context)
Attempts to load a symbol from a DOM element.
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
static QDomElement saveColorRamp(const QString &name, const QgsColorRamp *ramp, QDomDocument &doc)
Encodes a color ramp's settings to an XML element.
Abstract base class for all rendered symbols.
Definition qgssymbol.h:231
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
Container for all settings relating to text rendering.
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
Definition qgis.h:7145
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:7126
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6935
#define QgsDebugError(str)
Definition qgslogger.h:59