~ubuntu-branches/ubuntu/wily/qgis/wily

« back to all changes in this revision

Viewing changes to src/core/qgsmaplayer.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Johan Van de Wauw
  • Date: 2010-07-11 20:23:24 UTC
  • mfrom: (3.1.4 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100711202324-5ktghxa7hracohmr
Tags: 1.4.0+12730-3ubuntu1
* Merge from Debian unstable (LP: #540941).
* Fix compilation issues with QT 4.7
* Add build-depends on libqt4-webkit-dev 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
                          qgsmaplayer.cpp  -  description
 
3
                             -------------------
 
4
    begin                : Fri Jun 28 2002
 
5
    copyright            : (C) 2002 by Gary E.Sherman
 
6
    email                : sherman at mrcc.com
 
7
***************************************************************************/
 
8
 
 
9
/***************************************************************************
 
10
 *                                                                         *
 
11
 *   This program is free software; you can redistribute it and/or modify  *
 
12
 *   it under the terms of the GNU General Public License as published by  *
 
13
 *   the Free Software Foundation; either version 2 of the License, or     *
 
14
 *   (at your option) any later version.                                   *
 
15
 *                                                                         *
 
16
 ***************************************************************************/
 
17
/* $Id$ */
 
18
 
 
19
 
 
20
#include <QDateTime>
 
21
#include <QDomNode>
 
22
#include <QFileInfo>
 
23
#include <QSettings> // TODO: get rid of it [MD]
 
24
#include <QDir>
 
25
#include <QFile>
 
26
#include <QFileInfo>
 
27
#include <QDomDocument>
 
28
#include <QDomElement>
 
29
#include <QDomImplementation>
 
30
#include <QTextStream>
 
31
 
 
32
#include <sqlite3.h>
 
33
 
 
34
#include "qgslogger.h"
 
35
#include "qgsrectangle.h"
 
36
#include "qgssymbol.h"
 
37
#include "qgsmaplayer.h"
 
38
#include "qgscoordinatereferencesystem.h"
 
39
#include "qgsapplication.h"
 
40
#include "qgsproject.h"
 
41
#include "qgslogger.h"
 
42
#include "qgsdatasourceuri.h"
 
43
#include "qgsvectorlayer.h"
 
44
 
 
45
QgsMapLayer::QgsMapLayer( QgsMapLayer::LayerType type,
 
46
                          QString lyrname,
 
47
                          QString source ) :
 
48
    mTransparencyLevel( 255 ), // 0 is completely transparent
 
49
    mValid( FALSE ), // assume the layer is invalid
 
50
    mDataSource( source ),
 
51
    mID( "" ),
 
52
    mLayerType( type )
 
53
 
 
54
{
 
55
  QgsDebugMsg( "lyrname is '" + lyrname + "'" );
 
56
 
 
57
  mCRS = new QgsCoordinateReferenceSystem();
 
58
 
 
59
  // Set the display name = internal name
 
60
  mLayerName = capitaliseLayerName( lyrname );
 
61
  QgsDebugMsg( "layerName is '" + mLayerName + "'" );
 
62
 
 
63
  // Generate the unique ID of this layer
 
64
  QDateTime dt = QDateTime::currentDateTime();
 
65
  mID = lyrname + dt.toString( "yyyyMMddhhmmsszzz" );
 
66
  // Tidy the ID up to avoid characters that may cause problems
 
67
  // elsewhere (e.g in some parts of XML). Replaces every non-word
 
68
  // character (word characters are the alphabet, numbers and
 
69
  // underscore) with an underscore.
 
70
  // Note that the first backslashe in the regular expression is
 
71
  // there for the compiler, so the pattern is actually \W
 
72
  mID.replace( QRegExp( "[\\W]" ), "_" );
 
73
 
 
74
  //set some generous  defaults for scale based visibility
 
75
  mMinScale = 0;
 
76
  mMaxScale = 100000000;
 
77
  mScaleBasedVisibility = false;
 
78
  mpCacheImage = 0;
 
79
}
 
80
 
 
81
 
 
82
 
 
83
QgsMapLayer::~QgsMapLayer()
 
84
{
 
85
  delete mCRS;
 
86
  if ( mpCacheImage )
 
87
  {
 
88
    delete mpCacheImage;
 
89
  }
 
90
}
 
91
 
 
92
QgsMapLayer::LayerType QgsMapLayer::type() const
 
93
{
 
94
  return mLayerType;
 
95
}
 
96
 
 
97
/** Get this layer's unique ID */
 
98
QString QgsMapLayer::getLayerID() const
 
99
{
 
100
  return mID;
 
101
}
 
102
 
 
103
/** Write property of QString layerName. */
 
104
void QgsMapLayer::setLayerName( const QString & _newVal )
 
105
{
 
106
  QgsDebugMsg( "new name is '" + _newVal + "'" );
 
107
  mLayerName = capitaliseLayerName( _newVal );
 
108
  emit layerNameChanged();
 
109
}
 
110
 
 
111
/** Read property of QString layerName. */
 
112
QString const & QgsMapLayer::name() const
 
113
{
 
114
  QgsDebugMsgLevel( "returning name '" + mLayerName + "'", 3 );
 
115
  return mLayerName;
 
116
}
 
117
 
 
118
QString QgsMapLayer::publicSource() const
 
119
{
 
120
  // Redo this every time we're asked for it, as we don't know if
 
121
  // dataSource has changed.
 
122
  QString safeName = QgsDataSourceURI::removePassword( mDataSource );
 
123
  return safeName;
 
124
}
 
125
 
 
126
QString const & QgsMapLayer::source() const
 
127
{
 
128
  return mDataSource;
 
129
}
 
130
 
 
131
QgsRectangle QgsMapLayer::extent() const
 
132
{
 
133
  return mLayerExtent;
 
134
}
 
135
 
 
136
bool QgsMapLayer::draw( QgsRenderContext& rendererContext )
 
137
{
 
138
  return false;
 
139
}
 
140
 
 
141
void QgsMapLayer::drawLabels( QgsRenderContext& rendererContext )
 
142
{
 
143
  // QgsDebugMsg("entered.");
 
144
}
 
145
 
 
146
bool QgsMapLayer::readXML( QDomNode & layer_node )
 
147
{
 
148
  QgsCoordinateReferenceSystem savedCRS;
 
149
  CUSTOM_CRS_VALIDATION savedValidation;
 
150
  bool layerError;
 
151
 
 
152
  QDomElement element = layer_node.toElement();
 
153
 
 
154
  QDomNode mnl;
 
155
  QDomElement mne;
 
156
 
 
157
  // read provider
 
158
  QString provider;
 
159
  mnl = layer_node.namedItem( "provider" );
 
160
  mne = mnl.toElement();
 
161
  provider = mne.text();
 
162
 
 
163
  // set data source
 
164
  mnl = layer_node.namedItem( "datasource" );
 
165
  mne = mnl.toElement();
 
166
  mDataSource = mne.text();
 
167
 
 
168
  if ( provider == "spatialite" )
 
169
  {
 
170
    QgsDataSourceURI uri( mDataSource );
 
171
    uri.setDatabase( QgsProject::instance()->readPath( uri.database() ) );
 
172
    mDataSource = uri.uri();
 
173
  }
 
174
  else if ( provider == "ogr" )
 
175
  {
 
176
    QStringList theURIParts = mDataSource.split( "|" );
 
177
    theURIParts[0] = QgsProject::instance()->readPath( theURIParts[0] );
 
178
    mDataSource = theURIParts.join( "|" );
 
179
  }
 
180
  else
 
181
  {
 
182
    mDataSource = QgsProject::instance()->readPath( mDataSource );
 
183
  }
 
184
 
 
185
  // Set the CRS from project file, asking the user if necessary.
 
186
  // Make it the saved CRS to have WMS layer projected correctly.
 
187
  // We will still overwrite whatever GDAL etc picks up anyway
 
188
  // further down this function.
 
189
  QDomNode srsNode = layer_node.namedItem( "srs" );
 
190
  mCRS->readXML( srsNode );
 
191
  mCRS->validate();
 
192
  savedCRS = *mCRS;
 
193
 
 
194
  // Do not validate any projections in children, they will be overwritten anyway.
 
195
  // No need to ask the user for a projections when it is overwritten, is there?
 
196
  savedValidation = QgsCoordinateReferenceSystem::customSrsValidation();
 
197
  QgsCoordinateReferenceSystem::setCustomSrsValidation( NULL );
 
198
 
 
199
  // now let the children grab what they need from the Dom node.
 
200
  layerError = !readXml( layer_node );
 
201
 
 
202
  // overwrite CRS with what we read from project file before the raster/vector
 
203
  // file readnig functions changed it. They will if projections is specfied in the file.
 
204
  // FIXME: is this necessary?
 
205
  QgsCoordinateReferenceSystem::setCustomSrsValidation( savedValidation );
 
206
  *mCRS = savedCRS;
 
207
 
 
208
  // Abort if any error in layer, such as not found.
 
209
  if ( layerError )
 
210
  {
 
211
    return false;
 
212
  }
 
213
 
 
214
  // the internal name is just the data source basename
 
215
  //QFileInfo dataSourceFileInfo( mDataSource );
 
216
  //internalName = dataSourceFileInfo.baseName();
 
217
 
 
218
  // set ID
 
219
  mnl = layer_node.namedItem( "id" );
 
220
  if ( ! mnl.isNull() )
 
221
  {
 
222
    mne = mnl.toElement();
 
223
    if ( ! mne.isNull() && mne.text().length() > 10 ) // should be at least 17 (yyyyMMddhhmmsszzz)
 
224
    {
 
225
      mID = mne.text();
 
226
    }
 
227
  }
 
228
 
 
229
  // use scale dependent visibility flag
 
230
  toggleScaleBasedVisibility( element.attribute( "hasScaleBasedVisibilityFlag" ).toInt() == 1 );
 
231
  setMinimumScale( element.attribute( "minimumScale" ).toFloat() );
 
232
  setMaximumScale( element.attribute( "maximumScale" ).toFloat() );
 
233
 
 
234
  // set name
 
235
  mnl = layer_node.namedItem( "layername" );
 
236
  mne = mnl.toElement();
 
237
  setLayerName( mne.text() );
 
238
 
 
239
  //read transparency level
 
240
  QDomNode transparencyNode = layer_node.namedItem( "transparencyLevelInt" );
 
241
  if ( ! transparencyNode.isNull() )
 
242
  {
 
243
    // set transparency level only if it's in project
 
244
    // (otherwise it sets the layer transparent)
 
245
    QDomElement myElement = transparencyNode.toElement();
 
246
    setTransparency( myElement.text().toInt() );
 
247
  }
 
248
 
 
249
  readCustomProperties( layer_node );
 
250
 
 
251
  return true;
 
252
} // void QgsMapLayer::readXML
 
253
 
 
254
 
 
255
bool QgsMapLayer::readXml( QDomNode & layer_node )
 
256
{
 
257
  // NOP by default; children will over-ride with behavior specific to them
 
258
 
 
259
  return true;
 
260
} // void QgsMapLayer::readXml
 
261
 
 
262
 
 
263
 
 
264
bool QgsMapLayer::writeXML( QDomNode & layer_node, QDomDocument & document )
 
265
{
 
266
  // general layer metadata
 
267
  QDomElement maplayer = document.createElement( "maplayer" );
 
268
 
 
269
  // use scale dependent visibility flag
 
270
  maplayer.setAttribute( "hasScaleBasedVisibilityFlag", hasScaleBasedVisibility() ? 1 : 0 );
 
271
  maplayer.setAttribute( "minimumScale", minimumScale() );
 
272
  maplayer.setAttribute( "maximumScale", maximumScale() );
 
273
 
 
274
  // ID
 
275
  QDomElement id = document.createElement( "id" );
 
276
  QDomText idText = document.createTextNode( getLayerID() );
 
277
  id.appendChild( idText );
 
278
 
 
279
  maplayer.appendChild( id );
 
280
 
 
281
  // data source
 
282
  QDomElement dataSource = document.createElement( "datasource" );
 
283
 
 
284
  QString src = source();
 
285
 
 
286
  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
 
287
  if ( vlayer && vlayer->providerType() == "spatialite" )
 
288
  {
 
289
    QgsDataSourceURI uri( src );
 
290
    QString database = QgsProject::instance()->writePath( uri.database() );
 
291
    uri.setConnection( uri.host(), uri.port(), database, uri.username(), uri.password() );
 
292
    src = uri.uri();
 
293
  }
 
294
  else if ( vlayer && vlayer->providerType() == "ogr" )
 
295
  {
 
296
    QStringList theURIParts = src.split( "|" );
 
297
    theURIParts[0] = QgsProject::instance()->writePath( theURIParts[0] );
 
298
    src = theURIParts.join( "|" );
 
299
  }
 
300
  else
 
301
  {
 
302
    src = QgsProject::instance()->writePath( src );
 
303
  }
 
304
 
 
305
  QDomText dataSourceText = document.createTextNode( src );
 
306
  dataSource.appendChild( dataSourceText );
 
307
 
 
308
  maplayer.appendChild( dataSource );
 
309
 
 
310
 
 
311
  // layer name
 
312
  QDomElement layerName = document.createElement( "layername" );
 
313
  QDomText layerNameText = document.createTextNode( name() );
 
314
  layerName.appendChild( layerNameText );
 
315
 
 
316
  maplayer.appendChild( layerName );
 
317
 
 
318
  // zorder
 
319
  // This is no longer stored in the project file. It is superfluous since the layers
 
320
  // are written and read in the proper order.
 
321
 
 
322
  // spatial reference system id
 
323
  QDomElement mySrsElement = document.createElement( "srs" );
 
324
  mCRS->writeXML( mySrsElement, document );
 
325
  maplayer.appendChild( mySrsElement );
 
326
 
 
327
  // <transparencyLevelInt>
 
328
  QDomElement transparencyLevelIntElement = document.createElement( "transparencyLevelInt" );
 
329
  QDomText    transparencyLevelIntText    = document.createTextNode( QString::number( getTransparency() ) );
 
330
  transparencyLevelIntElement.appendChild( transparencyLevelIntText );
 
331
  maplayer.appendChild( transparencyLevelIntElement );
 
332
  // now append layer node to map layer node
 
333
 
 
334
  layer_node.appendChild( maplayer );
 
335
 
 
336
  writeCustomProperties( maplayer, document );
 
337
 
 
338
  return writeXml( maplayer, document );
 
339
 
 
340
} // bool QgsMapLayer::writeXML
 
341
 
 
342
 
 
343
 
 
344
bool QgsMapLayer::writeXml( QDomNode & layer_node, QDomDocument & document )
 
345
{
 
346
  // NOP by default; children will over-ride with behavior specific to them
 
347
 
 
348
  return true;
 
349
} // void QgsMapLayer::writeXml
 
350
 
 
351
 
 
352
 
 
353
 
 
354
bool QgsMapLayer::isValid()
 
355
{
 
356
  return mValid;
 
357
}
 
358
 
 
359
 
 
360
void QgsMapLayer::invalidTransformInput()
 
361
{
 
362
  QgsDebugMsg( "called" );
 
363
  // TODO: emit a signal - it will be used to update legend
 
364
}
 
365
 
 
366
 
 
367
QString QgsMapLayer::lastErrorTitle()
 
368
{
 
369
  return QString();
 
370
}
 
371
 
 
372
QString QgsMapLayer::lastError()
 
373
{
 
374
  return QString();
 
375
}
 
376
 
 
377
void QgsMapLayer::connectNotify( const char * signal )
 
378
{
 
379
  QgsDebugMsgLevel( "QgsMapLayer connected to " + QString( signal ), 3 );
 
380
} //  QgsMapLayer::connectNotify
 
381
 
 
382
 
 
383
 
 
384
void QgsMapLayer::toggleScaleBasedVisibility( bool theVisibilityFlag )
 
385
{
 
386
  mScaleBasedVisibility = theVisibilityFlag;
 
387
}
 
388
 
 
389
bool QgsMapLayer::hasScaleBasedVisibility()
 
390
{
 
391
  return mScaleBasedVisibility;
 
392
}
 
393
 
 
394
void QgsMapLayer::setMinimumScale( float theMinScale )
 
395
{
 
396
  mMinScale = theMinScale;
 
397
}
 
398
 
 
399
float QgsMapLayer::minimumScale()
 
400
{
 
401
  return mMinScale;
 
402
}
 
403
 
 
404
 
 
405
void QgsMapLayer::setMaximumScale( float theMaxScale )
 
406
{
 
407
  mMaxScale = theMaxScale;
 
408
}
 
409
 
 
410
float QgsMapLayer::maximumScale()
 
411
{
 
412
  return mMaxScale;
 
413
}
 
414
 
 
415
 
 
416
QStringList QgsMapLayer::subLayers()
 
417
{
 
418
  return QStringList();  // Empty
 
419
}
 
420
 
 
421
void QgsMapLayer::setLayerOrder( QStringList layers )
 
422
{
 
423
  // NOOP
 
424
}
 
425
 
 
426
void QgsMapLayer::setSubLayerVisibility( QString name, bool vis )
 
427
{
 
428
  // NOOP
 
429
}
 
430
 
 
431
const QgsCoordinateReferenceSystem& QgsMapLayer::crs()
 
432
{
 
433
  return *mCRS;
 
434
}
 
435
 
 
436
const QgsCoordinateReferenceSystem& QgsMapLayer::srs()
 
437
{
 
438
  // This will be dropped in QGIS 2.0 due to conflicting name
 
439
  // Please use crs() in the future
 
440
  return *mCRS;
 
441
}
 
442
 
 
443
void QgsMapLayer::setCrs( const QgsCoordinateReferenceSystem& srs, bool emitSignal )
 
444
{
 
445
  *mCRS = srs;
 
446
  if ( emitSignal )
 
447
    emit layerCrsChanged();
 
448
}
 
449
 
 
450
unsigned int QgsMapLayer::getTransparency()
 
451
{
 
452
  return mTransparencyLevel;
 
453
}
 
454
 
 
455
void QgsMapLayer::setTransparency( unsigned int theInt )
 
456
{
 
457
  mTransparencyLevel = theInt;
 
458
}
 
459
 
 
460
QString QgsMapLayer::capitaliseLayerName( const QString name )
 
461
{
 
462
  // Capitalise the first letter of the layer name if requested
 
463
  QSettings settings;
 
464
  bool capitaliseLayerName =
 
465
    settings.value( "qgis/capitaliseLayerName", QVariant( false ) ).toBool();
 
466
 
 
467
  QString layerName( name );
 
468
 
 
469
  if ( capitaliseLayerName )
 
470
    layerName = layerName.left( 1 ).toUpper() + layerName.mid( 1 );
 
471
 
 
472
  return layerName;
 
473
}
 
474
 
 
475
QString QgsMapLayer::loadDefaultStyle( bool & theResultFlag )
 
476
{
 
477
  QString myURI = publicSource();
 
478
  QFileInfo myFileInfo( myURI );
 
479
  QString key;
 
480
  if ( myFileInfo.exists() )
 
481
  {
 
482
    // get the file name for our .qml style file
 
483
    key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".qml";
 
484
  }
 
485
  else
 
486
  {
 
487
    key = myURI;
 
488
  }
 
489
  return loadNamedStyle( key, theResultFlag );
 
490
}
 
491
 
 
492
bool QgsMapLayer::loadNamedStyleFromDb( const QString db, const QString theURI, QString &qml )
 
493
{
 
494
  bool theResultFlag = false;
 
495
 
 
496
  // read from database
 
497
  sqlite3 *myDatabase;
 
498
  sqlite3_stmt *myPreparedStatement;
 
499
  const char *myTail;
 
500
  int myResult;
 
501
 
 
502
  QgsDebugMsg( QString( "Trying to load style for \"%1\" from \"%2\"" ).arg( theURI ).arg( db ) );
 
503
 
 
504
  if ( !QFile( db ).exists() )
 
505
    return false;
 
506
 
 
507
  myResult = sqlite3_open( db.toUtf8().data(), &myDatabase );
 
508
  if ( myResult != SQLITE_OK )
 
509
  {
 
510
    return false;
 
511
  }
 
512
 
 
513
  QString mySql = "select qml from tbl_styles where style=?";
 
514
  myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
 
515
  if ( myResult == SQLITE_OK )
 
516
  {
 
517
    QByteArray param = theURI.toUtf8();
 
518
 
 
519
    if ( sqlite3_bind_text( myPreparedStatement, 1, param.data(), param.length(), SQLITE_STATIC ) == SQLITE_OK &&
 
520
         sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
 
521
    {
 
522
      qml = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) );
 
523
      theResultFlag = true;
 
524
    }
 
525
 
 
526
    sqlite3_finalize( myPreparedStatement );
 
527
  }
 
528
 
 
529
  sqlite3_close( myDatabase );
 
530
 
 
531
  return theResultFlag;
 
532
}
 
533
 
 
534
QString QgsMapLayer::loadNamedStyle( const QString theURI, bool &theResultFlag )
 
535
{
 
536
  theResultFlag = false;
 
537
 
 
538
  QDomDocument myDocument( "qgis" );
 
539
 
 
540
  // location of problem associated with errorMsg
 
541
  int line, column;
 
542
  QString myErrorMessage;
 
543
 
 
544
  QFile myFile( theURI );
 
545
  if ( myFile.open( QFile::ReadOnly ) )
 
546
  {
 
547
    // read file
 
548
    theResultFlag = myDocument.setContent( &myFile, &myErrorMessage, &line, &column );
 
549
    if ( !theResultFlag )
 
550
      myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
 
551
    myFile.close();
 
552
  }
 
553
  else
 
554
  {
 
555
    QFileInfo project( QgsProject::instance()->fileName() );
 
556
    QgsDebugMsg( QString( "project fileName: %1" ).arg( project.absoluteFilePath() ) );
 
557
 
 
558
    QString qml;
 
559
    if ( loadNamedStyleFromDb( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( "qgis.qmldb" ), theURI, qml ) ||
 
560
         ( project.exists() && loadNamedStyleFromDb( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), theURI, qml ) ) ||
 
561
         loadNamedStyleFromDb( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( "resources/qgis.qmldb" ), theURI, qml ) )
 
562
    {
 
563
      theResultFlag = myDocument.setContent( qml, &myErrorMessage, &line, &column );
 
564
      if ( !theResultFlag )
 
565
      {
 
566
        myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
 
567
      }
 
568
    }
 
569
    else
 
570
    {
 
571
      myErrorMessage = tr( "style not found in database" );
 
572
    }
 
573
  }
 
574
 
 
575
  if ( !theResultFlag )
 
576
  {
 
577
    return myErrorMessage;
 
578
  }
 
579
 
 
580
  // now get the layer node out and pass it over to the layer
 
581
  // to deserialise...
 
582
  QDomElement myRoot = myDocument.firstChildElement( "qgis" );
 
583
  if ( myRoot.isNull() )
 
584
  {
 
585
    myErrorMessage = "Error: qgis element could not be found in " + theURI;
 
586
    theResultFlag = false;
 
587
    return myErrorMessage;
 
588
  }
 
589
 
 
590
  // use scale dependent visibility flag
 
591
  toggleScaleBasedVisibility( myRoot.attribute( "hasScaleBasedVisibilityFlag" ).toInt() == 1 );
 
592
  setMinimumScale( myRoot.attribute( "minimumScale" ).toFloat() );
 
593
  setMaximumScale( myRoot.attribute( "maximumScale" ).toFloat() );
 
594
 
 
595
  //read transparency level
 
596
  QDomNode transparencyNode = myRoot.namedItem( "transparencyLevelInt" );
 
597
  if ( ! transparencyNode.isNull() )
 
598
  {
 
599
    // set transparency level only if it's in project
 
600
    // (otherwise it sets the layer transparent)
 
601
    QDomElement myElement = transparencyNode.toElement();
 
602
    setTransparency( myElement.text().toInt() );
 
603
  }
 
604
 
 
605
  QString errorMsg;
 
606
  theResultFlag = readSymbology( myRoot, errorMsg );
 
607
  if ( !theResultFlag )
 
608
  {
 
609
    myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( theURI ).arg( errorMsg );
 
610
    return myErrorMessage;
 
611
  }
 
612
 
 
613
  return "";
 
614
}
 
615
 
 
616
QString QgsMapLayer::saveDefaultStyle( bool & theResultFlag )
 
617
{
 
618
  return saveNamedStyle( publicSource(), theResultFlag );
 
619
}
 
620
 
 
621
QString QgsMapLayer::saveNamedStyle( const QString theURI, bool & theResultFlag )
 
622
{
 
623
  QString myErrorMessage;
 
624
 
 
625
  QDomImplementation DomImplementation;
 
626
  QDomDocumentType documentType =
 
627
    DomImplementation.createDocumentType(
 
628
      "qgis", "http://mrcc.com/qgis.dtd", "SYSTEM" );
 
629
  QDomDocument myDocument( documentType );
 
630
  QDomElement myRootNode = myDocument.createElement( "qgis" );
 
631
  myRootNode.setAttribute( "version", QString( "%1" ).arg( QGis::QGIS_VERSION ) );
 
632
  myDocument.appendChild( myRootNode );
 
633
 
 
634
  // use scale dependent visibility flag
 
635
  myRootNode.setAttribute( "hasScaleBasedVisibilityFlag", hasScaleBasedVisibility() ? 1 : 0 );
 
636
  myRootNode.setAttribute( "minimumScale", minimumScale() );
 
637
  myRootNode.setAttribute( "maximumScale", maximumScale() );
 
638
 
 
639
  // <transparencyLevelInt>
 
640
  QDomElement transparencyLevelIntElement = myDocument.createElement( "transparencyLevelInt" );
 
641
  QDomText    transparencyLevelIntText    = myDocument.createTextNode( QString::number( getTransparency() ) );
 
642
  transparencyLevelIntElement.appendChild( transparencyLevelIntText );
 
643
  myRootNode.appendChild( transparencyLevelIntElement );
 
644
  // now append layer node to map layer node
 
645
 
 
646
  QString errorMsg;
 
647
  if ( !writeSymbology( myRootNode, myDocument, errorMsg ) )
 
648
  {
 
649
    return tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
 
650
  }
 
651
 
 
652
  // check if the uri is a file or ends with .qml,
 
653
  // which indicates that it should become one
 
654
  // everything else goes to the database
 
655
  QString filename;
 
656
 
 
657
  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
 
658
  if ( vlayer && vlayer->providerType() == "ogr" )
 
659
  {
 
660
    QStringList theURIParts = theURI.split( "|" );
 
661
    filename = theURIParts[0];
 
662
  }
 
663
  else
 
664
  {
 
665
    filename = theURI;
 
666
  }
 
667
 
 
668
  QFileInfo myFileInfo( filename );
 
669
  if ( myFileInfo.exists() || filename.endsWith( ".qml", Qt::CaseInsensitive ) )
 
670
  {
 
671
    QFileInfo myDirInfo( myFileInfo.path() );  //excludes file name
 
672
    if ( !myDirInfo.isWritable() )
 
673
    {
 
674
      return tr( "The directory containing your dataset needs to be writeable!" );
 
675
    }
 
676
 
 
677
    // now construct the file name for our .qml style file
 
678
    QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".qml";
 
679
 
 
680
    QFile myFile( myFileName );
 
681
    if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
 
682
    {
 
683
      QTextStream myFileStream( &myFile );
 
684
      // save as utf-8 with 2 spaces for indents
 
685
      myDocument.save( myFileStream, 2 );
 
686
      myFile.close();
 
687
      theResultFlag = true;
 
688
      return tr( "Created default style file as %1" ).arg( myFileName );
 
689
    }
 
690
    else
 
691
    {
 
692
      theResultFlag = false;
 
693
      return tr( "ERROR: Failed to created default style file as %1. Check file permissions and retry." ).arg( myFileName );
 
694
    }
 
695
  }
 
696
  else
 
697
  {
 
698
    QString qml = myDocument.toString();
 
699
 
 
700
    // read from database
 
701
    sqlite3 *myDatabase;
 
702
    sqlite3_stmt *myPreparedStatement;
 
703
    const char *myTail;
 
704
    int myResult;
 
705
 
 
706
    myResult = sqlite3_open( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( "qgis.qmldb" ).toUtf8().data(), &myDatabase );
 
707
    if ( myResult != SQLITE_OK )
 
708
    {
 
709
      return tr( "User database could not be opened." );
 
710
    }
 
711
 
 
712
    QByteArray param0 = theURI.toUtf8();
 
713
    QByteArray param1 = qml.toUtf8();
 
714
 
 
715
    QString mySql = "create table if not exists tbl_styles(style varchar primary key,qml varchar)";
 
716
    myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
 
717
    if ( myResult == SQLITE_OK )
 
718
    {
 
719
      if ( sqlite3_step( myPreparedStatement ) != SQLITE_DONE )
 
720
      {
 
721
        sqlite3_finalize( myPreparedStatement );
 
722
        sqlite3_close( myDatabase );
 
723
        theResultFlag = false;
 
724
        return tr( "The style table could not be created." );
 
725
      }
 
726
    }
 
727
 
 
728
    sqlite3_finalize( myPreparedStatement );
 
729
 
 
730
    mySql = "insert into tbl_styles(style,qml) values (?,?)";
 
731
    myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
 
732
    if ( myResult == SQLITE_OK )
 
733
    {
 
734
      if ( sqlite3_bind_text( myPreparedStatement, 1, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
 
735
           sqlite3_bind_text( myPreparedStatement, 2, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
 
736
           sqlite3_step( myPreparedStatement ) == SQLITE_DONE )
 
737
      {
 
738
        theResultFlag = true;
 
739
        myErrorMessage = tr( "The style %1 was saved to database" ).arg( theURI );
 
740
      }
 
741
    }
 
742
 
 
743
    sqlite3_finalize( myPreparedStatement );
 
744
 
 
745
    if ( !theResultFlag )
 
746
    {
 
747
      QString mySql = "update tbl_styles set qml=? where style=?";
 
748
      myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
 
749
      if ( myResult == SQLITE_OK )
 
750
      {
 
751
        if ( sqlite3_bind_text( myPreparedStatement, 2, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
 
752
             sqlite3_bind_text( myPreparedStatement, 1, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK &&
 
753
             sqlite3_step( myPreparedStatement ) == SQLITE_DONE )
 
754
        {
 
755
          theResultFlag = true;
 
756
          myErrorMessage = tr( "The style %1 was updated in the database." ).arg( theURI );
 
757
        }
 
758
        else
 
759
        {
 
760
          theResultFlag = false;
 
761
          myErrorMessage = tr( "The style %1 could not be updated in the database." ).arg( theURI );
 
762
        }
 
763
      }
 
764
      else
 
765
      {
 
766
        // try an update
 
767
        theResultFlag = false;
 
768
        myErrorMessage = tr( "The style %1 could not be inserted into database." ).arg( theURI );
 
769
      }
 
770
 
 
771
      sqlite3_finalize( myPreparedStatement );
 
772
    }
 
773
 
 
774
    sqlite3_close( myDatabase );
 
775
  }
 
776
 
 
777
  return myErrorMessage;
 
778
}
 
779
 
 
780
 
 
781
 
 
782
 
 
783
QUndoStack* QgsMapLayer::undoStack()
 
784
{
 
785
  return &mUndoStack;
 
786
}
 
787
 
 
788
 
 
789
void QgsMapLayer::setCustomProperty( const QString& key, const QVariant& value )
 
790
{
 
791
  mCustomProperties[key] = value;
 
792
}
 
793
 
 
794
QVariant QgsMapLayer::customProperty( const QString& value, const QVariant& defaultValue ) const
 
795
{
 
796
  return mCustomProperties.value( value, defaultValue );
 
797
}
 
798
 
 
799
void QgsMapLayer::removeCustomProperty( const QString& key )
 
800
{
 
801
  mCustomProperties.remove( key );
 
802
}
 
803
 
 
804
void QgsMapLayer::readCustomProperties( QDomNode & layerNode )
 
805
{
 
806
  QDomNode propsNode = layerNode.namedItem( "customproperties" );
 
807
  if ( propsNode.isNull() ) // no properties stored...
 
808
    return;
 
809
 
 
810
  mCustomProperties.clear();
 
811
 
 
812
  QDomNodeList nodes = propsNode.childNodes();
 
813
 
 
814
  for ( int i = 0; i < nodes.size(); i++ )
 
815
  {
 
816
    QDomNode propNode = nodes.at( i );
 
817
    if ( propNode.isNull() || propNode.nodeName() != "property" )
 
818
      continue;
 
819
    QDomElement propElement = propNode.toElement();
 
820
 
 
821
    QString key = propElement.attribute( "key" );
 
822
    QString value = propElement.attribute( "value" );
 
823
    mCustomProperties[key] = QVariant( value );
 
824
  }
 
825
 
 
826
}
 
827
 
 
828
void QgsMapLayer::writeCustomProperties( QDomNode & layerNode, QDomDocument & doc )
 
829
{
 
830
  QDomElement propsElement = doc.createElement( "customproperties" );
 
831
 
 
832
  for ( QMap<QString, QVariant>::const_iterator it = mCustomProperties.begin(); it != mCustomProperties.end(); ++it )
 
833
  {
 
834
    QDomElement propElement = doc.createElement( "property" );
 
835
    propElement.setAttribute( "key", it.key() );
 
836
    propElement.setAttribute( "value", it.value().toString() );
 
837
    propsElement.appendChild( propElement );
 
838
  }
 
839
 
 
840
  layerNode.appendChild( propsElement );
 
841
}
 
842
 
 
843
void QgsMapLayer::setCacheImage( QImage * thepImage )
 
844
{
 
845
  QgsDebugMsg( "cache Image set!" );
 
846
  if ( mpCacheImage )
 
847
  {
 
848
    delete mpCacheImage;
 
849
  }
 
850
  mpCacheImage = thepImage;
 
851
}
 
852