]> vaikene.ee Git - evaf/blob - src/apps/PswGen/Storage/module.cpp
Warning fixes and copyright update.
[evaf] / src / apps / PswGen / Storage / module.cpp
1 /**
2 * @file PswGen/Storage/module.cpp
3 * @brief Implementation of the iStorage interface
4 * @author Enar Vaikene
5 *
6 * Copyright (c) 2011-2019 Enar Vaikene
7 *
8 * This file is part of the eVaf C++ cross-platform application development framework.
9 *
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.
15 *
16 * Alternatively, this file may be used in accordance with the Commercial License
17 * Agreement provided with the Software.
18 */
19
20 #include "module.h"
21
22 #include <Common/Globals>
23 #include <Common/iLogger>
24 #include <Common/iRegistry>
25 #include <Common/iApp>
26
27 #include <QtCore>
28 #include <QtSql/QtSql>
29 #include <QtSql/QSqlDatabase>
30
31
32 VER_EXPORT_VERSION_INFO()
33
34 using namespace eVaf;
35 using namespace eVaf::PswGen;
36 using namespace eVaf::PswGen::Storage;
37
38 //-------------------------------------------------------------------
39
40 Module::Module()
41 : Plugins::iPlugin()
42 , mReady(false)
43 {
44 setObjectName(QString("%1.%2").arg(VER_MODULE_NAME_STR).arg(__FUNCTION__));
45
46 mStorage = new Internal::StorageImpl;
47
48 EVAF_INFO("%s created", qPrintable(objectName()));
49 }
50
51 Module::~Module()
52 {
53 delete mStorage;
54
55 EVAF_INFO("%s destroyed", qPrintable(objectName()));
56 }
57
58 bool Module::init(QString const & args)
59 {
60 Q_UNUSED(args)
61
62 if (!mStorage->init())
63 return false;
64
65 mReady = true;
66
67 EVAF_INFO("%s initialized", qPrintable(objectName()));
68
69 return true;
70 }
71
72 void Module::done()
73 {
74 mReady = false;
75
76 mStorage->done();
77
78 EVAF_INFO("%s finalized", qPrintable(objectName()));
79 }
80
81
82 //-------------------------------------------------------------------
83
84 using namespace eVaf::PswGen::Storage::Internal;
85
86 char const * const StorageImpl::DbConnectionName = "PswGenDB";
87
88 char const * const StorageImpl::DbName = "PswGen.sqlite";
89
90 StorageImpl::StorageImpl()
91 : QAbstractListModel()
92 {
93 setObjectName(QString("%1.iGenerator").arg(VER_MODULE_NAME_STR));
94
95 EVAF_INFO("%s created", qPrintable(objectName()));
96 }
97
98 StorageImpl::~StorageImpl()
99 {
100 EVAF_INFO("%s destroyed", qPrintable(objectName()));
101 }
102
103 bool StorageImpl::init()
104 {
105 // Open the database
106 QSqlDatabase db;
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);
112 if (!db.open()) {
113 QSqlError err = db.lastError();
114 EVAF_ERROR("Failed to open database : %s", qPrintable(err.text()));
115 return false;
116 }
117 }
118 else {
119 // Database connection already exists
120 db = QSqlDatabase::database(DbConnectionName);
121 }
122
123 // Create tables if necessary
124 if (!createTables(db))
125 return false;
126
127 // Load data
128 if (!loadData(db))
129 return false;
130
131 /// Register our interface
132 Common::iRegistry::instance()->registerInterface("iStorage", this);
133
134 EVAF_INFO("%s initialized", qPrintable(objectName()));
135
136 return true;
137 }
138
139 void StorageImpl::done()
140 {
141 mData.clear();
142 if (QSqlDatabase::contains(DbConnectionName))
143 {
144 QSqlDatabase::removeDatabase(DbConnectionName);
145 EVAF_INFO("Removed database %s", DbConnectionName);
146 }
147 EVAF_INFO("%s finalized", qPrintable(objectName()));
148 }
149
150 bool StorageImpl::save(QString const & name, QExplicitlySharedDataPointer<Storage::Data> data)
151 {
152 EVAF_TEST_X(data, "Data cannot be null")
153 EVAF_TEST_X(!name.isEmpty(), "Name cannot be empty")
154
155 if (!QSqlDatabase::contains(DbConnectionName))
156 {
157 EVAF_ERROR("Failed to get DB connection");
158 return false;
159 }
160 QSqlDatabase db = QSqlDatabase::database(DbConnectionName);
161
162 // Is it an update or a new data record?
163 if (mData.constFind(name) != mData.constEnd()) {
164 // This is an update
165 if (data->modified()) {
166 QSqlQuery q(db);
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()));
171 return false;
172 }
173 }
174 }
175 else {
176 // Store to the database
177 QSqlQuery q(db);
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()));
183 return false;
184 }
185
186 // Store also into the local hash
187 beginResetModel();
188 mData.insert(name, data);
189 endResetModel();
190
191 }
192
193 data->reset();
194
195 return true;
196 }
197
198 QExplicitlySharedDataPointer<Storage::Data> StorageImpl::query(QString const & name) const
199 {
200 QMap<QString, QExplicitlySharedDataPointer<Storage::Data> >::const_iterator it = mData.constFind(name);
201 if (it != mData.constEnd())
202 return it.value();
203 else
204 return QExplicitlySharedDataPointer<Storage::Data>();
205 }
206
207 QVariant StorageImpl::data(QModelIndex const & index, int role) const
208 {
209 if (!index.isValid() || index.row() < 0 || index.row() >= mData.size() || index.column() != 0)
210 return QVariant();
211
212 if (role == Qt::EditRole || role == Qt::DisplayRole)
213 return mData.keys().at(index.row());
214
215 return QVariant();
216 }
217
218 bool StorageImpl::createTables(QSqlDatabase & db)
219 {
220 QSqlQuery q(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()));
224 return false;
225 }
226
227 if (q.isActive() && q.isSelect() && q.first()) {
228 // Check if the table needs to be upgraded
229 return upgradeTables(db);
230 }
231
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()));
236 return false;
237 }
238
239 return true;
240 }
241
242 bool StorageImpl::upgradeTables(QSqlDatabase & db)
243 {
244 QSqlQuery q(db);
245
246 // Check if the 'suffix' column exists
247 if (q.exec("SELECT suffix from data;")) {
248 return true;
249 }
250
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()));
255 return false;
256 }
257
258 return true;
259 }
260
261 bool StorageImpl::loadData(QSqlDatabase & db)
262 {
263 QSqlQuery q(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()));
267 return false;
268 }
269
270 beginResetModel();
271 while (q.next()) {
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);
276 }
277 endResetModel();
278
279 return true;
280 }