Merge branch 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-1 into master-integration
[qt-netbsd.git] / tools / assistant / lib / qhelpdbreader.cpp
blob904124b5bac2ea5e4b29d8b2aae37ebee1c63f63
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the Qt Assistant of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 #include "qhelpdbreader_p.h"
43 #include "qhelp_global.h"
45 #include <QtCore/QVariant>
46 #include <QtCore/QFile>
47 #include <QtSql/QSqlError>
48 #include <QtSql/QSqlQuery>
50 QT_BEGIN_NAMESPACE
52 QHelpDBReader::QHelpDBReader(const QString &dbName)
53 : QObject(0)
55 initObject(dbName,
56 QHelpGlobal::uniquifyConnectionName(QLatin1String("QHelpDBReader"),
57 this));
60 QHelpDBReader::QHelpDBReader(const QString &dbName, const QString &uniqueId,
61 QObject *parent)
62 : QObject(parent)
64 initObject(dbName, uniqueId);
67 void QHelpDBReader::initObject(const QString &dbName, const QString &uniqueId)
69 m_dbName = dbName;
70 m_uniqueId = uniqueId;
71 m_initDone = false;
72 m_query = 0;
73 m_useAttributesCache = false;
76 QHelpDBReader::~QHelpDBReader()
78 if (m_initDone) {
79 delete m_query;
80 QSqlDatabase::removeDatabase(m_uniqueId);
84 bool QHelpDBReader::init()
86 if (m_initDone)
87 return true;
89 if (!QFile::exists(m_dbName))
90 return false;
92 QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), m_uniqueId);
93 db.setDatabaseName(m_dbName);
94 if (!db.open()) {
95 /*: The placeholders are: %1 - The name of the database which cannot be opened
96 %2 - The unique id for the connection
97 %3 - The actual error string */
98 m_error = tr("Cannot open database '%1' '%2': %3").arg(m_dbName, m_uniqueId, db.lastError().text());
99 QSqlDatabase::removeDatabase(m_uniqueId);
100 return false;
103 m_initDone = true;
104 m_query = new QSqlQuery(db);
106 return true;
109 QString QHelpDBReader::databaseName() const
111 return m_dbName;
114 QString QHelpDBReader::errorMessage() const
116 return m_error;
119 QString QHelpDBReader::namespaceName() const
121 if (!m_namespace.isEmpty())
122 return m_namespace;
123 if (m_query) {
124 m_query->exec(QLatin1String("SELECT Name FROM NamespaceTable"));
125 if (m_query->next())
126 m_namespace = m_query->value(0).toString();
128 return m_namespace;
131 QString QHelpDBReader::virtualFolder() const
133 if (m_query) {
134 m_query->exec(QLatin1String("SELECT Name FROM FolderTable WHERE Id=1"));
135 if (m_query->next())
136 return m_query->value(0).toString();
138 return QString();
141 QList<QStringList> QHelpDBReader::filterAttributeSets() const
143 QList<QStringList> result;
144 if (m_query) {
145 m_query->exec(QLatin1String("SELECT a.Id, b.Name FROM FileAttributeSetTable a, "
146 "FilterAttributeTable b WHERE a.FilterAttributeId=b.Id ORDER BY a.Id"));
147 int oldId = -1;
148 while (m_query->next()) {
149 int id = m_query->value(0).toInt();
150 if (id != oldId) {
151 result.append(QStringList());
152 oldId = id;
154 result.last().append(m_query->value(1).toString());
157 return result;
160 bool QHelpDBReader::fileExists(const QString &virtualFolder,
161 const QString &filePath,
162 const QStringList &filterAttributes) const
164 if (virtualFolder.isEmpty() || filePath.isEmpty() || !m_query)
165 return false;
167 //SELECT COUNT(a.Name) FROM FileNameTable a, FolderTable b, FileFilterTable c, FilterAttributeTable d WHERE a.FolderId=b.Id AND b.Name='qtdoc' AND a.Name='qstring.html' AND a.FileId=c.FileId AND c.FilterAttributeId=d.Id AND d.Name='qtrefdoc'
169 QString query;
170 namespaceName();
171 if (filterAttributes.isEmpty()) {
172 query = QString(QLatin1String("SELECT COUNT(a.Name) FROM FileNameTable a, FolderTable b "
173 "WHERE a.FolderId=b.Id AND b.Name=\'%1\' AND a.Name=\'%2\'")).arg(quote(virtualFolder)).arg(quote(filePath));
174 } else {
175 query = QString(QLatin1String("SELECT COUNT(a.Name) FROM FileNameTable a, FolderTable b, "
176 "FileFilterTable c, FilterAttributeTable d WHERE a.FolderId=b.Id "
177 "AND b.Name=\'%1\' AND a.Name=\'%2\' AND a.FileId=c.FileId AND "
178 "c.FilterAttributeId=d.Id AND d.Name=\'%3\'"))
179 .arg(quote(virtualFolder)).arg(quote(filePath))
180 .arg(quote(filterAttributes.first()));
181 for (int i=1; i<filterAttributes.count(); ++i) {
182 query.append(QString(QLatin1String(" INTERSECT SELECT COUNT(a.Name) FROM FileNameTable a, "
183 "FolderTable b, FileFilterTable c, FilterAttributeTable d WHERE a.FolderId=b.Id "
184 "AND b.Name=\'%1\' AND a.Name=\'%2\' AND a.FileId=c.FileId AND "
185 "c.FilterAttributeId=d.Id AND d.Name=\'%3\'"))
186 .arg(quote(virtualFolder)).arg(quote(filePath))
187 .arg(quote(filterAttributes.at(i))));
190 m_query->exec(query);
191 if (m_query->next() && m_query->isValid() && m_query->value(0).toInt())
192 return true;
193 return false;
196 QByteArray QHelpDBReader::fileData(const QString &virtualFolder,
197 const QString &filePath) const
199 QByteArray ba;
200 if (virtualFolder.isEmpty() || filePath.isEmpty() || !m_query)
201 return ba;
203 namespaceName();
204 m_query->prepare(QLatin1String("SELECT a.Data FROM FileDataTable a, FileNameTable b, FolderTable c, "
205 "NamespaceTable d WHERE a.Id=b.FileId AND (b.Name=? OR b.Name=?) AND b.FolderId=c.Id "
206 "AND c.Name=? AND c.NamespaceId=d.Id AND d.Name=?"));
207 m_query->bindValue(0, filePath);
208 m_query->bindValue(1, QLatin1String("./") + filePath);
209 m_query->bindValue(2, virtualFolder);
210 m_query->bindValue(3, m_namespace);
211 m_query->exec();
212 if (m_query->next() && m_query->isValid())
213 ba = qUncompress(m_query->value(0).toByteArray());
214 return ba;
217 QStringList QHelpDBReader::customFilters() const
219 QStringList lst;
220 if (m_query) {
221 m_query->exec(QLatin1String("SELECT Name FROM FilterNameTable"));
222 while (m_query->next())
223 lst.append(m_query->value(0).toString());
225 return lst;
228 QStringList QHelpDBReader::filterAttributes(const QString &filterName) const
230 QStringList lst;
231 if (m_query) {
232 if (filterName.isEmpty()) {
233 m_query->prepare(QLatin1String("SELECT Name FROM FilterAttributeTable"));
234 } else {
235 m_query->prepare(QLatin1String("SELECT a.Name FROM FilterAttributeTable a, "
236 "FilterTable b, FilterNameTable c WHERE c.Name=? "
237 "AND c.Id=b.NameId AND b.FilterAttributeId=a.Id"));
238 m_query->bindValue(0, filterName);
240 m_query->exec();
241 while (m_query->next())
242 lst.append(m_query->value(0).toString());
244 return lst;
247 QStringList QHelpDBReader::indicesForFilter(const QStringList &filterAttributes) const
249 QStringList indices;
250 if (!m_query)
251 return indices;
253 //SELECT DISTINCT a.Name FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c WHERE a.Id=b.IndexId AND b.FilterAttributeId=c.Id AND c.Name in ('4.2.3', 'qt')
255 QString query;
256 if (filterAttributes.isEmpty()) {
257 query = QLatin1String("SELECT DISTINCT Name FROM IndexTable");
258 } else {
259 query = QString(QLatin1String("SELECT DISTINCT a.Name FROM IndexTable a, "
260 "IndexFilterTable b, FilterAttributeTable c WHERE a.Id=b.IndexId "
261 "AND b.FilterAttributeId=c.Id AND c.Name='%1'")).arg(quote(filterAttributes.first()));
262 for (int i=1; i<filterAttributes.count(); ++i) {
263 query.append(QString(QLatin1String(" INTERSECT SELECT DISTINCT a.Name FROM IndexTable a, "
264 "IndexFilterTable b, FilterAttributeTable c WHERE a.Id=b.IndexId "
265 "AND b.FilterAttributeId=c.Id AND c.Name='%1'"))
266 .arg(quote(filterAttributes.at(i))));
270 m_query->exec(query);
271 while (m_query->next()) {
272 if (!m_query->value(0).toString().isEmpty())
273 indices.append(m_query->value(0).toString());
275 return indices;
278 void QHelpDBReader::linksForKeyword(const QString &keyword, const QStringList &filterAttributes,
279 QMap<QString, QUrl> &linkMap) const
281 if (!m_query)
282 return;
284 QString query;
285 if (filterAttributes.isEmpty()) {
286 query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor "
287 "FROM IndexTable a, FileNameTable d, "
288 "FolderTable e, NamespaceTable f WHERE "
289 "a.FileId=d.FileId AND d.FolderId=e.Id AND a.NamespaceId=f.Id "
290 "AND a.Name='%1'")).arg(quote(keyword));
291 } else if (m_useAttributesCache) {
292 query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor, a.Id "
293 "FROM IndexTable a, "
294 "FileNameTable d, FolderTable e, NamespaceTable f WHERE "
295 "a.FileId=d.FileId AND d.FolderId=e.Id "
296 "AND a.NamespaceId=f.Id AND a.Name='%1'"))
297 .arg(quote(keyword));
298 m_query->exec(query);
299 while (m_query->next()) {
300 if (m_indicesCache.contains(m_query->value(5).toInt())) {
301 linkMap.insertMulti(m_query->value(0).toString(), buildQUrl(m_query->value(1).toString(),
302 m_query->value(2).toString(), m_query->value(3).toString(),
303 m_query->value(4).toString()));
306 return;
307 } else {
308 query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor "
309 "FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c, "
310 "FileNameTable d, FolderTable e, NamespaceTable f "
311 "WHERE a.FileId=d.FileId AND d.FolderId=e.Id "
312 "AND a.NamespaceId=f.Id AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id "
313 "AND a.Name='%1' AND c.Name='%2'")).arg(quote(keyword))
314 .arg(quote(filterAttributes.first()));
315 for (int i=1; i<filterAttributes.count(); ++i) {
316 query.append(QString(QLatin1String(" INTERSECT SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor "
317 "FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c, "
318 "FileNameTable d, FolderTable e, NamespaceTable f "
319 "WHERE a.FileId=d.FileId AND d.FolderId=e.Id "
320 "AND a.NamespaceId=f.Id AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id "
321 "AND a.Name='%1' AND c.Name='%2'")).arg(quote(keyword))
322 .arg(quote(filterAttributes.at(i))));
326 QString title;
327 m_query->exec(query);
328 while (m_query->next()) {
329 title = m_query->value(0).toString();
330 if (title.isEmpty()) // generate a title + corresponding path
331 title = keyword + QLatin1String(" : ") + m_query->value(3).toString();
332 linkMap.insertMulti(title, buildQUrl(m_query->value(1).toString(),
333 m_query->value(2).toString(), m_query->value(3).toString(),
334 m_query->value(4).toString()));
338 void QHelpDBReader::linksForIdentifier(const QString &id,
339 const QStringList &filterAttributes,
340 QMap<QString, QUrl> &linkMap) const
342 if (!m_query)
343 return;
345 QString query;
346 if (filterAttributes.isEmpty()) {
347 query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor "
348 "FROM IndexTable a, FileNameTable d, FolderTable e, "
349 "NamespaceTable f WHERE a.FileId=d.FileId AND "
350 "d.FolderId=e.Id AND a.NamespaceId=f.Id AND a.Identifier='%1'"))
351 .arg(quote(id));
352 } else if (m_useAttributesCache) {
353 query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor, a.Id "
354 "FROM IndexTable a,"
355 "FileNameTable d, FolderTable e, NamespaceTable f WHERE "
356 "a.FileId=d.FileId AND d.FolderId=e.Id "
357 "AND a.NamespaceId=f.Id AND a.Identifier='%1'"))
358 .arg(quote(id));
359 m_query->exec(query);
360 while (m_query->next()) {
361 if (m_indicesCache.contains(m_query->value(5).toInt())) {
362 linkMap.insertMulti(m_query->value(0).toString(), buildQUrl(m_query->value(1).toString(),
363 m_query->value(2).toString(), m_query->value(3).toString(),
364 m_query->value(4).toString()));
367 return;
368 } else {
369 query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor "
370 "FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c, "
371 "FileNameTable d, FolderTable e, NamespaceTable f "
372 "WHERE a.FileId=d.FileId AND d.FolderId=e.Id "
373 "AND a.NamespaceId=f.Id AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id "
374 "AND a.Identifier='%1' AND c.Name='%2'")).arg(quote(id))
375 .arg(quote(filterAttributes.first()));
376 for (int i=0; i<filterAttributes.count(); ++i) {
377 query.append(QString(QLatin1String(" INTERSECT SELECT d.Title, f.Name, e.Name, "
378 "d.Name, a.Anchor FROM IndexTable a, IndexFilterTable b, "
379 "FilterAttributeTable c, FileNameTable d, "
380 "FolderTable e, NamespaceTable f WHERE "
381 "a.FileId=d.FileId AND d.FolderId=e.Id AND a.NamespaceId=f.Id "
382 "AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id AND "
383 "a.Identifier='%1' AND c.Name='%2'")).arg(quote(id))
384 .arg(quote(filterAttributes.at(i))));
388 m_query->exec(query);
389 while (m_query->next()) {
390 linkMap.insertMulti(m_query->value(0).toString(), buildQUrl(m_query->value(1).toString(),
391 m_query->value(2).toString(), m_query->value(3).toString(),
392 m_query->value(4).toString()));
396 QUrl QHelpDBReader::buildQUrl(const QString &ns, const QString &folder,
397 const QString &relFileName, const QString &anchor) const
399 QUrl url;
400 url.setScheme(QLatin1String("qthelp"));
401 url.setAuthority(ns);
402 url.setPath(folder + QLatin1Char('/') + relFileName);
403 url.setFragment(anchor);
404 return url;
407 QList<QByteArray> QHelpDBReader::contentsForFilter(const QStringList &filterAttributes) const
409 QList<QByteArray> contents;
410 if (!m_query)
411 return contents;
413 //SELECT DISTINCT a.Data FROM ContentsTable a, ContentsFilterTable b, FilterAttributeTable c WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id AND c.Name='qt' INTERSECT SELECT DISTINCT a.Data FROM ContentsTable a, ContentsFilterTable b, FilterAttributeTable c WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id AND c.Name='3.3.8';
415 QString query;
416 if (filterAttributes.isEmpty()) {
417 query = QLatin1String("SELECT Data from ContentsTable");
418 } else {
419 query = QString(QLatin1String("SELECT a.Data FROM ContentsTable a, "
420 "ContentsFilterTable b, FilterAttributeTable c "
421 "WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id "
422 "AND c.Name='%1'")).arg(quote(filterAttributes.first()));
423 for (int i=1; i<filterAttributes.count(); ++i) {
424 query.append(QString(QLatin1String(" INTERSECT SELECT a.Data FROM ContentsTable a, "
425 "ContentsFilterTable b, FilterAttributeTable c "
426 "WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id "
427 "AND c.Name='%1'")).arg(quote(filterAttributes.at(i))));
431 m_query->exec(query);
432 while (m_query->next()) {
433 contents.append(m_query->value(0).toByteArray());
435 return contents;
438 QUrl QHelpDBReader::urlOfPath(const QString &relativePath) const
440 QUrl url;
441 if (!m_query)
442 return url;
444 m_query->exec(QLatin1String("SELECT a.Name, b.Name FROM NamespaceTable a, "
445 "FolderTable b WHERE a.id=b.NamespaceId and a.Id=1"));
446 if (m_query->next()) {
447 QString rp = relativePath;
448 QString anchor;
449 int i = rp.indexOf(QLatin1Char('#'));
450 if (i > -1) {
451 rp = relativePath.left(i);
452 anchor = relativePath.mid(i+1);
454 url = buildQUrl(m_query->value(0).toString(),
455 m_query->value(1).toString(), rp, anchor);
457 return url;
460 QStringList QHelpDBReader::files(const QStringList &filterAttributes,
461 const QString &extensionFilter) const
463 QStringList lst;
464 if (!m_query)
465 return lst;
467 QString query;
468 QString extension;
469 if (!extensionFilter.isEmpty())
470 extension = QString(QLatin1String("AND b.Name like \'%.%1\'")).arg(extensionFilter);
472 if (filterAttributes.isEmpty()) {
473 query = QString(QLatin1String("SELECT a.Name, b.Name FROM FolderTable a, "
474 "FileNameTable b WHERE b.FolderId=a.Id %1"))
475 .arg(extension);
476 } else {
477 query = QString(QLatin1String("SELECT a.Name, b.Name FROM FolderTable a, "
478 "FileNameTable b, FileFilterTable c, FilterAttributeTable d "
479 "WHERE b.FolderId=a.Id AND b.FileId=c.FileId "
480 "AND c.FilterAttributeId=d.Id AND d.Name=\'%1\' %2"))
481 .arg(quote(filterAttributes.first())).arg(extension);
482 for (int i=1; i<filterAttributes.count(); ++i) {
483 query.append(QString(QLatin1String(" INTERSECT SELECT a.Name, b.Name FROM "
484 "FolderTable a, FileNameTable b, FileFilterTable c, "
485 "FilterAttributeTable d WHERE b.FolderId=a.Id AND "
486 "b.FileId=c.FileId AND c.FilterAttributeId=d.Id AND "
487 "d.Name=\'%1\' %2")).arg(quote(filterAttributes.at(i)))
488 .arg(extension));
491 m_query->exec(query);
492 while (m_query->next()) {
493 lst.append(m_query->value(0).toString() + QLatin1Char('/')
494 + m_query->value(1).toString());
497 return lst;
500 QVariant QHelpDBReader::metaData(const QString &name) const
502 QVariant v;
503 if (!m_query)
504 return v;
506 m_query->prepare(QLatin1String("SELECT COUNT(Value), Value FROM MetaDataTable "
507 "WHERE Name=?"));
508 m_query->bindValue(0, name);
509 if (m_query->exec() && m_query->next()
510 && m_query->value(0).toInt() == 1)
511 v = m_query->value(1);
512 return v;
515 QString QHelpDBReader::mergeList(const QStringList &list) const
517 QString str;
518 foreach (QString s, list)
519 str.append(QLatin1Char('\'') + quote(s) + QLatin1String("\', "));
520 if (str.endsWith(QLatin1String(", ")))
521 str = str.left(str.length()-2);
522 return str;
525 QString QHelpDBReader::quote(const QString &string) const
527 QString s = string;
528 s.replace(QLatin1Char('\''), QLatin1String("\'\'"));
529 return s;
532 QSet<int> QHelpDBReader::indexIds(const QStringList &attributes) const
534 QSet<int> ids;
536 if (attributes.isEmpty())
537 return ids;
539 QString query = QString(QLatin1String("SELECT a.IndexId FROM IndexFilterTable a, "
540 "FilterAttributeTable b WHERE a.FilterAttributeId=b.Id "
541 "AND b.Name='%1'")).arg(attributes.first());
542 for (int i=0; i<attributes.count(); ++i) {
543 query.append(QString(QLatin1String(" INTERSECT SELECT a.IndexId FROM "
544 "IndexFilterTable a, FilterAttributeTable b WHERE "
545 "a.FilterAttributeId=b.Id AND b.Name='%1'"))
546 .arg(attributes.at(i)));
549 if (!m_query->exec(query))
550 return ids;
552 while (m_query->next())
553 ids.insert(m_query->value(0).toInt());
555 return ids;
558 bool QHelpDBReader::createAttributesCache(const QStringList &attributes,
559 const QSet<int> &indexIds)
561 m_useAttributesCache = false;
563 if (attributes.count() < 2) {
564 m_viewAttributes.clear();
565 return true;
568 bool needUpdate = !m_viewAttributes.count();
570 foreach (QString s, attributes)
571 m_viewAttributes.remove(s);
573 if (m_viewAttributes.count() || needUpdate) {
574 m_viewAttributes.clear();
575 m_indicesCache = indexIds;
577 foreach (QString s, attributes)
578 m_viewAttributes.insert(s);
579 m_useAttributesCache = true;
580 return true;
583 QT_END_NAMESPACE