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
4142QgsMapLayer::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+
417423QString 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+
488524QString 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