QGIS API Documentation 3.41.0-Master (cea29feecf2)
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
16#include "qgscolorutils.h"
18#include "moc_qgsprojectstylesettings.cpp"
19#include "qgis.h"
20#include "qgsproject.h"
21#include "qgssymbol.h"
22#include "qgssymbollayerutils.h"
23#include "qgsmarkersymbol.h"
24#include "qgslinesymbol.h"
25#include "qgsfillsymbol.h"
26#include "qgscolorramp.h"
27#include "qgstextformat.h"
28#include "qgsstyle.h"
30#include "qgsxmlutils.h"
31
32#include <QDomElement>
33
35 : QObject( project )
36 , mProject( project )
37{
38 mCombinedStyleModel = new QgsCombinedStyleModel( this );
39}
40
42{
43 if ( mProjectStyle )
44 {
45 mProjectStyle->deleteLater();
46 mProjectStyle = nullptr;
47 }
48}
49
51{
52 switch ( symbolType )
53 {
55 return mDefaultMarkerSymbol ? mDefaultMarkerSymbol->clone() : nullptr;
56
58 return mDefaultLineSymbol ? mDefaultLineSymbol->clone() : nullptr;
59
61 return mDefaultFillSymbol ? mDefaultFillSymbol->clone() : nullptr;
62
64 break;
65 }
66
67 return nullptr;
68}
69
71{
72 switch ( symbolType )
73 {
75 if ( mDefaultMarkerSymbol.get() == symbol )
76 return;
77
78 mDefaultMarkerSymbol.reset( symbol ? symbol->clone() : nullptr );
79
80 makeDirty();
81 break;
82
84 if ( mDefaultLineSymbol.get() == symbol )
85 return;
86
87 mDefaultLineSymbol.reset( symbol ? symbol->clone() : nullptr );
88
89 makeDirty();
90 break;
91
93 if ( mDefaultFillSymbol.get() == symbol )
94 return;
95
96 mDefaultFillSymbol.reset( symbol ? symbol->clone() : nullptr );
97
98 makeDirty();
99 break;
100
102 break;
103 }
104}
105
107{
108 return mDefaultColorRamp ? mDefaultColorRamp->clone() : nullptr;
109}
110
112{
113 if ( mDefaultColorRamp.get() == colorRamp )
114 return;
115
116 mDefaultColorRamp.reset( colorRamp ? colorRamp->clone() : nullptr );
117
118 makeDirty();
119}
120
122{
123 return mDefaultTextFormat;
124}
125
127{
128 if ( mDefaultTextFormat == textFormat )
129 return;
130
131 mDefaultTextFormat = textFormat;
132
133 makeDirty();
134}
135
137{
138 if ( qgsDoubleNear( mDefaultSymbolOpacity, opacity ) )
139 return;
140
141 mDefaultSymbolOpacity = opacity;
142
143 makeDirty();
144}
145
147{
148 if ( mRandomizeDefaultSymbolColor == randomized )
149 return;
150
151 mRandomizeDefaultSymbolColor = randomized;
152
153 makeDirty();
154}
155
157{
158 mDefaultMarkerSymbol.reset();
159 mDefaultLineSymbol.reset();
160 mDefaultFillSymbol.reset();
161 mDefaultColorRamp.reset();
162 mDefaultTextFormat = QgsTextFormat();
163 mRandomizeDefaultSymbolColor = true;
164 mDefaultSymbolOpacity = 1.0;
165
166 clearStyles();
167
168 if ( mProject && ( mProject->capabilities() & Qgis::ProjectCapability::ProjectStyles ) )
169 {
170 const QString stylePath = mProject->createAttachedFile( QStringLiteral( "styles.db" ) );
171 QgsStyle *style = new QgsStyle();
172 style->createDatabase( stylePath );
173 style->setName( tr( "Project Style" ) );
174 style->setFileName( stylePath );
175 setProjectStyle( style );
176 }
177
179}
180
182{
183 if ( mProjectStyle )
184 {
185 mCombinedStyleModel->removeStyle( mProjectStyle );
186 delete mProjectStyle;
187 mProjectStyle = nullptr;
188 }
189}
190
192{
193 if ( mProjectStyle )
194 {
195 mCombinedStyleModel->removeStyle( mProjectStyle );
196 mProjectStyle->deleteLater();
197 }
198 mProjectStyle = style;
199 mProjectStyle->setName( tr( "Project Styles" ) );
200
201 // if project color scheme changes, we need to redraw symbols - they may use project colors and accordingly
202 // need updating to reflect the new colors
203 if ( mProject )
204 {
205 connect( mProject, &QgsProject::projectColorsChanged, mProjectStyle, &QgsStyle::triggerIconRebuild );
206 }
207 mCombinedStyleModel->addStyle( mProjectStyle );
208
209 emit projectStyleChanged();
210}
211
213{
214 return mProjectStyle;
215}
216
217bool QgsProjectStyleSettings::readXml( const QDomElement &element, const QgsReadWriteContext &context, Qgis::ProjectReadFlags )
218{
219 mRandomizeDefaultSymbolColor = element.attribute( QStringLiteral( "RandomizeDefaultSymbolColor" ), QStringLiteral( "0" ) ).toInt();
220 mDefaultSymbolOpacity = element.attribute( QStringLiteral( "DefaultSymbolOpacity" ), QStringLiteral( "1.0" ) ).toDouble();
221 mColorModel = qgsEnumKeyToValue( element.attribute( QStringLiteral( "colorModel" ) ), Qgis::ColorModel::Rgb );
222
223 QDomElement elem = element.firstChildElement( QStringLiteral( "markerSymbol" ) );
224 if ( !elem.isNull() )
225 {
226 QDomElement symbolElem = elem.firstChildElement( QStringLiteral( "symbol" ) );
227 mDefaultMarkerSymbol.reset( !symbolElem.isNull() ? QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( symbolElem, context ) : nullptr );
228 }
229 else
230 {
231 mDefaultMarkerSymbol.reset();
232 }
233
234 elem = element.firstChildElement( QStringLiteral( "lineSymbol" ) );
235 if ( !elem.isNull() )
236 {
237 QDomElement symbolElem = elem.firstChildElement( QStringLiteral( "symbol" ) );
238 mDefaultLineSymbol.reset( !symbolElem.isNull() ? QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( symbolElem, context ) : nullptr );
239 }
240 else
241 {
242 mDefaultLineSymbol.reset();
243 }
244
245 elem = element.firstChildElement( QStringLiteral( "fillSymbol" ) );
246 if ( !elem.isNull() )
247 {
248 QDomElement symbolElem = elem.firstChildElement( QStringLiteral( "symbol" ) );
249 mDefaultFillSymbol.reset( !symbolElem.isNull() ? QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElem, context ) : nullptr );
250 }
251 else
252 {
253 mDefaultFillSymbol.reset();
254 }
255
256 elem = element.firstChildElement( QStringLiteral( "colorramp" ) );
257 mDefaultColorRamp.reset( !elem.isNull() ? QgsSymbolLayerUtils::loadColorRamp( elem ) : nullptr );
258
259 elem = element.firstChildElement( QStringLiteral( "text-style" ) );
260 if ( !elem.isNull() )
261 {
262 mDefaultTextFormat.readXml( elem, context );
263 }
264 else
265 {
266 mDefaultTextFormat = QgsTextFormat();
267 }
268
269 {
270 clearStyles();
271 if ( !mProject || ( mProject->capabilities() & Qgis::ProjectCapability::ProjectStyles ) )
272 {
273 const QDomElement styleDatabases = element.firstChildElement( QStringLiteral( "databases" ) );
274 if ( !styleDatabases.isNull() )
275 {
276 const QDomNodeList styleEntries = styleDatabases.childNodes();
277 for ( int i = 0; i < styleEntries.count(); ++i )
278 {
279 const QDomElement styleElement = styleEntries.at( i ).toElement();
280 const QString path = styleElement.attribute( QStringLiteral( "path" ) );
281 const QString fullPath = context.pathResolver().readPath( path );
282 emit styleDatabaseAboutToBeAdded( fullPath );
283 mStyleDatabases.append( fullPath );
284 loadStyleAtPath( fullPath );
285 emit styleDatabaseAdded( fullPath );
286 }
287 }
288
289 if ( mProject && ( mProject->capabilities() & Qgis::ProjectCapability::ProjectStyles ) )
290 {
291 const QString projectStyleId = element.attribute( QStringLiteral( "projectStyleId" ) );
292 const QString projectStyleFile = mProject->resolveAttachmentIdentifier( projectStyleId );
293 QgsStyle *style = new QgsStyle();
294 if ( !projectStyleFile.isEmpty() && QFile::exists( projectStyleFile ) )
295 {
296 style->load( projectStyleFile );
297 style->setFileName( projectStyleFile );
298 }
299 else
300 {
301 const QString stylePath = mProject->createAttachedFile( QStringLiteral( "styles.db" ) );
302 style->createDatabase( stylePath );
303 style->setFileName( stylePath );
304 }
305 style->setName( tr( "Project Style" ) );
306 setProjectStyle( style );
307 }
308 }
309 }
310
311 const QString iccProfileId = element.attribute( QStringLiteral( "iccProfileId" ) );
312 mIccProfileFilePath = mProject ? mProject->resolveAttachmentIdentifier( iccProfileId ) : QString();
313 if ( !mIccProfileFilePath.isEmpty() )
314 {
315 QString errorMsg;
316 QColorSpace colorSpace = QgsColorUtils::iccProfile( mIccProfileFilePath, errorMsg );
317 if ( !errorMsg.isEmpty() )
318 context.pushMessage( errorMsg );
319
321 }
322
324
325 return true;
326}
327
328QDomElement QgsProjectStyleSettings::writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const
329{
330 QDomElement element = doc.createElement( QStringLiteral( "ProjectStyleSettings" ) );
331
332 element.setAttribute( QStringLiteral( "RandomizeDefaultSymbolColor" ), mRandomizeDefaultSymbolColor ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
333 element.setAttribute( QStringLiteral( "DefaultSymbolOpacity" ), QString::number( mDefaultSymbolOpacity ) );
334
335 element.setAttribute( QStringLiteral( "colorModel" ), qgsEnumValueToKey( mColorModel ) );
336
337 if ( mDefaultMarkerSymbol )
338 {
339 QDomElement markerSymbolElem = doc.createElement( QStringLiteral( "markerSymbol" ) );
340 markerSymbolElem.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mDefaultMarkerSymbol.get(), doc, context ) );
341 element.appendChild( markerSymbolElem );
342 }
343
344 if ( mDefaultLineSymbol )
345 {
346 QDomElement lineSymbolElem = doc.createElement( QStringLiteral( "lineSymbol" ) );
347 lineSymbolElem.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mDefaultLineSymbol.get(), doc, context ) );
348 element.appendChild( lineSymbolElem );
349 }
350
351 if ( mDefaultFillSymbol )
352 {
353 QDomElement fillSymbolElem = doc.createElement( QStringLiteral( "fillSymbol" ) );
354 fillSymbolElem.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mDefaultFillSymbol.get(), doc, context ) );
355 element.appendChild( fillSymbolElem );
356 }
357
358 if ( mDefaultColorRamp )
359 {
360 QDomElement colorRampElem = QgsSymbolLayerUtils::saveColorRamp( QString(), mDefaultColorRamp.get(), doc );
361 element.appendChild( colorRampElem );
362 }
363
364 if ( mDefaultTextFormat.isValid() )
365 {
366 QDomElement textFormatElem = mDefaultTextFormat.writeXml( doc, context );
367 element.appendChild( textFormatElem );
368 }
369
370 {
371 QDomElement styleDatabases = doc.createElement( QStringLiteral( "databases" ) );
372 for ( const QString &db : mStyleDatabases )
373 {
374 QDomElement dbElement = doc.createElement( QStringLiteral( "db" ) );
375 dbElement.setAttribute( QStringLiteral( "path" ), context.pathResolver().writePath( db ) );
376 styleDatabases.appendChild( dbElement );
377 }
378 element.appendChild( styleDatabases );
379 }
380
381 if ( mProject && mProjectStyle )
382 {
383 element.setAttribute( QStringLiteral( "projectStyleId" ), mProject->attachmentIdentifier( mProjectStyle->fileName() ) );
384 }
385
386 if ( mProject )
387 {
388 element.setAttribute( QStringLiteral( "iccProfileId" ), mProject->attachmentIdentifier( mIccProfileFilePath ) );
389 }
390
391 return element;
392}
393
394QList<QgsStyle *> QgsProjectStyleSettings::styles() const
395{
396 QList< QgsStyle * > res;
397 res.reserve( mStyles.size() );
398 for ( QgsStyle *style : mStyles )
399 {
400 if ( style )
401 res.append( style );
402 }
403 return res;
404}
405
407{
408 if ( path == QgsStyle::defaultStyle()->fileName() )
409 return QgsStyle::defaultStyle();
410
411 if ( mProjectStyle && path == mProjectStyle->fileName() )
412 return mProjectStyle;
413
414 for ( QgsStyle *style : std::as_const( mStyles ) )
415 {
416 if ( style->fileName() == path )
417 return style;
418 }
419
420 return nullptr;
421}
422
424{
425 if ( mStyleDatabases.contains( path ) )
426 return;
427
428 emit styleDatabaseAboutToBeAdded( path );
429 mStyleDatabases.append( path );
430 loadStyleAtPath( path );
431 emit styleDatabaseAdded( path );
432
434}
435
437{
438 if ( paths == mStyleDatabases )
439 return;
440
441 clearStyles();
442
443 for ( const QString &path : paths )
444 {
445 emit styleDatabaseAboutToBeAdded( path );
446 mStyleDatabases.append( path );
447 loadStyleAtPath( path );
448 emit styleDatabaseAdded( path );
449 }
451}
452
453void QgsProjectStyleSettings::loadStyleAtPath( const QString &path )
454{
455 QgsStyle *style = new QgsStyle( this );
456
457 const QFileInfo fileInfo( path );
458 if ( fileInfo.suffix().compare( QLatin1String( "xml" ), Qt::CaseInsensitive ) == 0 )
459 {
460 style->createMemoryDatabase();
461 style->importXml( path );
462 style->setFileName( path );
463 style->setReadOnly( true );
464 }
465 else
466 {
467 style->load( path );
468 }
469 style->setName( fileInfo.completeBaseName() );
470 mStyles.append( style );
471 mCombinedStyleModel->addStyle( style );
472
473 if ( mProject )
474 {
475 // if project color scheme changes, we need to redraw symbols - they may use project colors and accordingly
476 // need updating to reflect the new colors
478 }
479}
480
481void QgsProjectStyleSettings::clearStyles()
482{
483 const QStringList pathsToRemove = mStyleDatabases;
484 for ( const QString &path : pathsToRemove )
485 {
487 mStyleDatabases.removeAll( path );
488 if ( QgsStyle *style = styleAtPath( path ) )
489 {
490 mCombinedStyleModel->removeStyle( style );
491 style->deleteLater();
492 mStyles.removeAll( style );
493 }
494 emit styleDatabaseRemoved( path );
495 }
496
497 // should already be empty, but play it safe..!
498 for ( QgsStyle *style : std::as_const( mStyles ) )
499 {
500 mCombinedStyleModel->removeStyle( style );
501 }
502 qDeleteAll( mStyles );
503 mStyles.clear();
504}
505
507{
508 return mCombinedStyleModel;
509}
510
512{
513 if ( mColorModel == colorModel )
514 return;
515
516 mColorModel = colorModel;
517
518 makeDirty();
519
520#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
521 if ( mColorSpace.isValid() && QgsColorUtils::toColorModel( mColorSpace.colorModel() ) != colorModel )
522 {
523 setColorSpace( QColorSpace() );
524 }
525#endif
526}
527
529{
530 return mColorModel;
531}
532
533void QgsProjectStyleSettings::setColorSpace( const QColorSpace &colorSpace )
534{
535 if ( mColorSpace == colorSpace )
536 return;
537
538 if ( !mProject )
539 {
540 QgsDebugError( "Impossible to attach ICC profile, no project defined" );
541 return;
542 }
543
544 auto clearIccProfile = [this]()
545 {
546 mProject->removeAttachedFile( mIccProfileFilePath );
547 mIccProfileFilePath.clear();
548 mColorSpace = QColorSpace();
549 };
550
551 if ( !mIccProfileFilePath.isEmpty() )
552 clearIccProfile();
553
554#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
555 bool ok;
557 mColorSpace = ok ? colorSpace : QColorSpace();
558#else
559 mColorSpace = colorSpace;
560#endif
561
562 makeDirty();
563
564 if ( !mColorSpace.isValid() )
565 return;
566
567#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
568 if ( colorModel != mColorModel )
569 mColorModel = colorModel;
570#endif
571
572 mIccProfileFilePath = mProject->createAttachedFile( QStringLiteral( "profile.icc" ) );
573 QFile file( mIccProfileFilePath );
574 if ( !file.open( QIODevice::WriteOnly ) || file.write( colorSpace.iccProfile() ) < 0 )
575 clearIccProfile();
576}
577
579{
580 return mColorSpace;
581}
582
583void QgsProjectStyleSettings::makeDirty()
584{
585 if ( mProject )
586 mProject->setDirty( true );
587}
588
589//
590// QgsProjectStyleDatabaseModel
591//
592
594 : QAbstractListModel( parent )
595 , mSettings( settings )
596{
597 connect( mSettings, &QgsProjectStyleSettings::styleDatabaseAboutToBeAdded, this, &QgsProjectStyleDatabaseModel::styleDatabaseAboutToBeAdded );
598 connect( mSettings, &QgsProjectStyleSettings::styleDatabaseAdded, this, &QgsProjectStyleDatabaseModel::styleDatabaseAdded );
599 connect( mSettings, &QgsProjectStyleSettings::styleDatabaseAboutToBeRemoved, this, &QgsProjectStyleDatabaseModel::styleDatabaseAboutToBeRemoved );
600 connect( mSettings, &QgsProjectStyleSettings::styleDatabaseRemoved, this, &QgsProjectStyleDatabaseModel::styleDatabaseRemoved );
601
602 if ( mSettings->projectStyle() )
603 setProjectStyle( mSettings->projectStyle() );
604 connect( mSettings, &QgsProjectStyleSettings::projectStyleChanged, this, &QgsProjectStyleDatabaseModel::projectStyleChanged );
605}
606
607int QgsProjectStyleDatabaseModel::rowCount( const QModelIndex &parent ) const
608{
609 Q_UNUSED( parent )
610 return ( mSettings ? mSettings->styleDatabasePaths().count() : 0 ) + ( mProjectStyle ? 1 : 0 ) + ( mShowDefault ? 1 : 0 );
611}
612
613QVariant QgsProjectStyleDatabaseModel::data( const QModelIndex &index, int role ) const
614{
615 if ( index.row() < 0 || index.row() >= rowCount( QModelIndex() ) )
616 return QVariant();
617
618 const bool isProjectStyle = index.row() == 0 && mProjectStyle;
619 const bool isDefault = mShowDefault && ( ( index.row() == 0 && !mProjectStyle ) || ( index.row() == 1 && mProjectStyle ) );
620 const int styleRow = index.row() - ( mShowDefault ? 1 : 0 ) - ( mProjectStyle ? 1 : 0 );
621
622 switch ( role )
623 {
624 case Qt::DisplayRole:
625 case Qt::EditRole:
626 if ( isDefault )
627 return QgsStyle::defaultStyle()->name();
628 else if ( isProjectStyle )
629 return mProjectStyle->name();
630 else
631 return mSettings ? mSettings->styles().at( styleRow )->name() : QVariant();
632
633 case Qt::ToolTipRole:
634 if ( isDefault )
635 return QDir::toNativeSeparators( QgsStyle::defaultStyle()->fileName() );
636 else if ( isProjectStyle )
637 return mProjectStyle->name();
638 else
639 return mSettings ? QDir::toNativeSeparators( mSettings->styles().at( styleRow )->fileName() ) : QVariant();
640
641 case static_cast< int >( CustomRole::Style ):
642 {
643 if ( isDefault )
644 return QVariant::fromValue( QgsStyle::defaultStyle() );
645 else if ( isProjectStyle )
646 return QVariant::fromValue( mProjectStyle.data() );
647 else if ( QgsStyle *style = mSettings->styles().value( styleRow ) )
648 return QVariant::fromValue( style );
649 else
650 return QVariant();
651 }
652
653 case static_cast< int >( CustomRole::Path ):
654 if ( isDefault )
656 else if ( isProjectStyle )
657 return mProjectStyle->fileName();
658 else
659 return mSettings ? mSettings->styles().at( styleRow )->fileName() : QVariant();
660
661 default:
662 return QVariant();
663 }
664}
665
667{
668 if ( index.row() == 0 && mProjectStyle )
669 return mProjectStyle;
670 else if ( mShowDefault && ( ( index.row() == 0 && !mProjectStyle ) || ( index.row() == 1 && mProjectStyle ) ) )
671 return QgsStyle::defaultStyle();
672 else if ( QgsStyle *style = qobject_cast< QgsStyle * >( qvariant_cast<QObject *>( data( index, static_cast< int >( CustomRole::Style ) ) ) ) )
673 return style;
674 else
675 return nullptr;
676}
677
679{
680 if ( style == mProjectStyle )
681 return index( 0, 0, QModelIndex() );
682 else if ( style == QgsStyle::defaultStyle() && mShowDefault )
683 return index( mProjectStyle ? 1 : 0, 0, QModelIndex() );
684
685 if ( !mSettings )
686 {
687 return QModelIndex();
688 }
689
690 const int r = mSettings->styles().indexOf( style );
691 if ( r < 0 )
692 return QModelIndex();
693
694 QModelIndex idx = index( r + ( mShowDefault ? 1 : 0 ) + ( mProjectStyle ? 1 : 0 ), 0, QModelIndex() );
695 if ( idx.isValid() )
696 {
697 return idx;
698 }
699
700 return QModelIndex();
701}
702
704{
705 if ( show == mShowDefault )
706 return;
707
708 const int row = mProjectStyle ? 1 : 0;
709 if ( show )
710 {
711 beginInsertRows( QModelIndex(), row, row );
712 mShowDefault = true;
713 endInsertRows();
714 }
715 else
716 {
717 beginRemoveRows( QModelIndex(), row, row );
718 mShowDefault = false;
719 endRemoveRows();
720 }
721}
722
723void QgsProjectStyleDatabaseModel::setProjectStyle( QgsStyle *style )
724{
725 if ( style == mProjectStyle )
726 return;
727
728 if ( mProjectStyle )
729 {
730 disconnect( mProjectStyle, &QgsStyle::aboutToBeDestroyed, this, &QgsProjectStyleDatabaseModel::projectStyleAboutToBeDestroyed );
731 disconnect( mProjectStyle, &QgsStyle::destroyed, this, &QgsProjectStyleDatabaseModel::projectStyleDestroyed );
732 beginRemoveRows( QModelIndex(), 0, 0 );
733 mProjectStyle = nullptr;
734 endRemoveRows();
735 }
736
737 if ( style )
738 {
739 beginInsertRows( QModelIndex(), 0, 0 );
740 mProjectStyle = style;
741 endInsertRows();
742
743 connect( mProjectStyle, &QgsStyle::aboutToBeDestroyed, this, &QgsProjectStyleDatabaseModel::projectStyleAboutToBeDestroyed );
744 connect( mProjectStyle, &QgsStyle::destroyed, this, &QgsProjectStyleDatabaseModel::projectStyleDestroyed );
745 }
746}
747
748void QgsProjectStyleDatabaseModel::styleDatabaseAboutToBeAdded( const QString & )
749{
750 int row = mSettings->styles().count() + ( mShowDefault ? 1 : 0 ) + ( mProjectStyle ? 1 : 0 );
751 beginInsertRows( QModelIndex(), row, row );
752}
753
754void QgsProjectStyleDatabaseModel::styleDatabaseAboutToBeRemoved( const QString &path )
755{
756 QgsStyle *style = mSettings->styleAtPath( path );
757 int row = mSettings->styles().indexOf( style ) + ( mShowDefault ? 1 : 0 ) + ( mProjectStyle ? 1 : 0 );
758 if ( row >= 0 )
759 beginRemoveRows( QModelIndex(), row, row );
760}
761
762void QgsProjectStyleDatabaseModel::styleDatabaseAdded( const QString & )
763{
764 endInsertRows();
765}
766
767void QgsProjectStyleDatabaseModel::styleDatabaseRemoved( const QString & )
768{
769 endRemoveRows();
770}
771
772void QgsProjectStyleDatabaseModel::projectStyleAboutToBeDestroyed()
773{
774 beginRemoveRows( QModelIndex(), 0, 0 );
775}
776
777void QgsProjectStyleDatabaseModel::projectStyleDestroyed()
778{
779 endRemoveRows();
780}
781
782void QgsProjectStyleDatabaseModel::projectStyleChanged()
783{
784 setProjectStyle( mSettings->projectStyle() );
785}
786
787//
788// QgsProjectStyleDatabaseProxyModel
789//
790
792 : QSortFilterProxyModel( parent )
793{
794 setSourceModel( model );
795 setDynamicSortFilter( true );
796}
797
798bool QgsProjectStyleDatabaseProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
799{
800 if ( mFilters & Filter::FilterHideReadOnly )
801 {
802 if ( const QgsStyle *style = qobject_cast< QgsStyle * >( sourceModel()->data( sourceModel()->index( sourceRow, 0, sourceParent ), static_cast< int >( QgsProjectStyleDatabaseModel::CustomRole::Style ) ).value< QObject * >() ) )
803 {
804 if ( style->isReadOnly() )
805 return false;
806 }
807 }
808
809 return true;
810}
811
816
818{
819 mFilters = filters;
820 invalidateFilter();
821}
QFlags< ProjectReadFlag > ProjectReadFlags
Project load flags.
Definition qgis.h:4070
@ ProjectStyles
Enable the project embedded style library. Enabling this flag can increase the time required to clear...
SymbolType
Symbol types.
Definition qgis.h:574
@ Marker
Marker symbol.
@ Line
Line symbol.
@ Fill
Fill symbol.
@ Hybrid
Hybrid symbol.
ColorModel
Color model types.
Definition qgis.h:5629
@ Rgb
RGB color model.
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.
void removeStyle(QgsStyle *style)
Removes a style from the model.
void addStyle(QgsStyle *style)
Adds a style to the model.
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.
QStringList styleDatabasePaths() const
Returns a list of all style databases (file paths) associated with the project.
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:107
bool removeAttachedFile(const QString &path)
Removes the attached file.
QString createAttachedFile(const QString &nameTemplate)
Attaches a file to the project.
QString attachmentIdentifier(const QString &attachedFile) const
Returns an identifier for an attachment file path An attachment identifier is a string which does not...
QString resolveAttachmentIdentifier(const QString &identifier) const
Resolves an attachment identifier to a attachment file path.
void projectColorsChanged()
Emitted whenever the project's color scheme has been changed.
Qgis::ProjectCapabilities capabilities() const
Returns the project's capabilities, which dictate optional functionality which can be selectively ena...
Definition qgsproject.h:198
void setDirty(bool b=true)
Flag the project as dirty (modified).
The class is used as a container of context for various read/write operations on other 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.
void setFileName(const QString &filename)
Sets the current file name of the style database.
Definition qgsstyle.cpp:894
void aboutToBeDestroyed()
Emitted just before the style object is destroyed.
bool createDatabase(const QString &filename)
Creates an on-disk database.
Definition qgsstyle.cpp:549
void triggerIconRebuild()
Triggers emission of the rebuildIconPreviews() signal.
void setName(const QString &name)
Sets the name of the style.
Definition qgsstyle.cpp:102
QString fileName() const
Returns the current file name of the style database.
Definition qgsstyle.h:925
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:146
bool createMemoryDatabase()
Creates a temporary memory database.
Definition qgsstyle.cpp:564
bool load(const QString &filename)
Loads a file into the style.
Definition qgsstyle.cpp:639
QString name() const
Returns the name of the style.
Definition qgsstyle.cpp:107
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 QgsColorRamp * loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
static QDomElement saveColorRamp(const QString &name, QgsColorRamp *ramp, QDomDocument &doc)
Encodes a color ramp's settings to an XML element.
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
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.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Read settings from a DOM element.
bool isValid() const
Returns true if the format is valid.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
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:6234
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:6215
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:6024
#define QgsDebugError(str)
Definition qgslogger.h:38