src/hbwidgets/itemviews/hbtreelayout_p.cpp
changeset 0 16d8024aca5e
child 1 f7ac710697a9
equal deleted inserted replaced
-1:000000000000 0:16d8024aca5e
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (developer.feedback@nokia.com)
       
     6 **
       
     7 ** This file is part of the HbWidgets module of the UI Extensions for Mobile.
       
     8 **
       
     9 ** GNU Lesser General Public License Usage
       
    10 ** This file may be used under the terms of the GNU Lesser General Public
       
    11 ** License version 2.1 as published by the Free Software Foundation and
       
    12 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
       
    13 ** Please review the following information to ensure the GNU Lesser General
       
    14 ** Public License version 2.1 requirements will be met:
       
    15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    16 **
       
    17 ** In addition, as a special exception, Nokia gives you certain additional
       
    18 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    20 **
       
    21 ** If you have questions regarding the use of this file, please contact
       
    22 ** Nokia at developer.feedback@nokia.com.
       
    23 **
       
    24 ****************************************************************************/
       
    25 
       
    26 #include "hbtreelayout_p.h"
       
    27 #include "hblayoututils_p.h"
       
    28 
       
    29 #include "hbabstractitemcontainer.h"
       
    30 #include "hbapplication.h"
       
    31 
       
    32 #include <QWidget> // for QWIDGETSIZE_MAX
       
    33 
       
    34 namespace
       
    35 {
       
    36 static const qreal INVALID_ITEM_HEIGHT = -1.0;
       
    37 }
       
    38 
       
    39 
       
    40 /*
       
    41     \private
       
    42     \class HbTreeLayout
       
    43     \brief HbTreeLayout manages geometries of hierarchical tree view contents.
       
    44 */
       
    45 
       
    46 class HbTreeLayoutPrivate
       
    47 {
       
    48 public:
       
    49 
       
    50     struct TreeItem 
       
    51     {
       
    52         QGraphicsLayoutItem* mItem;
       
    53         int mLevel;
       
    54     };
       
    55 
       
    56     HbTreeLayoutPrivate(HbTreeLayout *q_ptr);
       
    57     bool uniformSizedItems() const;
       
    58     qreal calculateSmallestItemHeight() const;
       
    59 
       
    60     QList<TreeItem> mItems;
       
    61     HbTreeLayout *q;
       
    62     qreal mIndentation;
       
    63     qreal mSmallestItemHeight;
       
    64 };
       
    65 
       
    66 HbTreeLayoutPrivate::HbTreeLayoutPrivate(HbTreeLayout *q_ptr) :
       
    67     q(q_ptr),
       
    68     mIndentation(15.0),
       
    69     mSmallestItemHeight(INVALID_ITEM_HEIGHT)
       
    70 {
       
    71 }
       
    72 
       
    73 bool HbTreeLayoutPrivate::uniformSizedItems() const
       
    74 {
       
    75     if (q->parentLayoutItem() && (static_cast<HbAbstractItemContainer *>(q->parentLayoutItem()))->uniformItemSizes() ) {
       
    76         return true;
       
    77     } else {
       
    78         return false;
       
    79     }      
       
    80 }
       
    81 
       
    82 /*!
       
    83     Calculates the smallest item height from all items.
       
    84 */
       
    85 qreal HbTreeLayoutPrivate::calculateSmallestItemHeight() const
       
    86 {
       
    87     qreal smallestHeight(0);
       
    88     if (uniformSizedItems()) {
       
    89         QGraphicsLayoutItem *firstItem = mItems.value(0).mItem;
       
    90         if (firstItem) {
       
    91             smallestHeight = firstItem->preferredHeight();  
       
    92         } 
       
    93     } else {  
       
    94         int itemCount = mItems.count();
       
    95         if (itemCount > 0) {
       
    96             smallestHeight = mItems.first().mItem->preferredHeight();
       
    97         }
       
    98         for (int i = 1; i < itemCount; ++i) {       
       
    99             smallestHeight = qMin(smallestHeight, mItems.at(i).mItem->preferredHeight());
       
   100         }
       
   101     }
       
   102     return smallestHeight;
       
   103 }
       
   104 
       
   105 
       
   106 /*!
       
   107     Constructor.
       
   108     \param parent parent layout item.
       
   109  */
       
   110 HbTreeLayout::HbTreeLayout(QGraphicsLayoutItem *parent)
       
   111     : QGraphicsLayout(parent), d(new HbTreeLayoutPrivate(this))
       
   112 {
       
   113 }
       
   114 
       
   115 /*!
       
   116     Destructor.
       
   117     Does not clear the parentLayoutItem of it's sub items.
       
   118     If you want to reuse the sub items first call removeAt()
       
   119     for each of them.
       
   120  */
       
   121 HbTreeLayout::~HbTreeLayout()
       
   122 {
       
   123     delete d;
       
   124 }
       
   125 
       
   126 /*!
       
   127     \brief Appends a layout item to the list layout.
       
   128 
       
   129     This is convenience function which will internally call the \c insertItem method.
       
   130 
       
   131     \param item layout item to be added to list.
       
   132  */
       
   133 void HbTreeLayout::addItem(QGraphicsLayoutItem *item, int level)
       
   134 {
       
   135     insertItem( -1, item, level );
       
   136 }
       
   137 
       
   138 /*!
       
   139     \brief  Inserts a layout item to the list layout.
       
   140 
       
   141     Inserts the given \a item to given position \a index.
       
   142     Does not take ownership.
       
   143 
       
   144     If index is out of range, the item is appended to the end of the list.
       
   145 
       
   146     \param  index position where to insert the layout.
       
   147     \param  item layout item to be inserted to stack.
       
   148  */
       
   149 void HbTreeLayout::insertItem(int index, QGraphicsLayoutItem *item, int level)
       
   150 {
       
   151     index = qMin(index, d->mItems.count());
       
   152     if (index < 0) {
       
   153         index = d->mItems.count();
       
   154     }
       
   155     HbLayoutUtils::addChildItem(this, item);
       
   156 
       
   157     HbTreeLayoutPrivate::TreeItem listItem;
       
   158     listItem.mItem = item;
       
   159     listItem.mLevel = level;
       
   160 
       
   161     d->mItems.insert( index, listItem);
       
   162     invalidate();
       
   163 }
       
   164 
       
   165 /*!
       
   166     \brief Returns position of layout item in the list layout.
       
   167     \param item item to look for.
       
   168     \return position of layout item, or -1 if not found.
       
   169  */
       
   170 int HbTreeLayout::indexOf( QGraphicsLayoutItem *item ) const
       
   171 {
       
   172     for ( int i = 0; i < count(); ++i ) {
       
   173         if ( itemAt( i ) == item ) {
       
   174             return i;
       
   175         }
       
   176     }
       
   177     return -1;
       
   178 }
       
   179 
       
   180 /*!
       
   181     \brief Removes layout item from the list layout.
       
   182 
       
   183     Equivalent of calling removeAt(indexOf(item)).
       
   184 
       
   185     \param item item to be removed.
       
   186     \sa removeAt
       
   187  */
       
   188 void HbTreeLayout::removeItem( QGraphicsLayoutItem *item )
       
   189 {
       
   190     removeAt(indexOf(item));
       
   191 }
       
   192 
       
   193 /*!
       
   194     From QGraphicsLayout.
       
   195  */
       
   196 int HbTreeLayout::count() const
       
   197 {
       
   198     return d->mItems.count();
       
   199 }
       
   200 
       
   201 /*!
       
   202     From QGraphicsLayout.
       
   203  */
       
   204 QGraphicsLayoutItem *HbTreeLayout::itemAt(int i) const
       
   205 {
       
   206     return d->mItems.value(i).mItem;
       
   207 }
       
   208 
       
   209 /*!
       
   210     From QGraphicsLayout.
       
   211     Clears the parentLayoutItem of removed item.
       
   212  */
       
   213 void HbTreeLayout::removeAt(int index)
       
   214 {
       
   215     QGraphicsLayoutItem *item = itemAt(index);
       
   216     if ( item ) {
       
   217         d->mItems.removeAt(index);
       
   218         item->setParentLayoutItem(0);
       
   219         invalidate();
       
   220     }
       
   221 }
       
   222 
       
   223 /*!
       
   224     From QGraphicsLayout.
       
   225  */
       
   226 void HbTreeLayout::setGeometry( const QRectF &rect )
       
   227 {
       
   228     QGraphicsLayout::setGeometry(rect);
       
   229     QRectF effectiveRect = geometry();
       
   230     // TODO: Apply margins?
       
   231     //qreal left, top, right, bottom;
       
   232     //getContentsMargins(&left, &top, &right, &bottom);
       
   233     //effectiveRect.adjust(+left, +top, -right, -bottom);
       
   234 
       
   235     bool mirrorLayout = false;
       
   236     if (HbApplication::layoutDirection() == Qt::RightToLeft) {
       
   237         mirrorLayout = true;
       
   238     }
       
   239 
       
   240     qreal y = effectiveRect.y();
       
   241     int itemCount = count();
       
   242     for (int i = 0; i < itemCount; ++i) {
       
   243         HbTreeLayoutPrivate::TreeItem listItem = d->mItems.at(i);
       
   244 
       
   245         qreal itemHeight = listItem.mItem->preferredHeight();
       
   246         qreal itemWidth = listItem.mItem->preferredWidth();
       
   247 
       
   248         qreal viewWidth = minimumWidth();
       
   249         if (viewWidth > 0.0) {
       
   250             if (d->mIndentation * listItem.mLevel + itemWidth < viewWidth) {
       
   251                 itemWidth = viewWidth - (d->mIndentation * listItem.mLevel);
       
   252             } else if (itemWidth > viewWidth) {
       
   253                 itemWidth = viewWidth;
       
   254             }
       
   255         }
       
   256 
       
   257         qreal x;
       
   258         if (mirrorLayout) {
       
   259             x = effectiveRect.right() - d->mIndentation * listItem.mLevel - itemWidth;
       
   260         } else {
       
   261             x = d->mIndentation * listItem.mLevel + effectiveRect.left();
       
   262         }
       
   263 
       
   264         listItem.mItem->setGeometry( QRectF(x, y, itemWidth, itemHeight ) );
       
   265         y += itemHeight;
       
   266     }
       
   267 }
       
   268 
       
   269 /*!
       
   270     From QGraphicsLayout.
       
   271 
       
   272     The minimum size hint's width and height are the smallest ones of the
       
   273     child layout items.
       
   274 
       
   275     The preferred size hint is the sum of the preferred size hints of the
       
   276     child layout items..
       
   277 
       
   278     The maximum size hint "unlimited", i.e. the child layout items do not
       
   279     affect the maximum size hint.
       
   280  */
       
   281 QSizeF HbTreeLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
       
   282 {
       
   283     QSizeF sizeHint(0, 0);
       
   284 
       
   285     if (which == Qt::MaximumSize) {
       
   286         // Sub items do not affect the maximum size hint.
       
   287         sizeHint = QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
       
   288     } else if (which == Qt::PreferredSize) {
       
   289         QGraphicsWidget *view = 0;
       
   290         if (    parentLayoutItem()
       
   291             &&  !parentLayoutItem()->isLayout()
       
   292             &&  parentLayoutItem()->graphicsItem()) {
       
   293             view = parentLayoutItem()->graphicsItem()->parentWidget();
       
   294         }
       
   295         qreal viewWidth = view ? view->size().width() : 0.0;
       
   296 
       
   297         int itemCount = count();
       
   298         for (int i = 0; i < itemCount; ++i) {
       
   299             QSizeF itemSize(0, 0);
       
   300             HbTreeLayoutPrivate::TreeItem listItem = d->mItems.at(i);
       
   301 
       
   302             itemSize = listItem.mItem->effectiveSizeHint(which);
       
   303             if (viewWidth > 0.0) {
       
   304                 if (d->mIndentation * listItem.mLevel + itemSize.width() < viewWidth) {
       
   305                     // if indentation + item width fits into view, expand item so that
       
   306                     // indentation + item width == view width
       
   307                     itemSize.setWidth(viewWidth - (d->mIndentation * listItem.mLevel));
       
   308                 } else if (itemSize.width() > viewWidth) {
       
   309                     itemSize.setWidth(viewWidth);
       
   310                 }
       
   311             }
       
   312 
       
   313             if (itemSize.isValid()) {
       
   314                 sizeHint.rwidth() = qMax((d->mIndentation * listItem.mLevel + itemSize.width()), sizeHint.width());
       
   315                 sizeHint.rheight() = sizeHint.height() + itemSize.height();
       
   316             }
       
   317         }
       
   318     } else if (which == Qt::MinimumSize) {
       
   319         if(itemAt(0)) {
       
   320             sizeHint = itemAt(0)->effectiveSizeHint(Qt::PreferredSize);
       
   321         }
       
   322         if (d->uniformSizedItems()) {
       
   323             return sizeHint; //No need to goto loop below to check the sizes of every item
       
   324         }
       
   325         
       
   326         int itemCount = count();
       
   327         for( int i = 1; i < itemCount; ++i ) {
       
   328             QSizeF itemSize(0, 0);
       
   329             HbTreeLayoutPrivate::TreeItem listItem = d->mItems.at(i);
       
   330 
       
   331             itemSize = listItem.mItem->effectiveSizeHint(Qt::PreferredSize);
       
   332 
       
   333             if ( itemSize.isValid() ) {
       
   334                 sizeHint.rwidth() = qMin( itemSize.width(), sizeHint.width() );
       
   335                 sizeHint.rheight() = qMin( sizeHint.height(), itemSize.height() );
       
   336             }
       
   337         }
       
   338     } else {
       
   339         Q_ASSERT_X(false, "HbTreeLayout::sizeHint()", "Unhandled Qt::SizeHint type");
       
   340         return sizeHint;
       
   341     }
       
   342 
       
   343     if (constraint.height() >= 0) {
       
   344         sizeHint.setHeight(qMin(sizeHint.height(), constraint.height()));
       
   345     }
       
   346 
       
   347     if (constraint.width() >= 0) {
       
   348         sizeHint.setWidth(qMin(sizeHint.width(), constraint.width()));
       
   349     }
       
   350 
       
   351     return sizeHint;
       
   352 
       
   353 }
       
   354 
       
   355 void HbTreeLayout::setItemLevel(QGraphicsLayoutItem *item, int level)
       
   356 {
       
   357     for (int current = 0; current < d->mItems.count(); ++current) {
       
   358         if (d->mItems.at(current).mItem == item) {
       
   359             d->mItems[current].mLevel = level;
       
   360             invalidate();
       
   361             break;
       
   362         }
       
   363     }
       
   364 }
       
   365 
       
   366 qreal HbTreeLayout::indentation() const
       
   367 {
       
   368     return d->mIndentation;
       
   369 }
       
   370 
       
   371 void HbTreeLayout::setIndentation(qreal indentation)
       
   372 {
       
   373     if (indentation != d->mIndentation) {
       
   374         d->mIndentation = indentation;
       
   375         invalidate();
       
   376     }
       
   377 }
       
   378 
       
   379 /*!
       
   380     Returns the smallest item height.
       
   381 */
       
   382 qreal HbTreeLayout::smallestItemHeight() const
       
   383 {
       
   384     if (d->mSmallestItemHeight == INVALID_ITEM_HEIGHT) {
       
   385         d->mSmallestItemHeight = d->calculateSmallestItemHeight();
       
   386     }
       
   387     return d->mSmallestItemHeight;
       
   388 }
       
   389 
       
   390 /*!
       
   391 	\reimp
       
   392 	
       
   393 	Invalidates smallest item height cache.
       
   394 */
       
   395 void HbTreeLayout::invalidate()
       
   396 {
       
   397     QGraphicsLayout::invalidate();
       
   398 
       
   399     d->mSmallestItemHeight = INVALID_ITEM_HEIGHT;
       
   400 }
       
   401 
       
   402