1 /****************************************************************************
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the Qt Assistant of the Qt Toolkit.
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
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.
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>
52 QHelpDBReader::QHelpDBReader(const QString
&dbName
)
56 QHelpGlobal::uniquifyConnectionName(QLatin1String("QHelpDBReader"),
60 QHelpDBReader::QHelpDBReader(const QString
&dbName
, const QString
&uniqueId
,
64 initObject(dbName
, uniqueId
);
67 void QHelpDBReader::initObject(const QString
&dbName
, const QString
&uniqueId
)
70 m_uniqueId
= uniqueId
;
73 m_useAttributesCache
= false;
76 QHelpDBReader::~QHelpDBReader()
80 QSqlDatabase::removeDatabase(m_uniqueId
);
84 bool QHelpDBReader::init()
89 if (!QFile::exists(m_dbName
))
92 QSqlDatabase db
= QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), m_uniqueId
);
93 db
.setDatabaseName(m_dbName
);
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
);
104 m_query
= new QSqlQuery(db
);
109 QString
QHelpDBReader::databaseName() const
114 QString
QHelpDBReader::errorMessage() const
119 QString
QHelpDBReader::namespaceName() const
121 if (!m_namespace
.isEmpty())
124 m_query
->exec(QLatin1String("SELECT Name FROM NamespaceTable"));
126 m_namespace
= m_query
->value(0).toString();
131 QString
QHelpDBReader::virtualFolder() const
134 m_query
->exec(QLatin1String("SELECT Name FROM FolderTable WHERE Id=1"));
136 return m_query
->value(0).toString();
141 QList
<QStringList
> QHelpDBReader::filterAttributeSets() const
143 QList
<QStringList
> result
;
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"));
148 while (m_query
->next()) {
149 int id
= m_query
->value(0).toInt();
151 result
.append(QStringList());
154 result
.last().append(m_query
->value(1).toString());
160 bool QHelpDBReader::fileExists(const QString
&virtualFolder
,
161 const QString
&filePath
,
162 const QStringList
&filterAttributes
) const
164 if (virtualFolder
.isEmpty() || filePath
.isEmpty() || !m_query
)
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'
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
));
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())
196 QByteArray
QHelpDBReader::fileData(const QString
&virtualFolder
,
197 const QString
&filePath
) const
200 if (virtualFolder
.isEmpty() || filePath
.isEmpty() || !m_query
)
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
);
212 if (m_query
->next() && m_query
->isValid())
213 ba
= qUncompress(m_query
->value(0).toByteArray());
217 QStringList
QHelpDBReader::customFilters() const
221 m_query
->exec(QLatin1String("SELECT Name FROM FilterNameTable"));
222 while (m_query
->next())
223 lst
.append(m_query
->value(0).toString());
228 QStringList
QHelpDBReader::filterAttributes(const QString
&filterName
) const
232 if (filterName
.isEmpty()) {
233 m_query
->prepare(QLatin1String("SELECT Name FROM FilterAttributeTable"));
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
);
241 while (m_query
->next())
242 lst
.append(m_query
->value(0).toString());
247 QStringList
QHelpDBReader::indicesForFilter(const QStringList
&filterAttributes
) const
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')
256 if (filterAttributes
.isEmpty()) {
257 query
= QLatin1String("SELECT DISTINCT Name FROM IndexTable");
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());
278 void QHelpDBReader::linksForKeyword(const QString
&keyword
, const QStringList
&filterAttributes
,
279 QMap
<QString
, QUrl
> &linkMap
) const
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()));
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
))));
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
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'"))
352 } else if (m_useAttributesCache
) {
353 query
= QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor, a.Id "
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'"))
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()));
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
400 url
.setScheme(QLatin1String("qthelp"));
401 url
.setAuthority(ns
);
402 url
.setPath(folder
+ QLatin1Char('/') + relFileName
);
403 url
.setFragment(anchor
);
407 QList
<QByteArray
> QHelpDBReader::contentsForFilter(const QStringList
&filterAttributes
) const
409 QList
<QByteArray
> 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';
416 if (filterAttributes
.isEmpty()) {
417 query
= QLatin1String("SELECT Data from ContentsTable");
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());
438 QUrl
QHelpDBReader::urlOfPath(const QString
&relativePath
) const
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
;
449 int i
= rp
.indexOf(QLatin1Char('#'));
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
);
460 QStringList
QHelpDBReader::files(const QStringList
&filterAttributes
,
461 const QString
&extensionFilter
) const
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"))
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
)))
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());
500 QVariant
QHelpDBReader::metaData(const QString
&name
) const
506 m_query
->prepare(QLatin1String("SELECT COUNT(Value), Value FROM MetaDataTable "
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);
515 QString
QHelpDBReader::mergeList(const QStringList
&list
) const
518 foreach (QString s
, list
)
519 str
.append(QLatin1Char('\'') + quote(s
) + QLatin1String("\', "));
520 if (str
.endsWith(QLatin1String(", ")))
521 str
= str
.left(str
.length()-2);
525 QString
QHelpDBReader::quote(const QString
&string
) const
528 s
.replace(QLatin1Char('\''), QLatin1String("\'\'"));
532 QSet
<int> QHelpDBReader::indexIds(const QStringList
&attributes
) const
536 if (attributes
.isEmpty())
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
))
552 while (m_query
->next())
553 ids
.insert(m_query
->value(0).toInt());
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();
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;