18#include "moc_qgsprojectstylesettings.cpp"
45 mProjectStyle->deleteLater();
46 mProjectStyle =
nullptr;
55 return mDefaultMarkerSymbol ? mDefaultMarkerSymbol->clone() :
nullptr;
58 return mDefaultLineSymbol ? mDefaultLineSymbol->clone() :
nullptr;
61 return mDefaultFillSymbol ? mDefaultFillSymbol->clone() :
nullptr;
75 if ( mDefaultMarkerSymbol.get() == symbol )
78 mDefaultMarkerSymbol.reset( symbol ? symbol->
clone() : nullptr );
84 if ( mDefaultLineSymbol.get() == symbol )
87 mDefaultLineSymbol.reset( symbol ? symbol->
clone() : nullptr );
93 if ( mDefaultFillSymbol.get() == symbol )
96 mDefaultFillSymbol.reset( symbol ? symbol->
clone() : nullptr );
108 return mDefaultColorRamp ? mDefaultColorRamp->clone() :
nullptr;
113 if ( mDefaultColorRamp.get() == colorRamp )
116 mDefaultColorRamp.reset( colorRamp ? colorRamp->
clone() : nullptr );
123 return mDefaultTextFormat;
128 if ( mDefaultTextFormat == textFormat )
131 mDefaultTextFormat = textFormat;
141 mDefaultSymbolOpacity = opacity;
148 if ( mRandomizeDefaultSymbolColor == randomized )
151 mRandomizeDefaultSymbolColor = randomized;
158 mDefaultMarkerSymbol.reset();
159 mDefaultLineSymbol.reset();
160 mDefaultFillSymbol.reset();
161 mDefaultColorRamp.reset();
163 mRandomizeDefaultSymbolColor =
true;
164 mDefaultSymbolOpacity = 1.0;
170 const QString stylePath = mProject->
createAttachedFile( QStringLiteral(
"styles.db" ) );
173 style->
setName( tr(
"Project Style" ) );
186 delete mProjectStyle;
187 mProjectStyle =
nullptr;
196 mProjectStyle->deleteLater();
198 mProjectStyle = style;
199 mProjectStyle->
setName( tr(
"Project Styles" ) );
207 mCombinedStyleModel->
addStyle( mProjectStyle );
214 return mProjectStyle;
219 mRandomizeDefaultSymbolColor = element.attribute( QStringLiteral(
"RandomizeDefaultSymbolColor" ), QStringLiteral(
"0" ) ).toInt();
220 mDefaultSymbolOpacity = element.attribute( QStringLiteral(
"DefaultSymbolOpacity" ), QStringLiteral(
"1.0" ) ).toDouble();
223 QDomElement elem = element.firstChildElement( QStringLiteral(
"markerSymbol" ) );
224 if ( !elem.isNull() )
226 QDomElement symbolElem = elem.firstChildElement( QStringLiteral(
"symbol" ) );
227 mDefaultMarkerSymbol.reset( !symbolElem.isNull() ? QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( symbolElem, context ) : nullptr );
231 mDefaultMarkerSymbol.reset();
234 elem = element.firstChildElement( QStringLiteral(
"lineSymbol" ) );
235 if ( !elem.isNull() )
237 QDomElement symbolElem = elem.firstChildElement( QStringLiteral(
"symbol" ) );
238 mDefaultLineSymbol.reset( !symbolElem.isNull() ? QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( symbolElem, context ) : nullptr );
242 mDefaultLineSymbol.reset();
245 elem = element.firstChildElement( QStringLiteral(
"fillSymbol" ) );
246 if ( !elem.isNull() )
248 QDomElement symbolElem = elem.firstChildElement( QStringLiteral(
"symbol" ) );
249 mDefaultFillSymbol.reset( !symbolElem.isNull() ? QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElem, context ) : nullptr );
253 mDefaultFillSymbol.reset();
256 elem = element.firstChildElement( QStringLiteral(
"colorramp" ) );
259 elem = element.firstChildElement( QStringLiteral(
"text-style" ) );
260 if ( !elem.isNull() )
262 mDefaultTextFormat.
readXml( elem, context );
273 const QDomElement styleDatabases = element.firstChildElement( QStringLiteral(
"databases" ) );
274 if ( !styleDatabases.isNull() )
276 const QDomNodeList styleEntries = styleDatabases.childNodes();
277 for (
int i = 0; i < styleEntries.count(); ++i )
279 const QDomElement styleElement = styleEntries.at( i ).toElement();
280 const QString path = styleElement.attribute( QStringLiteral(
"path" ) );
283 mStyleDatabases.append( fullPath );
284 loadStyleAtPath( fullPath );
291 const QString projectStyleId = element.attribute( QStringLiteral(
"projectStyleId" ) );
294 if ( !projectStyleFile.isEmpty() && QFile::exists( projectStyleFile ) )
296 style->
load( projectStyleFile );
301 const QString stylePath = mProject->
createAttachedFile( QStringLiteral(
"styles.db" ) );
305 style->
setName( tr(
"Project Style" ) );
311 const QString iccProfileId = element.attribute( QStringLiteral(
"iccProfileId" ) );
313 if ( !mIccProfileFilePath.isEmpty() )
317 if ( !errorMsg.isEmpty() )
330 QDomElement element = doc.createElement( QStringLiteral(
"ProjectStyleSettings" ) );
332 element.setAttribute( QStringLiteral(
"RandomizeDefaultSymbolColor" ), mRandomizeDefaultSymbolColor ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
333 element.setAttribute( QStringLiteral(
"DefaultSymbolOpacity" ), QString::number( mDefaultSymbolOpacity ) );
335 element.setAttribute( QStringLiteral(
"colorModel" ),
qgsEnumValueToKey( mColorModel ) );
337 if ( mDefaultMarkerSymbol )
339 QDomElement markerSymbolElem = doc.createElement( QStringLiteral(
"markerSymbol" ) );
341 element.appendChild( markerSymbolElem );
344 if ( mDefaultLineSymbol )
346 QDomElement lineSymbolElem = doc.createElement( QStringLiteral(
"lineSymbol" ) );
348 element.appendChild( lineSymbolElem );
351 if ( mDefaultFillSymbol )
353 QDomElement fillSymbolElem = doc.createElement( QStringLiteral(
"fillSymbol" ) );
355 element.appendChild( fillSymbolElem );
358 if ( mDefaultColorRamp )
361 element.appendChild( colorRampElem );
364 if ( mDefaultTextFormat.
isValid() )
366 QDomElement textFormatElem = mDefaultTextFormat.
writeXml( doc, context );
367 element.appendChild( textFormatElem );
371 QDomElement styleDatabases = doc.createElement( QStringLiteral(
"databases" ) );
372 for (
const QString &db : mStyleDatabases )
374 QDomElement dbElement = doc.createElement( QStringLiteral(
"db" ) );
376 styleDatabases.appendChild( dbElement );
378 element.appendChild( styleDatabases );
381 if ( mProject && mProjectStyle )
388 element.setAttribute( QStringLiteral(
"iccProfileId" ), mProject->
attachmentIdentifier( mIccProfileFilePath ) );
396 QList< QgsStyle * > res;
397 res.reserve( mStyles.size() );
411 if ( mProjectStyle && path == mProjectStyle->
fileName() )
412 return mProjectStyle;
414 for (
QgsStyle *style : std::as_const( mStyles ) )
416 if ( style->fileName() == path )
425 if ( mStyleDatabases.contains( path ) )
429 mStyleDatabases.append( path );
430 loadStyleAtPath( path );
438 if ( paths == mStyleDatabases )
443 for (
const QString &path : paths )
446 mStyleDatabases.append( path );
447 loadStyleAtPath( path );
453void QgsProjectStyleSettings::loadStyleAtPath(
const QString &path )
457 const QFileInfo fileInfo( path );
458 if ( fileInfo.suffix().compare( QLatin1String(
"xml" ), Qt::CaseInsensitive ) == 0 )
469 style->
setName( fileInfo.completeBaseName() );
470 mStyles.append( style );
471 mCombinedStyleModel->
addStyle( style );
481void QgsProjectStyleSettings::clearStyles()
483 const QStringList pathsToRemove = mStyleDatabases;
484 for (
const QString &path : pathsToRemove )
487 mStyleDatabases.removeAll( path );
491 style->deleteLater();
492 mStyles.removeAll( style );
498 for (
QgsStyle *style : std::as_const( mStyles ) )
502 qDeleteAll( mStyles );
508 return mCombinedStyleModel;
520#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
540 QgsDebugError(
"Impossible to attach ICC profile, no project defined" );
544 auto clearIccProfile = [
this]()
547 mIccProfileFilePath.clear();
548 mColorSpace = QColorSpace();
551 if ( !mIccProfileFilePath.isEmpty() )
554#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
557 mColorSpace = ok ?
colorSpace : QColorSpace();
564 if ( !mColorSpace.isValid() )
567#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
572 mIccProfileFilePath = mProject->
createAttachedFile( QStringLiteral(
"profile.icc" ) );
573 QFile file( mIccProfileFilePath );
574 if ( !file.open( QIODevice::WriteOnly ) || file.write(
colorSpace.iccProfile() ) < 0 )
583void QgsProjectStyleSettings::makeDirty()
594 : QAbstractListModel( parent )
595 , mSettings( settings )
610 return ( mSettings ? mSettings->
styleDatabasePaths().count() : 0 ) + ( mProjectStyle ? 1 : 0 ) + ( mShowDefault ? 1 : 0 );
615 if ( index.row() < 0 || index.row() >=
rowCount( QModelIndex() ) )
618 const bool isProjectStyle = index.row() == 0 && mProjectStyle;
619 const bool isDefault = mShowDefault && ( ( index.row() == 0 && !mProjectStyle ) || ( index.row() == 1 && mProjectStyle ) );
620 const int styleRow = index.row() - ( mShowDefault ? 1 : 0 ) - ( mProjectStyle ? 1 : 0 );
624 case Qt::DisplayRole:
628 else if ( isProjectStyle )
629 return mProjectStyle->name();
631 return mSettings ? mSettings->
styles().at( styleRow )->name() : QVariant();
633 case Qt::ToolTipRole:
636 else if ( isProjectStyle )
637 return mProjectStyle->name();
639 return mSettings ? QDir::toNativeSeparators( mSettings->
styles().at( styleRow )->fileName() ) : QVariant();
645 else if ( isProjectStyle )
646 return QVariant::fromValue( mProjectStyle.data() );
647 else if (
QgsStyle *style = mSettings->
styles().value( styleRow ) )
648 return QVariant::fromValue( style );
656 else if ( isProjectStyle )
657 return mProjectStyle->fileName();
659 return mSettings ? mSettings->
styles().at( styleRow )->fileName() : QVariant();
668 if ( index.row() == 0 && mProjectStyle )
669 return mProjectStyle;
670 else if ( mShowDefault && ( ( index.row() == 0 && !mProjectStyle ) || ( index.row() == 1 && mProjectStyle ) ) )
672 else if (
QgsStyle *style = qobject_cast< QgsStyle * >( qvariant_cast<QObject *>(
data( index,
static_cast< int >(
CustomRole::Style ) ) ) ) )
680 if ( style == mProjectStyle )
681 return index( 0, 0, QModelIndex() );
683 return index( mProjectStyle ? 1 : 0, 0, QModelIndex() );
687 return QModelIndex();
690 const int r = mSettings->
styles().indexOf( style );
692 return QModelIndex();
694 QModelIndex idx = index( r + ( mShowDefault ? 1 : 0 ) + ( mProjectStyle ? 1 : 0 ), 0, QModelIndex() );
700 return QModelIndex();
705 if ( show == mShowDefault )
708 const int row = mProjectStyle ? 1 : 0;
711 beginInsertRows( QModelIndex(), row, row );
717 beginRemoveRows( QModelIndex(), row, row );
718 mShowDefault =
false;
723void QgsProjectStyleDatabaseModel::setProjectStyle(
QgsStyle *style )
725 if ( style == mProjectStyle )
731 disconnect( mProjectStyle, &QgsStyle::destroyed,
this, &QgsProjectStyleDatabaseModel::projectStyleDestroyed );
732 beginRemoveRows( QModelIndex(), 0, 0 );
733 mProjectStyle =
nullptr;
739 beginInsertRows( QModelIndex(), 0, 0 );
740 mProjectStyle = style;
744 connect( mProjectStyle, &QgsStyle::destroyed,
this, &QgsProjectStyleDatabaseModel::projectStyleDestroyed );
748void QgsProjectStyleDatabaseModel::styleDatabaseAboutToBeAdded(
const QString & )
750 int row = mSettings->
styles().count() + ( mShowDefault ? 1 : 0 ) + ( mProjectStyle ? 1 : 0 );
751 beginInsertRows( QModelIndex(), row, row );
754void QgsProjectStyleDatabaseModel::styleDatabaseAboutToBeRemoved(
const QString &path )
757 int row = mSettings->
styles().indexOf( style ) + ( mShowDefault ? 1 : 0 ) + ( mProjectStyle ? 1 : 0 );
759 beginRemoveRows( QModelIndex(), row, row );
762void QgsProjectStyleDatabaseModel::styleDatabaseAdded(
const QString & )
767void QgsProjectStyleDatabaseModel::styleDatabaseRemoved(
const QString & )
772void QgsProjectStyleDatabaseModel::projectStyleAboutToBeDestroyed()
774 beginRemoveRows( QModelIndex(), 0, 0 );
777void QgsProjectStyleDatabaseModel::projectStyleDestroyed()
782void QgsProjectStyleDatabaseModel::projectStyleChanged()
792 : QSortFilterProxyModel( parent )
794 setSourceModel( model );
795 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.
void removeStyle(QgsStyle *style)
Removes a style from the model.
void addStyle(QgsStyle *style)
Adds a style to the model.
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
List model representing the style databases associated with a QgsProject.
QVariant data(const QModelIndex &index, int role) const override
void setShowDefaultStyle(bool show)
Sets whether the default style should also be included in the model.
QModelIndex indexFromStyle(QgsStyle *style) const
Returns the model index corresponding to a style.
QgsProjectStyleDatabaseModel(QgsProjectStyleSettings *settings, QObject *parent=nullptr)
Constructor for QgsProjectStyleDatabaseModel, showing the styles from the specified settings.
QgsStyle * styleFromIndex(const QModelIndex &index) const
Returns the style at the corresponding index.
int rowCount(const QModelIndex &parent) const override
@ FilterHideReadOnly
Hide read-only style databases.
QgsProjectStyleDatabaseProxyModel::Filters filters() const
Returns the current filters used for filtering available style.
QFlags< Filter > Filters
Available filter flags for filtering the model.
void setFilters(QgsProjectStyleDatabaseProxyModel::Filters filters)
Sets the current filters used for filtering available styles.
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
QgsProjectStyleDatabaseProxyModel(QgsProjectStyleDatabaseModel *model, QObject *parent=nullptr)
Constructor for QgsProjectStyleDatabaseProxyModel, for the specified style database model.
Contains settings and properties relating to how a QgsProject should handle styling.
QColorSpace colorSpace() const
Returns the project's color space.
void setDefaultTextFormat(const QgsTextFormat &textFormat)
Sets the project default text format.
QList< QgsStyle * > styles() const
Returns a list of all the styles associated with the project.
void setStyleDatabasePaths(const QStringList &paths)
Sets the paths to all style databases associated with the project.
QgsStyle * styleAtPath(const QString &path)
Returns a reference to the style database associated with the project with matching file path.
QgsTextFormat defaultTextFormat() const
Returns the project default text format.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Returns a DOM element representing the settings.
~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.
QStringList styleDatabasePaths() const
Returns a list of all style databases (file paths) associated with the project.
void reset()
Resets the settings to a default state.
QgsProjectStyleSettings(QgsProject *project=nullptr)
Constructor for QgsProjectStyleSettings for the specified project.
void styleDatabaseAdded(const QString &path)
Emitted when a style database path is added.
void styleDatabaseAboutToBeRemoved(const QString &path)
Emitted when a style database path is about to be removed.
void removeProjectStyle()
Removes and deletes the project style database.
void setRandomizeDefaultSymbolColor(bool randomized)
Sets whether the default symbol fill color is randomized.
void setColorModel(Qgis::ColorModel colorModel)
Set the project's color model to colorModel.
void setColorSpace(const QColorSpace &colorSpace)
Set the project's current color space to colorSpace.
void setDefaultColorRamp(QgsColorRamp *colorRamp)
Sets the project default color ramp.
void addStyleDatabasePath(const QString &path)
Adds a style database path to the project.
void styleDatabaseRemoved(const QString &path)
Emitted when a style database path is removed.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context, Qgis::ProjectReadFlags flags=Qgis::ProjectReadFlags())
Reads the settings's state from a DOM element.
QgsStyle * projectStyle()
Returns the style database to use for project specific styles.
QgsCombinedStyleModel * combinedStyleModel()
Returns the combined style model which includes all style databases associated with the project.
void setDefaultSymbolOpacity(double opacity)
Sets the default symbol opacity.
void styleDatabaseAboutToBeAdded(const QString &path)
Emitted when a style database path is about to be added.
void styleDatabasesChanged()
Emitted whenever the set of style databases associated with the project is changed.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
bool removeAttachedFile(const QString &path)
Removes the attached file.
QString createAttachedFile(const QString &nameTemplate)
Attaches a file to the project.
QString attachmentIdentifier(const QString &attachedFile) const
Returns an identifier for an attachment file path An attachment identifier is a string which does not...
QString resolveAttachmentIdentifier(const QString &identifier) const
Resolves an attachment identifier to a attachment file path.
void projectColorsChanged()
Emitted whenever the project's color scheme has been changed.
Qgis::ProjectCapabilities capabilities() const
Returns the project's capabilities, which dictate optional functionality which can be selectively ena...
void setDirty(bool b=true)
Flag the project as dirty (modified).
The class is used as a container of context for various read/write operations on other objects.
void pushMessage(const QString &message, Qgis::MessageLevel level=Qgis::MessageLevel::Warning) const
Append a message to the context.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
void setFileName(const QString &filename)
Sets the current file name of the style database.
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 QgsColorRamp * loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
static QDomElement saveColorRamp(const QString &name, QgsColorRamp *ramp, QDomDocument &doc)
Encodes a color ramp's settings to an XML element.
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
Abstract base class for all rendered symbols.
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
Container for all settings relating to text rendering.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Read settings from a DOM element.
bool isValid() const
Returns true if the format is valid.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
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)