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