src/hbwidgets/dataform/hbdataformviewitem.cpp
author hgs
Tue, 07 Sep 2010 18:07:24 +0300
changeset 26 e45fc2ab7514
parent 7 923ff622b8b9
child 21 4633027730f5
permissions -rw-r--r--
201035_2

/****************************************************************************
**
** 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 "hbdataformviewitem.h"
#include "hbdataformviewitem_p.h"
#include "hbabstractitemcontainer_p_p.h"

#include "hbdataformmodelitem_p.h"
#include "hbdataform_p.h"
#include "hbdatagroup_p.h"
#include "hbstyleoptiondataformviewitem_p.h"

#include <hbtapgesture.h>

#ifdef HB_EFFECTS
#include "hbeffect.h"
#include "hbeffectinternal_p.h"
#define HB_DATAFORMVIEWITEM_TYPE "HB_DATAFORMVIEWITEM"
#endif

/*!
    @beta
    @hbwidgets
    \class HbDataFormViewItem
    \brief HbDataFormViewItem represents an item view in HbDataForm corresponding to model item.
    Each HbDataFormModelItem added inside model is represented using HbDataFormViewItem instance.
  
    HbDataFormViewItem have different visualization based upon the 
    HbDataFormModelItem::DataItemType:

    - FormPageItem: This type does not have any visualization. Whatever QString is passed while
        creating HbDataFormModelItem, is added in a combo box at the top level view. User can 
        switch between different form page using this combo.
    - GroupItem: A visualization is created for this type. Visualization includes +/- icon and 
        group heading. User can expand and collapse the group by clicking any where in 
        HbDataFormViewItem of this type. Whatever QString is passed while creating
        HbDataFormModelItem for this type is set as a group heading.
    - GroupPageItem: This type does not have any visualization. Whatever QString is passed while
        creating HbDataFormModelItem, is added in a group combo box. User can switch between 
        different group page using this combo.
    - DataItems: Any type other then FormPageItem, GroupItem and GroupPageItem is treated as
        a data item. Data item can contain label, description, icon and content widget. Data items
        can not have any children. They are always placed at the leaf. Data item content widget 
        can be set using HbDataFormModelItem::ItemTypeRole, label of data items can be set using 
        HbDataFormModelItem::LabelRole, description of data item can be set using 
        HbDataFormModelItem::DescriptionRole.
    
    If HbDataFormViewItem represents a GroupItem then it can be expanded and collapsed. 
    If group is expanded then all the child items are shown.

    If user wants to create a custom data item then he has to derive from this class and set that
    as a prototype for HbDataForm using HbAbstractItemView::setItemPrototype API. While creating
    data for custom data items user should pass value greater than or equal to 
    DataItemType::CustomItemBase. When visualization is created and if data item type is
    custom item then createCustomWidget() is called. User has to override this API and pass the
    custom widget which he wants to show in data item. Below is the code snippet:

    \code
    //Derive a class from HbDataFormViewItem
    class DataFormCustomItem : public HbDataFormViewItem
    {
        Q_OBJECT

    public:
        DataFormCustomItem(QGraphicsItem *parent);
        ~DataFormCustomItem();

        virtual HbAbstractViewItem* createItem()
        {
            return new DataFormCustomItem(*this);
        }

    protected:
        //Override createCustomWidget API
        virtual HbWidget* createCustomWidget()
        {
            HbDataFormModelItem::DataItemType itemType = static_cast<HbDataFormModelItem::DataItemType>(
            modelIndex().data(HbDataFormModelItem::ItemTypeRole).toInt());
            switch(itemType){
                case HbDataFormModelItem::CustomItemBase:{
                    //Create widget which you want for this data item
                    HbWidget *widget = new HbWidget();
                    QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(Qt::Horizontal);
                    widget->setLayout(layout);
                    HbLineEdit *button1 = new HbLineEdit();
                    layout->addItem(button1);
                    HbLabel *label = new HbLabel(QString("testing label"));
                    layout->addItem(label);
                    //Return the custom widget created
                    return widget;
                }
                //Some other cases can also be added if there are more than one custom data item
            default:
                return 0;
            }
        }

    private:
        Q_DECLARE_PRIVATE_D(d_ptr, DataFormCustomItem)
    };

    //some were is your application
    ContentWidget::ContentWidget(QGraphicsItem *parent)
    {
        HbDataForm *form = new HbDataForm();

        DataFormCustomItem *myPrototype = new DataFormCustomItem();
        form->setItemPrototype(myPrototype);
    }


    \endcode

    The signals emitted by this class are:
    \li itemShown(const QModelIndex&) This signal is emitted when ever this item becomes visible.
    
    Refer HbDataForm documentation for sample code.

    \sa HbDataForm, HbDataFormModel, HbDataFormModelItem
*/

/*!
    Constructs HbDataFormViewItem with given \a parent.
    \param parent parent .
 */
HbDataFormViewItem::HbDataFormViewItem(QGraphicsItem *parent):
    HbAbstractViewItem(*new HbDataFormViewItemPrivate(this), parent)
{
    Q_D(HbDataFormViewItem);
    d->q_ptr = this;
}

/*!
    Destructs the HbDataFormViewItem.
*/
HbDataFormViewItem::~HbDataFormViewItem()
{
}

/*!
    \reimp
    Creates HbDataFormViewItem. This function is called from HbAbstractItemContainer 
    when model is getting parsed for creating items. 

 */
HbAbstractViewItem* HbDataFormViewItem::createItem()
{
    return new HbDataFormViewItem(*this);
}
/*!
    \reimp
    Returns true if \a model index is supported by HbDataFormViewItem prototype, otherwise returns false.
    This function is called for every item on the prototype list (if several prototypes exist)
    until item is found, which can create view item for \a index.

    \sa HbAbstractItemView::setItemPrototype(HbAbstractViewItem *prototype)
    \sa HbAbstractItemView::setItemPrototype(const QList<HbAbstractViewItem *> &prototypes)
 */
bool HbDataFormViewItem::canSetModelIndex(const QModelIndex &index) const
{
    HbDataFormModelItem::DataItemType itemType = 
        static_cast<HbDataFormModelItem::DataItemType>(
        index.data(HbDataFormModelItem::ItemTypeRole).toInt());

    if( ( itemType >= HbDataFormModelItem::SliderItem 
        && itemType < HbDataFormModelItem::CustomItemBase ) ) {
        return true;
    } else {
        return false;
    }

}

/*!
    \reimp
    Updates child graphics items to represent current state and content stored in model. In case when 
    HbDataFormViewItem represents data item and DataItemType is set to custom item, then 
    createCustomWidget is called. User can override createCustomWidget and can pass his own
    custom widget.

    \sa createCustomWidget

*/
void HbDataFormViewItem::updateChildItems()
{
    Q_D( HbDataFormViewItem );

    d->init();
    //this will create the visualization for all standard data items
    d->createContentWidget( );

    //set the label in data iem
    QString itemLabel = d->mIndex.data( HbDataFormModelItem::LabelRole ).toString( );
    d->setLabel( itemLabel );

    // set the icon in data item
    QString icon = d->mIndex.data( Qt::DecorationRole ).toString( );
    d->setIcon( icon );

    // set the description of data item
    QString itemDescription = d->mIndex.data( HbDataFormModelItem::DescriptionRole ).toString();
    d->setDescription( itemDescription );

    //update visualization based on whether item is enabled or disabled
    HbDataFormModel* data_model = static_cast<HbDataFormModel*>(itemView()->model());
    HbDataFormModelItem *model_item = 
        static_cast<HbDataFormModelItem*>(data_model->itemFromIndex(d->mIndex));
    d->setEnabled(model_item->isEnabled());


#ifdef HB_EFFECTS
    //HbEffectInternal::add( HB_DATAFORMVIEWITEM_TYPE,"dataform_expand", "expanded" );
    //HbEffect::start( settingItem, HB_DATAFORMVIEWITEM_TYPE, "expanded" );  
#endif

    restore( );

    // Establish Signal Connections set in HbDataFormModel to th contentWidget of this item
    HbDataFormPrivate::d_ptr(
        static_cast<HbDataForm*>(d->mSharedData->mItemView))->makeConnection(
        d->mIndex.operator const QModelIndex & (),d->mContentWidget);
    //update only the background primitive
    HbStyleOptionDataFormViewItem options;
    initStyleOption(&options);
    if( d->mBackgroundItem ) {
        style()->updatePrimitive(
            d->mBackgroundItem, HbStyle::P_DataItem_background, &options );
    }

}

/*!
    \protected constructor
*/
HbDataFormViewItem::HbDataFormViewItem(HbDataFormViewItemPrivate &dd, QGraphicsItem *parent):
    HbAbstractViewItem(dd, parent)
{
    Q_D(HbDataFormViewItem);
    d->q_ptr = this;
    setProperty( "hasIcon", false );
}

/*!
    \protected constructor
*/
HbDataFormViewItem::HbDataFormViewItem(const HbDataFormViewItem &source):
    HbAbstractViewItem( *new HbDataFormViewItemPrivate(*source.d_func()), 0)
{
    Q_D(HbDataFormViewItem);
    d->q_ptr = this;
    setProperty( "hasIcon", false );
}

/*!
    \protected assignment operator
*/
HbDataFormViewItem& HbDataFormViewItem::operator=(const HbDataFormViewItem &source)
{
    Q_D(HbDataFormViewItem);
    *d = *source.d_func();
    setProperty( "hasIcon", false );
    return *this;
}

/*!
    @beta

    Restores the data from the model and assign to the widget.
    The content widget property for restoring and saving the data need to be initialized when the 
    data item is created. If model item type is custom, then application developer has to override
    this API in order to get notification when data is changed in model.

    \sa save
*/
void HbDataFormViewItem::restore()
{
    Q_D( HbDataFormViewItem );    

    if( d->mType < HbDataFormModelItem::CustomItemBase ) {
        if( d->mContentWidget ) {   
            QVariant newValue;
            QModelIndex itemIndex = modelIndex();
            QString currentProperty;

            // fetch all properties set on this model item
            QHash<QString, QVariant> properties = d->mModelItem->contentWidgetData( );
            QList <QString> propertyNames = properties.keys( );
            int upperBound = 1;
            int lowerBound = 0;

            // get the latest modified property
            QString dirtyProperty = 
                HbDataFormModelItemPrivate::d_ptr( d->mModelItem )->dirtyProperty( );

            // First time when DataItem is created load all property, at runtime load only  the modified
            // property. 
            if(  d->mSetAllProperty ) {
                upperBound = propertyNames.count() ;
                d->mSetAllProperty = false;
            } else {
                // Fetch only the last modified property
                lowerBound = propertyNames.indexOf(dirtyProperty);
                upperBound = lowerBound + 1;
            }
            if( lowerBound > -1 ) {
                for( ;lowerBound < upperBound ;lowerBound++) {
                    newValue = properties.value(propertyNames.at(lowerBound));
                    currentProperty = propertyNames.at(lowerBound);
                    if(newValue.isValid()) {                        
                        if(!d->mContentWidget) {
                            return;
                        }
                        d->mContentWidget->setProperty(currentProperty.toAscii().data(), newValue);
                    }
                }
            }
        }
    }
}

/*!
    @beta

    Saves the current data of the content widget in data item to the model.
    The property for restoring and saving the data need to be initialized when the 
    data item is created. If model item type is custom, then application developer has to override
    this API in order to save the content widget value in model.

    \sa restore
*/
void HbDataFormViewItem::save()
{
    Q_D(HbDataFormViewItem);
    if( d->mType < HbDataFormModelItem::CustomItemBase ) {
        if( d->mContentWidget ) {

            disconnect( d->mModel, SIGNAL( dataChanged( QModelIndex,QModelIndex ) ),
                d->mSharedData->mItemView, SLOT( dataChanged( QModelIndex,QModelIndex ) ) );

            d->mModelItem->setContentWidgetData(
                d->mProperty, d->mContentWidget->property(d->mProperty.toAscii( ).data( ) ) );            

            connect( d->mModel, SIGNAL( dataChanged( QModelIndex,QModelIndex ) ),
                d->mSharedData->mItemView, SLOT( dataChanged( QModelIndex,QModelIndex ) ) );
        }
    }
}

/*!
    @beta

    This is a virtual function which by default returns NULL. This function must be overridden
    in case user wants to create a data item of type custom item. The user is supposed to pass
    the widget which he wants to display in data item.
    If content widget grabs pan gesture and user wants data form to be scrollable even panning
    is done on disabled content widget then user is supposed to ungrab pan gesture when content 
    widget is disabled. And again grab pan gesture when state of content widget is changed to 
    enabled.
*/
HbWidget* HbDataFormViewItem::createCustomWidget()
{
    return 0;
}

/*!
    \reimp 
    Sets the item to either collapse or expanded state, depending on the value of \a expanded.
    The function calls setModelIndexes which inturn will make the child items visible/invisible 
    accordingly. This API is valid only if HbDataFormViewItem represents a FormPageItem, GroupItem
    or GroupPageItem.

    \sa isExpanded
*/
void HbDataFormViewItem::setExpanded(bool expanded)
{
    Q_D(HbDataFormViewItem);
    // Expansion is valid only for group ,form page and group page
    if( d->mType < HbDataFormModelItem::SliderItem ) {
        static_cast<HbDataGroup*>(this)->setExpanded(expanded);
    }  else {
        HbAbstractItemContainer *container = qobject_cast<HbAbstractItemContainer *>(
        static_cast<QGraphicsWidget *>( d->mSharedData->mItemView->contentWidget( ) ) );
        container->setItemTransientStateValue(d->mIndex, "expanded", expanded);
    }
}

/*!
    \reimp
    Returns the expanded state of item.

    \sa setExpanded
*/
bool HbDataFormViewItem::isExpanded() const
{
    Q_D( const HbDataFormViewItem);
    // Expansion is valid only for group ,form page and group page
    if( d->mType < HbDataFormModelItem::SliderItem ) {
        HbDataGroup *group = qobject_cast< HbDataGroup *>(const_cast<HbDataFormViewItem*>(this));
        if( group ) {
            return group->isExpanded();
        }
    } 
    if(d->mSharedData->mItemView) {
        HbAbstractItemContainer *container = qobject_cast<HbAbstractItemContainer *>(
            static_cast<QGraphicsWidget *>( d->mSharedData->mItemView->contentWidget( ) ) );
        if(container) {
            return container->itemTransientState(d->mIndex).value("expanded").toBool();
        }
    }
    return false;
}

/*!
    @beta

    Returns the content widget of data item. For example if data item is of type SliderItem 
    then this API will return the instance of HbSlider. If user wants to connect to some 
    signals of content widget in data item then this API can be used to fetch the instance
    of the widget. It will return the instance only if data item is visible. User can connect
    to HbDataForm::itemShown() signal and when this item is visible then he can query the 
    content widget using this API.
*/
HbWidget* HbDataFormViewItem::dataItemContentWidget()const
{
    Q_D(const HbDataFormViewItem);
    HbWidget *widget = d->mContentWidget;

    if(d->mContentWidget) {
        switch( d->mType ) {
            case HbDataFormModelItem::RadioButtonListItem:{
                widget = static_cast<HbRadioItem*>(d->mContentWidget)->createRadioButton();
            }
            break;
            case HbDataFormModelItem::MultiselectionItem:{
                widget = NULL;
            }
            break;
            case HbDataFormModelItem::ToggleValueItem:{
                widget = static_cast<HbToggleItem*>(d->mContentWidget)->contentWidget();
            }
            break;
            default:
            break;
        }
    }
    return widget;
}

/*!
    \reimp
*/
void HbDataFormViewItem::pressStateChanged(bool value, bool animate)
{
    //Since there are no effects defined for mousePressed and mouseReleased for 
    //HbDataFormViewItem we are overriding this function so that redundant effects functions are
    //not called in HbAbstractViewItem::pressStateChanged.
    Q_UNUSED(value);
    Q_UNUSED(animate);
}

/*!
    \reimp
*/
void HbDataFormViewItem::initStyleOption(HbStyleOptionDataFormViewItem *option) const
{
    Q_D( const HbDataFormViewItem );

    HbWidget::initStyleOption(option);
    option->label = d->mLabel;
    option->icon = d->mIcon;
    option->description = d->mDescription;
}

/*!
    \reimp
*/
void HbDataFormViewItem::showEvent(QShowEvent * event)
{
    Q_D( const HbDataFormViewItem );

    HbWidget::showEvent( event );
    if( d->mIndex.isValid( ) ) {
        emit itemShown( d->mIndex.operator const QModelIndex & ( ) );
    }
}

/*!
    \reimp
 */
QVariant HbDataFormViewItem::itemChange( GraphicsItemChange change, const QVariant &value )
{
    Q_D( HbDataFormViewItem );
    switch ( static_cast<HbPrivate::HbItemChangeValues>( change ) ) {
    case QGraphicsItem::ItemEnabledHasChanged: {
            HbStyleOptionDataFormViewItem options;
            initStyleOption(&options);
            if( d->mBackgroundItem ) {
                style()->updatePrimitive(
                d->mBackgroundItem, HbStyle::P_DataItem_background, &options );
            }
            //We are skipping call to abstractviewitem::itemChange here because updateChildItems is 
            //called in that function which will again create data view item primitives.
            return HbWidget::itemChange( change, value );
        }
        default:
            break;
  }
    return HbAbstractViewItem::itemChange( change, value );
}

#include "moc_hbdataformviewitem.cpp"