34#include "moc_qgsprojectstylesettings.cpp"
47 mProjectStyle->deleteLater();
48 mProjectStyle =
nullptr;
57 return mDefaultMarkerSymbol ? mDefaultMarkerSymbol->clone() :
nullptr;
60 return mDefaultLineSymbol ? mDefaultLineSymbol->clone() :
nullptr;
63 return mDefaultFillSymbol ? mDefaultFillSymbol->clone() :
nullptr;
77 if ( mDefaultMarkerSymbol.get() == symbol )
80 mDefaultMarkerSymbol.reset( symbol ? symbol->
clone() :
nullptr );
86 if ( mDefaultLineSymbol.get() == symbol )
89 mDefaultLineSymbol.reset( symbol ? symbol->
clone() :
nullptr );
95 if ( mDefaultFillSymbol.get() == symbol )
98 mDefaultFillSymbol.reset( symbol ? symbol->
clone() :
nullptr );
110 return mDefaultColorRamp ? mDefaultColorRamp->
clone() :
nullptr;
115 if ( mDefaultColorRamp.get() == colorRamp )
118 mDefaultColorRamp.reset( colorRamp ? colorRamp->
clone() :
nullptr );
125 return mDefaultTextFormat;
130 if ( mDefaultTextFormat == textFormat )
133 mDefaultTextFormat = textFormat;
143 mDefaultSymbolOpacity = opacity;
150 if ( mRandomizeDefaultSymbolColor == randomized )
153 mRandomizeDefaultSymbolColor = randomized;
160 mDefaultMarkerSymbol.reset();
161 mDefaultLineSymbol.reset();
162 mDefaultFillSymbol.reset();
163 mDefaultColorRamp.reset();
165 mRandomizeDefaultSymbolColor =
true;
166 mDefaultSymbolOpacity = 1.0;
172 const QString stylePath = mProject->createAttachedFile( QStringLiteral(
"styles.db" ) );
175 style->
setName( tr(
"Project Style" ) );
187 mCombinedStyleModel->removeStyle( mProjectStyle );
188 delete mProjectStyle;
189 mProjectStyle =
nullptr;
197 mCombinedStyleModel->removeStyle( mProjectStyle );
198 mProjectStyle->deleteLater();
200 mProjectStyle = style;
201 mProjectStyle->
setName( tr(
"Project Styles" ) );
209 mCombinedStyleModel->addStyle( mProjectStyle );
216 return mProjectStyle;
221 mRandomizeDefaultSymbolColor = element.attribute( QStringLiteral(
"RandomizeDefaultSymbolColor" ), QStringLiteral(
"0" ) ).toInt();
222 mDefaultSymbolOpacity = element.attribute( QStringLiteral(
"DefaultSymbolOpacity" ), QStringLiteral(
"1.0" ) ).toDouble();
225 QDomElement elem = element.firstChildElement( QStringLiteral(
"markerSymbol" ) );
226 if ( !elem.isNull() )
228 QDomElement symbolElem = elem.firstChildElement( QStringLiteral(
"symbol" ) );
233 mDefaultMarkerSymbol.reset();
236 elem = element.firstChildElement( QStringLiteral(
"lineSymbol" ) );
237 if ( !elem.isNull() )
239 QDomElement symbolElem = elem.firstChildElement( QStringLiteral(
"symbol" ) );
244 mDefaultLineSymbol.reset();
247 elem = element.firstChildElement( QStringLiteral(
"fillSymbol" ) );
248 if ( !elem.isNull() )
250 QDomElement symbolElem = elem.firstChildElement( QStringLiteral(
"symbol" ) );
255 mDefaultFillSymbol.reset();
258 elem = element.firstChildElement( QStringLiteral(
"colorramp" ) );
261 elem = element.firstChildElement( QStringLiteral(
"text-style" ) );
262 if ( !elem.isNull() )
264 mDefaultTextFormat.readXml( elem, context );
275 const QDomElement styleDatabases = element.firstChildElement( QStringLiteral(
"databases" ) );
276 if ( !styleDatabases.isNull() )
278 const QDomNodeList styleEntries = styleDatabases.childNodes();
279 for (
int i = 0; i < styleEntries.count(); ++i )
281 const QDomElement styleElement = styleEntries.at( i ).toElement();
282 const QString path = styleElement.attribute( QStringLiteral(
"path" ) );
285 mStyleDatabases.append( fullPath );
286 loadStyleAtPath( fullPath );
293 const QString projectStyleId = element.attribute( QStringLiteral(
"projectStyleId" ) );
294 const QString projectStyleFile = mProject->resolveAttachmentIdentifier( projectStyleId );
296 if ( !projectStyleFile.isEmpty() && QFile::exists( projectStyleFile ) )
298 style->
load( projectStyleFile );
303 const QString stylePath = mProject->createAttachedFile( QStringLiteral(
"styles.db" ) );
307 style->
setName( tr(
"Project Style" ) );
313 const QString iccProfileId = element.attribute( QStringLiteral(
"iccProfileId" ) );
314 mIccProfileFilePath = mProject ? mProject->resolveAttachmentIdentifier( iccProfileId ) : QString();
315 if ( !mIccProfileFilePath.isEmpty() )
319 if ( !errorMsg.isEmpty() )
332 QDomElement element = doc.createElement( QStringLiteral(
"ProjectStyleSettings" ) );
334 element.setAttribute( QStringLiteral(
"RandomizeDefaultSymbolColor" ), mRandomizeDefaultSymbolColor ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
335 element.setAttribute( QStringLiteral(
"DefaultSymbolOpacity" ), QString::number( mDefaultSymbolOpacity ) );
337 element.setAttribute( QStringLiteral(
"colorModel" ),
qgsEnumValueToKey( mColorModel ) );
339 if ( mDefaultMarkerSymbol )
341 QDomElement markerSymbolElem = doc.createElement( QStringLiteral(
"markerSymbol" ) );
343 element.appendChild( markerSymbolElem );
346 if ( mDefaultLineSymbol )
348 QDomElement lineSymbolElem = doc.createElement( QStringLiteral(
"lineSymbol" ) );
350 element.appendChild( lineSymbolElem );
353 if ( mDefaultFillSymbol )
355 QDomElement fillSymbolElem = doc.createElement( QStringLiteral(
"fillSymbol" ) );
357 element.appendChild( fillSymbolElem );
360 if ( mDefaultColorRamp )
363 element.appendChild( colorRampElem );
366 if ( mDefaultTextFormat.isValid() )
368 QDomElement textFormatElem = mDefaultTextFormat.writeXml( doc, context );
369 element.appendChild( textFormatElem );
373 QDomElement styleDatabases = doc.createElement( QStringLiteral(
"databases" ) );
374 for (
const QString &db : mStyleDatabases )
376 QDomElement dbElement = doc.createElement( QStringLiteral(
"db" ) );
378 styleDatabases.appendChild( dbElement );
380 element.appendChild( styleDatabases );
383 if ( mProject && mProjectStyle )
385 element.setAttribute( QStringLiteral(
"projectStyleId" ), mProject->attachmentIdentifier( mProjectStyle->fileName() ) );
390 element.setAttribute( QStringLiteral(
"iccProfileId" ), mProject->attachmentIdentifier( mIccProfileFilePath ) );
398 QList< QgsStyle * > res;
399 res.reserve( mStyles.size() );
413 if ( mProjectStyle && path == mProjectStyle->fileName() )
414 return mProjectStyle;
416 for (
QgsStyle *style : std::as_const( mStyles ) )
418 if ( style->fileName() == path )
427 if ( mStyleDatabases.contains( path ) )
431 mStyleDatabases.append( path );
432 loadStyleAtPath( path );
440 if ( paths == mStyleDatabases )
445 for (
const QString &path : paths )
448 mStyleDatabases.append( path );
449 loadStyleAtPath( path );
455void QgsProjectStyleSettings::loadStyleAtPath(
const QString &path )
459 const QFileInfo fileInfo( path );
460 if ( fileInfo.suffix().compare( QLatin1String(
"xml" ), Qt::CaseInsensitive ) == 0 )
471 style->
setName( fileInfo.completeBaseName() );
472 mStyles.append( style );
473 mCombinedStyleModel->addStyle( style );
483void QgsProjectStyleSettings::clearStyles()
485 const QStringList pathsToRemove = mStyleDatabases;
486 for (
const QString &path : pathsToRemove )
489 mStyleDatabases.removeAll( path );
492 mCombinedStyleModel->removeStyle( style );
493 style->deleteLater();
494 mStyles.removeAll( style );
500 for ( QgsStyle *style : std::as_const( mStyles ) )
502 mCombinedStyleModel->removeStyle( style );
504 qDeleteAll( mStyles );
510 return mCombinedStyleModel;
522#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
542 QgsDebugError(
"Impossible to attach ICC profile, no project defined" );
546 auto clearIccProfile = [
this]()
548 mProject->removeAttachedFile( mIccProfileFilePath );
549 mIccProfileFilePath.clear();
550 mColorSpace = QColorSpace();
553 if ( !mIccProfileFilePath.isEmpty() )
556#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
559 mColorSpace = ok ?
colorSpace : QColorSpace();
566 if ( !mColorSpace.isValid() )
569#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
574 mIccProfileFilePath = mProject->createAttachedFile( QStringLiteral(
"profile.icc" ) );
575 QFile file( mIccProfileFilePath );
576 if ( !file.open( QIODevice::WriteOnly ) || file.write(
colorSpace.iccProfile() ) < 0 )
585void QgsProjectStyleSettings::makeDirty()
596 : QAbstractListModel( parent )
597 , mSettings( settings )
604 if ( mSettings->projectStyle() )
605 setProjectStyle( mSettings->projectStyle() );
612 return ( mSettings ? mSettings->styleDatabasePaths().count() : 0 ) + ( mProjectStyle ? 1 : 0 ) + ( mShowDefault ? 1 : 0 );
617 if ( index.row() < 0 || index.row() >=
rowCount( QModelIndex() ) )
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 );
626 case Qt::DisplayRole:
630 else if ( isProjectStyle )
631 return mProjectStyle->name();
633 return mSettings ? mSettings->styles().at( styleRow )->name() : QVariant();
635 case Qt::ToolTipRole:
638 else if ( isProjectStyle )
639 return mProjectStyle->name();
641 return mSettings ? QDir::toNativeSeparators( mSettings->styles().at( styleRow )->fileName() ) : QVariant();
647 else if ( isProjectStyle )
648 return QVariant::fromValue( mProjectStyle.data() );
649 else if (
QgsStyle *style = mSettings->styles().value( styleRow ) )
650 return QVariant::fromValue( style );
658 else if ( isProjectStyle )
659 return mProjectStyle->fileName();
661 return mSettings ? mSettings->styles().at( styleRow )->fileName() : QVariant();
670 if ( index.row() == 0 && mProjectStyle )
671 return mProjectStyle;
672 else if ( mShowDefault && ( ( index.row() == 0 && !mProjectStyle ) || ( index.row() == 1 && mProjectStyle ) ) )
674 else if (
QgsStyle *style = qobject_cast< QgsStyle * >( qvariant_cast<QObject *>(
data( index,
static_cast< int >(
CustomRole::Style ) ) ) ) )
682 if ( style == mProjectStyle )
683 return index( 0, 0, QModelIndex() );
685 return index( mProjectStyle ? 1 : 0, 0, QModelIndex() );
689 return QModelIndex();
692 const int r = mSettings->styles().indexOf( style );
694 return QModelIndex();
696 QModelIndex idx = index( r + ( mShowDefault ? 1 : 0 ) + ( mProjectStyle ? 1 : 0 ), 0, QModelIndex() );
702 return QModelIndex();
707 if ( show == mShowDefault )
710 const int row = mProjectStyle ? 1 : 0;
713 beginInsertRows( QModelIndex(), row, row );
719 beginRemoveRows( QModelIndex(), row, row );
720 mShowDefault =
false;
725void QgsProjectStyleDatabaseModel::setProjectStyle(
QgsStyle *style )
727 if ( style == mProjectStyle )
733 disconnect( mProjectStyle, &QgsStyle::destroyed,
this, &QgsProjectStyleDatabaseModel::projectStyleDestroyed );
734 beginRemoveRows( QModelIndex(), 0, 0 );
735 mProjectStyle =
nullptr;
741 beginInsertRows( QModelIndex(), 0, 0 );
742 mProjectStyle = style;
746 connect( mProjectStyle, &QgsStyle::destroyed,
this, &QgsProjectStyleDatabaseModel::projectStyleDestroyed );
750void QgsProjectStyleDatabaseModel::styleDatabaseAboutToBeAdded(
const QString & )
752 int row = mSettings->styles().count() + ( mShowDefault ? 1 : 0 ) + ( mProjectStyle ? 1 : 0 );
753 beginInsertRows( QModelIndex(), row, row );
756void QgsProjectStyleDatabaseModel::styleDatabaseAboutToBeRemoved(
const QString &path )
758 QgsStyle *style = mSettings->styleAtPath( path );
759 int row = mSettings->styles().indexOf( style ) + ( mShowDefault ? 1 : 0 ) + ( mProjectStyle ? 1 : 0 );
761 beginRemoveRows( QModelIndex(), row, row );
764void QgsProjectStyleDatabaseModel::styleDatabaseAdded(
const QString & )
769void QgsProjectStyleDatabaseModel::styleDatabaseRemoved(
const QString & )
774void QgsProjectStyleDatabaseModel::projectStyleAboutToBeDestroyed()
776 beginRemoveRows( QModelIndex(), 0, 0 );
779void QgsProjectStyleDatabaseModel::projectStyleDestroyed()
784void QgsProjectStyleDatabaseModel::projectStyleChanged()
786 setProjectStyle( mSettings->projectStyle() );
794 : QSortFilterProxyModel( parent )
796 setSourceModel( model );
797 setDynamicSortFilter(
true );
QFlags< ProjectReadFlag > ProjectReadFlags
Project load flags.
@ ProjectStyles
Enable the project embedded style library. Enabling this flag can increase the time required to clear...
ColorModel
Color model types.
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.
~QgsProjectStyleSettings() override
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,...
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.
void setFileName(const QString &filename)
Sets the current file name of the style database.
void aboutToBeDestroyed()
Emitted just before the style object is destroyed.
bool createDatabase(const QString &filename)
Creates an on-disk database.
void triggerIconRebuild()
Triggers emission of the rebuildIconPreviews() signal.
void setName(const QString &name)
Sets the name of the style.
QString fileName() const
Returns the current file name of the style database.
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.
bool createMemoryDatabase()
Creates a temporary memory database.
bool load(const QString &filename)
Loads a file into the style.
QString name() const
Returns the name of the style.
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.
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.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
#define QgsDebugError(str)