Merge branch 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-1 into master-integration
[qt-netbsd.git] / tools / assistant / lib / qhelpcontentwidget.cpp
blob3986afba423f8d63696d921a51e4c5146bbb7e03
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 "qhelpcontentwidget.h"
43 #include "qhelpenginecore.h"
44 #include "qhelpengine_p.h"
45 #include "qhelpdbreader_p.h"
47 #include <QtCore/QDir>
48 #include <QtCore/QStack>
49 #include <QtCore/QThread>
50 #include <QtCore/QMutex>
51 #include <QtGui/QHeaderView>
53 QT_BEGIN_NAMESPACE
55 class QHelpContentItemPrivate
57 public:
58 QHelpContentItemPrivate(const QString &t, const QString &l,
59 QHelpDBReader *r, QHelpContentItem *p)
61 parent = p;
62 title = t;
63 link = l;
64 helpDBReader = r;
67 QList<QHelpContentItem*> childItems;
68 QHelpContentItem *parent;
69 QString title;
70 QString link;
71 QHelpDBReader *helpDBReader;
74 class QHelpContentProvider : public QThread
76 public:
77 QHelpContentProvider(QHelpEnginePrivate *helpEngine);
78 ~QHelpContentProvider();
79 void collectContents(const QString &customFilterName);
80 void stopCollecting();
81 QHelpContentItem *rootItem();
82 int nextChildCount() const;
84 private:
85 void run();
87 QHelpEnginePrivate *m_helpEngine;
88 QHelpContentItem *m_rootItem;
89 QStringList m_filterAttributes;
90 QQueue<QHelpContentItem*> m_rootItems;
91 QMutex m_mutex;
92 bool m_abort;
95 class QHelpContentModelPrivate
97 public:
98 QHelpContentItem *rootItem;
99 QHelpContentProvider *qhelpContentProvider;
105 \class QHelpContentItem
106 \inmodule QtHelp
107 \brief The QHelpContentItem class provides an item for use with QHelpContentModel.
108 \since 4.4
111 QHelpContentItem::QHelpContentItem(const QString &name, const QString &link,
112 QHelpDBReader *reader, QHelpContentItem *parent)
114 d = new QHelpContentItemPrivate(name, link, reader, parent);
118 Destroys the help content item.
120 QHelpContentItem::~QHelpContentItem()
122 qDeleteAll(d->childItems);
123 delete d;
126 void QHelpContentItem::appendChild(QHelpContentItem *item)
128 d->childItems.append(item);
132 Returns the child of the content item in the give \a row.
134 \sa parent()
136 QHelpContentItem *QHelpContentItem::child(int row) const
138 if (row >= childCount())
139 return 0;
140 return d->childItems.value(row);
144 Returns the number of child items.
146 int QHelpContentItem::childCount() const
148 return d->childItems.count();
152 Returns the row of this item from its parents view.
154 int QHelpContentItem::row() const
156 if (d->parent)
157 return d->parent->d->childItems.indexOf(const_cast<QHelpContentItem*>(this));
158 return 0;
162 Returns the title of the content item.
164 QString QHelpContentItem::title() const
166 return d->title;
170 Returns the URL of this content item.
172 QUrl QHelpContentItem::url() const
174 return d->helpDBReader->urlOfPath(d->link);
178 Returns the parent content item.
180 QHelpContentItem *QHelpContentItem::parent() const
182 return d->parent;
186 Returns the position of a given \a child.
188 int QHelpContentItem::childPosition(QHelpContentItem *child) const
190 return d->childItems.indexOf(child);
195 QHelpContentProvider::QHelpContentProvider(QHelpEnginePrivate *helpEngine)
196 : QThread(helpEngine)
198 m_helpEngine = helpEngine;
199 m_rootItem = 0;
200 m_abort = false;
203 QHelpContentProvider::~QHelpContentProvider()
205 stopCollecting();
208 void QHelpContentProvider::collectContents(const QString &customFilterName)
210 m_mutex.lock();
211 m_filterAttributes = m_helpEngine->q->filterAttributes(customFilterName);
212 m_mutex.unlock();
213 if (!isRunning()) {
214 start(LowPriority);
215 } else {
216 stopCollecting();
217 start(LowPriority);
221 void QHelpContentProvider::stopCollecting()
223 if (!isRunning())
224 return;
225 m_mutex.lock();
226 m_abort = true;
227 m_mutex.unlock();
228 wait();
231 QHelpContentItem *QHelpContentProvider::rootItem()
233 QMutexLocker locker(&m_mutex);
234 return m_rootItems.dequeue();
237 int QHelpContentProvider::nextChildCount() const
239 return m_rootItems.head()->childCount();
242 void QHelpContentProvider::run()
244 QString title;
245 QString link;
246 int depth = 0;
247 QHelpContentItem *item = 0;
249 m_mutex.lock();
250 m_rootItem = new QHelpContentItem(QString(), QString(), 0);
251 m_rootItems.enqueue(m_rootItem);
252 QStringList atts = m_filterAttributes;
253 const QStringList fileNames = m_helpEngine->orderedFileNameList;
254 m_mutex.unlock();
256 foreach (QString dbFileName, fileNames) {
257 m_mutex.lock();
258 if (m_abort) {
259 m_abort = false;
260 m_mutex.unlock();
261 break;
263 m_mutex.unlock();
264 QHelpDBReader reader(dbFileName,
265 QHelpGlobal::uniquifyConnectionName(dbFileName +
266 QLatin1String("FromQHelpContentProvider"),
267 QThread::currentThread()), 0);
268 if (!reader.init())
269 continue;
270 foreach (const QByteArray& ba, reader.contentsForFilter(atts)) {
271 if (ba.size() < 1)
272 continue;
274 int _depth = 0;
275 bool _root = false;
276 QStack<QHelpContentItem*> stack;
278 QDataStream s(ba);
279 for (;;) {
280 s >> depth;
281 s >> link;
282 s >> title;
283 if (title.isEmpty())
284 break;
285 CHECK_DEPTH:
286 if (depth == 0) {
287 m_mutex.lock();
288 item = new QHelpContentItem(title, link,
289 m_helpEngine->fileNameReaderMap.value(dbFileName), m_rootItem);
290 m_rootItem->appendChild(item);
291 m_mutex.unlock();
292 stack.push(item);
293 _depth = 1;
294 _root = true;
295 } else {
296 if (depth > _depth && _root) {
297 _depth = depth;
298 stack.push(item);
300 if (depth == _depth) {
301 item = new QHelpContentItem(title, link,
302 m_helpEngine->fileNameReaderMap.value(dbFileName), stack.top());
303 stack.top()->appendChild(item);
304 } else if (depth < _depth) {
305 stack.pop();
306 --_depth;
307 goto CHECK_DEPTH;
313 m_mutex.lock();
314 m_abort = false;
315 m_mutex.unlock();
321 \class QHelpContentModel
322 \inmodule QtHelp
323 \brief The QHelpContentModel class provides a model that supplies content to views.
324 \since 4.4
328 \fn void QHelpContentModel::contentsCreationStarted()
330 This signal is emitted when the creation of the contents has
331 started. The current contents are invalid from this point on
332 until the signal contentsCreated() is emitted.
334 \sa isCreatingContents()
338 \fn void QHelpContentModel::contentsCreated()
340 This signal is emitted when the contents have been created.
343 QHelpContentModel::QHelpContentModel(QHelpEnginePrivate *helpEngine)
344 : QAbstractItemModel(helpEngine)
346 d = new QHelpContentModelPrivate();
347 d->rootItem = 0;
348 d->qhelpContentProvider = new QHelpContentProvider(helpEngine);
350 connect(d->qhelpContentProvider, SIGNAL(finished()),
351 this, SLOT(insertContents()), Qt::QueuedConnection);
352 connect(helpEngine->q, SIGNAL(setupStarted()), this, SLOT(invalidateContents()));
356 Destroys the help content model.
358 QHelpContentModel::~QHelpContentModel()
360 delete d->rootItem;
361 delete d;
364 void QHelpContentModel::invalidateContents(bool onShutDown)
366 if (onShutDown)
367 disconnect(this, SLOT(insertContents()));
368 d->qhelpContentProvider->stopCollecting();
369 if (d->rootItem) {
370 delete d->rootItem;
371 d->rootItem = 0;
373 reset();
377 Creates new contents by querying the help system
378 for contents specified for the \a customFilterName.
380 void QHelpContentModel::createContents(const QString &customFilterName)
382 d->qhelpContentProvider->collectContents(customFilterName);
383 emit contentsCreationStarted();
386 void QHelpContentModel::insertContents()
388 int count;
389 if (d->rootItem) {
390 count = d->rootItem->childCount() - 1;
391 beginRemoveRows(QModelIndex(), 0, count > 0 ? count : 0);
392 delete d->rootItem;
393 d->rootItem = 0;
394 endRemoveRows();
397 count = d->qhelpContentProvider->nextChildCount() - 1;
398 beginInsertRows(QModelIndex(), 0, count > 0 ? count : 0);
399 d->rootItem = d->qhelpContentProvider->rootItem();
400 endInsertRows();
401 reset();
402 emit contentsCreated();
406 Returns true if the contents are currently rebuilt, otherwise
407 false.
409 bool QHelpContentModel::isCreatingContents() const
411 return d->qhelpContentProvider->isRunning();
415 Returns the help content item at the model index position
416 \a index.
418 QHelpContentItem *QHelpContentModel::contentItemAt(const QModelIndex &index) const
420 if (index.isValid())
421 return static_cast<QHelpContentItem*>(index.internalPointer());
422 else
423 return d->rootItem;
427 Returns the index of the item in the model specified by
428 the given \a row, \a column and \a parent index.
430 QModelIndex QHelpContentModel::index(int row, int column, const QModelIndex &parent) const
432 if (!d->rootItem)
433 return QModelIndex();
435 QHelpContentItem *parentItem = contentItemAt(parent);
436 QHelpContentItem *item = parentItem->child(row);
437 if (!item)
438 return QModelIndex();
439 return createIndex(row, column, item);
443 Returns the parent of the model item with the given
444 \a index, or QModelIndex() if it has no parent.
446 QModelIndex QHelpContentModel::parent(const QModelIndex &index) const
448 QHelpContentItem *item = contentItemAt(index);
449 if (!item)
450 return QModelIndex();
452 QHelpContentItem *parentItem = static_cast<QHelpContentItem*>(item->parent());
453 if (!parentItem)
454 return QModelIndex();
456 QHelpContentItem *grandparentItem = static_cast<QHelpContentItem*>(parentItem->parent());
457 if (!grandparentItem)
458 return QModelIndex();
460 int row = grandparentItem->childPosition(parentItem);
461 return createIndex(row, index.column(), parentItem);
465 Returns the number of rows under the given \a parent.
467 int QHelpContentModel::rowCount(const QModelIndex &parent) const
469 QHelpContentItem *parentItem = contentItemAt(parent);
470 if (!parentItem)
471 return 0;
472 return parentItem->childCount();
476 Returns the number of columns under the given \a parent. Currently returns always 1.
478 int QHelpContentModel::columnCount(const QModelIndex &parent) const
480 Q_UNUSED(parent)
482 return 1;
486 Returns the data stored under the given \a role for
487 the item referred to by the \a index.
489 QVariant QHelpContentModel::data(const QModelIndex &index, int role) const
491 if (role != Qt::DisplayRole)
492 return QVariant();
494 QHelpContentItem *item = contentItemAt(index);
495 if (!item)
496 return QVariant();
497 return item->title();
503 \class QHelpContentWidget
504 \inmodule QtHelp
505 \brief The QHelpContentWidget class provides a tree view for displaying help content model items.
506 \since 4.4
510 \fn void QHelpContentWidget::linkActivated(const QUrl &link)
512 This signal is emitted when a content item is activated and
513 its associated \a link should be shown.
516 QHelpContentWidget::QHelpContentWidget()
517 : QTreeView(0)
519 header()->hide();
520 setUniformRowHeights(true);
521 connect(this, SIGNAL(activated(QModelIndex)),
522 this, SLOT(showLink(QModelIndex)));
526 Returns the index of the content item with the \a link.
527 An invalid index is returned if no such an item exists.
529 QModelIndex QHelpContentWidget::indexOf(const QUrl &link)
531 QHelpContentModel *contentModel =
532 qobject_cast<QHelpContentModel*>(model());
533 if (!contentModel || link.scheme() != QLatin1String("qthelp"))
534 return QModelIndex();
536 m_syncIndex = QModelIndex();
537 for (int i=0; i<contentModel->rowCount(); ++i) {
538 QHelpContentItem *itm =
539 contentModel->contentItemAt(contentModel->index(i, 0));
540 if (itm && itm->url().host() == link.host()) {
541 QString path = link.path();
542 if (path.startsWith(QLatin1Char('/')))
543 path = path.mid(1);
544 if (searchContentItem(contentModel, contentModel->index(i, 0), path)) {
545 return m_syncIndex;
549 return QModelIndex();
552 bool QHelpContentWidget::searchContentItem(QHelpContentModel *model,
553 const QModelIndex &parent, const QString &path)
555 QHelpContentItem *parentItem = model->contentItemAt(parent);
556 if (!parentItem)
557 return false;
559 if (QDir::cleanPath(parentItem->url().path()) == path) {
560 m_syncIndex = parent;
561 return true;
564 for (int i=0; i<parentItem->childCount(); ++i) {
565 if (searchContentItem(model, model->index(i, 0, parent), path))
566 return true;
568 return false;
571 void QHelpContentWidget::showLink(const QModelIndex &index)
573 QHelpContentModel *contentModel = qobject_cast<QHelpContentModel*>(model());
574 if (!contentModel)
575 return;
577 QHelpContentItem *item = contentModel->contentItemAt(index);
578 if (!item)
579 return;
580 QUrl url = item->url();
581 if (url.isValid())
582 emit linkActivated(url);
585 QT_END_NAMESPACE