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