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]() {
550 mProject->removeAttachedFile( mIccProfileFilePath );
551 mIccProfileFilePath.clear();
552 mColorSpace = QColorSpace();
555 if ( !mIccProfileFilePath.isEmpty() )
558#if QT_VERSION >= QT_VERSION_CHECK( 6, 8, 0 )
561 mColorSpace = ok ?
colorSpace : QColorSpace();
568 if ( !mColorSpace.isValid() )
571#if QT_VERSION >= QT_VERSION_CHECK( 6, 8, 0 )
576 mIccProfileFilePath = mProject->createAttachedFile( u
"profile.icc"_s );
577 QFile file( mIccProfileFilePath );
578 if ( !file.open( QIODevice::WriteOnly ) || file.write(
colorSpace.iccProfile() ) < 0 )
587void QgsProjectStyleSettings::makeDirty()
598 : QAbstractListModel( parent )
599 , mSettings( settings )
606 if ( mSettings->projectStyle() )
607 setProjectStyle( mSettings->projectStyle() );
614 return ( mSettings ? mSettings->styleDatabasePaths().count() : 0 ) + ( mProjectStyle ? 1 : 0 ) + ( mShowDefault ? 1 : 0 );
619 if ( index.row() < 0 || index.row() >=
rowCount( QModelIndex() ) )
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 );
628 case Qt::DisplayRole:
632 else if ( isProjectStyle )
633 return mProjectStyle->name();
635 return mSettings ? mSettings->styles().at( styleRow )->name() : QVariant();
637 case Qt::ToolTipRole:
640 else if ( isProjectStyle )
641 return mProjectStyle->name();
643 return mSettings ? QDir::toNativeSeparators( mSettings->styles().at( styleRow )->fileName() ) : QVariant();
649 else if ( isProjectStyle )
650 return QVariant::fromValue( mProjectStyle.data() );
651 else if (
QgsStyle *style = mSettings->styles().value( styleRow ) )
652 return QVariant::fromValue( style );
660 else if ( isProjectStyle )
661 return mProjectStyle->fileName();
663 return mSettings ? mSettings->styles().at( styleRow )->fileName() : QVariant();
672 if ( index.row() == 0 && mProjectStyle )
673 return mProjectStyle;
674 else if ( mShowDefault && ( ( index.row() == 0 && !mProjectStyle ) || ( index.row() == 1 && mProjectStyle ) ) )
676 else if (
QgsStyle *style = qobject_cast< QgsStyle * >( qvariant_cast<QObject *>(
data( index,
static_cast< int >(
CustomRole::Style ) ) ) ) )
684 if ( style == mProjectStyle )
685 return index( 0, 0, QModelIndex() );
687 return index( mProjectStyle ? 1 : 0, 0, QModelIndex() );
691 return QModelIndex();
694 const int r = mSettings->styles().indexOf( style );
696 return QModelIndex();
698 QModelIndex idx = index( r + ( mShowDefault ? 1 : 0 ) + ( mProjectStyle ? 1 : 0 ), 0, QModelIndex() );
704 return QModelIndex();
709 if ( show == mShowDefault )
712 const int row = mProjectStyle ? 1 : 0;
715 beginInsertRows( QModelIndex(), row, row );
721 beginRemoveRows( QModelIndex(), row, row );
722 mShowDefault =
false;
727void QgsProjectStyleDatabaseModel::setProjectStyle(
QgsStyle *style )
729 if ( style == mProjectStyle )
735 disconnect( mProjectStyle, &QgsStyle::destroyed,
this, &QgsProjectStyleDatabaseModel::projectStyleDestroyed );
736 beginRemoveRows( QModelIndex(), 0, 0 );
737 mProjectStyle =
nullptr;
743 beginInsertRows( QModelIndex(), 0, 0 );
744 mProjectStyle = style;
748 connect( mProjectStyle, &QgsStyle::destroyed,
this, &QgsProjectStyleDatabaseModel::projectStyleDestroyed );
752void QgsProjectStyleDatabaseModel::styleDatabaseAboutToBeAdded(
const QString & )
754 int row = mSettings->styles().count() + ( mShowDefault ? 1 : 0 ) + ( mProjectStyle ? 1 : 0 );
755 beginInsertRows( QModelIndex(), row, row );
758void QgsProjectStyleDatabaseModel::styleDatabaseAboutToBeRemoved(
const QString &path )
760 QgsStyle *style = mSettings->styleAtPath( path );
761 int row = mSettings->styles().indexOf( style ) + ( mShowDefault ? 1 : 0 ) + ( mProjectStyle ? 1 : 0 );
763 beginRemoveRows( QModelIndex(), row, row );
766void QgsProjectStyleDatabaseModel::styleDatabaseAdded(
const QString & )
771void QgsProjectStyleDatabaseModel::styleDatabaseRemoved(
const QString & )
776void QgsProjectStyleDatabaseModel::projectStyleAboutToBeDestroyed()
778 beginRemoveRows( QModelIndex(), 0, 0 );
781void QgsProjectStyleDatabaseModel::projectStyleDestroyed()
786void QgsProjectStyleDatabaseModel::projectStyleChanged()
788 setProjectStyle( mSettings->projectStyle() );
796 : QSortFilterProxyModel( parent )
798 setSourceModel( model );
799 setDynamicSortFilter(
true );
806 if (
const QgsStyle *style = qobject_cast< QgsStyle * >(
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)