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