source: trunk/tools/assistant/lib/qhelpdbreader.cpp@ 552

Last change on this file since 552 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 21.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the Qt Assistant of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qhelpdbreader_p.h"
43#include "qhelp_global.h"
44
45#include <QtCore/QVariant>
46#include <QtCore/QFile>
47#include <QtSql/QSqlError>
48#include <QtSql/QSqlQuery>
49
50QT_BEGIN_NAMESPACE
51
52QHelpDBReader::QHelpDBReader(const QString &dbName)
53 : QObject(0)
54{
55 initObject(dbName,
56 QHelpGlobal::uniquifyConnectionName(QLatin1String("QHelpDBReader"),
57 this));
58}
59
60QHelpDBReader::QHelpDBReader(const QString &dbName, const QString &uniqueId,
61 QObject *parent)
62 : QObject(parent)
63{
64 initObject(dbName, uniqueId);
65}
66
67void QHelpDBReader::initObject(const QString &dbName, const QString &uniqueId)
68{
69 m_dbName = dbName;
70 m_uniqueId = uniqueId;
71 m_initDone = false;
72 m_query = 0;
73 m_useAttributesCache = false;
74}
75
76QHelpDBReader::~QHelpDBReader()
77{
78 if (m_initDone) {
79 delete m_query;
80 QSqlDatabase::removeDatabase(m_uniqueId);
81 }
82}
83
84bool QHelpDBReader::init()
85{
86 if (m_initDone)
87 return true;
88
89 if (!QFile::exists(m_dbName))
90 return false;
91
92 QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), m_uniqueId);
93 db.setDatabaseName(m_dbName);
94 if (!db.open()) {
95 m_error = tr("Cannot open database '%1' '%2': %3").arg(m_dbName, m_uniqueId, db.lastError().text());
96 QSqlDatabase::removeDatabase(m_uniqueId);
97 return false;
98 }
99
100 m_initDone = true;
101 m_query = new QSqlQuery(db);
102
103 return true;
104}
105
106QString QHelpDBReader::databaseName() const
107{
108 return m_dbName;
109}
110
111QString QHelpDBReader::errorMessage() const
112{
113 return m_error;
114}
115
116QString QHelpDBReader::namespaceName() const
117{
118 if (!m_namespace.isEmpty())
119 return m_namespace;
120 if (m_query) {
121 m_query->exec(QLatin1String("SELECT Name FROM NamespaceTable"));
122 if (m_query->next())
123 m_namespace = m_query->value(0).toString();
124 }
125 return m_namespace;
126}
127
128QString QHelpDBReader::virtualFolder() const
129{
130 if (m_query) {
131 m_query->exec(QLatin1String("SELECT Name FROM FolderTable WHERE Id=1"));
132 if (m_query->next())
133 return m_query->value(0).toString();
134 }
135 return QString();
136}
137
138QList<QStringList> QHelpDBReader::filterAttributeSets() const
139{
140 QList<QStringList> result;
141 if (m_query) {
142 m_query->exec(QLatin1String("SELECT a.Id, b.Name FROM FileAttributeSetTable a, "
143 "FilterAttributeTable b WHERE a.FilterAttributeId=b.Id ORDER BY a.Id"));
144 int oldId = -1;
145 while (m_query->next()) {
146 int id = m_query->value(0).toInt();
147 if (id != oldId) {
148 result.append(QStringList());
149 oldId = id;
150 }
151 result.last().append(m_query->value(1).toString());
152 }
153 }
154 return result;
155}
156
157bool QHelpDBReader::fileExists(const QString &virtualFolder,
158 const QString &filePath,
159 const QStringList &filterAttributes) const
160{
161 if (virtualFolder.isEmpty() || filePath.isEmpty() || !m_query)
162 return false;
163
164//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'
165
166 QString query;
167 namespaceName();
168 if (filterAttributes.isEmpty()) {
169 query = QString(QLatin1String("SELECT COUNT(a.Name) FROM FileNameTable a, FolderTable b "
170 "WHERE a.FolderId=b.Id AND b.Name=\'%1\' AND a.Name=\'%2\'")).arg(quote(virtualFolder)).arg(quote(filePath));
171 } else {
172 query = QString(QLatin1String("SELECT COUNT(a.Name) FROM FileNameTable a, FolderTable b, "
173 "FileFilterTable c, FilterAttributeTable d WHERE a.FolderId=b.Id "
174 "AND b.Name=\'%1\' AND a.Name=\'%2\' AND a.FileId=c.FileId AND "
175 "c.FilterAttributeId=d.Id AND d.Name=\'%3\'"))
176 .arg(quote(virtualFolder)).arg(quote(filePath))
177 .arg(quote(filterAttributes.first()));
178 for (int i=1; i<filterAttributes.count(); ++i) {
179 query.append(QString(QLatin1String(" INTERSECT SELECT COUNT(a.Name) FROM FileNameTable a, "
180 "FolderTable b, FileFilterTable c, FilterAttributeTable d WHERE a.FolderId=b.Id "
181 "AND b.Name=\'%1\' AND a.Name=\'%2\' AND a.FileId=c.FileId AND "
182 "c.FilterAttributeId=d.Id AND d.Name=\'%3\'"))
183 .arg(quote(virtualFolder)).arg(quote(filePath))
184 .arg(quote(filterAttributes.at(i))));
185 }
186 }
187 m_query->exec(query);
188 if (m_query->next() && m_query->isValid() && m_query->value(0).toInt())
189 return true;
190 return false;
191}
192
193QByteArray QHelpDBReader::fileData(const QString &virtualFolder,
194 const QString &filePath) const
195{
196 QByteArray ba;
197 if (virtualFolder.isEmpty() || filePath.isEmpty() || !m_query)
198 return ba;
199
200 namespaceName();
201 m_query->prepare(QLatin1String("SELECT a.Data FROM FileDataTable a, FileNameTable b, FolderTable c, "
202 "NamespaceTable d WHERE a.Id=b.FileId AND (b.Name=? OR b.Name=?) AND b.FolderId=c.Id "
203 "AND c.Name=? AND c.NamespaceId=d.Id AND d.Name=?"));
204 m_query->bindValue(0, filePath);
205 m_query->bindValue(1, QLatin1String("./") + filePath);
206 m_query->bindValue(2, virtualFolder);
207 m_query->bindValue(3, m_namespace);
208 m_query->exec();
209 if (m_query->next() && m_query->isValid())
210 ba = qUncompress(m_query->value(0).toByteArray());
211 return ba;
212}
213
214QStringList QHelpDBReader::customFilters() const
215{
216 QStringList lst;
217 if (m_query) {
218 m_query->exec(QLatin1String("SELECT Name FROM FilterNameTable"));
219 while (m_query->next())
220 lst.append(m_query->value(0).toString());
221 }
222 return lst;
223}
224
225QStringList QHelpDBReader::filterAttributes(const QString &filterName) const
226{
227 QStringList lst;
228 if (m_query) {
229 if (filterName.isEmpty()) {
230 m_query->prepare(QLatin1String("SELECT Name FROM FilterAttributeTable"));
231 } else {
232 m_query->prepare(QLatin1String("SELECT a.Name FROM FilterAttributeTable a, "
233 "FilterTable b, FilterNameTable c WHERE c.Name=? "
234 "AND c.Id=b.NameId AND b.FilterAttributeId=a.Id"));
235 m_query->bindValue(0, filterName);
236 }
237 m_query->exec();
238 while (m_query->next())
239 lst.append(m_query->value(0).toString());
240 }
241 return lst;
242}
243
244QStringList QHelpDBReader::indicesForFilter(const QStringList &filterAttributes) const
245{
246 QStringList indices;
247 if (!m_query)
248 return indices;
249
250 //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')
251
252 QString query;
253 if (filterAttributes.isEmpty()) {
254 query = QLatin1String("SELECT DISTINCT Name FROM IndexTable");
255 } else {
256 query = QString(QLatin1String("SELECT DISTINCT a.Name FROM IndexTable a, "
257 "IndexFilterTable b, FilterAttributeTable c WHERE a.Id=b.IndexId "
258 "AND b.FilterAttributeId=c.Id AND c.Name='%1'")).arg(quote(filterAttributes.first()));
259 for (int i=1; i<filterAttributes.count(); ++i) {
260 query.append(QString(QLatin1String(" INTERSECT SELECT DISTINCT a.Name FROM IndexTable a, "
261 "IndexFilterTable b, FilterAttributeTable c WHERE a.Id=b.IndexId "
262 "AND b.FilterAttributeId=c.Id AND c.Name='%1'"))
263 .arg(quote(filterAttributes.at(i))));
264 }
265 }
266
267 m_query->exec(query);
268 while (m_query->next()) {
269 if (!m_query->value(0).toString().isEmpty())
270 indices.append(m_query->value(0).toString());
271 }
272 return indices;
273}
274
275void QHelpDBReader::linksForKeyword(const QString &keyword, const QStringList &filterAttributes,
276 QMap<QString, QUrl> &linkMap) const
277{
278 if (!m_query)
279 return;
280
281 QString query;
282 if (filterAttributes.isEmpty()) {
283 query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor "
284 "FROM IndexTable a, FileNameTable d, "
285 "FolderTable e, NamespaceTable f WHERE "
286 "a.FileId=d.FileId AND d.FolderId=e.Id AND a.NamespaceId=f.Id "
287 "AND a.Name='%1'")).arg(quote(keyword));
288 } else if (m_useAttributesCache) {
289 query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor, a.Id "
290 "FROM IndexTable a, "
291 "FileNameTable d, FolderTable e, NamespaceTable f WHERE "
292 "a.FileId=d.FileId AND d.FolderId=e.Id "
293 "AND a.NamespaceId=f.Id AND a.Name='%1'"))
294 .arg(quote(keyword));
295 m_query->exec(query);
296 while (m_query->next()) {
297 if (m_indicesCache.contains(m_query->value(5).toInt())) {
298 linkMap.insertMulti(m_query->value(0).toString(), buildQUrl(m_query->value(1).toString(),
299 m_query->value(2).toString(), m_query->value(3).toString(),
300 m_query->value(4).toString()));
301 }
302 }
303 return;
304 } else {
305 query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor "
306 "FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c, "
307 "FileNameTable d, FolderTable e, NamespaceTable f "
308 "WHERE a.FileId=d.FileId AND d.FolderId=e.Id "
309 "AND a.NamespaceId=f.Id AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id "
310 "AND a.Name='%1' AND c.Name='%2'")).arg(quote(keyword))
311 .arg(quote(filterAttributes.first()));
312 for (int i=1; i<filterAttributes.count(); ++i) {
313 query.append(QString(QLatin1String(" INTERSECT SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor "
314 "FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c, "
315 "FileNameTable d, FolderTable e, NamespaceTable f "
316 "WHERE a.FileId=d.FileId AND d.FolderId=e.Id "
317 "AND a.NamespaceId=f.Id AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id "
318 "AND a.Name='%1' AND c.Name='%2'")).arg(quote(keyword))
319 .arg(quote(filterAttributes.at(i))));
320 }
321 }
322
323 QString title;
324 m_query->exec(query);
325 while (m_query->next()) {
326 title = m_query->value(0).toString();
327 if (title.isEmpty()) // generate a title + corresponding path
328 title = keyword + QLatin1String(" : ") + m_query->value(3).toString();
329 linkMap.insertMulti(title, buildQUrl(m_query->value(1).toString(),
330 m_query->value(2).toString(), m_query->value(3).toString(),
331 m_query->value(4).toString()));
332 }
333}
334
335void QHelpDBReader::linksForIdentifier(const QString &id,
336 const QStringList &filterAttributes,
337 QMap<QString, QUrl> &linkMap) const
338{
339 if (!m_query)
340 return;
341
342 QString query;
343 if (filterAttributes.isEmpty()) {
344 query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor "
345 "FROM IndexTable a, FileNameTable d, FolderTable e, "
346 "NamespaceTable f WHERE a.FileId=d.FileId AND "
347 "d.FolderId=e.Id AND a.NamespaceId=f.Id AND a.Identifier='%1'"))
348 .arg(quote(id));
349 } else if (m_useAttributesCache) {
350 query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor, a.Id "
351 "FROM IndexTable a,"
352 "FileNameTable d, FolderTable e, NamespaceTable f WHERE "
353 "a.FileId=d.FileId AND d.FolderId=e.Id "
354 "AND a.NamespaceId=f.Id AND a.Identifier='%1'"))
355 .arg(quote(id));
356 m_query->exec(query);
357 while (m_query->next()) {
358 if (m_indicesCache.contains(m_query->value(5).toInt())) {
359 linkMap.insertMulti(m_query->value(0).toString(), buildQUrl(m_query->value(1).toString(),
360 m_query->value(2).toString(), m_query->value(3).toString(),
361 m_query->value(4).toString()));
362 }
363 }
364 return;
365 } else {
366 query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor "
367 "FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c, "
368 "FileNameTable d, FolderTable e, NamespaceTable f "
369 "WHERE a.FileId=d.FileId AND d.FolderId=e.Id "
370 "AND a.NamespaceId=f.Id AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id "
371 "AND a.Identifier='%1' AND c.Name='%2'")).arg(quote(id))
372 .arg(quote(filterAttributes.first()));
373 for (int i=0; i<filterAttributes.count(); ++i) {
374 query.append(QString(QLatin1String(" INTERSECT SELECT d.Title, f.Name, e.Name, "
375 "d.Name, a.Anchor FROM IndexTable a, IndexFilterTable b, "
376 "FilterAttributeTable c, FileNameTable d, "
377 "FolderTable e, NamespaceTable f WHERE "
378 "a.FileId=d.FileId AND d.FolderId=e.Id AND a.NamespaceId=f.Id "
379 "AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id AND "
380 "a.Identifier='%1' AND c.Name='%2'")).arg(quote(id))
381 .arg(quote(filterAttributes.at(i))));
382 }
383 }
384
385 m_query->exec(query);
386 while (m_query->next()) {
387 linkMap.insertMulti(m_query->value(0).toString(), buildQUrl(m_query->value(1).toString(),
388 m_query->value(2).toString(), m_query->value(3).toString(),
389 m_query->value(4).toString()));
390 }
391}
392
393QUrl QHelpDBReader::buildQUrl(const QString &ns, const QString &folder,
394 const QString &relFileName, const QString &anchor) const
395{
396 QUrl url;
397 url.setScheme(QLatin1String("qthelp"));
398 url.setAuthority(ns);
399 url.setPath(folder + QLatin1Char('/') + relFileName);
400 url.setFragment(anchor);
401 return url;
402}
403
404QList<QByteArray> QHelpDBReader::contentsForFilter(const QStringList &filterAttributes) const
405{
406 QList<QByteArray> contents;
407 if (!m_query)
408 return contents;
409
410 //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';
411
412 QString query;
413 if (filterAttributes.isEmpty()) {
414 query = QLatin1String("SELECT Data from ContentsTable");
415 } else {
416 query = QString(QLatin1String("SELECT a.Data FROM ContentsTable a, "
417 "ContentsFilterTable b, FilterAttributeTable c "
418 "WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id "
419 "AND c.Name='%1'")).arg(quote(filterAttributes.first()));
420 for (int i=1; i<filterAttributes.count(); ++i) {
421 query.append(QString(QLatin1String(" INTERSECT SELECT a.Data FROM ContentsTable a, "
422 "ContentsFilterTable b, FilterAttributeTable c "
423 "WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id "
424 "AND c.Name='%1'")).arg(quote(filterAttributes.at(i))));
425 }
426 }
427
428 m_query->exec(query);
429 while (m_query->next()) {
430 contents.append(m_query->value(0).toByteArray());
431 }
432 return contents;
433}
434
435QUrl QHelpDBReader::urlOfPath(const QString &relativePath) const
436{
437 QUrl url;
438 if (!m_query)
439 return url;
440
441 m_query->exec(QLatin1String("SELECT a.Name, b.Name FROM NamespaceTable a, "
442 "FolderTable b WHERE a.id=b.NamespaceId and a.Id=1"));
443 if (m_query->next()) {
444 QString rp = relativePath;
445 QString anchor;
446 int i = rp.indexOf(QLatin1Char('#'));
447 if (i > -1) {
448 rp = relativePath.left(i);
449 anchor = relativePath.mid(i+1);
450 }
451 url = buildQUrl(m_query->value(0).toString(),
452 m_query->value(1).toString(), rp, anchor);
453 }
454 return url;
455}
456
457QStringList QHelpDBReader::files(const QStringList &filterAttributes,
458 const QString &extensionFilter) const
459{
460 QStringList lst;
461 if (!m_query)
462 return lst;
463
464 QString query;
465 QString extension;
466 if (!extensionFilter.isEmpty())
467 extension = QString(QLatin1String("AND b.Name like \'%.%1\'")).arg(extensionFilter);
468
469 if (filterAttributes.isEmpty()) {
470 query = QString(QLatin1String("SELECT a.Name, b.Name FROM FolderTable a, "
471 "FileNameTable b WHERE b.FolderId=a.Id %1"))
472 .arg(extension);
473 } else {
474 query = QString(QLatin1String("SELECT a.Name, b.Name FROM FolderTable a, "
475 "FileNameTable b, FileFilterTable c, FilterAttributeTable d "
476 "WHERE b.FolderId=a.Id AND b.FileId=c.FileId "
477 "AND c.FilterAttributeId=d.Id AND d.Name=\'%1\' %2"))
478 .arg(quote(filterAttributes.first())).arg(extension);
479 for (int i=1; i<filterAttributes.count(); ++i) {
480 query.append(QString(QLatin1String(" INTERSECT SELECT a.Name, b.Name FROM "
481 "FolderTable a, FileNameTable b, FileFilterTable c, "
482 "FilterAttributeTable d WHERE b.FolderId=a.Id AND "
483 "b.FileId=c.FileId AND c.FilterAttributeId=d.Id AND "
484 "d.Name=\'%1\' %2")).arg(quote(filterAttributes.at(i)))
485 .arg(extension));
486 }
487 }
488 m_query->exec(query);
489 while (m_query->next()) {
490 lst.append(m_query->value(0).toString() + QLatin1Char('/')
491 + m_query->value(1).toString());
492 }
493
494 return lst;
495}
496
497QVariant QHelpDBReader::metaData(const QString &name) const
498{
499 QVariant v;
500 if (!m_query)
501 return v;
502
503 m_query->prepare(QLatin1String("SELECT COUNT(Value), Value FROM MetaDataTable "
504 "WHERE Name=?"));
505 m_query->bindValue(0, name);
506 if (m_query->exec() && m_query->next()
507 && m_query->value(0).toInt() == 1)
508 v = m_query->value(1);
509 return v;
510}
511
512QString QHelpDBReader::mergeList(const QStringList &list) const
513{
514 QString str;
515 foreach (QString s, list)
516 str.append(QLatin1Char('\'') + quote(s) + QLatin1String("\', "));
517 if (str.endsWith(QLatin1String(", ")))
518 str = str.left(str.length()-2);
519 return str;
520}
521
522QString QHelpDBReader::quote(const QString &string) const
523{
524 QString s = string;
525 s.replace(QLatin1Char('\''), QLatin1String("\'\'"));
526 return s;
527}
528
529QSet<int> QHelpDBReader::indexIds(const QStringList &attributes) const
530{
531 QSet<int> ids;
532
533 if (attributes.isEmpty())
534 return ids;
535
536 QString query = QString(QLatin1String("SELECT a.IndexId FROM IndexFilterTable a, "
537 "FilterAttributeTable b WHERE a.FilterAttributeId=b.Id "
538 "AND b.Name='%1'")).arg(attributes.first());
539 for (int i=0; i<attributes.count(); ++i) {
540 query.append(QString(QLatin1String(" INTERSECT SELECT a.IndexId FROM "
541 "IndexFilterTable a, FilterAttributeTable b WHERE "
542 "a.FilterAttributeId=b.Id AND b.Name='%1'"))
543 .arg(attributes.at(i)));
544 }
545
546 if (!m_query->exec(query))
547 return ids;
548
549 while (m_query->next())
550 ids.insert(m_query->value(0).toInt());
551
552 return ids;
553}
554
555bool QHelpDBReader::createAttributesCache(const QStringList &attributes,
556 const QSet<int> &indexIds)
557{
558 m_useAttributesCache = false;
559
560 if (attributes.count() < 2) {
561 m_viewAttributes.clear();
562 return true;
563 }
564
565 bool needUpdate = !m_viewAttributes.count();
566
567 foreach (QString s, attributes)
568 m_viewAttributes.remove(s);
569
570 if (m_viewAttributes.count() || needUpdate) {
571 m_viewAttributes.clear();
572 m_indicesCache = indexIds;
573 }
574 foreach (QString s, attributes)
575 m_viewAttributes.insert(s);
576 m_useAttributesCache = true;
577 return true;
578}
579
580QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.