/**************************************************************************** ** ** 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 // 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 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 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 items) { addActivity(new AppendItemsActivity(*this, items)); }