source: trunk/tools/assistant/lib/qhelpenginecore.cpp@ 275

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

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

File size: 22.2 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 "qhelpenginecore.h"
43#include "qhelpengine_p.h"
44#include "qhelpdbreader_p.h"
45#include "qhelpcollectionhandler_p.h"
46
47#include <QtCore/QDir>
48#include <QtCore/QFile>
49#include <QtCore/QLibrary>
50#include <QtCore/QPluginLoader>
51#include <QtCore/QFileInfo>
52#include <QtCore/QThread>
53#include <QtGui/QApplication>
54#include <QtSql/QSqlQuery>
55
56QT_BEGIN_NAMESPACE
57
58QHelpEngineCorePrivate::QHelpEngineCorePrivate()
59{
60 QHelpGlobal::uniquifyConnectionName(QString(), this);
61 autoSaveFilter = true;
62}
63
64void QHelpEngineCorePrivate::init(const QString &collectionFile,
65 QHelpEngineCore *helpEngineCore)
66{
67 q = helpEngineCore;
68 collectionHandler = new QHelpCollectionHandler(collectionFile, helpEngineCore);
69 connect(collectionHandler, SIGNAL(error(const QString&)),
70 this, SLOT(errorReceived(const QString&)));
71 needsSetup = true;
72}
73
74QHelpEngineCorePrivate::~QHelpEngineCorePrivate()
75{
76 delete collectionHandler;
77 clearMaps();
78}
79
80void QHelpEngineCorePrivate::clearMaps()
81{
82 QMap<QString, QHelpDBReader*>::iterator it = readerMap.begin();
83 while (it != readerMap.end()) {
84 delete it.value();
85 ++it;
86 }
87 readerMap.clear();
88 fileNameReaderMap.clear();
89 virtualFolderMap.clear();
90 orderedFileNameList.clear();
91}
92
93bool QHelpEngineCorePrivate::setup()
94{
95 error.clear();
96 if (!needsSetup)
97 return true;
98
99 needsSetup = false;
100 emit q->setupStarted();
101 clearMaps();
102
103 if (!collectionHandler->openCollectionFile()) {
104 emit q->setupFinished();
105 return false;
106 }
107
108 const QHelpCollectionHandler::DocInfoList docList =
109 collectionHandler->registeredDocumentations();
110 QFileInfo fi(collectionHandler->collectionFile());
111 QString absFileName;
112 foreach(const QHelpCollectionHandler::DocInfo &info, docList) {
113 if (QDir::isAbsolutePath(info.fileName)) {
114 absFileName = info.fileName;
115 } else {
116 absFileName = QFileInfo(fi.absolutePath() + QDir::separator() + info.fileName)
117 .absoluteFilePath();
118 }
119 QHelpDBReader *reader = new QHelpDBReader(absFileName,
120 QHelpGlobal::uniquifyConnectionName(info.fileName, this), this);
121 if (!reader->init()) {
122 emit q->warning(tr("Cannot open documentation file %1: %2!")
123 .arg(absFileName, reader->errorMessage()));
124 continue;
125 }
126
127 readerMap.insert(info.namespaceName, reader);
128 fileNameReaderMap.insert(absFileName, reader);
129 virtualFolderMap.insert(info.folderName, reader);
130 orderedFileNameList.append(absFileName);
131 }
132 q->currentFilter();
133 emit q->setupFinished();
134 return true;
135}
136
137void QHelpEngineCorePrivate::errorReceived(const QString &msg)
138{
139 error = msg;
140}
141
142
143
144/*!
145 \class QHelpEngineCore
146 \since 4.4
147 \inmodule QtHelp
148 \brief The QHelpEngineCore class provides the core functionality
149 of the help system.
150
151 Before the help engine can be used, it must be initialized by
152 calling setupData(). At the beginning of the setup process the
153 signal setupStarted() is emitted. From this point on until
154 the signal setupFinished() is emitted, is the help data in an
155 undefined meaning unusable state.
156
157 The core help engine can be used to perform different tasks.
158 By calling linksForIdentifier() the engine returns
159 urls specifying the file locations inside the help system. The
160 actual file data can then be retrived by calling fileData(). In
161 contrast to all other functions in this class, linksForIdentifier()
162 depends on the currently set custom filter. Depending on the filter,
163 the function may return different hits.
164
165 Every help engine can contain any number of custom filters. A custom
166 filter is defined by a name and set of filter attributes and can be
167 added to the help engine by calling addCustomFilter(). Analogous,
168 it is removed by calling removeCustomFilter(). customFilters() returns
169 all defined filters.
170
171 The help engine also offers the possiblity to set and read values
172 in a persistant way comparable to ini files or Windows registry
173 entries. For more information see setValue() or value().
174
175 This class does not offer any GUI components or functionality for
176 indices or contents. If you need one of those use QHelpEngine
177 instead.
178*/
179
180/*!
181 \fn void QHelpEngineCore::setupStarted()
182
183 This signal is emitted when setup is started.
184*/
185
186/*!
187 \fn void QHelpEngineCore::setupFinished()
188
189 This signal is emitted when the setup is complete.
190*/
191
192/*!
193 \fn void QHelpEngineCore::currentFilterChanged(const QString &newFilter)
194
195 This signal is emitted when the current filter is changed to
196 \a newFilter.
197*/
198
199/*!
200 \fn void QHelpEngineCore::warning(const QString &msg)
201
202 This signal is emitted when a non critical error occurs.
203 The warning message is stored in \a msg.
204*/
205
206/*!
207 Constructs a new core help engine with a \a parent. The help engine
208 uses the information stored in the \a collectionFile to provide help.
209 If the collection file does not exist yet, it'll be created.
210*/
211QHelpEngineCore::QHelpEngineCore(const QString &collectionFile, QObject *parent)
212 : QObject(parent)
213{
214 d = new QHelpEngineCorePrivate();
215 d->init(collectionFile, this);
216}
217
218/*!
219 \internal
220*/
221QHelpEngineCore::QHelpEngineCore(QHelpEngineCorePrivate *helpEngineCorePrivate,
222 QObject *parent)
223 : QObject(parent)
224{
225 d = helpEngineCorePrivate;
226}
227
228/*!
229 Destructs the help engine.
230*/
231QHelpEngineCore::~QHelpEngineCore()
232{
233 delete d;
234}
235
236/*!
237 \property QHelpEngineCore::collectionFile
238 \brief the absolute file name of the collection file currently used.
239 \since 4.5
240
241 Setting this property leaves the help engine in an invalid state. It is
242 important to invoke setupData() or any getter function in order to setup
243 the help engine again.
244*/
245QString QHelpEngineCore::collectionFile() const
246{
247 return d->collectionHandler->collectionFile();
248}
249
250void QHelpEngineCore::setCollectionFile(const QString &fileName)
251{
252 if (fileName == collectionFile())
253 return;
254
255 if (d->collectionHandler) {
256 delete d->collectionHandler;
257 d->collectionHandler = 0;
258 d->clearMaps();
259 }
260 d->init(fileName, this);
261 d->needsSetup = true;
262}
263
264/*!
265 Sets up the help engine by processing the information found
266 in the collection file and returns true if successful; otherwise
267 returns false.
268
269 By calling the function, the help
270 engine is forced to initialize itself immediately. Most of
271 the times, this function does not have to be called
272 explicitly because getter functions which depend on a correctly
273 set up help engine do that themselves.
274
275 \note \c{qsqlite4.dll} needs to be deployed with the application as the
276 help system uses the sqlite driver when loading help collections.
277*/
278bool QHelpEngineCore::setupData()
279{
280 d->needsSetup = true;
281 return d->setup();
282}
283
284/*!
285 Creates the file \a fileName and copies all contents from
286 the current collection file into the newly created file,
287 and returns true if successful; otherwise returns false.
288
289 The copying process makes sure that file references to Qt
290 Collection files (\c{.qch}) files are updated accordingly.
291*/
292bool QHelpEngineCore::copyCollectionFile(const QString &fileName)
293{
294 if (!d->setup())
295 return false;
296 return d->collectionHandler->copyCollectionFile(fileName);
297}
298
299/*!
300 Returns the namespace name defined for the Qt compressed help file (.qch)
301 specified by its \a documentationFileName. If the file is not valid, an
302 empty string is returned.
303
304 \sa documentationFileName()
305*/
306QString QHelpEngineCore::namespaceName(const QString &documentationFileName)
307{
308 QHelpDBReader reader(documentationFileName,
309 QHelpGlobal::uniquifyConnectionName(QLatin1String("GetNamespaceName"),
310 QThread::currentThread()), 0);
311 if (reader.init())
312 return reader.namespaceName();
313 return QString();
314}
315
316/*!
317 Registers the Qt compressed help file (.qch) contained in the file
318 \a documentationFileName. One compressed help file, uniquely
319 identified by its namespace can only be registered once.
320 True is returned if the registration was successful, otherwise
321 false.
322
323 \sa unregisterDocumentation(), error()
324*/
325bool QHelpEngineCore::registerDocumentation(const QString &documentationFileName)
326{
327 d->error.clear();
328 d->needsSetup = true;
329 return d->collectionHandler->registerDocumentation(documentationFileName);
330}
331
332/*!
333 Unregisters the Qt compressed help file (.qch) identified by its
334 \a namespaceName from the help collection. Returns true
335 on success, otherwise false.
336
337 \sa registerDocumentation(), error()
338*/
339bool QHelpEngineCore::unregisterDocumentation(const QString &namespaceName)
340{
341 d->error.clear();
342 d->needsSetup = true;
343 return d->collectionHandler->unregisterDocumentation(namespaceName);
344}
345
346/*!
347 Returns the absolute file name of the Qt compressed help file (.qch)
348 identified by the \a namespaceName. If there is no Qt compressed help file
349 with the specified namespace registered, an empty string is returned.
350
351 \sa namespaceName()
352*/
353QString QHelpEngineCore::documentationFileName(const QString &namespaceName)
354{
355 QString res;
356 if (!d->setup())
357 return res;
358 const QHelpCollectionHandler::DocInfoList docList = d->collectionHandler->registeredDocumentations();
359 foreach(const QHelpCollectionHandler::DocInfo info, docList) {
360 if (info.namespaceName == namespaceName) {
361 QFileInfo fi(d->collectionHandler->collectionFile());
362 fi.setFile(fi.absolutePath() + QDir::separator() + info.fileName);
363 res = QDir::cleanPath(fi.absoluteFilePath());
364 break;
365 }
366 }
367 return res;
368}
369
370/*!
371 Returns a list of all registered Qt compressed help files of the current collection file.
372 The returned names are the namespaces of the registered Qt compressed help files (.qch).
373*/
374QStringList QHelpEngineCore::registeredDocumentations() const
375{
376 QStringList list;
377 if (!d->setup())
378 return list;
379 const QHelpCollectionHandler::DocInfoList docList = d->collectionHandler->registeredDocumentations();
380 foreach(const QHelpCollectionHandler::DocInfo info, docList) {
381 list.append(info.namespaceName);
382 }
383 return list;
384}
385
386/*!
387 Returns a list of custom filters.
388
389 \sa addCustomFilter(), removeCustomFilter()
390*/
391QStringList QHelpEngineCore::customFilters() const
392{
393 if (!d->setup())
394 return QStringList();
395 return d->collectionHandler->customFilters();
396}
397
398/*!
399 Adds the new custom filter \a filterName. The filter attributes
400 are specified by \a attributes. The function returns false if
401 the filter can not be added, e.g. when the filter already exists.
402
403 \sa customFilters(), removeCustomFilter()
404*/
405bool QHelpEngineCore::addCustomFilter(const QString &filterName,
406 const QStringList &attributes)
407{
408 d->error.clear();
409 d->needsSetup = true;
410 return d->collectionHandler->addCustomFilter(filterName,
411 attributes);
412}
413
414/*!
415 Returns true if the filter \a filterName was removed successfully,
416 otherwise false.
417
418 \sa addCustomFilter(), customFilters()
419*/
420bool QHelpEngineCore::removeCustomFilter(const QString &filterName)
421{
422 d->error.clear();
423 d->needsSetup = true;
424 return d->collectionHandler->removeCustomFilter(filterName);
425}
426
427/*!
428 Returns a list of all defined filter attributes.
429*/
430QStringList QHelpEngineCore::filterAttributes() const
431{
432 if (!d->setup())
433 return QStringList();
434 return d->collectionHandler->filterAttributes();
435}
436
437/*!
438 Returns a list of filter attributes used by the custom
439 filter \a filterName.
440*/
441QStringList QHelpEngineCore::filterAttributes(const QString &filterName) const
442{
443 if (!d->setup())
444 return QStringList();
445 return d->collectionHandler->filterAttributes(filterName);
446}
447
448/*!
449 \property QHelpEngineCore::currentFilter
450 \brief the name of the custom filter currently applied.
451 \since 4.5
452
453 Setting this property will save the new custom filter permanently in the
454 help collection file. To set a custom filter without saving it
455 permanently, disable the auto save filter mode.
456
457 \sa autoSaveFilter()
458*/
459QString QHelpEngineCore::currentFilter() const
460{
461 if (!d->setup())
462 return QString();
463
464 if (d->currentFilter.isEmpty()) {
465 QString filter =
466 d->collectionHandler->customValue(QLatin1String("CurrentFilter"),
467 QString()).toString();
468 if (!filter.isEmpty()
469 && d->collectionHandler->customFilters().contains(filter))
470 d->currentFilter = filter;
471 }
472 return d->currentFilter;
473}
474
475void QHelpEngineCore::setCurrentFilter(const QString &filterName)
476{
477 if (!d->setup() || filterName == d->currentFilter)
478 return;
479 d->currentFilter = filterName;
480 if (d->autoSaveFilter) {
481 d->collectionHandler->setCustomValue(QLatin1String("CurrentFilter"),
482 d->currentFilter);
483 }
484 emit currentFilterChanged(d->currentFilter);
485}
486
487/*!
488 Returns a list of filter attributes for the different filter sections
489 defined in the Qt compressed help file with the given namespace
490 \a namespaceName.
491*/
492QList<QStringList> QHelpEngineCore::filterAttributeSets(const QString &namespaceName) const
493{
494 if (d->setup()) {
495 QHelpDBReader *reader = d->readerMap.value(namespaceName);
496 if (reader)
497 return reader->filterAttributeSets();
498 }
499 return QList<QStringList>();
500}
501
502/*!
503 Returns a list of files contained in the Qt compressed help file \a
504 namespaceName. The files can be filtered by \a filterAttributes as
505 well as by their extension \a extensionFilter (e.g. 'html').
506*/
507QList<QUrl> QHelpEngineCore::files(const QString namespaceName,
508 const QStringList &filterAttributes,
509 const QString &extensionFilter)
510{
511 QList<QUrl> res;
512 if (!d->setup())
513 return res;
514 QHelpDBReader *reader = d->readerMap.value(namespaceName);
515 if (!reader) {
516 d->error = tr("The specified namespace does not exist!");
517 return res;
518 }
519
520 QUrl url;
521 url.setScheme(QLatin1String("qthelp"));
522 url.setAuthority(namespaceName);
523
524 const QStringList files = reader->files(filterAttributes, extensionFilter);
525 foreach (const QString file, files) {
526 url.setPath(QLatin1String("/") + file);
527 res.append(url);
528 }
529 return res;
530}
531
532/*!
533 Returns an invalid URL if the file \a url cannot be found.
534 If the file exists, either the same url is returned or a
535 different url if the file is located in a different namespace
536 which is merged via a common virtual folder.
537*/
538QUrl QHelpEngineCore::findFile(const QUrl &url) const
539{
540 QUrl res;
541 if (!d->setup() || !url.isValid() || url.toString().count(QLatin1Char('/')) < 4
542 || url.scheme() != QLatin1String("qthelp"))
543 return res;
544
545 QString ns = url.authority();
546 QString filePath = QDir::cleanPath(url.path());
547 if (filePath.startsWith(QLatin1Char('/')))
548 filePath = filePath.mid(1);
549 QString virtualFolder = filePath.mid(0, filePath.indexOf(QLatin1Char('/'), 1));
550 filePath = filePath.mid(virtualFolder.length()+1);
551
552 QHelpDBReader *defaultReader = 0;
553 if (d->readerMap.contains(ns)) {
554 defaultReader = d->readerMap.value(ns);
555 if (defaultReader->fileExists(virtualFolder, filePath))
556 return url;
557 }
558
559 QStringList filterAtts = filterAttributes(currentFilter());
560 foreach (QHelpDBReader *reader, d->virtualFolderMap.values(virtualFolder)) {
561 if (reader == defaultReader)
562 continue;
563 if (reader->fileExists(virtualFolder, filePath, filterAtts)) {
564 res = url;
565 res.setAuthority(reader->namespaceName());
566 return res;
567 }
568 }
569
570 foreach (QHelpDBReader *reader, d->virtualFolderMap.values(virtualFolder)) {
571 if (reader == defaultReader)
572 continue;
573 if (reader->fileExists(virtualFolder, filePath)) {
574 res = url;
575 res.setAuthority(reader->namespaceName());
576 break;
577 }
578 }
579
580 return res;
581}
582
583/*!
584 Returns the data of the file specified by \a url. If the
585 file does not exist, an empty QByteArray is returned.
586
587 \sa findFile()
588*/
589QByteArray QHelpEngineCore::fileData(const QUrl &url) const
590{
591 if (!d->setup() || !url.isValid() || url.toString().count(QLatin1Char('/')) < 4
592 || url.scheme() != QLatin1String("qthelp"))
593 return QByteArray();
594
595 QString ns = url.authority();
596 QString filePath = QDir::cleanPath(url.path());
597 if (filePath.startsWith(QLatin1Char('/')))
598 filePath = filePath.mid(1);
599 QString virtualFolder = filePath.mid(0, filePath.indexOf(QLatin1Char('/'), 1));
600 filePath = filePath.mid(virtualFolder.length()+1);
601
602 QByteArray ba;
603 QHelpDBReader *defaultReader = 0;
604 if (d->readerMap.contains(ns)) {
605 defaultReader = d->readerMap.value(ns);
606 ba = defaultReader->fileData(virtualFolder, filePath);
607 }
608
609 if (ba.isEmpty()) {
610 foreach (QHelpDBReader *reader, d->virtualFolderMap.values(virtualFolder)) {
611 if (reader == defaultReader)
612 continue;
613 ba = reader->fileData(virtualFolder, filePath);
614 if (!ba.isEmpty())
615 return ba;
616 }
617 }
618 return ba;
619}
620
621/*!
622 Returns a map of hits found for the \a id. A hit contains the
623 title of the document and the url where the keyword is located.
624 The result depends on the current filter, meaning only the keywords
625 registered for the current filter will be returned.
626*/
627QMap<QString, QUrl> QHelpEngineCore::linksForIdentifier(const QString &id) const
628{
629 QMap<QString, QUrl> linkMap;
630 if (!d->setup())
631 return linkMap;
632
633 QStringList atts = filterAttributes(d->currentFilter);
634 foreach (QHelpDBReader *reader, d->readerMap)
635 reader->linksForIdentifier(id, atts, linkMap);
636
637 return linkMap;
638}
639
640/*!
641 Removes the \a key from the settings section in the
642 collection file. Returns true if the value was removed
643 successfully, otherwise false.
644
645 \sa customValue(), setCustomValue()
646*/
647bool QHelpEngineCore::removeCustomValue(const QString &key)
648{
649 d->error.clear();
650 return d->collectionHandler->removeCustomValue(key);
651}
652
653/*!
654 Returns the value assigned to the \a key. If the requested
655 key does not exist, the specified \a defaultValue is
656 returned.
657
658 \sa setCustomValue(), removeCustomValue()
659*/
660QVariant QHelpEngineCore::customValue(const QString &key, const QVariant &defaultValue) const
661{
662 if (!d->setup())
663 return QVariant();
664 return d->collectionHandler->customValue(key, defaultValue);
665}
666
667/*!
668 Save the \a value under the \a key. If the key already exist,
669 the value will be overwritten. Returns true if the value was
670 saved successfully, otherwise false.
671
672 \sa customValue(), removeCustomValue()
673*/
674bool QHelpEngineCore::setCustomValue(const QString &key, const QVariant &value)
675{
676 d->error.clear();
677 return d->collectionHandler->setCustomValue(key, value);
678}
679
680/*!
681 Returns the meta data for the Qt compressed help file \a
682 documentationFileName. If there is no data available for
683 \a name, an invalid QVariant() is returned. The meta
684 data is defined when creating the Qt compressed help file and
685 cannot be modified later. Common meta data includes e.g.
686 the author of the documentation.
687*/
688QVariant QHelpEngineCore::metaData(const QString &documentationFileName,
689 const QString &name)
690{
691 QHelpDBReader reader(documentationFileName, QLatin1String("GetMetaData"), 0);
692
693 if (reader.init())
694 return reader.metaData(name);
695 return QVariant();
696}
697
698/*!
699 Returns a description of the last error that occured.
700*/
701QString QHelpEngineCore::error() const
702{
703 return d->error;
704}
705
706/*!
707 \property QHelpEngineCore::autoSaveFilter
708 \brief whether QHelpEngineCore is in auto save filter mode or not.
709 \since 4.5
710
711 If QHelpEngineCore is in auto save filter mode, the current filter is
712 automatically saved when it is changed by the setCurrentFilter()
713 function. The filter is saved persistently in the help collection file.
714
715 By default, this mode is on.
716*/
717void QHelpEngineCore::setAutoSaveFilter(bool save)
718{
719 d->autoSaveFilter = save;
720}
721
722bool QHelpEngineCore::autoSaveFilter() const
723{
724 return d->autoSaveFilter;
725}
726
727QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.