Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsmaplayerstylemanager.cpp 3 : : -------------------------------------- 4 : : Date : January 2015 5 : : Copyright : (C) 2015 by Martin Dobias 6 : : Email : wonder dot sk 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 : : 16 : : #include "qgsmaplayerstylemanager.h" 17 : : #include "qgsmaplayerstyle.h" 18 : : #include "qgsmaplayer.h" 19 : : 20 : : #include "qgslogger.h" 21 : : 22 : : #include <QDomElement> 23 : : #include <QTextStream> 24 : : 25 : 83 : QgsMapLayerStyleManager::QgsMapLayerStyleManager( QgsMapLayer *layer ) 26 : 83 : : mLayer( layer ) 27 : : 28 : 166 : { 29 : 83 : reset(); 30 : 83 : } 31 : : 32 : 166 : QString QgsMapLayerStyleManager::defaultStyleName() const 33 : : { 34 : 166 : return tr( "default" ); 35 : : } 36 : : 37 : : 38 : 83 : void QgsMapLayerStyleManager::reset() 39 : : { 40 : 83 : mStyles.insert( defaultStyleName(), QgsMapLayerStyle() ); // insert entry for the default current style 41 : 83 : mCurrentStyle = defaultStyleName(); 42 : 83 : } 43 : : 44 : 0 : void QgsMapLayerStyleManager::readXml( const QDomElement &mgrElement ) 45 : : { 46 : 0 : mCurrentStyle = mgrElement.attribute( QStringLiteral( "current" ) ); 47 : 0 : if ( mCurrentStyle.isEmpty() ) 48 : : { 49 : : // For old project made with QGIS 2, we migrate to "default". 50 : 0 : mCurrentStyle = defaultStyleName(); 51 : 0 : } 52 : : 53 : 0 : mStyles.clear(); 54 : 0 : QDomElement ch = mgrElement.firstChildElement( QStringLiteral( "map-layer-style" ) ); 55 : 0 : while ( !ch.isNull() ) 56 : : { 57 : 0 : QString name = ch.attribute( QStringLiteral( "name" ) ); 58 : 0 : if ( name.isEmpty() ) 59 : : { 60 : : // For old project made with QGIS 2, we migrate to "default". 61 : 0 : name = defaultStyleName(); 62 : 0 : } 63 : 0 : QgsMapLayerStyle style; 64 : 0 : style.readXml( ch ); 65 : 0 : mStyles.insert( name, style ); 66 : : 67 : 0 : ch = ch.nextSiblingElement( QStringLiteral( "map-layer-style" ) ); 68 : 0 : } 69 : 0 : } 70 : : 71 : 0 : void QgsMapLayerStyleManager::writeXml( QDomElement &mgrElement ) const 72 : : { 73 : 0 : QDomDocument doc = mgrElement.ownerDocument(); 74 : 0 : mgrElement.setAttribute( QStringLiteral( "current" ), mCurrentStyle ); 75 : : 76 : 0 : const auto constStyles = styles(); 77 : 0 : for ( const QString &name : constStyles ) 78 : : { 79 : 0 : QDomElement ch = doc.createElement( QStringLiteral( "map-layer-style" ) ); 80 : 0 : ch.setAttribute( QStringLiteral( "name" ), name ); 81 : 0 : mStyles[name].writeXml( ch ); 82 : 0 : mgrElement.appendChild( ch ); 83 : 0 : } 84 : 0 : } 85 : : 86 : 0 : QStringList QgsMapLayerStyleManager::styles() const 87 : : { 88 : 0 : return mStyles.keys(); 89 : : } 90 : : 91 : 0 : QMap<QString, QgsMapLayerStyle> QgsMapLayerStyleManager::mapLayerStyles() const 92 : : { 93 : 0 : return mStyles; 94 : : } 95 : : 96 : 0 : QgsMapLayerStyle QgsMapLayerStyleManager::style( const QString &name ) const 97 : : { 98 : 0 : if ( name == mCurrentStyle ) 99 : : { 100 : : // current style's entry is always kept invalid - get the style data from layer's properties 101 : 0 : QgsMapLayerStyle curr; 102 : 0 : curr.readFromLayer( mLayer ); 103 : 0 : return curr; 104 : 0 : } 105 : : 106 : 0 : return mStyles.value( name ); 107 : 0 : } 108 : : 109 : 0 : bool QgsMapLayerStyleManager::addStyle( const QString &name, const QgsMapLayerStyle &style ) 110 : : { 111 : 0 : if ( mStyles.contains( name ) ) 112 : 0 : return false; 113 : 0 : if ( !style.isValid() ) 114 : 0 : return false; 115 : : 116 : 0 : mStyles.insert( name, style ); 117 : 0 : emit styleAdded( name ); 118 : 0 : return true; 119 : 0 : } 120 : : 121 : 0 : bool QgsMapLayerStyleManager::addStyleFromLayer( const QString &name ) 122 : : { 123 : 0 : QgsMapLayerStyle style; 124 : 0 : style.readFromLayer( mLayer ); 125 : 0 : return addStyle( name, style ); 126 : 0 : } 127 : : 128 : 0 : bool QgsMapLayerStyleManager::removeStyle( const QString &name ) 129 : : { 130 : 0 : if ( !mStyles.contains( name ) ) 131 : 0 : return false; 132 : 0 : if ( mStyles.count() == 1 ) 133 : 0 : return false; // cannot remove the last one 134 : : 135 : : // change to a different style if this one is the current 136 : 0 : if ( mCurrentStyle == name ) 137 : : { 138 : 0 : QStringList keys = mStyles.keys(); 139 : 0 : QString newCurrent = keys[0]; 140 : 0 : if ( newCurrent == name ) 141 : 0 : newCurrent = keys[1]; // there must be at least one more 142 : 0 : setCurrentStyle( newCurrent ); 143 : 0 : } 144 : : 145 : 0 : mStyles.remove( name ); 146 : 0 : emit styleRemoved( name ); 147 : 0 : return true; 148 : 0 : } 149 : : 150 : 0 : bool QgsMapLayerStyleManager::renameStyle( const QString &name, const QString &newName ) 151 : : { 152 : 0 : if ( !mStyles.contains( name ) || mStyles.contains( newName ) ) 153 : 0 : return false; 154 : : 155 : 0 : if ( name == mCurrentStyle ) 156 : 0 : mCurrentStyle = newName; 157 : : 158 : 0 : mStyles[newName] = mStyles[name]; 159 : 0 : mStyles.remove( name ); 160 : 0 : emit styleRenamed( name, newName ); 161 : 0 : return true; 162 : 0 : } 163 : 83 : 164 : 0 : QString QgsMapLayerStyleManager::currentStyle() const 165 : : { 166 : 0 : return mCurrentStyle; 167 : : } 168 : : 169 : 0 : bool QgsMapLayerStyleManager::setCurrentStyle( const QString &name ) 170 : : { 171 : 0 : if ( !mStyles.contains( name ) ) 172 : 0 : return false; 173 : : 174 : 0 : if ( mCurrentStyle == name ) 175 : 0 : return true; // nothing to do 176 : : 177 : 0 : mStyles[mCurrentStyle].readFromLayer( mLayer ); // sync before unloading it 178 : 0 : mCurrentStyle = name; 179 : 0 : mStyles[mCurrentStyle].writeToLayer( mLayer ); 180 : 0 : mStyles[mCurrentStyle].clear(); // current style does not keep any stored data 181 : 0 : emit currentStyleChanged( mCurrentStyle ); 182 : : 183 : 0 : mLayer->triggerRepaint(); 184 : 0 : return true; 185 : 0 : } 186 : : 187 : 0 : bool QgsMapLayerStyleManager::setOverrideStyle( const QString &styleDef ) 188 : : { 189 : 0 : if ( mOverriddenOriginalStyle ) 190 : 0 : return false; // cannot override the style more than once! 191 : : 192 : 0 : mLayer->blockSignals( true ); 193 : 0 : if ( mStyles.contains( styleDef ) ) 194 : : { 195 : 0 : mOverriddenOriginalStyle = new QgsMapLayerStyle; 196 : 0 : mOverriddenOriginalStyle->readFromLayer( mLayer ); 197 : : 198 : : // apply style name 199 : 0 : mStyles[styleDef].writeToLayer( mLayer ); 200 : 0 : } 201 : 0 : else if ( styleDef.startsWith( '<' ) ) 202 : : { 203 : 0 : mOverriddenOriginalStyle = new QgsMapLayerStyle; 204 : 0 : mOverriddenOriginalStyle->readFromLayer( mLayer ); 205 : : 206 : : // apply style XML 207 : 0 : QgsMapLayerStyle overrideStyle( styleDef ); 208 : 0 : overrideStyle.writeToLayer( mLayer ); 209 : 0 : } 210 : 0 : mLayer->blockSignals( false ); 211 : : 212 : 0 : return true; 213 : 0 : } 214 : : 215 : 0 : bool QgsMapLayerStyleManager::restoreOverrideStyle() 216 : : { 217 : 0 : if ( !mOverriddenOriginalStyle ) 218 : 0 : return false; 219 : : 220 : 0 : mLayer->blockSignals( true ); 221 : 0 : mOverriddenOriginalStyle->writeToLayer( mLayer ); 222 : 0 : mLayer->blockSignals( false ); 223 : : 224 : 0 : delete mOverriddenOriginalStyle; 225 : 0 : mOverriddenOriginalStyle = nullptr; 226 : 0 : return true; 227 : 0 : } 228 : : 229 : 0 : bool QgsMapLayerStyleManager::isDefault( const QString &styleName ) const 230 : : { 231 : 0 : return styleName == defaultStyleName(); 232 : : } 233 : : 234 : 0 : void QgsMapLayerStyleManager::copyStylesFrom( QgsMapLayerStyleManager *other ) 235 : : { 236 : 0 : const QStringList styleNames = other->mStyles.keys(); 237 : : 238 : 0 : for ( const QString &styleName : styleNames ) 239 : : { 240 : 0 : mStyles.remove( styleName ); 241 : 0 : addStyle( styleName, other->style( styleName ) ); 242 : : } 243 : 0 : }