widgetmodel/alfwidgetmodel/src/alfvisualtemplate.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:  Visual template class for alfred widget model.
*      This class creates and updates visual tree.
*
*/




//INCLUDES
#include <algorithm>
#include <assert.h>
#include <alf/alfcontrol.h>
#include <alf/alfbrush.h>
#include <alf/alfvisualfactory.h>
#include <alf/alfbrusharray.h>
#include <utf.h>
#include <alf/alfimagevisual.h>
#include <alf/alftexture.h>
#include <alf/alfenv.h>
#include <alf/alfexceptions.h>
//#include "alf/alfperf.h"
#include <osn/osnnew.h>
#include <alf/ialfelement.h>
#include "alf/alfvisualtemplate.h"
#include "alf/alfvarianttype.h"
#include "alf/ialfattributesetter.h"
#include "alf/alfattributecontainer.h"
#include "alf/alfattribute.h"

// The number of attribute setters is usually between 1 and 5
static const int KAttributeArrayGranularity = 4;
static const int KContainerArrayGranularity = 4;

namespace Alf
    {

struct DeleteTemplate
{
    void operator()(const IAlfVisualTemplate* aTemplate) const
        {
        delete aTemplate;
        }
};

// -----------------------------------------------------------------------------
// Helper function to iterate through a visual template hierarchy and
// investigate whether a given visual template exists in it.
// -----------------------------------------------------------------------------
bool existsInHierarchy(IAlfVisualTemplate& aRoot, const IAlfVisualTemplate& aTemplate)
    {
    // Check the template against the root node.
    if(&aTemplate == &aRoot)
        {
        return true;
        }
    
    // Iterate through all the root's children
    for(int i = 0; i < aRoot.numChildTemplates(); ++i)
        {
        if(existsInHierarchy(aRoot.childTemplate(i), aTemplate))
            {
            return true;
            }
        }
        
    return false;        
    }    
    
// ============================ MEMBER FUNCTIONS ===============================

// ---------------------------------------------------------------------------
// Description : Constructor
// ---------------------------------------------------------------------------
OSN_EXPORT AlfVisualTemplate* AlfVisualTemplate::create()
    {
    return new( EMM ) AlfVisualTemplate;
    }

// ---------------------------------------------------------------------------
// Description : Constructor
// ---------------------------------------------------------------------------
OSN_EXPORT AlfVisualTemplate* AlfVisualTemplate::create(TAlfVisualType aType)
    {
    return new( EMM ) AlfVisualTemplate( aType );
    }

// ---------------------------------------------------------------------------
// Description : Constructor
// ---------------------------------------------------------------------------
OSN_EXPORT AlfVisualTemplate* AlfVisualTemplate::create(TAlfLayoutType aType)
    {
    return new( EMM ) AlfVisualTemplate( aType );
    }

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

// ---------------------------------------------------------------------------
// Description : Constructor
// ---------------------------------------------------------------------------
OSN_EXPORT AlfVisualTemplate::AlfVisualTemplate():
    mVisualType(EAlfVisualTypeVisual),
    mAttributeArray(KAttributeArrayGranularity),
    mContainerArray(KContainerArrayGranularity),
    mSelectOneChild(false),
    mOwner(0),
    mParent(0)
    {
    }

// ---------------------------------------------------------------------------
// Description : Constructor
// ---------------------------------------------------------------------------
OSN_EXPORT AlfVisualTemplate::AlfVisualTemplate(TAlfVisualType aType):
    mVisualType(aType),
    mAttributeArray(KAttributeArrayGranularity),
    mContainerArray(KContainerArrayGranularity),
    mSelectOneChild(false),
    mOwner(0),
    mParent(0)
    {
    }

// ---------------------------------------------------------------------------
// Description : Constructor
// ---------------------------------------------------------------------------
OSN_EXPORT AlfVisualTemplate::AlfVisualTemplate(TAlfLayoutType aType):
    mVisualType(-1 - aType),
    mAttributeArray(KAttributeArrayGranularity),
    mContainerArray(KContainerArrayGranularity),
    mSelectOneChild(false),
    mOwner(0),
    mParent(0)
    {
    }

// ---------------------------------------------------------------------------
// Description : Destructor
// ---------------------------------------------------------------------------
OSN_EXPORT AlfVisualTemplate::~AlfVisualTemplate()
    {
    mBrushArray.clear();
    mAttributeArray.clear();
    mContainerArray.clear();
    
    // Remove this visual template from it's parent or owner
    if(parent())
        {
        parent()->removeChildTemplate(*this);
        }
    if(owner())
        {
        owner()->removeVisualTemplate();
        }
    
    // Destroy child visual templates in two passes, since destructor of a child
    // visual template could affect the content of the this visual template's child vector.
    vector<IAlfVisualTemplate*> children(mChildren);
    mChildren.clear();
    for_each(children.begin(), children.end(), DeleteTemplate());
    }

// ---------------------------------------------------------------------------
// Description : Set the owner element.
// ---------------------------------------------------------------------------
OSN_EXPORT void AlfVisualTemplate::setOwner(IAlfElement* aOwner) throw()
    {
	if(aOwner != mOwner)
	    {
	    // Remove this visual template from it's parent. Parent and owner are
	    // mutually exclusive properties on a visual template.
	    if(aOwner && (parent() != 0))
	        {
	        parent()->removeChildTemplate(*this);
	        }
	    
	    // Set the owner of this visual template.
		mOwner = aOwner;
	    }
    }

OSN_EXPORT IAlfElement* AlfVisualTemplate::owner() const throw()
    {
	return mOwner;
    }
    
// ---------------------------------------------------------------------------
// Description : Set the name of the visual, i.e., the tag.
// ---------------------------------------------------------------------------
OSN_EXPORT void AlfVisualTemplate::setName(const char* aName)
    {
    mVisualName = UString(aName);
    }

// ---------------------------------------------------------------------------
// Description : Get the name of the visual, i.e., the tag.
// ---------------------------------------------------------------------------
OSN_EXPORT const char* AlfVisualTemplate::name() const throw()
    {
    return mVisualName.getUtf8();
    }

// ---------------------------------------------------------------------------
// Description : Add a child visual template.
// ---------------------------------------------------------------------------
OSN_EXPORT void AlfVisualTemplate::addChildTemplate(IAlfVisualTemplate& aChild)
    {    
    insertChildTemplate(aChild, mChildren.size());
    }

// ---------------------------------------------------------------------------
// Description : Inserts a child visual template at given index
// ---------------------------------------------------------------------------
OSN_EXPORT void AlfVisualTemplate::insertChildTemplate(IAlfVisualTemplate& aChild, int aIndex)
	{
	if(!(aIndex >=0 && aIndex <= mChildren.size()))
	    ALF_THROW(AlfException, EInvalidArrayIndex, "AlfVisualTemplate::insertChildTemplate() - Index out of bounds.");
	     	
    // Verify that the given argument is valid
    if(existsInHierarchy(*this, aChild))
        {
        ALF_THROW(AlfException, EInvalidHierarchy, "AlfVisualTemplate::insertChildTemplate() - Adding a child visual template that is already in the hierarchy.");
        }
    if(existsInHierarchy(aChild, *this))
        {
        ALF_THROW(AlfException, EInvalidHierarchy, "AlfVisualTemplate::insertChildTemplate() - Attempt to create a recursive visual template tree.");
        }
    if(layoutType() < 0)
        {
        ALF_THROW(AlfException, EInvalidHierarchy, "AlfVisualTemplate::insertChildTemplate() - Attempt to add a child visual into a non-layout visual template.");
        }     	
     	
    // Insert child visual template to the array
	mChildren.insert(mChildren.begin() + aIndex, &aChild);
	
    // Remove child from previous hierarchy and add it under this visual template.
    if(aChild.parent())
        {
        // Visual template cannot have a parent and owner at the same time.
        assert(aChild.owner() == 0);
        aChild.parent()->removeChildTemplate(aChild);        
        }
    if(aChild.owner())
        {
        // Visual template cannot have a parent and owner at the same time.
        assert(aChild.parent() == 0);
        aChild.owner()->removeVisualTemplate();
        }
    
    // Set a new parent for this visual template.
    aChild.setParent(this);	
	}

// ---------------------------------------------------------------------------
// Description : Destroyes a child visual template at given index
// ---------------------------------------------------------------------------
OSN_EXPORT void AlfVisualTemplate::destroyChildTemplate(int aIndex) throw()
	{
	// Remove and destroy a child template by the given index
	if(aIndex >=0 && aIndex < mChildren.size())
		{
		IAlfVisualTemplate* child = mChildren[aIndex];				
		removeChildTemplate(*child);
		delete child;
		}				
	}
	
// ---------------------------------------------------------------------------
// Description : Destroyes a child visual template.with the given name
// ---------------------------------------------------------------------------
OSN_EXPORT void AlfVisualTemplate::destroyChildTemplate(const char* aName) throw()
	{
	// Search through the children for the given name.
	for(int i = 0; i < mChildren.size() ;i++)
    	{
		if(!strcmp(mChildren[i]->name(), aName))
    		{
    		// Remove and destroy the found child visual template
    		IAlfVisualTemplate* child = mChildren[i];
    		removeChildTemplate(*child);
    		delete child;
    		}
    	}
	}
	
// ---------------------------------------------------------------------------
// Description : Get the number of child visual templates.
// ---------------------------------------------------------------------------
OSN_EXPORT int AlfVisualTemplate::numChildTemplates() const throw()
    {
    return mChildren.size();
    }

// ---------------------------------------------------------------------------
// Description : Get a child visual template.
// ---------------------------------------------------------------------------
OSN_EXPORT IAlfVisualTemplate& AlfVisualTemplate::childTemplate(int aIndex) const
    {
    if((aIndex < 0) || (aIndex >= numChildTemplates()))
        {
        ALF_THROW(AlfException, EInvalidArrayIndex, "AlfVisualTemplate::childTemplate() - Index out of bounds.");
        }
    return *mChildren[aIndex];
    }

// -----------------------------------------------------------------------------
// Description : Add a new visual attribute setter. The ownership is not passed.
// -----------------------------------------------------------------------------
OSN_EXPORT void AlfVisualTemplate::addAttributeSetter(
    IAlfAttributeSetter* aSetter, AlfAttributeContainer* aContainer )
    {
    mAttributeArray.resize(mAttributeArray.count()+1);
    mContainerArray.resize(mContainerArray.count()+1);

    mAttributeArray.insert(mAttributeArray.count(),aSetter);
    mContainerArray.insert(mContainerArray.count(),aContainer);
    }

// -----------------------------------------------------------------------------
// Description : Get the number of visual attribute setters.
// -----------------------------------------------------------------------------
OSN_EXPORT int AlfVisualTemplate::numAttributeSetters() const throw()
    {
    return mAttributeArray.count();
    }

// -----------------------------------------------------------------------------
// Description : Get a visual attribute setter.
// -----------------------------------------------------------------------------
OSN_EXPORT IAlfAttributeSetter& AlfVisualTemplate::attributeSetter(int aIndex) const
    {
    if((aIndex < 0) || (aIndex >= mAttributeArray.count()))
        {
        ALF_THROW(AlfException, EInvalidArrayIndex, "AlfVisualTemplate::attributeSetter() - Index out of bounds.");
        }    
    return *mAttributeArray[aIndex];
    }

// -----------------------------------------------------------------------------
// Description :
// -----------------------------------------------------------------------------
OSN_EXPORT AlfAttributeContainer& AlfVisualTemplate::attributeContainer(int aIndex) const
    {
    if((aIndex < 0) || (aIndex >= mContainerArray.count()))
        {
        ALF_THROW(AlfException, EInvalidArrayIndex, "AlfVisualTemplate::attributeContainer() - Index out of bounds.");
        }        
    return *mContainerArray[aIndex];
    }

// -----------------------------------------------------------------------------
// Description : Update an existing visual tree with new values
// -----------------------------------------------------------------------------
OSN_EXPORT CAlfVisual* AlfVisualTemplate::updateVisualTree(IAlfMap* aData, IAlfMap* aOldData, CAlfVisual& aVisual)
    {

    CAlfVisual* retVisual = &aVisual;
    // Update the attributes.
    for (int i = 0; i < mAttributeArray.count(); ++i)
        {
        try
            {
            //ALF_PERF_START( perfdata, "AlfVisualTemplate-updateVisualTree-SetAttributeValue")
            mAttributeArray[i]->setAttributeValue(aVisual, mContainerArray[i], aData);
            //ALF_PERF_STOP( perfdata, "AlfVisualTemplate-updateVisualTree-setAttributeValue")
            }
        catch (...)
            {
            ALF_THROW(AlfAttributeException,EInvalidAttributeValue,"AlfVisualTemplate")
            }
        }
    // Pass to children
    if (mChildren.size())
        {
        int ind = selectedChildInd( aData );
        if (ind >= 0 && ind < mChildren.size())
            {
            CAlfLayout *layout = (CAlfLayout *)&aVisual;
            int indOld = selectedChildInd( aOldData );
            if ( ind == indOld )
                {
                mChildren[ind]->updateVisualTree( aData, aOldData, *layout );
                }
            else
                {
                CAlfControl& c(aVisual.Owner());

                //new visual tree is created. Replaces the current (now old) layout,
                //which is removed from its parent and destroyed.
                //new layout is returned from the function.
                CAlfLayout* parentLayout = layout->Layout();
                TInt ind = parentLayout->FindVisual(layout);
                parentLayout->Remove(layout);
                layout->RemoveAndDestroyAllD();
                CAlfLayout* newLayout = (CAlfLayout *) createVisualTree(c, aData, parentLayout, ind);
                retVisual = newLayout;
                }
            }
        else
            {
            CAlfLayout *layout = (CAlfLayout *)&aVisual;
            for (int i = 0; i < mChildren.size(); ++i)
                {
                mChildren[i]->updateVisualTree(aData, aOldData, layout->Visual(i));
                }
            }
        }
    return retVisual;
    }
    
// -----------------------------------------------------------------------------
// Description : create a new visual tree and initialize the visuals
// -----------------------------------------------------------------------------
OSN_EXPORT CAlfVisual* AlfVisualTemplate::createVisualTree(CAlfControl& aControl,
        IAlfMap* aData, CAlfLayout* aParentLayout, int aLayoutIndex)
    {
    // create the visual
    CAlfVisual *result = NULL;
    CAlfLayout *layout = NULL;
    if (!mSelectOneChild)
        {
        if (mVisualType < 0)
            {
            //ALF_PERF_START( perfdata, "AlfVisualTemplate-createVisualTree-NewLayout")
            // create layout
            result = layout = AlfVisualFactory::NewLayoutL(
                                  (TAlfLayoutType)(-1 - mVisualType), aParentLayout, aControl, aControl.Env());
            //ALF_PERF_STOP( perfdata, "AlfVisualTemplate-createVisualTree-NewLayout")
            if (!result)
                {
                ALF_THROW(AlfVisualException,ECanNotCreateVisual,"AlfVisualTemplate")
                }
            }
        else
            {
            // create visual
            //ALF_PERF_START( perfdata, "AlfVisualTemplate-createVisualTree-NewVisual")
            result = AlfVisualFactory::NewVisualL(
                         (TAlfVisualType)mVisualType, aParentLayout, aControl, aControl.Env());
            //ALF_PERF_STOP( perfdata, "AlfVisualTemplate-createVisualTree-NewVisual")
            if (!result)
                {
                ALF_THROW(AlfVisualException,ECanNotCreateVisual,"AlfVisualTemplate")
                }

            //Add the brushes to the visual
            result->EnableBrushesL(true);
            for (int i=0; i < mBrushArray.count(); i++)
                {
                result->Brushes()->AppendL(mBrushArray[i], EAlfDoesNotHaveOwnership);
                }
            }
        if (aParentLayout &&
                aLayoutIndex >= 0 && aLayoutIndex <= aParentLayout->Count())
            {
            //when aConstructedWithParentInformation- parameter is ETrue,
            //no message sent to server
            aParentLayout->Append(result, ETrue);

            //reorder, if needed.
            if (aLayoutIndex != aParentLayout->Count() - 1)
                {
                aParentLayout->Reorder(*result, aLayoutIndex);
                }
            }
        aControl.Append(result);

        if (mVisualName.isNull())
            mVisualName = UString("");
        result->SetTagL(TPtrC8((unsigned char*)mVisualName.getUtf8()));
        
        // Set the attributes
        for (int i = 0; i < mAttributeArray.count(); ++i)
            {
            try
                {
                //ALF_PERF_START( perfdata, "AlfVisualTemplate-createVisualTree-setAttributeValue")
                // set dirtines of all attribute in createvisualtree
                for(int j = 0; j < mContainerArray[i]->attributeCount() ;j++ )
                    {
                    mContainerArray[i]->getAttribute(j).setDirty(true);
                    }
                mAttributeArray[i]->setAttributeValue(*result, mContainerArray[i], aData);
                //ALF_PERF_STOP( perfdata, "AlfVisualTemplate-createVisualTree-setAttributeValue")
                }
            catch (...)
                {
                ALF_THROW(AlfAttributeException,EInvalidAttributeValue,"AlfVisualTemplate")
                }
            }        
        }
    
    // Pass to children
    int ind = selectedChildInd( aData );
    if (ind >= 0 && ind < mChildren.size())
        {
        result = mChildren[ind]->createVisualTree(aControl, aData, aParentLayout, aLayoutIndex);
        }
    else if (!mSelectOneChild)
        {
        for (int i = 0; i < mChildren.size(); ++i)
            {
            mChildren[i]->createVisualTree(aControl, aData, layout, i);
            }
        }
    return result;
    }

// -----------------------------------------------------------------------------
// reads and returns selected ind from data, if set. If not set returns -1.
// -----------------------------------------------------------------------------
int AlfVisualTemplate::selectedChildInd( IAlfMap* aData )
    {
    int ind = -1;
    if (aData && mSelectOneChild)
        {
        IAlfVariantType* data = aData->item(mChildIndFieldName);

        //field value contains index to child array.
        //if field contains no data and template has only one
        // child, assume it's the child wanted.
        bool valueIsEmpty = false;
        if (!data)
            {
            valueIsEmpty = true;
            }
        else
            {
            switch ( data->type() )
                {
                case IAlfVariantType::EInt:
                    ind = data->integer();
                    break;
                default:
                    break;
                }
            }
        if ( valueIsEmpty && mChildren.size() == 1 )
            {
            ind = 0;
            }
        }
    return ind;
    }

// -----------------------------------------------------------------------------
// Description : Removes a visual template from the child array without
// destroying the child template object.
// -----------------------------------------------------------------------------
void AlfVisualTemplate::removeChildTemplate(IAlfVisualTemplate& aChild) throw()
    {
    std::vector<IAlfVisualTemplate*>::iterator it = find(mChildren.begin(), mChildren.end(), &aChild);
    if(it != mChildren.end())
        {
        mChildren.erase(it);
        aChild.setParent(0);
        }
    }

// -----------------------------------------------------------------------------
// Description : Returns the parent visual template object
// -----------------------------------------------------------------------------
OSN_EXPORT IAlfVisualTemplate* AlfVisualTemplate::parent() const throw()
    {
    return mParent;
    }
    
// -----------------------------------------------------------------------------
// Description : Set the visual type
// -----------------------------------------------------------------------------
OSN_EXPORT void AlfVisualTemplate::setParent(IAlfVisualTemplate* aParent) throw()
    {
    mParent = aParent;
    }

// -----------------------------------------------------------------------------
// Description : Set the visual type
// -----------------------------------------------------------------------------
OSN_EXPORT void AlfVisualTemplate::setVisualType(TAlfVisualType aType)
    {
    mVisualType = aType;
    }

// -----------------------------------------------------------------------------
// Description : Get the visual type
// -----------------------------------------------------------------------------
OSN_EXPORT int AlfVisualTemplate::visualType() const throw()
    {
    return mVisualType;
    }
// -----------------------------------------------------------------------------
// Description : Set the layout type
// -----------------------------------------------------------------------------
OSN_EXPORT void AlfVisualTemplate::setLayoutType(TAlfLayoutType aType)
    {
    mVisualType = -1 - aType;
    }

// -----------------------------------------------------------------------------
// Description : Get the layout type
// -----------------------------------------------------------------------------
OSN_EXPORT int AlfVisualTemplate::layoutType() const throw()
    {
    return -1 - mVisualType;
    }

// -----------------------------------------------------------------------------
// Description : Adds brush to the brush array.
// -----------------------------------------------------------------------------
OSN_EXPORT void AlfVisualTemplate::addBrush(CAlfBrush& aBrush)
    {
    mBrushArray.resize(mBrushArray.count()+1);
    mBrushArray.insert(mBrushArray.count(),&aBrush);
    }

// -----------------------------------------------------------------------------
// Description : Get the munber of brushes
// -----------------------------------------------------------------------------
OSN_EXPORT int AlfVisualTemplate::numBrushes() const
    {
    return mBrushArray.count();
    }

// -----------------------------------------------------------------------------
// Description : Get a Brush
// -----------------------------------------------------------------------------
OSN_EXPORT CAlfBrush& AlfVisualTemplate::brush(int aIndex) const
    {
    return *mBrushArray[aIndex];
    }


// -----------------------------------------------------------------------------
// Description : puts the class in to selected child mode.
// -----------------------------------------------------------------------------
OSN_EXPORT void AlfVisualTemplate::setSelectChildMode(bool aSelectChild,
        const UString& aChildIndFieldName )
    {
    mSelectOneChild = aSelectChild;
    mChildIndFieldName = aChildIndFieldName;
    }


// ---------------------------------------------------------------------------
// From class IAlfInterfaceBase.
// Getter for interfaces provided by the visual template.
// ---------------------------------------------------------------------------
//
OSN_EXPORT IAlfInterfaceBase* AlfVisualTemplate::makeInterface( const IfId& aType )
    {
    UString param(aType.mImplementationId);
    if (param == IAlfVisualTemplate::type().mImplementationId)
        {
        return static_cast<IAlfVisualTemplate*>(this);
        }
    return NULL;
    }

    } //Alf