source: trunk/tools/assistant/lib/qhelpcollectionhandler.cpp@ 987

Last change on this file since 987 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 19.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the Qt Assistant of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qhelpcollectionhandler_p.h"
43#include "qhelp_global.h"
44#include "qhelpdbreader_p.h"
45
46#include <QtCore/QFile>
47#include <QtCore/QDir>
48#include <QtCore/QFileInfo>
49#include <QtCore/QDebug>
50
51#include <QtSql/QSqlError>
52#include <QtSql/QSqlDriver>
53
54QT_BEGIN_NAMESPACE
55
56QHelpCollectionHandler::QHelpCollectionHandler(const QString &collectionFile, QObject *parent)
57 : QObject(parent)
58 , m_dbOpened(false)
59 , m_collectionFile(collectionFile)
60 , m_connectionName(QString())
61{
62 QFileInfo fi(m_collectionFile);
63 if (!fi.isAbsolute())
64 m_collectionFile = fi.absoluteFilePath();
65 m_query.clear();
66}
67
68QHelpCollectionHandler::~QHelpCollectionHandler()
69{
70 m_query.clear();
71 if (m_dbOpened)
72 QSqlDatabase::removeDatabase(m_connectionName);
73}
74
75bool QHelpCollectionHandler::isDBOpened()
76{
77 if (m_dbOpened)
78 return true;
79 emit error(tr("The collection file '%1' is not set up yet!").
80 arg(m_collectionFile));
81 return false;
82}
83
84QString QHelpCollectionHandler::collectionFile() const
85{
86 return m_collectionFile;
87}
88
89bool QHelpCollectionHandler::openCollectionFile()
90{
91 if (m_dbOpened)
92 return m_dbOpened;
93
94 m_connectionName = QHelpGlobal::uniquifyConnectionName(
95 QLatin1String("QHelpCollectionHandler"), this);
96 bool openingOk = true;
97 {
98 QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"),
99 m_connectionName);
100 if (db.driver()
101 && db.driver()->lastError().type() == QSqlError::ConnectionError) {
102 emit error(tr("Cannot load sqlite database driver!"));
103 return false;
104 }
105
106 db.setDatabaseName(collectionFile());
107 openingOk = db.open();
108 if (openingOk)
109 m_query = QSqlQuery(db);
110 }
111 if (!openingOk) {
112 QSqlDatabase::removeDatabase(m_connectionName);
113 emit error(tr("Cannot open collection file: %1").arg(collectionFile()));
114 return false;
115 }
116
117 m_query.exec(QLatin1String("PRAGMA synchronous=OFF"));
118 m_query.exec(QLatin1String("PRAGMA cache_size=3000"));
119
120 m_query.exec(QLatin1String("SELECT COUNT(*) FROM sqlite_master WHERE TYPE=\'table\'"
121 "AND Name=\'NamespaceTable\'"));
122 m_query.next();
123 if (m_query.value(0).toInt() < 1) {
124 if (!createTables(&m_query)) {
125 emit error(tr("Cannot create tables in file %1!").arg(collectionFile()));
126 return false;
127 }
128 }
129
130 m_dbOpened = true;
131 return m_dbOpened;
132}
133
134bool QHelpCollectionHandler::copyCollectionFile(const QString &fileName)
135{
136 if (!m_dbOpened)
137 return false;
138
139 QFileInfo fi(fileName);
140 if (fi.exists()) {
141 emit error(tr("The collection file '%1' already exists!").
142 arg(fileName));
143 return false;
144 }
145
146 if (!fi.absoluteDir().exists() && !QDir().mkpath(fi.absolutePath())) {
147 emit error(tr("Cannot create directory: %1").arg(fi.absolutePath()));
148 return false;
149 }
150
151 QString colFile = fi.absoluteFilePath();
152 QString connectionName = QHelpGlobal::uniquifyConnectionName(
153 QLatin1String("QHelpCollectionHandlerCopy"), this);
154 QSqlQuery *copyQuery = 0;
155 bool openingOk = true;
156 {
157 QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), connectionName);
158 db.setDatabaseName(colFile);
159 openingOk = db.open();
160 if (openingOk)
161 copyQuery = new QSqlQuery(db);
162 }
163
164 if (!openingOk) {
165 emit error(tr("Cannot open collection file: %1").arg(colFile));
166 return false;
167 }
168
169 copyQuery->exec(QLatin1String("PRAGMA synchronous=OFF"));
170 copyQuery->exec(QLatin1String("PRAGMA cache_size=3000"));
171
172 if (!createTables(copyQuery)) {
173 emit error(tr("Cannot copy collection file: %1").arg(colFile));
174 return false;
175 }
176
177 QString oldBaseDir = QFileInfo(collectionFile()).absolutePath();
178 QString oldFilePath;
179 QFileInfo newColFi(colFile);
180 m_query.exec(QLatin1String("SELECT Name, FilePath FROM NamespaceTable"));
181 while (m_query.next()) {
182 copyQuery->prepare(QLatin1String("INSERT INTO NamespaceTable VALUES(NULL, ?, ?)"));
183 copyQuery->bindValue(0, m_query.value(0).toString());
184 oldFilePath = m_query.value(1).toString();
185 if (!QDir::isAbsolutePath(oldFilePath))
186 oldFilePath = oldBaseDir + QDir::separator() + oldFilePath;
187 copyQuery->bindValue(1, newColFi.absoluteDir().relativeFilePath(oldFilePath));
188 copyQuery->exec();
189 }
190
191 m_query.exec(QLatin1String("SELECT NamespaceId, Name FROM FolderTable"));
192 while (m_query.next()) {
193 copyQuery->prepare(QLatin1String("INSERT INTO FolderTable VALUES(NULL, ?, ?)"));
194 copyQuery->bindValue(0, m_query.value(0).toString());
195 copyQuery->bindValue(1, m_query.value(1).toString());
196 copyQuery->exec();
197 }
198
199 m_query.exec(QLatin1String("SELECT Name FROM FilterAttributeTable"));
200 while (m_query.next()) {
201 copyQuery->prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)"));
202 copyQuery->bindValue(0, m_query.value(0).toString());
203 copyQuery->exec();
204 }
205
206 m_query.exec(QLatin1String("SELECT Name FROM FilterNameTable"));
207 while (m_query.next()) {
208 copyQuery->prepare(QLatin1String("INSERT INTO FilterNameTable VALUES(NULL, ?)"));
209 copyQuery->bindValue(0, m_query.value(0).toString());
210 copyQuery->exec();
211 }
212
213 m_query.exec(QLatin1String("SELECT NameId, FilterAttributeId FROM FilterTable"));
214 while (m_query.next()) {
215 copyQuery->prepare(QLatin1String("INSERT INTO FilterTable VALUES(?, ?)"));
216 copyQuery->bindValue(0, m_query.value(0).toInt());
217 copyQuery->bindValue(1, m_query.value(1).toInt());
218 copyQuery->exec();
219 }
220
221 m_query.exec(QLatin1String("SELECT Key, Value FROM SettingsTable"));
222 while (m_query.next()) {
223 if (m_query.value(0).toString() == QLatin1String("CluceneSearchNamespaces"))
224 continue;
225 copyQuery->prepare(QLatin1String("INSERT INTO SettingsTable VALUES(?, ?)"));
226 copyQuery->bindValue(0, m_query.value(0).toString());
227 copyQuery->bindValue(1, m_query.value(1));
228 copyQuery->exec();
229 }
230
231 copyQuery->clear();
232 delete copyQuery;
233 QSqlDatabase::removeDatabase(connectionName);
234 return true;
235}
236
237bool QHelpCollectionHandler::createTables(QSqlQuery *query)
238{
239 QStringList tables;
240 tables << QLatin1String("CREATE TABLE NamespaceTable ("
241 "Id INTEGER PRIMARY KEY, "
242 "Name TEXT, "
243 "FilePath TEXT )")
244 << QLatin1String("CREATE TABLE FolderTable ("
245 "Id INTEGER PRIMARY KEY, "
246 "NamespaceId INTEGER, "
247 "Name TEXT )")
248 << QLatin1String("CREATE TABLE FilterAttributeTable ("
249 "Id INTEGER PRIMARY KEY, "
250 "Name TEXT )")
251 << QLatin1String("CREATE TABLE FilterNameTable ("
252 "Id INTEGER PRIMARY KEY, "
253 "Name TEXT )")
254 << QLatin1String("CREATE TABLE FilterTable ("
255 "NameId INTEGER, "
256 "FilterAttributeId INTEGER )")
257 << QLatin1String("CREATE TABLE SettingsTable ("
258 "Key TEXT PRIMARY KEY, "
259 "Value BLOB )");
260
261 foreach (const QString &q, tables) {
262 if (!query->exec(q))
263 return false;
264 }
265 return true;
266}
267
268QStringList QHelpCollectionHandler::customFilters() const
269{
270 QStringList list;
271 if (m_dbOpened) {
272 m_query.exec(QLatin1String("SELECT Name FROM FilterNameTable"));
273 while (m_query.next())
274 list.append(m_query.value(0).toString());
275 }
276 return list;
277}
278
279bool QHelpCollectionHandler::removeCustomFilter(const QString &filterName)
280{
281 if (!isDBOpened() || filterName.isEmpty())
282 return false;
283
284 int filterNameId = -1;
285 m_query.prepare(QLatin1String("SELECT Id FROM FilterNameTable WHERE Name=?"));
286 m_query.bindValue(0, filterName);
287 m_query.exec();
288 if (m_query.next())
289 filterNameId = m_query.value(0).toInt();
290
291 if (filterNameId < 0) {
292 emit error(tr("Unknown filter '%1'!").arg(filterName));
293 return false;
294 }
295
296 m_query.prepare(QLatin1String("DELETE FROM FilterTable WHERE NameId=?"));
297 m_query.bindValue(0, filterNameId);
298 m_query.exec();
299
300 m_query.prepare(QLatin1String("DELETE FROM FilterNameTable WHERE Id=?"));
301 m_query.bindValue(0, filterNameId);
302 m_query.exec();
303
304 return true;
305}
306
307bool QHelpCollectionHandler::addCustomFilter(const QString &filterName,
308 const QStringList &attributes)
309{
310 if (!isDBOpened() || filterName.isEmpty())
311 return false;
312
313 int nameId = -1;
314 m_query.prepare(QLatin1String("SELECT Id FROM FilterNameTable WHERE Name=?"));
315 m_query.bindValue(0, filterName);
316 m_query.exec();
317 if (m_query.next())
318 nameId = m_query.value(0).toInt();
319
320 m_query.exec(QLatin1String("SELECT Id, Name FROM FilterAttributeTable"));
321 QStringList idsToInsert = attributes;
322 QMap<QString, int> attributeMap;
323 while (m_query.next()) {
324 attributeMap.insert(m_query.value(1).toString(),
325 m_query.value(0).toInt());
326 if (idsToInsert.contains(m_query.value(1).toString()))
327 idsToInsert.removeAll(m_query.value(1).toString());
328 }
329
330 foreach (const QString &id, idsToInsert) {
331 m_query.prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)"));
332 m_query.bindValue(0, id);
333 m_query.exec();
334 attributeMap.insert(id, m_query.lastInsertId().toInt());
335 }
336
337 if (nameId < 0) {
338 m_query.prepare(QLatin1String("INSERT INTO FilterNameTable VALUES(NULL, ?)"));
339 m_query.bindValue(0, filterName);
340 if (m_query.exec())
341 nameId = m_query.lastInsertId().toInt();
342 }
343
344 if (nameId < 0) {
345 emit error(tr("Cannot register filter %1!").arg(filterName));
346 return false;
347 }
348
349 m_query.prepare(QLatin1String("DELETE FROM FilterTable WHERE NameId=?"));
350 m_query.bindValue(0, nameId);
351 m_query.exec();
352
353 foreach (const QString &att, attributes) {
354 m_query.prepare(QLatin1String("INSERT INTO FilterTable VALUES(?, ?)"));
355 m_query.bindValue(0, nameId);
356 m_query.bindValue(1, attributeMap[att]);
357 if (!m_query.exec())
358 return false;
359 }
360 return true;
361}
362
363QHelpCollectionHandler::DocInfoList QHelpCollectionHandler::registeredDocumentations() const
364{
365 DocInfoList list;
366 if (m_dbOpened) {
367 m_query.exec(QLatin1String("SELECT a.Name, a.FilePath, b.Name "
368 "FROM NamespaceTable a, FolderTable b WHERE a.Id=b.NamespaceId"));
369
370 while (m_query.next()) {
371 DocInfo info;
372 info.fileName = m_query.value(1).toString();
373 info.folderName = m_query.value(2).toString();
374 info.namespaceName = m_query.value(0).toString();
375 list.append(info);
376 }
377 }
378 return list;
379}
380
381bool QHelpCollectionHandler::registerDocumentation(const QString &fileName)
382{
383 if (!isDBOpened())
384 return false;
385
386 QHelpDBReader reader(fileName, QHelpGlobal::uniquifyConnectionName(
387 QLatin1String("QHelpCollectionHandler"), this), 0);
388 if (!reader.init()) {
389 emit error(tr("Cannot open documentation file %1!").arg(fileName));
390 return false;
391 }
392
393 QString ns = reader.namespaceName();
394 if (ns.isEmpty()) {
395 emit error(tr("Invalid documentation file '%1'!").arg(fileName));
396 return false;
397 }
398
399 int nsId = registerNamespace(ns, fileName);
400 if (nsId < 1)
401 return false;
402
403 if (!registerVirtualFolder(reader.virtualFolder(), nsId))
404 return false;
405
406 addFilterAttributes(reader.filterAttributes());
407 foreach (const QString &filterName, reader.customFilters())
408 addCustomFilter(filterName, reader.filterAttributes(filterName));
409
410 optimizeDatabase(fileName);
411
412 return true;
413}
414
415bool QHelpCollectionHandler::unregisterDocumentation(const QString &namespaceName)
416{
417 if (!isDBOpened())
418 return false;
419
420 m_query.prepare(QLatin1String("SELECT Id FROM NamespaceTable WHERE Name=?"));
421 m_query.bindValue(0, namespaceName);
422 m_query.exec();
423
424 int nsId = -1;
425 if (m_query.next())
426 nsId = m_query.value(0).toInt();
427
428 if (nsId < 0) {
429 emit error(tr("The namespace %1 was not registered!").arg(namespaceName));
430 return false;
431 }
432
433 m_query.prepare(QLatin1String("DELETE FROM NamespaceTable WHERE Id=?"));
434 m_query.bindValue(0, nsId);
435 m_query.exec();
436
437 m_query.prepare(QLatin1String("DELETE FROM FolderTable WHERE NamespaceId=?"));
438 m_query.bindValue(0, nsId);
439 return m_query.exec();
440}
441
442bool QHelpCollectionHandler::removeCustomValue(const QString &key)
443{
444 if (!isDBOpened())
445 return false;
446
447 m_query.prepare(QLatin1String("DELETE FROM SettingsTable WHERE Key=?"));
448 m_query.bindValue(0, key);
449 return m_query.exec();
450}
451
452QVariant QHelpCollectionHandler::customValue(const QString &key,
453 const QVariant &defaultValue) const
454{
455 QVariant value = defaultValue;
456 if (m_dbOpened) {
457 m_query.prepare(QLatin1String("SELECT COUNT(Key) FROM SettingsTable WHERE Key=?"));
458 m_query.bindValue(0, key);
459 if (!m_query.exec() || !m_query.next() || !m_query.value(0).toInt()) {
460 m_query.clear();
461 return defaultValue;
462 }
463
464 m_query.clear();
465 m_query.prepare(QLatin1String("SELECT Value FROM SettingsTable WHERE Key=?"));
466 m_query.bindValue(0, key);
467 if (m_query.exec() && m_query.next())
468 value = m_query.value(0);
469 m_query.clear();
470 }
471 return value;
472}
473
474bool QHelpCollectionHandler::setCustomValue(const QString &key,
475 const QVariant &value)
476{
477 if (!isDBOpened())
478 return false;
479
480 m_query.prepare(QLatin1String("SELECT Value FROM SettingsTable WHERE Key=?"));
481 m_query.bindValue(0, key);
482 m_query.exec();
483 if (m_query.next()) {
484 m_query.prepare(QLatin1String("UPDATE SettingsTable SET Value=? where Key=?"));
485 m_query.bindValue(0, value);
486 m_query.bindValue(1, key);
487 }
488 else {
489 m_query.prepare(QLatin1String("INSERT INTO SettingsTable VALUES(?, ?)"));
490 m_query.bindValue(0, key);
491 m_query.bindValue(1, value);
492 }
493 return m_query.exec();
494}
495
496bool QHelpCollectionHandler::addFilterAttributes(const QStringList &attributes)
497{
498 if (!isDBOpened())
499 return false;
500
501 m_query.exec(QLatin1String("SELECT Name FROM FilterAttributeTable"));
502 QSet<QString> atts;
503 while (m_query.next())
504 atts.insert(m_query.value(0).toString());
505
506 foreach (const QString &s, attributes) {
507 if (!atts.contains(s)) {
508 m_query.prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)"));
509 m_query.bindValue(0, s);
510 m_query.exec();
511 }
512 }
513 return true;
514}
515
516QStringList QHelpCollectionHandler::filterAttributes() const
517{
518 QStringList list;
519 if (m_dbOpened) {
520 m_query.exec(QLatin1String("SELECT Name FROM FilterAttributeTable"));
521 while (m_query.next())
522 list.append(m_query.value(0).toString());
523 }
524 return list;
525}
526
527QStringList QHelpCollectionHandler::filterAttributes(const QString &filterName) const
528{
529 QStringList list;
530 if (m_dbOpened) {
531 m_query.prepare(QLatin1String("SELECT a.Name FROM FilterAttributeTable a, "
532 "FilterTable b, FilterNameTable c WHERE a.Id=b.FilterAttributeId "
533 "AND b.NameId=c.Id AND c.Name=?"));
534 m_query.bindValue(0, filterName);
535 m_query.exec();
536 while (m_query.next())
537 list.append(m_query.value(0).toString());
538 }
539 return list;
540}
541
542int QHelpCollectionHandler::registerNamespace(const QString &nspace, const QString &fileName)
543{
544 m_query.prepare(QLatin1String("SELECT COUNT(Id) FROM NamespaceTable WHERE Name=?"));
545 m_query.bindValue(0, nspace);
546 m_query.exec();
547 while (m_query.next()) {
548 if (m_query.value(0).toInt() > 0) {
549 emit error(tr("Namespace %1 already exists!").arg(nspace));
550 return -1;
551 }
552 }
553
554 QFileInfo fi(m_collectionFile);
555 m_query.prepare(QLatin1String("INSERT INTO NamespaceTable VALUES(NULL, ?, ?)"));
556 m_query.bindValue(0, nspace);
557 m_query.bindValue(1, fi.absoluteDir().relativeFilePath(fileName));
558 int namespaceId = -1;
559 if (m_query.exec())
560 namespaceId = m_query.lastInsertId().toInt();
561 if (namespaceId < 1) {
562 emit error(tr("Cannot register namespace '%1'!").arg(nspace));
563 return -1;
564 }
565 return namespaceId;
566}
567
568bool QHelpCollectionHandler::registerVirtualFolder(const QString &folderName, int namespaceId)
569{
570 m_query.prepare(QLatin1String("INSERT INTO FolderTable VALUES(NULL, ?, ?)"));
571 m_query.bindValue(0, namespaceId);
572 m_query.bindValue(1, folderName);
573 return m_query.exec();
574}
575
576void QHelpCollectionHandler::optimizeDatabase(const QString &fileName)
577{
578 if (!QFile::exists(fileName))
579 return;
580
581 { // according to removeDatabase() documentation
582 QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), QLatin1String("optimize"));
583 db.setDatabaseName(fileName);
584 if (!db.open()) {
585 QSqlDatabase::removeDatabase(QLatin1String("optimize"));
586 emit error(tr("Cannot open database '%1' to optimize!").arg(fileName));
587 return;
588 }
589
590 QSqlQuery query(db);
591 db.exec(QLatin1String("PRAGMA synchronous=OFF"));
592 db.exec(QLatin1String("PRAGMA cache_size=3000"));
593 db.exec(QLatin1String("CREATE INDEX IF NOT EXISTS NameIndex ON IndexTable(Name)"));
594 db.exec(QLatin1String("CREATE INDEX IF NOT EXISTS FileNameIndex ON FileNameTable(Name)"));
595 db.exec(QLatin1String("CREATE INDEX IF NOT EXISTS FileIdIndex ON FileNameTable(FileId)"));
596
597 db.close();
598 }
599
600 QSqlDatabase::removeDatabase(QLatin1String("optimize"));
601}
602
603QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.