1 /****************************************************************************
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the Qt Assistant of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include "qhelpcontentwidget.h"
43 #include "qhelpenginecore.h"
44 #include "qhelpengine_p.h"
45 #include "qhelpdbreader_p.h"
47 #include <QtCore/QStack>
48 #include <QtCore/QThread>
49 #include <QtCore/QMutex>
50 #include <QtGui/QHeaderView>
54 class QHelpContentItemPrivate
57 QHelpContentItemPrivate(const QString &t, const QString &l,
58 QHelpDBReader *r, QHelpContentItem *p)
66 QList<QHelpContentItem*> childItems;
67 QHelpContentItem *parent;
70 QHelpDBReader *helpDBReader;
73 class QHelpContentProvider : public QThread
76 QHelpContentProvider(QHelpEnginePrivate *helpEngine);
77 ~QHelpContentProvider();
78 void collectContents(const QString &customFilterName);
79 void stopCollecting();
80 QHelpContentItem *rootItem();
81 int nextChildCount() const;
86 QHelpEnginePrivate *m_helpEngine;
87 QHelpContentItem *m_rootItem;
88 QStringList m_filterAttributes;
89 QQueue<QHelpContentItem*> m_rootItems;
94 class QHelpContentModelPrivate
97 QHelpContentItem *rootItem;
98 QHelpContentProvider *qhelpContentProvider;
104 \class QHelpContentItem
106 \brief The QHelpContentItem class provides an item for use with QHelpContentModel.
110 QHelpContentItem::QHelpContentItem(const QString &name, const QString &link,
111 QHelpDBReader *reader, QHelpContentItem *parent)
113 d = new QHelpContentItemPrivate(name, link, reader, parent);
117 Destroys the help content item.
119 QHelpContentItem::~QHelpContentItem()
121 qDeleteAll(d->childItems);
125 void QHelpContentItem::appendChild(QHelpContentItem *item)
127 d->childItems.append(item);
131 Returns the child of the content item in the give \a row.
135 QHelpContentItem *QHelpContentItem::child(int row) const
137 if (row >= childCount())
139 return d->childItems.value(row);
143 Returns the number of child items.
145 int QHelpContentItem::childCount() const
147 return d->childItems.count();
151 Returns the row of this item from its parents view.
153 int QHelpContentItem::row() const
156 return d->parent->d->childItems.indexOf(const_cast<QHelpContentItem*>(this));
161 Returns the title of the content item.
163 QString QHelpContentItem::title() const
169 Returns the URL of this content item.
171 QUrl QHelpContentItem::url() const
173 return d->helpDBReader->urlOfPath(d->link);
177 Returns the parent content item.
179 QHelpContentItem *QHelpContentItem::parent() const
185 Returns the position of a given \a child.
187 int QHelpContentItem::childPosition(QHelpContentItem *child) const
189 return d->childItems.indexOf(child);
194 QHelpContentProvider::QHelpContentProvider(QHelpEnginePrivate *helpEngine)
195 : QThread(helpEngine)
197 m_helpEngine = helpEngine;
202 QHelpContentProvider::~QHelpContentProvider()
207 void QHelpContentProvider::collectContents(const QString &customFilterName)
210 m_filterAttributes = m_helpEngine->q->filterAttributes(customFilterName);
220 void QHelpContentProvider::stopCollecting()
228 qDeleteAll(m_rootItems);
232 QHelpContentItem *QHelpContentProvider::rootItem()
234 QMutexLocker locker(&m_mutex);
235 if (m_rootItems.isEmpty())
237 return m_rootItems.dequeue();
240 int QHelpContentProvider::nextChildCount() const
242 if (m_rootItems.isEmpty())
244 return m_rootItems.head()->childCount();
247 void QHelpContentProvider::run()
252 QHelpContentItem *item = 0;
255 m_rootItem = new QHelpContentItem(QString(), QString(), 0);
256 m_rootItems.enqueue(m_rootItem);
257 QStringList atts = m_filterAttributes;
258 const QStringList fileNames = m_helpEngine->orderedFileNameList;
261 foreach (const QString &dbFileName, fileNames) {
269 QHelpDBReader reader(dbFileName,
270 QHelpGlobal::uniquifyConnectionName(dbFileName +
271 QLatin1String("FromQHelpContentProvider"),
272 QThread::currentThread()), 0);
275 foreach (const QByteArray& ba, reader.contentsForFilter(atts)) {
281 QStack<QHelpContentItem*> stack;
293 item = new QHelpContentItem(title, link,
294 m_helpEngine->fileNameReaderMap.value(dbFileName), m_rootItem);
295 m_rootItem->appendChild(item);
301 if (depth > _depth && _root) {
305 if (depth == _depth) {
306 item = new QHelpContentItem(title, link,
307 m_helpEngine->fileNameReaderMap.value(dbFileName), stack.top());
308 stack.top()->appendChild(item);
309 } else if (depth < _depth) {
326 \class QHelpContentModel
328 \brief The QHelpContentModel class provides a model that supplies content to views.
333 \fn void QHelpContentModel::contentsCreationStarted()
335 This signal is emitted when the creation of the contents has
336 started. The current contents are invalid from this point on
337 until the signal contentsCreated() is emitted.
339 \sa isCreatingContents()
343 \fn void QHelpContentModel::contentsCreated()
345 This signal is emitted when the contents have been created.
348 QHelpContentModel::QHelpContentModel(QHelpEnginePrivate *helpEngine)
349 : QAbstractItemModel(helpEngine)
351 d = new QHelpContentModelPrivate();
353 d->qhelpContentProvider = new QHelpContentProvider(helpEngine);
355 connect(d->qhelpContentProvider, SIGNAL(finished()),
356 this, SLOT(insertContents()), Qt::QueuedConnection);
357 connect(helpEngine->q, SIGNAL(readersAboutToBeInvalidated()), this, SLOT(invalidateContents()));
361 Destroys the help content model.
363 QHelpContentModel::~QHelpContentModel()
369 void QHelpContentModel::invalidateContents(bool onShutDown)
372 disconnect(this, SLOT(insertContents()));
373 d->qhelpContentProvider->stopCollecting();
383 Creates new contents by querying the help system
384 for contents specified for the \a customFilterName.
386 void QHelpContentModel::createContents(const QString &customFilterName)
388 d->qhelpContentProvider->collectContents(customFilterName);
389 emit contentsCreationStarted();
392 void QHelpContentModel::insertContents()
396 count = d->rootItem->childCount() - 1;
397 beginRemoveRows(QModelIndex(), 0, count > 0 ? count : 0);
403 count = d->qhelpContentProvider->nextChildCount() - 1;
404 beginInsertRows(QModelIndex(), 0, count > 0 ? count : 0);
405 d->rootItem = d->qhelpContentProvider->rootItem();
408 emit contentsCreated();
412 Returns true if the contents are currently rebuilt, otherwise
415 bool QHelpContentModel::isCreatingContents() const
417 return d->qhelpContentProvider->isRunning();
421 Returns the help content item at the model index position
424 QHelpContentItem *QHelpContentModel::contentItemAt(const QModelIndex &index) const
427 return static_cast<QHelpContentItem*>(index.internalPointer());
433 Returns the index of the item in the model specified by
434 the given \a row, \a column and \a parent index.
436 QModelIndex QHelpContentModel::index(int row, int column, const QModelIndex &parent) const
439 return QModelIndex();
441 QHelpContentItem *parentItem = contentItemAt(parent);
442 QHelpContentItem *item = parentItem->child(row);
444 return QModelIndex();
445 return createIndex(row, column, item);
449 Returns the parent of the model item with the given
450 \a index, or QModelIndex() if it has no parent.
452 QModelIndex QHelpContentModel::parent(const QModelIndex &index) const
454 QHelpContentItem *item = contentItemAt(index);
456 return QModelIndex();
458 QHelpContentItem *parentItem = static_cast<QHelpContentItem*>(item->parent());
460 return QModelIndex();
462 QHelpContentItem *grandparentItem = static_cast<QHelpContentItem*>(parentItem->parent());
463 if (!grandparentItem)
464 return QModelIndex();
466 int row = grandparentItem->childPosition(parentItem);
467 return createIndex(row, index.column(), parentItem);
471 Returns the number of rows under the given \a parent.
473 int QHelpContentModel::rowCount(const QModelIndex &parent) const
475 QHelpContentItem *parentItem = contentItemAt(parent);
478 return parentItem->childCount();
482 Returns the number of columns under the given \a parent. Currently returns always 1.
484 int QHelpContentModel::columnCount(const QModelIndex &parent) const
492 Returns the data stored under the given \a role for
493 the item referred to by the \a index.
495 QVariant QHelpContentModel::data(const QModelIndex &index, int role) const
497 if (role != Qt::DisplayRole)
500 QHelpContentItem *item = contentItemAt(index);
503 return item->title();
509 \class QHelpContentWidget
511 \brief The QHelpContentWidget class provides a tree view for displaying help content model items.
516 \fn void QHelpContentWidget::linkActivated(const QUrl &link)
518 This signal is emitted when a content item is activated and
519 its associated \a link should be shown.
522 QHelpContentWidget::QHelpContentWidget()
526 setUniformRowHeights(true);
527 connect(this, SIGNAL(activated(QModelIndex)),
528 this, SLOT(showLink(QModelIndex)));
532 Returns the index of the content item with the \a link.
533 An invalid index is returned if no such an item exists.
535 QModelIndex QHelpContentWidget::indexOf(const QUrl &link)
537 QHelpContentModel *contentModel =
538 qobject_cast<QHelpContentModel*>(model());
539 if (!contentModel || link.scheme() != QLatin1String("qthelp"))
540 return QModelIndex();
542 m_syncIndex = QModelIndex();
543 for (int i=0; i<contentModel->rowCount(); ++i) {
544 QHelpContentItem *itm =
545 contentModel->contentItemAt(contentModel->index(i, 0));
546 if (itm && itm->url().host() == link.host()) {
547 QString path = link.path();
548 if (path.startsWith(QLatin1Char('/')))
550 if (searchContentItem(contentModel, contentModel->index(i, 0), path)) {
555 return QModelIndex();
558 bool QHelpContentWidget::searchContentItem(QHelpContentModel *model,
559 const QModelIndex &parent, const QString &path)
561 QHelpContentItem *parentItem = model->contentItemAt(parent);
565 if (parentItem->url().path() == path) {
566 m_syncIndex = parent;
570 for (int i=0; i<parentItem->childCount(); ++i) {
571 if (searchContentItem(model, model->index(i, 0, parent), path))
577 void QHelpContentWidget::showLink(const QModelIndex &index)
579 QHelpContentModel *contentModel = qobject_cast<QHelpContentModel*>(model());
583 QHelpContentItem *item = contentModel->contentItemAt(index);
586 QUrl url = item->url();
588 emit linkActivated(url);