Skip to content

Commit 118f57e

Browse files
author
jef
committed
save qml of non-file datasources to qgis user database
git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@8587 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent 3690acc commit 118f57e

File tree

1 file changed

+201
-84
lines changed

1 file changed

+201
-84
lines changed

src/core/qgsmaplayer.cpp

Lines changed: 201 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,14 @@
3030
#include <QDomImplementation>
3131
#include <QTextStream>
3232

33+
#include <sqlite3.h>
3334

3435
#include "qgslogger.h"
3536
#include "qgsrect.h"
3637
#include "qgssymbol.h"
3738
#include "qgsmaplayer.h"
3839
#include "qgsspatialrefsys.h"
39-
40+
#include "qgsapplication.h"
4041

4142
QgsMapLayer::QgsMapLayer(int type,
4243
QString lyrname,
@@ -409,104 +410,125 @@ QString QgsMapLayer::loadDefaultStyle ( bool & theResultFlag )
409410
{
410411
QString myURI = publicSource();
411412
QFileInfo myFileInfo ( myURI );
412-
//get the file name for our .qml style file
413-
QString myFileName = myFileInfo.path() + QDir::separator() +
414-
myFileInfo.completeBaseName () + ".qml";
415-
return loadNamedStyle ( myFileName, theResultFlag );
413+
QString key;
414+
if( myFileInfo.exists() ) {
415+
// get the file name for our .qml style file
416+
key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName () + ".qml";
417+
} else {
418+
key = myURI;
419+
}
420+
return loadNamedStyle ( key, theResultFlag );
416421
}
422+
417423
QString QgsMapLayer::loadNamedStyle ( const QString theURI , bool & theResultFlag )
418424
{
419425
theResultFlag = false;
420-
//first check if its a file - we will add support for
421-
//database etc uris later
422-
QFileInfo myFileInfo ( theURI );
423-
if ( !myFileInfo.isFile() )
424-
{
425-
return QObject::tr( "Currently only filebased datasets are supported" );
426-
}
427-
QFile myFile ( theURI );
428-
if ( !myFile.open(QFile::ReadOnly ) )
429-
{
430-
return QObject::tr( "File could not been opened." );
431-
}
432426

433427
QDomDocument myDocument ( "qgis" );
428+
434429
// location of problem associated with errorMsg
435430
int line, column;
436431
QString myErrorMessage;
437-
if ( !myDocument.setContent ( &myFile, &myErrorMessage, &line, &column ) )
438-
{
432+
433+
QFile myFile ( theURI );
434+
if ( myFile.open(QFile::ReadOnly ) )
435+
{
436+
// read file
437+
theResultFlag = myDocument.setContent ( &myFile, &myErrorMessage, &line, &column );
438+
if(!theResultFlag)
439+
myErrorMessage = tr("%1 at line %2 column %3").arg( myErrorMessage ).arg( line ).arg(column);
439440
myFile.close();
440-
return myErrorMessage + " at line " + QString::number( line ) +
441-
" column " + QString::number( column );
442441
}
443-
else //dom parsed in ok
442+
else
444443
{
445-
myFile.close();
446-
447-
// now get the layer node out and pass it over to the layer
448-
// to deserialise...
449-
QDomElement myRoot = myDocument.firstChildElement("qgis");
450-
if (myRoot.isNull())
444+
// read from database
445+
sqlite3 *myDatabase;
446+
sqlite3_stmt *myPreparedStatement;
447+
const char *myTail;
448+
int myResult;
449+
450+
myResult = sqlite3_open(QgsApplication::qgisUserDbFilePath().toUtf8().data(), &myDatabase);
451+
if (myResult)
451452
{
452-
myErrorMessage = "Error: qgis element could not be found in " + theURI;
453-
return myErrorMessage;
453+
return tr("could not open user database");
454454
}
455455

456-
QDomElement myLayer = myRoot.firstChildElement("maplayer");
457-
if (myLayer.isNull())
456+
QString mySql = "select qml from tbl_styles where style=?";
457+
myResult = sqlite3_prepare(myDatabase, mySql.toUtf8().data(), mySql.length(), &myPreparedStatement, &myTail);
458+
if (myResult==SQLITE_OK)
458459
{
459-
myErrorMessage = "Error: maplayer element could not be found in " + theURI;
460-
return myErrorMessage;
460+
QByteArray param = theURI.toUtf8();
461+
462+
if( sqlite3_bind_text(myPreparedStatement, 1, param.data(), param.length(), SQLITE_STATIC)==SQLITE_OK &&
463+
sqlite3_step(myPreparedStatement)==SQLITE_ROW )
464+
{
465+
QString qml = QString::fromUtf8( (char *)sqlite3_column_text(myPreparedStatement, 0) );
466+
theResultFlag = myDocument.setContent ( qml, &myErrorMessage, &line, &column );
467+
if(!theResultFlag)
468+
myErrorMessage = tr("%1 at line %2 column %3").arg( myErrorMessage ).arg( line ).arg(column);
469+
}
461470
}
462-
463-
//
464-
// we need to ensure the data source matches the layers
465-
// current datasource not the one specified in the qml
466-
//
467-
QDomElement myDataSource = myLayer.firstChildElement("datasource");
468-
if (myDataSource.isNull())
471+
else
469472
{
470-
myErrorMessage = "Error: datasource element could not be found in " + theURI;
471-
return myErrorMessage;
473+
theResultFlag = false;
474+
myErrorMessage = tr("style %1 not found in database").arg(theURI);
472475
}
473-
QDomElement myNewDataSource = myDocument.createElement( "datasource" );
474-
QDomText myDataSourceText = myDocument.createTextNode( source() );
475-
myNewDataSource.appendChild( myDataSourceText );
476-
myLayer.replaceChild( myNewDataSource ,
477-
myLayer.firstChildElement("datasource") );
478-
479-
//
480-
// Now go on to parse the xml (QDomElement inherits QDomNode
481-
// so we can just pass along the element to readXML)
482-
//
483-
theResultFlag = readXML ( myLayer );
484-
485-
return QObject::tr( "Loaded default style file from " ) + theURI;
476+
477+
sqlite3_finalize(myPreparedStatement);
478+
sqlite3_close(myDatabase);
479+
}
480+
481+
if(!theResultFlag)
482+
return myErrorMessage;
483+
484+
// now get the layer node out and pass it over to the layer
485+
// to deserialise...
486+
QDomElement myRoot = myDocument.firstChildElement("qgis");
487+
if (myRoot.isNull())
488+
{
489+
myErrorMessage = "Error: qgis element could not be found in " + theURI;
490+
return myErrorMessage;
491+
}
492+
493+
QDomElement myLayer = myRoot.firstChildElement("maplayer");
494+
if (myLayer.isNull())
495+
{
496+
myErrorMessage = "Error: maplayer element could not be found in " + theURI;
497+
return myErrorMessage;
498+
}
499+
500+
//
501+
// we need to ensure the data source matches the layers
502+
// current datasource not the one specified in the qml
503+
//
504+
QDomElement myDataSource = myLayer.firstChildElement("datasource");
505+
if (myDataSource.isNull())
506+
{
507+
myErrorMessage = "Error: datasource element could not be found in " + theURI;
508+
return myErrorMessage;
486509
}
510+
QDomElement myNewDataSource = myDocument.createElement( "datasource" );
511+
QDomText myDataSourceText = myDocument.createTextNode( source() );
512+
myNewDataSource.appendChild( myDataSourceText );
513+
myLayer.replaceChild( myNewDataSource, myLayer.firstChildElement("datasource") );
514+
515+
//
516+
// Now go on to parse the xml (QDomElement inherits QDomNode
517+
// so we can just pass along the element to readXML)
518+
//
519+
theResultFlag = readXML ( myLayer );
520+
521+
return QObject::tr( "Loaded default style file from " ) + theURI;
487522
}
523+
488524
QString QgsMapLayer::saveDefaultStyle ( bool & theResultFlag )
489525
{
490-
QString myURI = publicSource();
491-
QFileInfo myFileInfo ( myURI );
492-
//get the file name for our .qml style file
493-
QString myFileName = myFileInfo.path() + QDir::separator() +
494-
myFileInfo.completeBaseName () + ".qml";
495-
return saveNamedStyle ( myFileName, theResultFlag );
526+
return saveNamedStyle ( publicSource(), theResultFlag );
496527
}
497-
QString QgsMapLayer::saveNamedStyle ( const QString theURI , bool & theResultFlag )
528+
529+
QString QgsMapLayer::saveNamedStyle ( const QString theURI, bool & theResultFlag )
498530
{
499-
QFileInfo myFileInfo ( theURI );
500-
//now check if we can write to the dir where the layer
501-
//exists...
502-
QFileInfo myDirInfo ( myFileInfo.path() ); //excludes filename
503-
if ( !myDirInfo.isWritable() )
504-
{
505-
return QObject::tr( "The directory containing your dataset needs to be writeable!" );
506-
}
507-
//now construct the file name for our .qml style file
508-
QString myFileName = myFileInfo.path() + QDir::separator() +
509-
myFileInfo.completeBaseName () + ".qml";
531+
QString myErrorMessage;
510532

511533
QDomImplementation DOMImplementation;
512534
QDomDocumentType documentType =
@@ -518,19 +540,114 @@ QString QgsMapLayer::saveNamedStyle ( const QString theURI , bool & theResultFla
518540
myDocument.appendChild( myRootNode );
519541
writeXML( myRootNode, myDocument );
520542

521-
522-
QFile myFile ( myFileName );
523-
if ( myFile.open(QFile::WriteOnly | QFile::Truncate ) )
543+
// check if the uri is a file or ends with .qml,
544+
// which indicates that it should become one
545+
// everything else goes to the database.
546+
QFileInfo myFileInfo ( theURI );
547+
if ( myFileInfo.exists() || theURI.endsWith(".qml", Qt::CaseInsensitive) )
524548
{
525-
QTextStream myFileStream( &myFile );
526-
// save as utf-8 with 2 spaces for indents
527-
myDocument.save( myFileStream, 2 );
528-
myFile.close();
529-
return QObject::tr( "Created default style file as " ) + myFileName;
549+
QFileInfo myDirInfo ( myFileInfo.path() ); //excludes filename
550+
if ( !myDirInfo.isWritable() )
551+
{
552+
return QObject::tr( "The directory containing your dataset needs to be writeable!" );
553+
}
554+
555+
// now construct the file name for our .qml style file
556+
QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName () + ".qml";
557+
558+
QFile myFile ( myFileName );
559+
if ( myFile.open(QFile::WriteOnly | QFile::Truncate ) )
560+
{
561+
QTextStream myFileStream( &myFile );
562+
// save as utf-8 with 2 spaces for indents
563+
myDocument.save( myFileStream, 2 );
564+
myFile.close();
565+
return QObject::tr( "Created default style file as " ) + myFileName;
566+
}
567+
else
568+
{
569+
return QObject::tr( "ERROR: Failed to created default style file as %1 Check file permissions and retry." ).arg(myFileName);
570+
}
530571
}
531572
else
532573
{
533-
return QObject::tr( "ERROR: Failed to created default style file as " ) + myFileName +
534-
tr( " Check file permissions and retry." );
574+
QString qml = myDocument.toString();
575+
576+
// read from database
577+
sqlite3 *myDatabase;
578+
sqlite3_stmt *myPreparedStatement;
579+
const char *myTail;
580+
int myResult;
581+
582+
myResult = sqlite3_open(QgsApplication::qgisUserDbFilePath().toUtf8().data(), &myDatabase);
583+
if (myResult)
584+
{
585+
return tr("User database could not be opened.");
586+
}
587+
588+
QByteArray param0 = theURI.toUtf8();
589+
QByteArray param1 = qml.toUtf8();
590+
591+
QString mySql = "create table if not exists tbl_styles(style varchar primary key,qml varchar)";
592+
myResult = sqlite3_prepare(myDatabase, mySql.toUtf8().data(), mySql.length(), &myPreparedStatement, &myTail);
593+
if (myResult==SQLITE_OK)
594+
{
595+
if( sqlite3_step(myPreparedStatement)!=SQLITE_DONE )
596+
{
597+
sqlite3_finalize(myPreparedStatement);
598+
sqlite3_close(myDatabase);
599+
return tr("The style table could not be created.");
600+
}
601+
}
602+
603+
sqlite3_finalize(myPreparedStatement);
604+
605+
mySql = "insert into tbl_styles(style,qml) values (?,?)";
606+
myResult = sqlite3_prepare(myDatabase, mySql.toUtf8().data(), mySql.length(), &myPreparedStatement, &myTail);
607+
if (myResult==SQLITE_OK)
608+
{
609+
if( sqlite3_bind_text(myPreparedStatement, 1, param0.data(), param0.length(), SQLITE_STATIC)==SQLITE_OK &&
610+
sqlite3_bind_text(myPreparedStatement, 2, param1.data(), param1.length(), SQLITE_STATIC)==SQLITE_OK &&
611+
sqlite3_step(myPreparedStatement)==SQLITE_DONE )
612+
{
613+
theResultFlag = true;
614+
myErrorMessage = tr("The style %1 was saved to database").arg(theURI);
615+
}
616+
}
617+
618+
sqlite3_finalize(myPreparedStatement);
619+
620+
if(!theResultFlag)
621+
{
622+
QString mySql = "update tbl_styles set qml=? where style=?";
623+
myResult = sqlite3_prepare(myDatabase, mySql.toUtf8().data(), mySql.length(), &myPreparedStatement, &myTail);
624+
if (myResult==SQLITE_OK)
625+
{
626+
if( sqlite3_bind_text(myPreparedStatement, 2, param0.data(), param0.length(), SQLITE_STATIC)==SQLITE_OK &&
627+
sqlite3_bind_text(myPreparedStatement, 1, param1.data(), param1.length(), SQLITE_STATIC)==SQLITE_OK &&
628+
sqlite3_step(myPreparedStatement)==SQLITE_DONE )
629+
{
630+
theResultFlag = true;
631+
myErrorMessage = tr("The style %1 was updated in the database.").arg(theURI);
632+
}
633+
else
634+
{
635+
theResultFlag = true;
636+
myErrorMessage = tr("The style %1 could not be updated in the database.").arg(theURI);
637+
}
638+
}
639+
else
640+
{
641+
// try an update
642+
theResultFlag = false;
643+
myErrorMessage = tr("The style %1 could not be inserted into database.").arg(theURI);
644+
}
645+
646+
sqlite3_finalize(myPreparedStatement);
647+
}
648+
649+
sqlite3_close(myDatabase);
535650
}
651+
652+
return myErrorMessage;
536653
}

0 commit comments

Comments
 (0)