]> vaikene.ee Git - evaf/blob - src/apps/PswGen/Storage/module.cpp
3c18b9a7cf64b3870eefa0b1aa9d0a16e357a623
[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-2012 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
30 VER_EXPORT_VERSION_INFO()
31
32 using namespace eVaf;
33 using namespace eVaf::PswGen;
34 using namespace eVaf::PswGen::Storage;
35
36 //-------------------------------------------------------------------
37
38 Module::Module()
39 : Plugins::iPlugin()
40 , mReady(false)
41 {
42 setObjectName(QString("%1.%2").arg(VER_MODULE_NAME_STR).arg(__FUNCTION__));
43
44 mStorage = new Internal::StorageImpl;
45
46 EVAF_INFO("%s created", qPrintable(objectName()));
47 }
48
49 Module::~Module()
50 {
51 delete mStorage;
52
53 EVAF_INFO("%s destroyed", qPrintable(objectName()));
54 }
55
56 bool Module::init(QString const & args)
57 {
58 Q_UNUSED(args);
59
60 if (!mStorage->init())
61 return false;
62
63 mReady = true;
64
65 EVAF_INFO("%s initialized", qPrintable(objectName()));
66
67 return true;
68 }
69
70 void Module::done()
71 {
72 mReady = false;
73
74 mStorage->done();
75
76 EVAF_INFO("%s finalized", qPrintable(objectName()));
77 }
78
79
80 //-------------------------------------------------------------------
81
82 using namespace eVaf::PswGen::Storage::Internal;
83
84 char const * const StorageImpl::DbConnectionName = "PswGenDB";
85
86 char const * const StorageImpl::DbName = "PswGen.sqlite";
87
88 StorageImpl::StorageImpl()
89 : QAbstractListModel()
90 {
91 setObjectName(QString("%1.iGenerator").arg(VER_MODULE_NAME_STR));
92
93 EVAF_INFO("%s created", qPrintable(objectName()));
94 }
95
96 StorageImpl::~StorageImpl()
97 {
98 EVAF_INFO("%s destroyed", qPrintable(objectName()));
99 }
100
101 bool StorageImpl::init()
102 {
103 // Open the database
104 if (!QSqlDatabase::contains(DbConnectionName)) {
105 // No database connection yet
106 mDb = QSqlDatabase::addDatabase("QSQLITE", DbConnectionName);
107 mDb.setDatabaseName(Common::iApp::instance()->dataRootDir() + DbName);
108 if (!mDb.open()) {
109 QSqlError err = mDb.lastError();
110 EVAF_ERROR("Failed to open database : %s", qPrintable(err.text()));
111 return false;
112 }
113 }
114 else {
115 // Database connection already exists
116 mDb = QSqlDatabase::database(DbConnectionName);
117 }
118
119 // Create tables if necessary
120 if (!createTables())
121 return false;
122
123 // Load data
124 if (!loadData())
125 return false;
126
127 /// Register our interface
128 Common::iRegistry::instance()->registerInterface("iStorage", this);
129
130 EVAF_INFO("%s initialized", qPrintable(objectName()));
131
132 return true;
133 }
134
135 void StorageImpl::done()
136 {
137 mData.clear();
138 EVAF_INFO("%s finalized", qPrintable(objectName()));
139 }
140
141 bool StorageImpl::save(QString const & name, QExplicitlySharedDataPointer<Storage::Data> data)
142 {
143 EVAF_TEST_X(data, "Data cannot be null");
144 EVAF_TEST_X(!name.isEmpty(), "Name cannot be empty");
145
146 // Is it an update or a new data record?
147 if (mData.constFind(name) != mData.constEnd()) {
148 // This is an update
149 if (data->modified()) {
150 QSqlQuery q(mDb);
151 if (!q.exec(QString("UPDATE data SET suffix = \'%1\', length = \'%2\', flags = \'%3\' WHERE name = \'%4\';")
152 .arg(data->suffix()).arg(data->length()).arg(data->flags()).arg(name))) {
153 QSqlError err = mDb.lastError();
154 EVAF_ERROR("Failed to update \'%s\' : %s", qPrintable(name), qPrintable(err.text()));
155 return false;
156 }
157 }
158 }
159 else {
160 // Store to the database
161 QSqlQuery q(mDb);
162 if (!q.exec(QString("INSERT INTO data (name, suffix, length, flags) VALUES (\'%1\', \'%2\', %3, %4);")
163 .arg(name).arg(data->suffix()).arg(data->length())
164 .arg(int(data->flags())))) {
165 QSqlError err = mDb.lastError();
166 EVAF_ERROR("Failed to insert \'%s\' : %s", qPrintable(name), qPrintable(err.text()));
167 return false;
168 }
169
170 // Store also into the local hash
171 beginResetModel();
172 mData.insert(name, data);
173 endResetModel();
174
175 }
176
177 data->reset();
178
179 return true;
180 }
181
182 QExplicitlySharedDataPointer<Storage::Data> StorageImpl::query(QString const & name) const
183 {
184 QMap<QString, QExplicitlySharedDataPointer<Storage::Data> >::const_iterator it = mData.constFind(name);
185 if (it != mData.constEnd())
186 return it.value();
187 else
188 return QExplicitlySharedDataPointer<Storage::Data>();
189 }
190
191 QVariant StorageImpl::data(QModelIndex const & index, int role) const
192 {
193 if (!index.isValid() || index.row() < 0 || index.row() >= mData.size() || index.column() != 0)
194 return QVariant();
195
196 if (role == Qt::EditRole || role == Qt::DisplayRole)
197 return mData.keys().at(index.row());
198
199 return QVariant();
200 }
201
202 bool StorageImpl::createTables()
203 {
204 QSqlQuery q(mDb);
205 if (!q.exec("SELECT name FROM sqlite_master WHERE type=\'table\' AND name=\'data\';")) {
206 QSqlError err = mDb.lastError();
207 EVAF_ERROR("Failed to query database : %s", qPrintable(err.text()));
208 return false;
209 }
210
211 if (q.isActive() && q.isSelect() && q.first()) {
212 // Check if the table needs to be upgraded
213 return upgradeTables();
214 }
215
216 // Create the 'data' table
217 if (!q.exec("CREATE TABLE data (name text primary key not null, suffix text, length integer, flags integer);")) {
218 QSqlError err = mDb.lastError();
219 EVAF_ERROR("Failed to create table \'data\' : %s", qPrintable(err.text()));
220 return false;
221 }
222
223 return true;
224 }
225
226 bool StorageImpl::upgradeTables()
227 {
228 QSqlQuery q(mDb);
229
230 // Check if the 'suffix' column exists
231 if (q.exec("SELECT suffix from data;")) {
232 return true;
233 }
234
235 // Add the 'suffix' columnt
236 if (!q.exec("ALTER TABLE data ADD COLUMN suffix TEXT;")) {
237 QSqlError err = mDb.lastError();
238 EVAF_ERROR("Failed to upgrade table \'data\' : %s", qPrintable(err.text()));
239 return false;
240 }
241
242 return true;
243 }
244
245 bool StorageImpl::loadData()
246 {
247 QSqlQuery q(mDb);
248 if (!q.exec("SELECT name, suffix, length, flags FROM data;")) {
249 QSqlError err = mDb.lastError();
250 EVAF_ERROR("Failed to query database : %s", qPrintable(err.text()));
251 return false;
252 }
253
254 beginResetModel();
255 while (q.next()) {
256 QString name = q.value(0).toString();
257 QExplicitlySharedDataPointer<Storage::Data> data(
258 new Storage::Data(name, q.value(1).toString(), q.value(2).toInt(), uint(q.value(3).toInt())));
259 mData.insert(name, data);
260 }
261 endResetModel();
262
263 return true;
264 }