src/hbwidgets/itemviews/hbtreelayout_p.cpp
changeset 0 16d8024aca5e
child 1 f7ac710697a9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hbwidgets/itemviews/hbtreelayout_p.cpp	Mon Apr 19 14:02:13 2010 +0300
@@ -0,0 +1,402 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (developer.feedback@nokia.com)
+**
+** This file is part of the HbWidgets module of the UI Extensions for Mobile.
+**
+** GNU Lesser General Public License Usage
+** 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
+** Nokia at developer.feedback@nokia.com.
+**
+****************************************************************************/
+
+#include "hbtreelayout_p.h"
+#include "hblayoututils_p.h"
+
+#include "hbabstractitemcontainer.h"
+#include "hbapplication.h"
+
+#include <QWidget> // for QWIDGETSIZE_MAX
+
+namespace
+{
+static const qreal INVALID_ITEM_HEIGHT = -1.0;
+}
+
+
+/*
+    \private
+    \class HbTreeLayout
+    \brief HbTreeLayout manages geometries of hierarchical tree view contents.
+*/
+
+class HbTreeLayoutPrivate
+{
+public:
+
+    struct TreeItem 
+    {
+        QGraphicsLayoutItem* mItem;
+        int mLevel;
+    };
+
+    HbTreeLayoutPrivate(HbTreeLayout *q_ptr);
+    bool uniformSizedItems() const;
+    qreal calculateSmallestItemHeight() const;
+
+    QList<TreeItem> mItems;
+    HbTreeLayout *q;
+    qreal mIndentation;
+    qreal mSmallestItemHeight;
+};
+
+HbTreeLayoutPrivate::HbTreeLayoutPrivate(HbTreeLayout *q_ptr) :
+    q(q_ptr),
+    mIndentation(15.0),
+    mSmallestItemHeight(INVALID_ITEM_HEIGHT)
+{
+}
+
+bool HbTreeLayoutPrivate::uniformSizedItems() const
+{
+    if (q->parentLayoutItem() && (static_cast<HbAbstractItemContainer *>(q->parentLayoutItem()))->uniformItemSizes() ) {
+        return true;
+    } else {
+        return false;
+    }      
+}
+
+/*!
+    Calculates the smallest item height from all items.
+*/
+qreal HbTreeLayoutPrivate::calculateSmallestItemHeight() const
+{
+    qreal smallestHeight(0);
+    if (uniformSizedItems()) {
+        QGraphicsLayoutItem *firstItem = mItems.value(0).mItem;
+        if (firstItem) {
+            smallestHeight = firstItem->preferredHeight();  
+        } 
+    } else {  
+        int itemCount = mItems.count();
+        if (itemCount > 0) {
+            smallestHeight = mItems.first().mItem->preferredHeight();
+        }
+        for (int i = 1; i < itemCount; ++i) {       
+            smallestHeight = qMin(smallestHeight, mItems.at(i).mItem->preferredHeight());
+        }
+    }
+    return smallestHeight;
+}
+
+
+/*!
+    Constructor.
+    \param parent parent layout item.
+ */
+HbTreeLayout::HbTreeLayout(QGraphicsLayoutItem *parent)
+    : QGraphicsLayout(parent), d(new HbTreeLayoutPrivate(this))
+{
+}
+
+/*!
+    Destructor.
+    Does not clear the parentLayoutItem of it's sub items.
+    If you want to reuse the sub items first call removeAt()
+    for each of them.
+ */
+HbTreeLayout::~HbTreeLayout()
+{
+    delete d;
+}
+
+/*!
+    \brief Appends a layout item to the list layout.
+
+    This is convenience function which will internally call the \c insertItem method.
+
+    \param item layout item to be added to list.
+ */
+void HbTreeLayout::addItem(QGraphicsLayoutItem *item, int level)
+{
+    insertItem( -1, item, level );
+}
+
+/*!
+    \brief  Inserts a layout item to the list layout.
+
+    Inserts the given \a item to given position \a index.
+    Does not take ownership.
+
+    If index is out of range, the item is appended to the end of the list.
+
+    \param  index position where to insert the layout.
+    \param  item layout item to be inserted to stack.
+ */
+void HbTreeLayout::insertItem(int index, QGraphicsLayoutItem *item, int level)
+{
+    index = qMin(index, d->mItems.count());
+    if (index < 0) {
+        index = d->mItems.count();
+    }
+    HbLayoutUtils::addChildItem(this, item);
+
+    HbTreeLayoutPrivate::TreeItem listItem;
+    listItem.mItem = item;
+    listItem.mLevel = level;
+
+    d->mItems.insert( index, listItem);
+    invalidate();
+}
+
+/*!
+    \brief Returns position of layout item in the list layout.
+    \param item item to look for.
+    \return position of layout item, or -1 if not found.
+ */
+int HbTreeLayout::indexOf( QGraphicsLayoutItem *item ) const
+{
+    for ( int i = 0; i < count(); ++i ) {
+        if ( itemAt( i ) == item ) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+/*!
+    \brief Removes layout item from the list layout.
+
+    Equivalent of calling removeAt(indexOf(item)).
+
+    \param item item to be removed.
+    \sa removeAt
+ */
+void HbTreeLayout::removeItem( QGraphicsLayoutItem *item )
+{
+    removeAt(indexOf(item));
+}
+
+/*!
+    From QGraphicsLayout.
+ */
+int HbTreeLayout::count() const
+{
+    return d->mItems.count();
+}
+
+/*!
+    From QGraphicsLayout.
+ */
+QGraphicsLayoutItem *HbTreeLayout::itemAt(int i) const
+{
+    return d->mItems.value(i).mItem;
+}
+
+/*!
+    From QGraphicsLayout.
+    Clears the parentLayoutItem of removed item.
+ */
+void HbTreeLayout::removeAt(int index)
+{
+    QGraphicsLayoutItem *item = itemAt(index);
+    if ( item ) {
+        d->mItems.removeAt(index);
+        item->setParentLayoutItem(0);
+        invalidate();
+    }
+}
+
+/*!
+    From QGraphicsLayout.
+ */
+void HbTreeLayout::setGeometry( const QRectF &rect )
+{
+    QGraphicsLayout::setGeometry(rect);
+    QRectF effectiveRect = geometry();
+    // TODO: Apply margins?
+    //qreal left, top, right, bottom;
+    //getContentsMargins(&left, &top, &right, &bottom);
+    //effectiveRect.adjust(+left, +top, -right, -bottom);
+
+    bool mirrorLayout = false;
+    if (HbApplication::layoutDirection() == Qt::RightToLeft) {
+        mirrorLayout = true;
+    }
+
+    qreal y = effectiveRect.y();
+    int itemCount = count();
+    for (int i = 0; i < itemCount; ++i) {
+        HbTreeLayoutPrivate::TreeItem listItem = d->mItems.at(i);
+
+        qreal itemHeight = listItem.mItem->preferredHeight();
+        qreal itemWidth = listItem.mItem->preferredWidth();
+
+        qreal viewWidth = minimumWidth();
+        if (viewWidth > 0.0) {
+            if (d->mIndentation * listItem.mLevel + itemWidth < viewWidth) {
+                itemWidth = viewWidth - (d->mIndentation * listItem.mLevel);
+            } else if (itemWidth > viewWidth) {
+                itemWidth = viewWidth;
+            }
+        }
+
+        qreal x;
+        if (mirrorLayout) {
+            x = effectiveRect.right() - d->mIndentation * listItem.mLevel - itemWidth;
+        } else {
+            x = d->mIndentation * listItem.mLevel + effectiveRect.left();
+        }
+
+        listItem.mItem->setGeometry( QRectF(x, y, itemWidth, itemHeight ) );
+        y += itemHeight;
+    }
+}
+
+/*!
+    From QGraphicsLayout.
+
+    The minimum size hint's width and height are the smallest ones of the
+    child layout items.
+
+    The preferred size hint is the sum of the preferred size hints of the
+    child layout items..
+
+    The maximum size hint "unlimited", i.e. the child layout items do not
+    affect the maximum size hint.
+ */
+QSizeF HbTreeLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
+{
+    QSizeF sizeHint(0, 0);
+
+    if (which == Qt::MaximumSize) {
+        // Sub items do not affect the maximum size hint.
+        sizeHint = QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
+    } else if (which == Qt::PreferredSize) {
+        QGraphicsWidget *view = 0;
+        if (    parentLayoutItem()
+            &&  !parentLayoutItem()->isLayout()
+            &&  parentLayoutItem()->graphicsItem()) {
+            view = parentLayoutItem()->graphicsItem()->parentWidget();
+        }
+        qreal viewWidth = view ? view->size().width() : 0.0;
+
+        int itemCount = count();
+        for (int i = 0; i < itemCount; ++i) {
+            QSizeF itemSize(0, 0);
+            HbTreeLayoutPrivate::TreeItem listItem = d->mItems.at(i);
+
+            itemSize = listItem.mItem->effectiveSizeHint(which);
+            if (viewWidth > 0.0) {
+                if (d->mIndentation * listItem.mLevel + itemSize.width() < viewWidth) {
+                    // if indentation + item width fits into view, expand item so that
+                    // indentation + item width == view width
+                    itemSize.setWidth(viewWidth - (d->mIndentation * listItem.mLevel));
+                } else if (itemSize.width() > viewWidth) {
+                    itemSize.setWidth(viewWidth);
+                }
+            }
+
+            if (itemSize.isValid()) {
+                sizeHint.rwidth() = qMax((d->mIndentation * listItem.mLevel + itemSize.width()), sizeHint.width());
+                sizeHint.rheight() = sizeHint.height() + itemSize.height();
+            }
+        }
+    } else if (which == Qt::MinimumSize) {
+        if(itemAt(0)) {
+            sizeHint = itemAt(0)->effectiveSizeHint(Qt::PreferredSize);
+        }
+        if (d->uniformSizedItems()) {
+            return sizeHint; //No need to goto loop below to check the sizes of every item
+        }
+        
+        int itemCount = count();
+        for( int i = 1; i < itemCount; ++i ) {
+            QSizeF itemSize(0, 0);
+            HbTreeLayoutPrivate::TreeItem listItem = d->mItems.at(i);
+
+            itemSize = listItem.mItem->effectiveSizeHint(Qt::PreferredSize);
+
+            if ( itemSize.isValid() ) {
+                sizeHint.rwidth() = qMin( itemSize.width(), sizeHint.width() );
+                sizeHint.rheight() = qMin( sizeHint.height(), itemSize.height() );
+            }
+        }
+    } else {
+        Q_ASSERT_X(false, "HbTreeLayout::sizeHint()", "Unhandled Qt::SizeHint type");
+        return sizeHint;
+    }
+
+    if (constraint.height() >= 0) {
+        sizeHint.setHeight(qMin(sizeHint.height(), constraint.height()));
+    }
+
+    if (constraint.width() >= 0) {
+        sizeHint.setWidth(qMin(sizeHint.width(), constraint.width()));
+    }
+
+    return sizeHint;
+
+}
+
+void HbTreeLayout::setItemLevel(QGraphicsLayoutItem *item, int level)
+{
+    for (int current = 0; current < d->mItems.count(); ++current) {
+        if (d->mItems.at(current).mItem == item) {
+            d->mItems[current].mLevel = level;
+            invalidate();
+            break;
+        }
+    }
+}
+
+qreal HbTreeLayout::indentation() const
+{
+    return d->mIndentation;
+}
+
+void HbTreeLayout::setIndentation(qreal indentation)
+{
+    if (indentation != d->mIndentation) {
+        d->mIndentation = indentation;
+        invalidate();
+    }
+}
+
+/*!
+    Returns the smallest item height.
+*/
+qreal HbTreeLayout::smallestItemHeight() const
+{
+    if (d->mSmallestItemHeight == INVALID_ITEM_HEIGHT) {
+        d->mSmallestItemHeight = d->calculateSmallestItemHeight();
+    }
+    return d->mSmallestItemHeight;
+}
+
+/*!
+	\reimp
+	
+	Invalidates smallest item height cache.
+*/
+void HbTreeLayout::invalidate()
+{
+    QGraphicsLayout::invalidate();
+
+    d->mSmallestItemHeight = INVALID_ITEM_HEIGHT;
+}
+
+