diff options
Diffstat (limited to 'weather/src/contentlist.cpp')
-rw-r--r-- | weather/src/contentlist.cpp | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/weather/src/contentlist.cpp b/weather/src/contentlist.cpp new file mode 100644 index 0000000..8b054aa --- /dev/null +++ b/weather/src/contentlist.cpp @@ -0,0 +1,441 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: openBossa - INdT (renato.chencarek@openbossa.org) +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** the openBossa stream from INdT (renato.chencarek@openbossa.org). +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "contentlist.h" +#include <QPointer> + +// ContentListItem + +ContentListItem::ContentListItem(QGraphicsItem *parent) + : QGraphicsItem(parent) + , m_geometry(QRectF(0.0, 0.0, 0.0, 0.0)) + , m_geometryReady(false) +{ + setFlag(QGraphicsItem::ItemHasNoContents, true); + setFlag(QGraphicsItem::ItemSendsGeometryChanges, true); +} + +QRectF ContentListItem::boundingRect() const +{ + if (!m_geometryReady) + return QRectF(0.0, 0.0, 0.0, contentHeight()); + return m_geometry; +} + +void ContentListItem::updateGeometry() +{ + m_geometryReady = parentItem() != 0; + qreal width = parentItem() ? parentItem()->boundingRect().width() - pos().x() : 0.0; + QRectF geometry(0.0, 0.0, width, contentHeight()); + if (m_geometry != geometry) { + prepareGeometryChange(); + m_geometry = geometry; + update(); + } +} + +QVariant ContentListItem::itemChange(GraphicsItemChange change, const QVariant &value) +{ + Q_UNUSED(value); + switch (change) { + case QGraphicsItem::ItemParentHasChanged: + case QGraphicsItem::ItemPositionHasChanged: + updateGeometry(); + break; + default: + break; + } + return value; +} + +void ContentListItem::paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(painter); + Q_UNUSED(option); + Q_UNUSED(widget); +} + +// ContentListActivity + +void ContentListActivity::addActivity(ContentListActivity *activity) +{ + int idx = m_list.m_queue.indexOf(this) + 1; + if (idx > 0) + m_list.m_queue.insert(idx + m_insertPos++, activity); +} + +bool ContentListActivity::active() +{ + return false; +} + +// SignalActivity + + +bool SignalActivity::run() +{ + emit notify(); + return false; +} + +// SortActivity + +bool SortActivity::run() +{ + qSort(m_list.m_items.begin(), m_list.m_items.end(), m_compare); + m_list.updateItems(); + return false; +} + +// AppendItemsActivity + +bool AppendItemsActivity::run() +{ + m_list.prepareGeometryChange(); + m_list.doAppendItems(m_items, true); + m_list.update(); + return false; +} + +// AnimationActivity + +AnimationActivity::AnimationActivity(QAbstractAnimation *animation, ContentList &list) + : ContentListActivity(list) + , m_animation(animation) +{ +} + +AnimationActivity::~AnimationActivity() +{ + if (m_animation && m_animation->state() == QAbstractAnimation::Stopped) + m_animation->deleteLater(); +} + + +bool AnimationActivity::run() +{ + if (!m_animation || m_animation->state() != QAbstractAnimation::Stopped) + return false; + + connect(m_animation, SIGNAL(finished()), this, SLOT(animationEnd())); + m_animation->start(QAbstractAnimation::DeleteWhenStopped); + return true; +} + +void AnimationActivity::animationEnd() +{ + m_animation = 0; + activityEnd(); +} + +// RemoveActivity + +RemoveActivity::RemoveActivity(int idx, bool destroyItem, bool notify, ContentList &list) + : ContentListActivity(list) + , m_idx(idx) + , m_destroyItem(destroyItem) + , m_item(0) + , m_active(false) + , m_notify(notify) +{ +} + +bool RemoveActivity::run() +{ + if (m_active) + return false; + + m_item = m_list.getItem(m_idx); + if (!m_item) + return false; + + QAbstractAnimation *animation = m_item->getHideAnimation(); + if (animation) { + connect(animation, SIGNAL(finished()), this, SLOT(hideEnd())); + animation->start(QAbstractAnimation::DeleteWhenStopped); + m_active = true; + } else + hideEnd(); + + return m_active; +} + +void RemoveActivity::hideEnd() +{ + m_item->hide(); + QAbstractAnimation *animation = m_list.getRemoveAnimation(m_idx); + m_list.doRemoveItem(m_idx, m_notify); + if (m_destroyItem) + m_item->deleteLater(); + m_active = animation != 0; + if (animation) { + connect(animation, SIGNAL(finished()), this, SLOT(activityEnd())); + animation->start(QAbstractAnimation::DeleteWhenStopped); + } else + activityEnd(); +} + +// InsertActivity + +InsertActivity::InsertActivity(int idx, ContentListItem* item, bool notify, ContentList &list) + : ContentListActivity(list) + , m_idx(idx) + , m_item(item) + , m_active(false) + , m_notify(notify) +{ +} + +bool InsertActivity::run() +{ + if (m_active || !m_item) + return false; + + m_idx = m_idx < 0 ? 0 : m_idx > m_list.itemCount() ? m_list.itemCount() : m_idx; + + + QAbstractAnimation *animation = m_list.getInsertAnimation(m_idx, m_item->contentHeight()); + if (animation) { + connect(animation, SIGNAL(finished()), this, SLOT(showItem())); + animation->start(QAbstractAnimation::DeleteWhenStopped); + m_active = true; + } else + showItem(); + + return m_active; +} + +void InsertActivity::showItem() +{ + m_list.doInsertItem(m_idx, m_item, m_notify); + m_item->show(); + QAbstractAnimation *animation = m_item->getShowAnimation(); + m_active = animation != 0; + if (animation) { + connect(animation, SIGNAL(finished()), this, SLOT(activityEnd())); + animation->start(QAbstractAnimation::DeleteWhenStopped); + } else + activityEnd(); +} + +// MoveActivity + +MoveActivity::MoveActivity(int from, int to, ContentList &list) + : ContentListActivity(list) + , m_from(from) + , m_to(to) +{ +} + +bool MoveActivity::run() +{ + if (m_from < 0 || m_from >= m_list.itemCount()) + return false; + + m_to = m_to < 0 ? 0 : m_to > m_list.itemCount() ? m_list.itemCount() : m_to; + + if (m_from == m_to || (m_from == m_list.itemCount() - 1 && m_to > m_from)) + return false; + + addActivity(new RemoveActivity(m_from, false, false, m_list)); + addActivity(new InsertActivity(m_to, m_list.getItem(m_from), false, m_list)); + + return false; +} + +// ContentList + +ContentList::ContentList(QGraphicsItem *parent) + : QGraphicsItem(parent) + , m_boundingRect(0.0, 0.0, 0.0, 0.0) +{ + setFlag(QGraphicsItem::ItemHasNoContents, true); +} + +ContentList::ContentList(QList<ContentListItem*> items, QGraphicsItem *parent) + : QGraphicsItem(parent) + , m_boundingRect(0.0, 0.0, 0.0, 0.0) +{ + setFlag(QGraphicsItem::ItemHasNoContents, true); + doAppendItems(items, false); +} + +void ContentList::doAppendItems(QList<ContentListItem*> items, bool notify) +{ + qreal top = 0; + foreach(ContentListItem *item, m_items) + top += item->contentHeight(); + foreach(ContentListItem *item, items) { + item->setParentItem(this); + item->setPos(0, top); + top += item->contentHeight(); + m_items.append(item); + m_boundingRect.setHeight(m_boundingRect.height() + item->contentHeight()); + if (notify) + emit newContentItem(item); + } +} + +ContentList::~ContentList() +{ + foreach(ContentListActivity *activity, m_queue) + activity->deleteLater(); +} + +qreal ContentList::width() const +{ + return m_boundingRect.width(); +} + +void ContentList::setWidth(qreal width) +{ + if (m_boundingRect.width() != width) { + prepareGeometryChange(); + m_boundingRect.setWidth(width); + update(); + foreach(ContentListItem *item, m_items) + item->updateGeometry(); + } +} + +QRectF ContentList::boundingRect() const +{ + return m_boundingRect; +} + +void ContentList::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(painter); + Q_UNUSED(option); + Q_UNUSED(widget); +} + +bool ContentList::insertItem(int idx, ContentListItem* item) +{ + if (getItemIndex(item) != -1) + return false; + addActivity(new InsertActivity(idx, item, true, *this)); + return true; +} + +bool ContentList::removeItem(int idx) +{ + if (idx < 0 || idx >= m_items.count()) + return false; + addActivity(new RemoveActivity(idx, true, true, *this)); + return true; +} + +bool ContentList::moveItem(int from, int to) +{ + if (from < 0 || from >= m_items.count()) + return false; + + to = to < 0 ? 0 : to > m_items.count() ? m_items.count() : to; + + if (from == to) + return true; + addActivity(new MoveActivity(from, to, *this)); + return true; +} + +void ContentList::addActivity(ContentListActivity *activity) +{ + m_queue.append(activity); + checkQueue(); +} + +void ContentList::checkQueue() +{ + while (m_queue.count() > 0 && !m_queue[0]->active()) + if (!m_queue[0]->run()) + m_queue.takeFirst()->deleteLater(); +} + +void ContentList::activityEnd() +{ + m_queue.takeFirst()->deleteLater(); + checkQueue(); +} + +void ContentList::doRemoveItem(int idx, bool notify) +{ + if (idx >= 0 && idx < m_items.count()) { + ContentListItem *item = m_items[idx]; + item->setParentItem(0); + m_items.removeAt(idx); + if (notify) { + prepareGeometryChange(); + m_boundingRect.setHeight(m_boundingRect.height() - item->contentHeight()); + update(); + emit contentItemRemoved(item); + } + } +} + +void ContentList::doInsertItem(int idx, ContentListItem * item, bool notify) +{ + if (idx >= 0 && idx <= m_items.count()) { + qreal top = 0; + for (int i = 0; i < idx; ++i) + top += m_items[i]->contentHeight(); + item->setPos(0, top); + item->setParentItem(this); + if (notify) { + prepareGeometryChange(); + m_boundingRect.setHeight(m_boundingRect.height() + item->contentHeight()); + update(); + emit newContentItem(item); + } + m_items.insert(idx, item); + } +} + +void ContentList::updateItems() +{ + qreal top = 0; + foreach(ContentListItem *item, m_items) { + item->setPos(0, top); + top += item->contentHeight(); + } + update(); +} + +void ContentList::sortItems(ContentListItemCompare compare) +{ + addActivity(new SortActivity(*this, compare)); +} + +void ContentList::appendItems(QList<ContentListItem*> items) +{ + addActivity(new AppendItemsActivity(*this, items)); +} |