]> vaikene.ee Git - evaf/blob - src/apps/PswGen/Storage/module.cpp
Mac OS changes
[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 mDb.close();
139 EVAF_INFO("%s finalized", qPrintable(objectName()));
140 }
141
142 bool StorageImpl::save(QString const & name, QExplicitlySharedDataPointer<Storage::Data> data)
143 {
144 EVAF_TEST_X(data, "Data cannot be null");
145 EVAF_TEST_X(!name.isEmpty(), "Name cannot be empty");
146
147 // Is it an update or a new data record?
148 if (mData.constFind(name) != mData.constEnd()) {
149 // This is an update
150 if (data->modified()) {
151 QSqlQuery q(mDb);
152 if (!q.exec(QString("UPDATE data SET suffix = \'%1\', length = \'%2\', flags = \'%3\' WHERE name = \'%4\';")
153 .arg(data->suffix()).arg(data->length()).arg(data->flags()).arg(name))) {
154 QSqlError err = mDb.lastError();
155 EVAF_ERROR("Failed to update \'%s\' : %s", qPrintable(name), qPrintable(err.text()));
156 return false;
157 }
158 }
159 }
160 else {
161 // Store to the database
162 QSqlQuery q(mDb);
163 if (!q.exec(QString("INSERT INTO data (name, suffix, length, flags) VALUES (\'%1\', \'%2\', %3, %4);")
164 .arg(name).arg(data->suffix()).arg(data->length())
165 .arg(int(data->flags())))) {
166 QSqlError err = mDb.lastError();
167 EVAF_ERROR("Failed to insert \'%s\' : %s", qPrintable(name), qPrintable(err.text()));
168 return false;
169 }
170
171 // Store also into the local hash
172 beginResetModel();
173 mData.insert(name, data);
174 endResetModel();
175
176 }
177
178 data->reset();
179
180 return true;
181 }
182
183 QExplicitlySharedDataPointer<Storage::Data> StorageImpl::query(QString const & name) const
184 {
185 QMap<QString, QExplicitlySharedDataPointer<Storage::Data> >::const_iterator it = mData.constFind(name);
186 if (it != mData.constEnd())
187 return it.value();
188 else
189 return QExplicitlySharedDataPointer<Storage::Data>();
190 }
191
192 QVariant StorageImpl::data(QModelIndex const & index, int role) const
193 {
194 if (!index.isValid() || index.row() < 0 || index.row() >= mData.size() || index.column() != 0)
195 return QVariant();
196
197 if (role == Qt::EditRole || role == Qt::DisplayRole)
198 return mData.keys().at(index.row());
199
200 return QVariant();
201 }
202
203 bool StorageImpl::createTables()
204 {
205 QSqlQuery q(mDb);
206 if (!q.exec("SELECT name FROM sqlite_master WHERE type=\'table\' AND name=\'data\';")) {
207 QSqlError err = mDb.lastError();
208 EVAF_ERROR("Failed to query database : %s", qPrintable(err.text()));
209 return false;
210 }
211
212 if (q.isActive() && q.isSelect() && q.first()) {
213 // Check if the table needs to be upgraded
214 return upgradeTables();
215 }
216
217 // Create the 'data' table
218 if (!q.exec("CREATE TABLE data (name text primary key not null, suffix text, length integer, flags integer);")) {
219 QSqlError err = mDb.lastError();
220 EVAF_ERROR("Failed to create table \'data\' : %s", qPrintable(err.text()));
221 return false;
222 }
223
224 return true;
225 }
226
227 bool StorageImpl::upgradeTables()
228 {
229 QSqlQuery q(mDb);
230
231 // Check if the 'suffix' column exists
232 if (q.exec("SELECT suffix from data;")) {
233 return true;
234 }
235
236 // Add the 'suffix' columnt
237 if (!q.exec("ALTER TABLE data ADD COLUMN suffix TEXT;")) {
238 QSqlError err = mDb.lastError();
239 EVAF_ERROR("Failed to upgrade table \'data\' : %s", qPrintable(err.text()));
240 return false;
241 }
242
243 return true;
244 }
245
246 bool StorageImpl::loadData()
247 {
248 QSqlQuery q(mDb);
249 if (!q.exec("SELECT name, suffix, length, flags FROM data;")) {
250 QSqlError err = mDb.lastError();
251 EVAF_ERROR("Failed to query database : %s", qPrintable(err.text()));
252 return false;
253 }
254
255 beginResetModel();
256 while (q.next()) {
257 QString name = q.value(0).toString();
258 QExplicitlySharedDataPointer<Storage::Data> data(
259 new Storage::Data(name, q.value(1).toString(), q.value(2).toInt(), uint(q.value(3).toInt())));
260 mData.insert(name, data);
261 }
262 endResetModel();
263
264 return true;
265 }