src/hbwidgets/itemviews/hbradiobuttonlist.cpp
changeset 0 16d8024aca5e
child 1 f7ac710697a9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hbwidgets/itemviews/hbradiobuttonlist.cpp	Mon Apr 19 14:02:13 2010 +0300
@@ -0,0 +1,453 @@
+/****************************************************************************
+**
+** 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 "hbradiobuttonlist.h"
+
+#include "hblistview_p.h"
+#include "hblistviewitem.h"
+#include "hblistitemcontainer_p.h"
+#include "hbradiobuttonlistviewitem_p.h"
+#include "hbmodeliterator.h"
+
+#include <QStringListModel>
+#include <QGraphicsSceneMouseEvent>
+
+//TODO: consider moving these two to proper place (widget params?)
+const int HB_RADIOBUTTONLIST_ITEM_ACTIVATION_TIMER = 150;
+const int HB_RADIOBUTTONLIST_PREVIEW_TIMER = 500;
+
+const int HB_RADIOBUTTONLIST_MINIMUM_ITEM_COUNT_IN_SIZE_HINT = 4;
+
+/*!
+    \class HbRadioButtonList
+    \brief HbRadioButtonList provides a widget for a string list with radio buttons
+    @alpha
+    @hbwidgets
+
+    This class has been provided for convenience for a simple creation of a radio button list.
+    The same functionality could be implemented using HbListWidget or HbListView API.
+
+    The Radio Button List consists of items with a radio button and a line of text.
+    Only one item may be selected at a time. Once an item is selected, it can be deselected only by 
+    selecting another item.  Initial item selection may be set at the list construction. If not 
+    set, the list is shown without a selection.
+
+    The Radio Button List has two working modes, Preview Mode and No Preview Mode. In No Preview 
+    Mode it emits activated signal after the first tap to the item. In Preview Mode the first tap
+    causes emission of the preview signal and the item is not yet selected. The second consecutive 
+    tap on the item causes the activation of the item. The application has the responsibility of 
+    the preview itself. 
+
+    User does not need to set the model using base class function setModel() because the model is 
+    created internally. If necessary the model can be changed e.g. to QDirModel. A use case for 
+    this is to view a contents of a folder containing sound clips. Application can then play
+    a preview of these sound clips based on the signal emitted by the radio button list.
+
+    An example of how to create a radiobuttonlist inside a popup.
+    \snippet{decoratorlistdemo/contentwidget.cpp,3}
+
+*/
+
+/*!
+    \fn void HbRadioButtonList::itemSelected(int index)
+
+    This signal is emitted when a list item is selected by user action.
+    
+    The pressed item is specified by \a index.
+
+*/
+
+/*!
+    \fn void HbRadioButtonList::startPreview(int index)
+
+    This signal is emitted when a list item is pressed the first time when the PreviewMode 
+    is set to Preview. The user of this API should use this signal to start application 
+    specific preview.
+
+    If the preview mode is NoPreview this signal is not emitted.
+
+    The pressed item is specified by \a item.
+*/
+
+/*!
+    \enum HbRadioButtonList::PreviewMode
+
+    The preview mode defines whether the list is in the preview mode or not. 
+*/
+
+/*!
+    \var HbRadioButtonList::Preview
+
+    In this mode the application is signaled to show a preview. 
+    This signal is emitted after a short delay after the list item has been pressed.
+    The reason behing the short delay is that the user could select the item without seeing or 
+    listening the start of the preview. 
+*/
+
+/*!
+    \var HbRadioButtonList::NoPreview
+
+    In this mode the application is not signaled for a preview.
+*/
+
+class HbRadioButtonListPrivate: public HbListViewPrivate {
+    Q_DECLARE_PUBLIC(HbRadioButtonList)
+public:
+    HbRadioButtonListPrivate();
+    ~HbRadioButtonListPrivate();
+
+    void init(QAbstractItemModel *model, int selected=-1, HbRadioButtonList::PreviewMode previewMode=HbRadioButtonList::NoPreview);
+    void emitStartPreview(int row);
+    void calculateItemHeight();
+    void _q_itemActivated(const QModelIndex &modelIndex);
+    void _q_itemActivationTimerExpired();
+    void _q_itemPreviewTimerExpired();
+
+    QModelIndex mCurrentIndex; //Note that this is not the same as d->mHitItem
+    HbRadioButtonList::PreviewMode mPreviewMode;
+    bool mPreviewGoingOn;
+    bool mStartUp;
+    qreal mHeight;
+};
+
+HbRadioButtonListPrivate::HbRadioButtonListPrivate() :
+    HbListViewPrivate(),
+    mPreviewMode(HbRadioButtonList::NoPreview),
+    mPreviewGoingOn(false),
+    mStartUp(true),
+    mHeight(0)
+{     
+}
+
+HbRadioButtonListPrivate::~HbRadioButtonListPrivate() 
+{
+}
+
+void HbRadioButtonListPrivate::_q_itemActivated(const QModelIndex &modelIndex)
+{
+    Q_Q(HbRadioButtonList);
+    emit q->itemSelected(modelIndex.row());
+}
+
+void HbRadioButtonListPrivate::_q_itemActivationTimerExpired()
+{
+    Q_Q(HbRadioButtonList);
+    emit q->activated(mCurrentIndex);
+}
+
+void HbRadioButtonListPrivate::_q_itemPreviewTimerExpired()
+{
+    emitStartPreview(mCurrentIndex.row()); 
+}
+
+void HbRadioButtonListPrivate::init(QAbstractItemModel *model, int selected, 
+                                    HbRadioButtonList::PreviewMode previewMode)
+{
+    Q_Q(HbRadioButtonList);
+    q->setModel(model, new HbRadioButtonListViewItem());
+    q->setSelectionMode(q->HbAbstractItemView::SingleSelection);
+    q->setSelected(selected);   
+    q->setPreviewMode(previewMode);
+    q->setLongPressEnabled(false);
+    calculateItemHeight();
+}
+
+void HbRadioButtonListPrivate::calculateItemHeight()
+{
+    Q_Q(HbRadioButtonList);
+    if (!q->items().isEmpty()) {
+        //Let's create a temporary item and take the height for the size hint
+        HbAbstractViewItem *tempItem = q->itemPrototypes().first()->createItem();
+        tempItem->setModelIndex(mModelIterator->nextIndex(QModelIndex()));
+
+        qreal oldHeight = mHeight;
+        mHeight = tempItem->effectiveSizeHint(Qt::PreferredSize).height();
+
+        delete tempItem;
+
+        if (mHeight != oldHeight) {
+            q->updateGeometry();
+        }
+    }
+}
+
+void HbRadioButtonListPrivate::emitStartPreview(int row)
+{
+    Q_Q(HbRadioButtonList);
+    emit q->startPreview(row); 
+}
+
+/*!
+    Constructs the radio button list with a given \a parent.
+*/
+HbRadioButtonList::HbRadioButtonList(QGraphicsItem *parent) :
+    HbListView(*new HbRadioButtonListPrivate, new HbListItemContainer, parent)
+{
+    Q_D(HbRadioButtonList);
+    connect(this, SIGNAL(activated(QModelIndex)), this, SLOT(_q_itemActivated(QModelIndex))); 
+    d->init(new QStringListModel(this));
+}
+
+/*!
+    Constructs the radio button list with a given \a parent, initial \a list, pre-selected item \a selected and \a previewMode.
+*/
+HbRadioButtonList::HbRadioButtonList(const QStringList &list, int selected, PreviewMode previewMode, QGraphicsItem *parent) :
+    HbListView(*new HbRadioButtonListPrivate, new HbListItemContainer, parent)
+{
+    Q_D(HbRadioButtonList);
+    connect(this, SIGNAL(activated(QModelIndex)), this, SLOT(_q_itemActivated(QModelIndex))); 
+    d->init(new QStringListModel(list, this), selected, previewMode);
+}
+
+/*!
+    \internal
+*/
+HbRadioButtonList::HbRadioButtonList(HbRadioButtonListPrivate &dd, HbAbstractItemContainer *container, QGraphicsItem *parent) :
+    HbListView(dd, container, parent)
+{
+    Q_D(HbRadioButtonList);
+    connect(this, SIGNAL(activated(QModelIndex)), this, SLOT(_q_itemActivated(QModelIndex))); 
+    d->init( new QStringListModel(this) );
+}
+
+/*!
+    Destructs the radio button list.
+*/
+HbRadioButtonList::~HbRadioButtonList ()
+{
+}
+
+/*!
+    Replaces the whole list content with a new list \a list. This resets the selected property 
+    to -1.
+    This function does not work if the user has been chenged the model.
+*/
+void HbRadioButtonList::setItems(const QStringList &list)
+{
+    Q_D(HbRadioButtonList);
+    QStringListModel *stringListModel = qobject_cast<QStringListModel *>(d->mModelIterator->model());
+    if (stringListModel) {
+        stringListModel->setStringList(list);
+        //Calculate the item height only if needed
+        if(d->mHeight==0){
+            d->calculateItemHeight();
+        }
+        updateGeometry();
+    } else {
+        //TODO: set the item here using the base model class
+        //or document that this is not in use with own models
+    }
+}
+
+/*!
+    Returns the whole list as a QStringList.
+    This function does not work if the user has been changed the model.
+*/
+QStringList HbRadioButtonList::items() const
+{
+    Q_D(const HbRadioButtonList);
+    QStringListModel *stringListModel = qobject_cast<QStringListModel *>(d->mModelIterator->model());
+    if (stringListModel)
+        return stringListModel->stringList();
+    else {
+        //TODO: get the item here using the base model class
+        //or document that this is not in use with own models
+        return QStringList();
+    }       
+}
+
+/*!
+    Sets the selected item to be \a index.
+*/
+void HbRadioButtonList::setSelected(int index)
+{
+    Q_D(HbRadioButtonList);
+    if(index < d->mModelIterator->indexCount()){
+        setCurrentIndex(d->mModelIterator->index(index), QItemSelectionModel::SelectCurrent);
+        if (d->mStartUp) {
+           QModelIndex topIndex;
+           if (index > 0) {
+               topIndex = d->mModelIterator->index(index - 1);
+           } else {
+               topIndex = d->mModelIterator->index(index);
+           }
+           scrollTo(topIndex, HbAbstractItemView::PositionAtTop);
+        }
+    }
+}
+
+/*!
+    Returns the index on selected item, -1 if there are no selected item.
+*/
+int HbRadioButtonList::selected() const
+{
+    return currentIndex().row(); 
+}
+
+/*!
+    Sets the preview mode to be \a previewMode.
+*/
+void HbRadioButtonList::setPreviewMode(PreviewMode previewMode)
+{
+    Q_D(HbRadioButtonList);
+    d->mPreviewMode=previewMode;
+}
+
+/*!
+    Returns current preview mode.
+*/
+HbRadioButtonList::PreviewMode HbRadioButtonList::previewMode() const
+{
+    Q_D(const HbRadioButtonList);
+    return d->mPreviewMode;
+}
+
+/*
+    \reimp
+*/
+int HbRadioButtonList::type() const
+{
+   return Hb::ItemType_RadioButtonList;
+}
+
+/*!
+    \reimp 
+*/
+void HbRadioButtonList::emitActivated(const QModelIndex &modelIndex)
+{
+    Q_D( HbRadioButtonList );
+     
+    if(d->mPreviewMode == HbRadioButtonList::Preview && d->mCurrentIndex != modelIndex){
+        QTimer::singleShot(HB_RADIOBUTTONLIST_PREVIEW_TIMER, this, SLOT(_q_itemPreviewTimerExpired()));          
+        d->mCurrentIndex=modelIndex;
+    }else {
+        //Now we let the activate signal go to the application
+        d->mCurrentIndex=modelIndex;
+        QTimer::singleShot(HB_RADIOBUTTONLIST_ITEM_ACTIVATION_TIMER, this, SLOT(_q_itemActivationTimerExpired()));
+    }
+}
+
+/*!
+    \reimp
+*/
+void HbRadioButtonList::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+    Q_D(HbRadioButtonList);     
+    if(d->mPreviewMode == HbRadioButtonList::Preview ){    
+        HbAbstractViewItem *hitItem = d->itemAt(event->scenePos());
+        if (hitItem){
+            if (hitItem->modelIndex() == d->mCurrentIndex) {
+                d->mPreviewGoingOn=false;
+            } else {
+                d->mPreviewGoingOn=true;
+            }
+        }
+    }
+    HbListView::mouseReleaseEvent(event);
+}
+
+/*!
+    \reimp
+*/
+QItemSelectionModel::SelectionFlags HbRadioButtonList::selectionCommand(const HbAbstractViewItem *item,
+                                                                          const QEvent *event)
+{  
+    Q_D(HbRadioButtonList);
+
+    if (!item->modelIndex().isValid() 
+        || selectionMode()!=SingleSelection
+        || !d->mHitItem
+        ||event->type() != QEvent::GraphicsSceneMouseRelease){
+            return QItemSelectionModel::NoUpdate;
+    } else if (item->modelIndex() == d->mHitItem->modelIndex()) {
+        if(d->mPreviewGoingOn==true) {
+            return QItemSelectionModel::NoUpdate;
+        } else {
+            return QItemSelectionModel::ClearAndSelect;
+        }
+    } else {
+        return QItemSelectionModel::NoUpdate;
+    }
+}
+
+
+/*!
+    \reimp
+*/
+bool HbRadioButtonList::event(QEvent *e)
+{
+    Q_D(HbRadioButtonList);
+    bool result = HbListView::event(e);
+    if (e->type()==QEvent::LayoutRequest) {
+        d->mStartUp=false;
+    }
+    return result;
+}
+
+/*!
+    \reimp
+*/
+QSizeF HbRadioButtonList::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
+{
+    Q_D(const HbRadioButtonList);
+    if (which == Qt::PreferredSize) {
+        QSizeF defaultSize = HbListView::sizeHint(which,constraint);
+        qreal minHeight = (d->mHeight) * HB_RADIOBUTTONLIST_MINIMUM_ITEM_COUNT_IN_SIZE_HINT;
+        defaultSize.setHeight(qMax(defaultSize.height(), minHeight));
+        
+        qreal height = (d->mHeight) * (d->mModelIterator->indexCount());
+        if( height <= defaultSize.height()) {
+            return QSizeF(defaultSize.width(), height);
+        } else {
+            return defaultSize;
+        } 
+    } else {
+        return HbListView::sizeHint(which, constraint);
+    }
+}
+
+void HbRadioButtonList::rowsInserted(const QModelIndex &parent, int start, int end)
+{
+    Q_D(HbRadioButtonList);
+    HbListView::rowsInserted(parent,start,end);
+    //Calculate the item height only if needed
+    if(d->mHeight==0){
+        d->calculateItemHeight();
+    }
+    updateGeometry();
+}
+
+void HbRadioButtonList::rowsRemoved(const QModelIndex &parent, int start, int end)
+{
+    HbListView::rowsRemoved(parent,start,end);
+    updateGeometry();
+}
+
+void HbRadioButtonList::reset()
+{
+    HbListView::reset();
+    updateGeometry();
+}
+#include "moc_hbradiobuttonlist.cpp"
+