35#include "moc_qgsprojectstylesettings.cpp"
37using namespace Qt::StringLiterals;
50 mProjectStyle->deleteLater();
51 mProjectStyle =
nullptr;
60 return mDefaultMarkerSymbol ? mDefaultMarkerSymbol->clone() :
nullptr;
63 return mDefaultLineSymbol ? mDefaultLineSymbol->clone() :
nullptr;
66 return mDefaultFillSymbol ? mDefaultFillSymbol->clone() :
nullptr;
80 if ( mDefaultMarkerSymbol.get() == symbol )
83 mDefaultMarkerSymbol.reset( symbol ? symbol->
clone() :
nullptr );
89 if ( mDefaultLineSymbol.get() == symbol )
92 mDefaultLineSymbol.reset( symbol ? symbol->
clone() :
nullptr );
98 if ( mDefaultFillSymbol.get() == symbol )
101 mDefaultFillSymbol.reset( symbol ? symbol->
clone() :
nullptr );
113 return mDefaultColorRamp ? mDefaultColorRamp->
clone() :
nullptr;
118 if ( mDefaultColorRamp.get() == colorRamp )
121 mDefaultColorRamp.reset( colorRamp ? colorRamp->
clone() :
nullptr );
128 return mDefaultTextFormat;
133 if ( mDefaultTextFormat == textFormat )
136 mDefaultTextFormat = textFormat;
146 mDefaultSymbolOpacity = opacity;
153 if ( mRandomizeDefaultSymbolColor == randomized )
156 mRandomizeDefaultSymbolColor = randomized;
163 mDefaultMarkerSymbol.reset();
164 mDefaultLineSymbol.reset();
165 mDefaultFillSymbol.reset();
166 mDefaultColorRamp.reset();
168 mRandomizeDefaultSymbolColor =
true;
169 mDefaultSymbolOpacity = 1.0;
175 const QString stylePath = mProject->createAttachedFile( u
"styles.db"_s );
178 style->
setName( tr(
"Project Style" ) );
190 mCombinedStyleModel->removeStyle( mProjectStyle );
191 delete mProjectStyle;
192 mProjectStyle =
nullptr;
200 mCombinedStyleModel->removeStyle( mProjectStyle );
201 mProjectStyle->deleteLater();
203 mProjectStyle = style;
204 mProjectStyle->
setName( tr(
"Project Styles" ) );
212 mCombinedStyleModel->addStyle( mProjectStyle );
219 return mProjectStyle;
224 mRandomizeDefaultSymbolColor = element.attribute( u
"RandomizeDefaultSymbolColor"_s, u
"0"_s ).toInt();
225 mDefaultSymbolOpacity = element.attribute( u
"DefaultSymbolOpacity"_s, u
"1.0"_s ).toDouble();
228 QDomElement elem = element.firstChildElement( u
"markerSymbol"_s );
229 if ( !elem.isNull() )
231 QDomElement symbolElem = elem.firstChildElement( u
"symbol"_s );
236 mDefaultMarkerSymbol.reset();
239 elem = element.firstChildElement( u
"lineSymbol"_s );
240 if ( !elem.isNull() )
242 QDomElement symbolElem = elem.firstChildElement( u
"symbol"_s );
247 mDefaultLineSymbol.reset();
250 elem = element.firstChildElement( u
"fillSymbol"_s );
251 if ( !elem.isNull() )
253 QDomElement symbolElem = elem.firstChildElement( u
"symbol"_s );
258 mDefaultFillSymbol.reset();
261 elem = element.firstChildElement( u
"colorramp"_s );
264 elem = element.firstChildElement( u
"text-style"_s );
265 if ( !elem.isNull() )
267 mDefaultTextFormat.readXml( elem, context );
278 const QDomElement styleDatabases = element.firstChildElement( u
"databases"_s );
279 if ( !styleDatabases.isNull() )
281 const QDomNodeList styleEntries = styleDatabases.childNodes();
282 for (
int i = 0; i < styleEntries.count(); ++i )
284 const QDomElement styleElement = styleEntries.at( i ).toElement();
285 const QString path = styleElement.attribute( u
"path"_s );
288 mStyleDatabases.append( fullPath );
289 loadStyleAtPath( fullPath );
296 const QString projectStyleId = element.attribute( u
"projectStyleId"_s );
297 const QString projectStyleFile = mProject->resolveAttachmentIdentifier( projectStyleId );
299 if ( !projectStyleFile.isEmpty() && QFile::exists( projectStyleFile ) )
301 style->
load( projectStyleFile );
306 const QString stylePath = mProject->createAttachedFile( u
"styles.db"_s );
310 style->
setName( tr(
"Project Style" ) );
316 const QString iccProfileId = element.attribute( u
"iccProfileId"_s );
317 mIccProfileFilePath = mProject ? mProject->resolveAttachmentIdentifier( iccProfileId ) : QString();
318 if ( !mIccProfileFilePath.isEmpty() )
322 if ( !errorMsg.isEmpty() )
335 QDomElement element = doc.createElement( u
"ProjectStyleSettings"_s );
337 element.setAttribute( u
"RandomizeDefaultSymbolColor"_s, mRandomizeDefaultSymbolColor ? u
"1"_s : u
"0"_s );
338 element.setAttribute( u
"DefaultSymbolOpacity"_s, QString::number( mDefaultSymbolOpacity ) );
342 if ( mDefaultMarkerSymbol )
344 QDomElement markerSymbolElem = doc.createElement( u
"markerSymbol"_s );
346 element.appendChild( markerSymbolElem );
349 if ( mDefaultLineSymbol )
351 QDomElement lineSymbolElem = doc.createElement( u
"lineSymbol"_s );
353 element.appendChild( lineSymbolElem );
356 if ( mDefaultFillSymbol )
358 QDomElement fillSymbolElem = doc.createElement( u
"fillSymbol"_s );
360 element.appendChild( fillSymbolElem );
363 if ( mDefaultColorRamp )
366 element.appendChild( colorRampElem );
369 if ( mDefaultTextFormat.isValid() )
371 QDomElement textFormatElem = mDefaultTextFormat.writeXml( doc, context );
372 element.appendChild( textFormatElem );
376 QDomElement styleDatabases = doc.createElement( u
"databases"_s );
377 for (
const QString &db : mStyleDatabases )
379 QDomElement dbElement = doc.createElement( u
"db"_s );
381 styleDatabases.appendChild( dbElement );
383 element.appendChild( styleDatabases );
386 if ( mProject && mProjectStyle )
388 element.setAttribute( u
"projectStyleId"_s, mProject->attachmentIdentifier( mProjectStyle->fileName() ) );
393 element.setAttribute( u
"iccProfileId"_s, mProject->attachmentIdentifier( mIccProfileFilePath ) );
401 QList< QgsStyle * > res;
402 res.reserve( mStyles.size() );
416 if ( mProjectStyle && path == mProjectStyle->fileName() )
417 return mProjectStyle;
419 for (
QgsStyle *style : std::as_const( mStyles ) )
421 if ( style->fileName() == path )
430 if ( mStyleDatabases.contains( path ) )
434 mStyleDatabases.append( path );
435 loadStyleAtPath( path );
443 if ( paths == mStyleDatabases )
448 for (
const QString &path : paths )
451 mStyleDatabases.append( path );
452 loadStyleAtPath( path );
458void QgsProjectStyleSettings::loadStyleAtPath(
const QString &path )
462 const QFileInfo fileInfo( path );
463 if ( fileInfo.suffix().compare(
"xml"_L1, Qt::CaseInsensitive ) == 0 )
474 style->
setName( fileInfo.completeBaseName() );
475 mStyles.append( style );
476 mCombinedStyleModel->addStyle( style );
486void QgsProjectStyleSettings::clearStyles()
488 const QStringList pathsToRemove = mStyleDatabases;
489 for (
const QString &path : pathsToRemove )
492 mStyleDatabases.removeAll( path );
495 mCombinedStyleModel->removeStyle( style );
496 style->deleteLater();
497 mStyles.removeAll( style );
503 for ( QgsStyle *style : std::as_const( mStyles ) )
505 mCombinedStyleModel->removeStyle( style );
507 qDeleteAll( mStyles );
513 return mCombinedStyleModel;
525#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
545 QgsDebugError(
"Impossible to attach ICC profile, no project defined" );
549 auto clearIccProfile = [
this]()
551 mProject->removeAttachedFile( mIccProfileFilePath );
552 mIccProfileFilePath.clear();
553 mColorSpace = QColorSpace();
556 if ( !mIccProfileFilePath.isEmpty() )
559#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
562 mColorSpace = ok ?
colorSpace : QColorSpace();
569 if ( !mColorSpace.isValid() )
572#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
577 mIccProfileFilePath = mProject->createAttachedFile( u
"profile.icc"_s );
578 QFile file( mIccProfileFilePath );
579 if ( !file.open( QIODevice::WriteOnly ) || file.write(
colorSpace.iccProfile() ) < 0 )
588void QgsProjectStyleSettings::makeDirty()
599 : QAbstractListModel( parent )
600 , mSettings( settings )
607 if ( mSettings->projectStyle() )
608 setProjectStyle( mSettings->projectStyle() );
615 return ( mSettings ? mSettings->styleDatabasePaths().count() : 0 ) + ( mProjectStyle ? 1 : 0 ) + ( mShowDefault ? 1 : 0 );
620 if ( index.row() < 0 || index.row() >=
rowCount( QModelIndex() ) )
623 const bool isProjectStyle = index.row() == 0 && mProjectStyle;
624 const bool isDefault = mShowDefault && ( ( index.row() == 0 && !mProjectStyle ) || ( index.row() == 1 && mProjectStyle ) );
625 const int styleRow = index.row() - ( mShowDefault ? 1 : 0 ) - ( mProjectStyle ? 1 : 0 );
629 case Qt::DisplayRole:
633 else if ( isProjectStyle )
634 return mProjectStyle->name();
636 return mSettings ? mSettings->styles().at( styleRow )->name() : QVariant();
638 case Qt::ToolTipRole:
641 else if ( isProjectStyle )
642 return mProjectStyle->name();
644 return mSettings ? QDir::toNativeSeparators( mSettings->styles().at( styleRow )->fileName() ) : QVariant();
650 else if ( isProjectStyle )
651 return QVariant::fromValue( mProjectStyle.data() );
652 else if (
QgsStyle *style = mSettings->styles().value( styleRow ) )
653 return QVariant::fromValue( style );
661 else if ( isProjectStyle )
662 return mProjectStyle->fileName();
664 return mSettings ? mSettings->styles().at( styleRow )->fileName() : QVariant();
673 if ( index.row() == 0 && mProjectStyle )
674 return mProjectStyle;
675 else if ( mShowDefault && ( ( index.row() == 0 && !mProjectStyle ) || ( index.row() == 1 && mProjectStyle ) ) )
677 else if (
QgsStyle *style = qobject_cast< QgsStyle * >( qvariant_cast<QObject *>(
data( index,
static_cast< int >(
CustomRole::Style ) ) ) ) )
685 if ( style == mProjectStyle )
686 return index( 0, 0, QModelIndex() );
688 return index( mProjectStyle ? 1 : 0, 0, QModelIndex() );
692 return QModelIndex();
695 const int r = mSettings->styles().indexOf( style );
697 return QModelIndex();
699 QModelIndex idx = index( r + ( mShowDefault ? 1 : 0 ) + ( mProjectStyle ? 1 : 0 ), 0, QModelIndex() );
705 return QModelIndex();
710 if ( show == mShowDefault )
713 const int row = mProjectStyle ? 1 : 0;
716 beginInsertRows( QModelIndex(), row, row );
722 beginRemoveRows( QModelIndex(), row, row );
723 mShowDefault =
false;
728void QgsProjectStyleDatabaseModel::setProjectStyle(
QgsStyle *style )
730 if ( style == mProjectStyle )
736 disconnect( mProjectStyle, &QgsStyle::destroyed,
this, &QgsProjectStyleDatabaseModel::projectStyleDestroyed );
737 beginRemoveRows( QModelIndex(), 0, 0 );
738 mProjectStyle =
nullptr;
744 beginInsertRows( QModelIndex(), 0, 0 );
745 mProjectStyle = style;
749 connect( mProjectStyle, &QgsStyle::destroyed,
this, &QgsProjectStyleDatabaseModel::projectStyleDestroyed );
753void QgsProjectStyleDatabaseModel::styleDatabaseAboutToBeAdded(
const QString & )
755 int row = mSettings->styles().count() + ( mShowDefault ? 1 : 0 ) + ( mProjectStyle ? 1 : 0 );
756 beginInsertRows( QModelIndex(), row, row );
759void QgsProjectStyleDatabaseModel::styleDatabaseAboutToBeRemoved(
const QString &path )
761 QgsStyle *style = mSettings->styleAtPath( path );
762 int row = mSettings->styles().indexOf( style ) + ( mShowDefault ? 1 : 0 ) + ( mProjectStyle ? 1 : 0 );
764 beginRemoveRows( QModelIndex(), row, row );
767void QgsProjectStyleDatabaseModel::styleDatabaseAdded(
const QString & )
772void QgsProjectStyleDatabaseModel::styleDatabaseRemoved(
const QString & )
777void QgsProjectStyleDatabaseModel::projectStyleAboutToBeDestroyed()
779 beginRemoveRows( QModelIndex(), 0, 0 );
782void QgsProjectStyleDatabaseModel::projectStyleDestroyed()
787void QgsProjectStyleDatabaseModel::projectStyleChanged()
789 setProjectStyle( mSettings->projectStyle() );
797 : QSortFilterProxyModel( parent )
799 setSourceModel( model );
800 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)