widgetmodel/alfwidgetmodel/src/alfelement.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 00:28:09 +0200
changeset 3 4526337fb576
parent 0 e83bab7cf002
permissions -rw-r--r--
Revision: 201003 Kit: 201005

/*
* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  The basic implementation for presentation elements.
*
*/


#include "alf/alfelement.h"
#include <alf/alfwidgetcontrol.h>
#include <alf/alfvarianttype.h>
#include "alf/ialfvisualtemplate.h"
#include "alf/alfreferencetovisual.h"
//#include "alf/alfperf.h"
#include <alf/alfexceptions.h>

#include "alfelementattributeownerimpl.h"

namespace Alf
    {

class  AlfVisualData
    {
public:
    AlfVisualData( CAlfVisual* aVisualTree, uint aDataID ) :
            mVisualTree( aVisualTree ), mDataID( aDataID )
        {
        }
    CAlfVisual *mVisualTree;
    uint mDataID;
    ~AlfVisualData()
        {

        }

    };

class AlfElementImpl
    {
public:
    AlfElementImpl()
        {
        mControl = 0;
        mVisualTemplate = 0;
        mParentElement = 0;
 	    mParentLayout = 0;
        }
    ~AlfElementImpl()
        {
        if (mVisualTemplate)
            {
            delete mVisualTemplate;
            mVisualTemplate = 0;
            }
        if (mParentLayout)
            {
            delete mParentLayout;
            mParentLayout = 0;
            }

        mVisualTreeArray.clear();
        }
    /**
     * The control. Not own.
     */
    CAlfWidgetControl* mControl;

    /**
     * The element name.
     */
    UString mName;

    /**
     * The visual template for creating visual trees. Own.
     */
    IAlfVisualTemplate* mVisualTemplate;

    /*
     * Parent element. NULL for root elements. Not own.
     */
    IAlfElement *mParentElement;

    /*
     * Array of created visual trees with the associated data IDs.
     */
    AlfPtrVector<AlfVisualData>mVisualTreeArray; //RArray<TAlfVisualData> mVisualTreeArray;

    /*
     * Reference to the default parent layout. Own.
     */
    AlfReferenceToVisual *mParentLayout;
    
    /*
     * IAlfAttributeOwner implementation. Own.
     */
    auto_ptr<AlfElementAttributeOwnerImpl> mAttributeOwnerImpl;
    };

// ======== MEMBER FUNCTIONS ========

OSN_EXPORT AlfElement::AlfElement()
    {
    }

OSN_EXPORT void AlfElement::construct( CAlfWidgetControl& aControl, const char* aName )
    {
    mData.reset(new (EMM) AlfElementImpl());

    mData->mControl = &aControl;
    mData->mName = UString(aName);
    mData->mParentLayout=NULL;
    mData->mParentElement=NULL;
    mData->mVisualTemplate=NULL;
    mData->mVisualTreeArray.setAutoDelete(true);
    mData->mAttributeOwnerImpl.reset(new (EMM) AlfElementAttributeOwnerImpl(*this, 
        *mData->mControl));
    aControl.addElement(this);
    }


OSN_EXPORT AlfElement::AlfElement(CAlfWidgetControl& aControl, const char* aName)
    {
    construct( aControl, aName );

    }

OSN_EXPORT AlfElement::~AlfElement()
    {
    }

OSN_EXPORT const char* AlfElement::name() const
    {
    return mData->mName.getUtf8();
    }

OSN_EXPORT void AlfElement::createChildVisualTree(
    IAlfElement* aElement, IAlfVariantType& aChildData,
    IAlfBranch& aData, int aIndex, uint aDataID )
    {
    // Pass directly to the child element CreateVisualTree, no need
    // to do anything else. Derived classes may need additional steps here.
//    ALF_PERF_START( perfdata, "AlfElement-createVisualTree-createChildVisualTree")
    aElement->createVisualTree( aChildData, aData, aIndex, aDataID,
                                aElement->defaultParentLayout( aDataID ),
                                aIndex );
//    ALF_PERF_STOP( perfdata, "AlfElement-createVisualTree-createChildVisualTree")
    }

OSN_EXPORT CAlfVisual* AlfElement::createVisualTree(
    IAlfVariantType& aData, IAlfBranch& aParentData, int aIndex,
    uint aParentDataID, CAlfLayout* aParentLayout, int aLayoutIndex )
    {
    if ( aIndex >= 0 && aIndex <= aParentData.childrenCount() )
        {
        // Update data IDs of all visual trees after the new visual tree
        // Start from the aIndex, and increase all indices by one
        updateDataIDs( aParentData, aIndex, 1, aParentDataID, aParentDataID );

        // Create the new visual tree
        uint dataID = control().elementDataId( *this, aIndex, aParentDataID );
        return createVisualTree( aData, dataID, aParentLayout, aLayoutIndex );
        }
    ALF_THROW(AlfElementException,EInvalidElement,"AlfElement")
    }

OSN_EXPORT CAlfVisual* AlfElement::createVisualTree(
    IAlfVariantType& aData, uint aDataID, CAlfLayout* aParentLayout, int aLayoutIndex )
    {
    CAlfVisual *retVisual = NULL;
    IAlfMap* currentData = NULL;
    IAlfBranch* branch = NULL;
    if ( aData.type()== IAlfVariantType::EMap )
        {
        currentData = aData.map();
        }
    else if (aData.type()== IAlfVariantType::EBranch)
        {
        branch = aData.branch();
        currentData = aData.branch()->data();
        }

    if ( currentData && mData->mVisualTemplate )
        {
        //Find the visual tree with data id
        int index = findFromArray( aDataID );
        if ( index < 0 )
            {
            // Create a new visual tree
            try
                {
                retVisual = mData->mVisualTemplate->createVisualTree(*mData->mControl,
                            currentData, aParentLayout, aLayoutIndex);
                }
            catch (...)
                {
                ALF_THROW(AlfVisualException,ECanNotCreateVisual,"AlfElement")
                }
            // Append the visual into the array
            mData->mVisualTreeArray.resize(mData->mVisualTreeArray.count()+1);
            mData->mVisualTreeArray.insert(mData->mVisualTreeArray.count(),(new (EMM) AlfVisualData(retVisual, aDataID)));
            }
        else
            {
            ALF_THROW(AlfVisualException,EInvalidElement,"AlfElement")
            }
        }

    if ( branch )
        {
        // Pass to children
        int count = branch->childrenCount();
        for ( int i = 0; i < count; ++i )
            {
            IAlfElement* element = mData->mControl->findElement(
                                       branch->childName( i ).getUtf8() );
            if ( element )
                {
                createChildVisualTree(
                    element, *branch->childData( i ), *branch, i, aDataID );
                }
            }
        }

    return retVisual;
    }

OSN_EXPORT void AlfElement::removeChildVisualTree(
    IAlfElement* aElement, IAlfBranch& aData, int aIndex, uint aDataID )
    {
    // Pass directly to the child element RemoveVisualTree, no need
    // to do anything else. Derived classes may need additional steps here.
    aElement->removeVisualTree( aData, aIndex, aDataID );
    }

OSN_EXPORT void AlfElement::removeVisualTree( IAlfBranch& aParentData,
        int aIndex, uint aParentDataID )
    {
    if ( aIndex < aParentData.childrenCount() )
        {
        IAlfVariantType* data = aParentData.childData( aIndex );
        uint dataID = control().elementDataId( *this, aIndex, aParentDataID );

        removeVisualTree( *data, dataID );

        // Update data IDs of all visual trees after the removed visual tree
        // Start from the aIndex + 1, and decrease all indices by one
        updateDataIDs( aParentData, aIndex + 1, -1, aParentDataID, aParentDataID );
        }
    else
        ALF_THROW(AlfVisualException,EInvalidElement,"AlfElement")
        }

OSN_EXPORT void AlfElement::removeVisualTree( IAlfVariantType& aData, uint aDataID )
    {
    if ( aData.type() == IAlfVariantType::EBranch )
        {
        // Pass to children
        IAlfBranch* branch = aData.branch();
        int count = branch->childrenCount();
        for ( int i = 0; i < count; ++i )
            {
            IAlfElement* element = mData->mControl->findElement( branch->childName( i ).getUtf8() );
            if ( element )
                {
                removeChildVisualTree( element, *branch, i, aDataID );
                }
            }
        }

    // Remove visual tree from this element
    int index = findFromArray( aDataID );
    if (index >= 0)
        {
        CAlfVisual* visual = mData->mVisualTreeArray[index]->mVisualTree;
        visual->RemoveAndDestroyAllD();
        mData->mVisualTreeArray.remove( index );
        }
    else
        {
        ALF_THROW(AlfVisualException,EInvalidElement,"AlfElement")
        }
    }

OSN_EXPORT void AlfElement::updateVisualTree(
    IAlfVariantType& aNewData, IAlfVariantType& aOldData, uint aDataID )
    {
    IAlfMap* currentNewData = NULL;
    IAlfMap* currentOldData = NULL;
    IAlfBranch* branch = NULL;
    IAlfBranch* oldBranch = NULL;

    if ( aNewData.type()== IAlfVariantType::EMap )
        {
        currentNewData = aNewData.map();
        }
    else if (aNewData.type()== IAlfVariantType::EBranch)
        {
        branch = aNewData.branch();
        currentNewData = branch->data();
        }

    if (&aOldData)
        {
        if (aOldData.type()== IAlfVariantType::EMap)
            {
            currentOldData = aOldData.map();
            }
        else if (aOldData.type()== IAlfVariantType::EBranch)
            {
            oldBranch = aOldData.branch();
            currentOldData = aOldData.branch()->data();
            }
        }

    if ( currentNewData && mData->mVisualTemplate )
        {
        //Find the visual tree with data id
        int index = findFromArray( aDataID );
        if (index >= 0)
            {
            // Update the contents of the visual tree
            CAlfVisual* visual = mData->mVisualTreeArray[index]->mVisualTree;
            //ALF_PERF_START( perfdata, "AlfElement-updateVisualTree-VTUpdateVisualTree")
            mData->mVisualTreeArray[index]->mVisualTree =
                mData->mVisualTemplate->updateVisualTree(
                    currentNewData, currentOldData, *visual );
            //ALF_PERF_STOP( perfdata, "AlfElement-UpdateVisualTree-VTUpdateVisualTree")
            }
        }

    if ( branch )
        {
        // Pass to children
        int count = branch->childrenCount();
        for ( int i = 0; i < count; ++i )
            {
            IAlfElement* element = mData->mControl->findElement( branch->childName( i ).getUtf8() );
            if ( element )
                {
                IAlfVariantType* oldData = NULL;
                if (oldBranch)
                    {
                    oldData = oldBranch->childData( i );
                    }

                element->updateVisualTree( *branch->childData( i ), *oldData,
                                           mData->mControl->elementDataId( *element, i, aDataID ) );
                }
            }
        }
    }

OSN_EXPORT void AlfElement::addVisualTree(CAlfVisual* aVisualTree, uint aDataID)
    {
    int index = findFromArray( aDataID );
    if ( index >= 0 || aVisualTree == NULL )
        {
        ALF_THROW(AlfVisualException,EInvalidElement,"AlfElement")
        }
    // Append the visual with the assiciated data id into the array

    mData->mVisualTreeArray.resize(mData->mVisualTreeArray.count()+1);
    mData->mVisualTreeArray.insert(mData->mVisualTreeArray.count(),(new (EMM) AlfVisualData(aVisualTree, aDataID)));
    }

OSN_EXPORT void AlfElement::replaceVisualTree( IAlfVariantType& aData, uint aDataID, uint aOldDataID )
    {
    IAlfVariantType* oldData = control().elementData(*this, aOldDataID );

    int index = findFromArray( aOldDataID );
    if ( index < 0 )
        {
        ALF_THROW(AlfVisualException,EInvalidElement,"AlfElement")
        }
    mData->mVisualTreeArray[index]->mDataID = aDataID;

    // Update the contents of the visual tree with the new data
    updateVisualTree( aData, *oldData, aDataID );
    }

OSN_EXPORT void AlfElement::updateDataIDs(
    IAlfBranch& aParentBranch, int aStartIndex,
    int aOffset, uint /*aOldParentDataId*/, uint aParentDataID )
    {

    for ( int i = 0; i < mData->mVisualTreeArray.count(); ++i )
        {
        uint oldDataID = mData->mVisualTreeArray[i]->mDataID;
        uint index = control().dataIdToIndex( *this, oldDataID );
        uint newDataID = control().elementDataId(
                             *this, index + aOffset, aParentDataID );
        if ( index >= aStartIndex && oldDataID != newDataID )
            {
            // Update the data ID
            mData->mVisualTreeArray[i]->mDataID = newDataID;
            // The old data ID was used to calculate the child element data IDs
            // We need to update the visual trees in child elements
            IAlfVariantType* data = aParentBranch.childData( index );
            if ( data != NULL )
                {
                if ( data->type() == IAlfVariantType::EBranch )
                    {
                    IAlfBranch* branch = data->branch();
                    for ( int j = 0; j < branch->childrenCount(); ++j )
                        {
                        IAlfElement* childElement =
                            mData->mControl->findElement( branch->childName( j ).getUtf8() );
                        if ( childElement )
                            {
                            childElement->updateDataIDs(
                                *branch, 0, 0, oldDataID, newDataID );
                            }
                        }
                    }
                }
            }
        }
    }

OSN_EXPORT CAlfLayout* AlfElement::defaultParentLayout(uint aParentDataID)
    {
    if (mData->mParentLayout)
        {
        CAlfVisual* visual=NULL;
        try
            {
            visual = mData->mParentLayout->resolve(*mData->mControl, aParentDataID);
            }
        catch (...)
            {
            ALF_THROW(AlfVisualException,EInvalidVisual,"AlfElement")
            }
        return (CAlfLayout *)visual;
        }
    return NULL;
    }

OSN_EXPORT void AlfElement::setDefaultParentLayout(AlfReferenceToVisual* aReference)
    {
    if (mData->mParentLayout)
        {
        delete mData->mParentLayout;
        mData->mParentLayout = 0;
        }
    mData->mParentLayout = aReference;
    }

OSN_EXPORT void AlfElement::setVisualTemplate(IAlfVisualTemplate& aTemplate) throw()
    {
    // Remove the visual template from its previous owner
    if(aTemplate.owner())
        {
        aTemplate.owner()->removeVisualTemplate();
        }
    
    // Set the visual template to this element
    mData->mVisualTemplate = &aTemplate;
    mData->mVisualTemplate->setOwner(this);
    }

OSN_EXPORT IAlfVisualTemplate* AlfElement::getVisualTemplate() const throw()
    {
    return mData->mVisualTemplate;
    }

OSN_EXPORT void AlfElement::destroyVisualTemplate() throw()
    {
    if (mData->mVisualTemplate)
        {
        delete mData->mVisualTemplate;
        mData->mVisualTemplate = 0;
        }    
    }

OSN_EXPORT IAlfVisualTemplate* AlfElement::removeVisualTemplate() throw()
    {
    IAlfVisualTemplate* ret = mData->mVisualTemplate;
    
    // Set owner to NULL in removed visual template
    if(mData->mVisualTemplate)
        {
        mData->mVisualTemplate->setOwner(0);
        }    
    mData->mVisualTemplate = 0;

    return ret;
    }

OSN_EXPORT CAlfVisual* AlfElement::findVisual(const char* aName, uint aDataID)
    {
    int index = findFromArray( aDataID );
    if ( index < 0 )
        {
        return NULL;
        }
    return mData->mVisualTreeArray[index]->mVisualTree->FindTag(TPtrC8((unsigned char*)aName));//Alf dependency
    }

OSN_EXPORT CAlfVisual* AlfElement::findVisual(uint aDataID)
    {
    int index = findFromArray( aDataID );
    if ( index < 0 )
        {
        return NULL;
        }
    return mData->mVisualTreeArray[index]->mVisualTree;
    }

OSN_EXPORT uint AlfElement::dataID( const CAlfVisual& aVisual ) const
    {
    for ( int i = 0; i < mData->mVisualTreeArray.count(); ++i )
        {
        if ( mData->mVisualTreeArray[i]->mVisualTree == &aVisual )
            {
            return mData->mVisualTreeArray[i]->mDataID;
            }
        }
    return 0;
    }

int AlfElement::findFromArray( uint aDataID ) const
    {
    for ( int i = 0; i < mData->mVisualTreeArray.count(); ++i )
        {
        if ( mData->mVisualTreeArray[i]->mDataID == aDataID )
            {
            return i;
            }
        }
    return -1;
    }

OSN_EXPORT const IAlfElement* AlfElement::parentElement() const
    {
    return mData->mParentElement;
    }

OSN_EXPORT void AlfElement::setParentElement(IAlfElement& aParent)
    {
    mData->mParentElement = &aParent;
    }

OSN_EXPORT  CAlfWidgetControl& AlfElement::control()
    {
    return *mData->mControl;
    }

OSN_EXPORT  void AlfElement::removeAndDestroyVisuals( int aTimeMilliseconds )
    {
    //remove child elements
    for (int i = 0; i<control().numElements(); i++)
        {
        IAlfElement& element = control().element(i);
        if (element.parentElement() == this)
            {
            element.removeAndDestroyVisuals(aTimeMilliseconds);
            }
        }
    
    //remove visual trees and elements, that are linked 
    //to this element with parentlayout.
    for (int i = 0 ; i < mData->mVisualTreeArray.count(); i++)
        {
        AlfVisualData* vData = mData->mVisualTreeArray[i];
        CAlfVisual* visual = vData->mVisualTree;
        if(visual)
            {
            CAlfLayout* layout = dynamic_cast<CAlfLayout*>(visual);
            if (layout)
                {
                for (int j = 0; j<control().numElements(); j++)
                    {
                    IAlfElement& element = control().element(j);
                    CAlfLayout* parent = element.defaultParentLayout(vData->mDataID);
                    if (parent && contains(*parent))
                        {
                        element.removeAndDestroyVisuals(aTimeMilliseconds);
                        }
                    }
                }
            visual->RemoveAndDestroyAllD();
            vData->mVisualTree = NULL;
            }
        }
        
    mData->mVisualTreeArray.clear();
    }


//From IAlfElement
OSN_EXPORT bool AlfElement::contains(CAlfVisual& aVisual) const
    {
    CAlfVisual* visual = &aVisual;
    //traverse back to the root parent
    while (visual)
        {
        for (int i = 0 ; i < mData->mVisualTreeArray.count(); i++)
            {
            if (visual == mData->mVisualTreeArray[i]->mVisualTree)//is this visual parent of passed visual?
                return true;
            }
        visual = visual->Layout();
        }
    return false; //referred visual is not part of this element.
    }

// ---------------------------------------------------------------------------
// From class IAlfInterfaceBase.
// Getter for interfaces provided by the element.
// ---------------------------------------------------------------------------
//
OSN_EXPORT IAlfInterfaceBase* AlfElement::makeInterface( const IfId& aType )
    {
    UString param(aType.mImplementationId);
    if (param == IAlfElement::type().mImplementationId)
        {
        return static_cast<IAlfElement*>(this);
        }
    else if (param == IAlfAttributeOwner::type().mImplementationId)
        {
    	return static_cast<IAlfAttributeOwner*>(mData->mAttributeOwnerImpl.get());
        }
    return NULL;
    }
    
    } // Alf