2 * @file PswGen/Storage/module.cpp
3 * @brief Implementation of the iStorage interface
6 * Copyright (c) 2011-2012 Enar Vaikene
8 * This file is part of the eVaf C++ cross-platform application development framework.
10 * This file can be used under the terms of the GNU General Public License
11 * version 3.0 as published by the Free Software Foundation and appearing in
12 * the file LICENSE included in the packaging of this file. Please review the
13 * the following information to ensure the GNU General Public License version
14 * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
16 * Alternatively, this file may be used in accordance with the Commercial License
17 * Agreement provided with the Software.
22 #include <Common/Globals>
23 #include <Common/iLogger>
24 #include <Common/iRegistry>
25 #include <Common/iApp>
28 #include <QtSql/QtSql>
29 #include <QtSql/QSqlDatabase>
32 VER_EXPORT_VERSION_INFO()
35 using namespace eVaf::PswGen
;
36 using namespace eVaf::PswGen::Storage
;
38 //-------------------------------------------------------------------
44 setObjectName(QString("%1.%2").arg(VER_MODULE_NAME_STR
).arg(__FUNCTION__
));
46 mStorage
= new Internal::StorageImpl
;
48 EVAF_INFO("%s created", qPrintable(objectName()));
55 EVAF_INFO("%s destroyed", qPrintable(objectName()));
58 bool Module::init(QString
const & args
)
62 if (!mStorage
->init())
67 EVAF_INFO("%s initialized", qPrintable(objectName()));
78 EVAF_INFO("%s finalized", qPrintable(objectName()));
82 //-------------------------------------------------------------------
84 using namespace eVaf::PswGen::Storage::Internal
;
86 char const * const StorageImpl::DbConnectionName
= "PswGenDB";
88 char const * const StorageImpl::DbName
= "PswGen.sqlite";
90 StorageImpl::StorageImpl()
91 : QAbstractListModel()
93 setObjectName(QString("%1.iGenerator").arg(VER_MODULE_NAME_STR
));
95 EVAF_INFO("%s created", qPrintable(objectName()));
98 StorageImpl::~StorageImpl()
100 EVAF_INFO("%s destroyed", qPrintable(objectName()));
103 bool StorageImpl::init()
107 if (!QSqlDatabase::contains(DbConnectionName
)) {
108 // No database connection yet
109 db
= QSqlDatabase::addDatabase("QSQLITE", DbConnectionName
);
110 EVAF_INFO("Added database %s", DbConnectionName
);
111 db
.setDatabaseName(Common::iApp::instance()->dataRootDir() + DbName
);
113 QSqlError err
= db
.lastError();
114 EVAF_ERROR("Failed to open database : %s", qPrintable(err
.text()));
119 // Database connection already exists
120 db
= QSqlDatabase::database(DbConnectionName
);
123 // Create tables if necessary
124 if (!createTables(db
))
131 /// Register our interface
132 Common::iRegistry::instance()->registerInterface("iStorage", this);
134 EVAF_INFO("%s initialized", qPrintable(objectName()));
139 void StorageImpl::done()
142 if (QSqlDatabase::contains(DbConnectionName
))
144 QSqlDatabase::removeDatabase(DbConnectionName
);
145 EVAF_INFO("Removed database %s", DbConnectionName
);
147 EVAF_INFO("%s finalized", qPrintable(objectName()));
150 bool StorageImpl::save(QString
const & name
, QExplicitlySharedDataPointer
<Storage::Data
> data
)
152 EVAF_TEST_X(data
, "Data cannot be null");
153 EVAF_TEST_X(!name
.isEmpty(), "Name cannot be empty");
155 if (!QSqlDatabase::contains(DbConnectionName
))
157 EVAF_ERROR("Failed to get DB connection");
160 QSqlDatabase db
= QSqlDatabase::database(DbConnectionName
);
162 // Is it an update or a new data record?
163 if (mData
.constFind(name
) != mData
.constEnd()) {
165 if (data
->modified()) {
167 if (!q
.exec(QString("UPDATE data SET suffix = \'%1\', length = \'%2\', flags = \'%3\' WHERE name = \'%4\';")
168 .arg(data
->suffix()).arg(data
->length()).arg(data
->flags()).arg(name
))) {
169 QSqlError err
= db
.lastError();
170 EVAF_ERROR("Failed to update \'%s\' : %s", qPrintable(name
), qPrintable(err
.text()));
176 // Store to the database
178 if (!q
.exec(QString("INSERT INTO data (name, suffix, length, flags) VALUES (\'%1\', \'%2\', %3, %4);")
179 .arg(name
).arg(data
->suffix()).arg(data
->length())
180 .arg(int(data
->flags())))) {
181 QSqlError err
= db
.lastError();
182 EVAF_ERROR("Failed to insert \'%s\' : %s", qPrintable(name
), qPrintable(err
.text()));
186 // Store also into the local hash
188 mData
.insert(name
, data
);
198 QExplicitlySharedDataPointer
<Storage::Data
> StorageImpl::query(QString
const & name
) const
200 QMap
<QString
, QExplicitlySharedDataPointer
<Storage::Data
> >::const_iterator it
= mData
.constFind(name
);
201 if (it
!= mData
.constEnd())
204 return QExplicitlySharedDataPointer
<Storage::Data
>();
207 QVariant
StorageImpl::data(QModelIndex
const & index
, int role
) const
209 if (!index
.isValid() || index
.row() < 0 || index
.row() >= mData
.size() || index
.column() != 0)
212 if (role
== Qt::EditRole
|| role
== Qt::DisplayRole
)
213 return mData
.keys().at(index
.row());
218 bool StorageImpl::createTables(QSqlDatabase
& db
)
221 if (!q
.exec("SELECT name FROM sqlite_master WHERE type=\'table\' AND name=\'data\';")) {
222 QSqlError err
= db
.lastError();
223 EVAF_ERROR("Failed to query database : %s", qPrintable(err
.text()));
227 if (q
.isActive() && q
.isSelect() && q
.first()) {
228 // Check if the table needs to be upgraded
229 return upgradeTables(db
);
232 // Create the 'data' table
233 if (!q
.exec("CREATE TABLE data (name text primary key not null, suffix text, length integer, flags integer);")) {
234 QSqlError err
= db
.lastError();
235 EVAF_ERROR("Failed to create table \'data\' : %s", qPrintable(err
.text()));
242 bool StorageImpl::upgradeTables(QSqlDatabase
& db
)
246 // Check if the 'suffix' column exists
247 if (q
.exec("SELECT suffix from data;")) {
251 // Add the 'suffix' columnt
252 if (!q
.exec("ALTER TABLE data ADD COLUMN suffix TEXT;")) {
253 QSqlError err
= db
.lastError();
254 EVAF_ERROR("Failed to upgrade table \'data\' : %s", qPrintable(err
.text()));
261 bool StorageImpl::loadData(QSqlDatabase
& db
)
264 if (!q
.exec("SELECT name, suffix, length, flags FROM data;")) {
265 QSqlError err
= db
.lastError();
266 EVAF_ERROR("Failed to query database : %s", qPrintable(err
.text()));
272 QString name
= q
.value(0).toString();
273 QExplicitlySharedDataPointer
<Storage::Data
> data(
274 new Storage::Data(name
, q
.value(1).toString(), q
.value(2).toInt(), uint(q
.value(3).toInt())));
275 mData
.insert(name
, data
);