widgetmodel/alfwidgetmodel/src/alfwidget.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:23:18 +0100
branchRCL_3
changeset 26 0e9bb658ef58
parent 0 e83bab7cf002
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* 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 base class for all widgets.
*
*/


#include <alf/alfenv.h>
#include "alf/alfwidget.h"
#include <alf/alfwidgetcontrol.h>
#include <alf/ialfmodel.h>
#include <alf/ialfviewwidget.h>
#include <alf/alfcontrolgroup.h>
#include <osn/ustring.h>
#include <alf/alfvarianttype.h>
#include <alf/alfexceptions.h>
#include <alf/alflayout.h>
#include "alf/alfattribute.h"
#include "alf/alfattributevaluetype.h"
#include "alf/ialfattributeowner.h"
#include <alf/ialfwidgetfactory.h>
#include <alf/alfevent.h>
#include <alf/alfwidgetevents.h>
#include <alf/alfwidgetenvextension.h>
#include <osn/osnnew.h>
#include <assert.h>

#include "alfwidgetimpl.h"
#include "alfwidgetattributeownerimpl.h"
#include "ialfhostapi.h"

namespace Alf
    {

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

OSN_EXPORT AlfWidget::AlfWidget()
    {
    }

OSN_EXPORT AlfWidget::AlfWidget(const char* aWidgetName)
	{
    mImpl.reset(new (EMM) AlfWidgetImpl());
    mImpl->setWidgetName(UString(aWidgetName));
    addCommonWidgetProperties();	
	}

OSN_EXPORT AlfWidget::AlfWidget(const char* aWidgetName, IAlfContainerWidget& aContainer, CAlfEnv& aEnv)    
    {    
    mImpl.reset(new (EMM) AlfWidgetImpl());
    mImpl->setWidgetName(UString(aWidgetName));
    addCommonWidgetProperties();    
    
    // Create default control for the widget so that widget containment hierarchy can be
    // created.
    if(!control())
        {
        auto_ptr<CAlfWidgetControl> control(new (EMM) CAlfWidgetControl(aEnv));
        setControl(control.get(), false);
        control.release();
        }
    
    // Add this widget to the container widget
    aContainer.addWidget(*this);
    }

void AlfWidget::addCommonWidgetProperties()
    {
    }

void AlfWidget::removeReferenceFromControl()
    {
    // Make sure that the widget's control is not pointing to this widget anymore
    if(control() && (control()->widget() == this))
    	{
    	control()->setOwnerWidget(0);
    	}	
    }

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
//
OSN_EXPORT AlfWidget::~AlfWidget()
    {

    if( control() && control()->Host() )
        {
        CAlfWidgetControl* parentControl =
            dynamic_cast<CAlfWidgetControl*>( control()->Host() );
        
        if (control()->Focus())
            {
            control()->CAlfWidgetControl::RelinquishFocus();
            }
         
         // This widget is now deleted and it needs to be removed from the
        // container to avoid double deletion.
        if (parentControl)
            {
            AlfWidget* widget = parentControl->widget();
            if (widget)
                {
                widget->removeWidget( *this );
                }
            }
        }
            
    // Delete and remove all the connected child widgets.
    // AlfWidgetFactory::destroyWidget causes ~AlfWidget to be called for
    // the child widget so this works recursively. Note that it also
    // then removes the connection to the container widget in the beginning
    // of ~AlfWidget destructor call.
    
    IAlfWidgetFactory& factory = AlfWidgetEnvExtension::widgetFactory(*(CAlfEnv::Static()));
    
    while ( widgetCount() )
        {
        // Destroy the child widget and also remove it from the child widget
        // array to make sure that this loop terminates.
        // Normally also ~AlfWidget of the child widget removes the destroyed widget
        // from this widget's child array, but that might not be the case
        // if the child widget has not been added in the CAlfEnv
        // (all widgets should always be added there).
        // If not added in the env, destroyWidget does not delete the widget!
        
        IAlfWidget* child = mImpl->getWidget( 0 );

        removeWidget( *child );        
        IAlfWidget* actual = factory.findWidget( child->widgetName() );
        if( actual )
        	{
        	factory.destroyWidget(actual);
        	}              
        }
 
    // Ensure that the control is not pointing back to this widget
    removeReferenceFromControl();
    }


OSN_EXPORT CAlfWidgetControl* AlfWidget::control() const
    {
    return mImpl->control();
    }
    
// ---------------------------------------------------------------------------
// return the parent container
// ---------------------------------------------------------------------------
//
OSN_EXPORT IAlfContainerWidget* AlfWidget::parent() const
    {
    CAlfWidgetControl* ctrl = control();
    assert(ctrl); //should always be set.
    
    IAlfContainerWidget* containerWidget = 0;
    CAlfWidgetControl* parentControl =
        dynamic_cast<CAlfWidgetControl*>(ctrl->Host());
    IAlfWidgetFactory& factory = AlfWidgetEnvExtension::widgetFactory(*(CAlfEnv::Static()));
    if (parentControl)
        {
        IAlfWidget* widget = parentControl->widget();
        if (widget)
            {
            //control->widget may return wrong instance, temporary fix,
            // find widget from the CAlfEnv.
            const char* name = widget->widgetName();
            IAlfWidget* w = factory.findWidget(name);
            containerWidget = 
                IAlfWidget::makeInterface<IAlfContainerWidget>(w);
            assert(containerWidget);
            }
        }
        
    return containerWidget;
    }

// ---------------------------------------------------------------------------
// Sets the new control for this widget. The control will be automatically
// added as an observer for the model, and notified about any
// model changes (e.g., modelChangedL()).
// ---------------------------------------------------------------------------
//
OSN_EXPORT void AlfWidget::setControl(CAlfWidgetControl* aControl, bool aDeletePreviousControl)
    { 
    CAlfWidgetControl* myControl = control();
    if(aControl && (aControl != myControl))
        {
        // Throw exception if the set control is still a control of another widget
        if(aControl->widget())
            {
            ALF_THROW(AlfException, EInvalidArgument, "AlfWidget::setControl() - Control is already set to another widget.");
            }
        
        // Append control to widget's control group
        if(myControl)
            {
            assert(myControl->ControlGroup() != 0);
            aControl->resetControlGroup(*myControl->ControlGroup());
        
            // Move connections from old control to new control
            IAlfHostAPI& oldHostApi = myControl->hostAPI();
            IAlfHostAPI& newHostApi = aControl->hostAPI();
            
            // Move old controls children under new control
            int childCount = oldHostApi.getConnectionCount();
            while(childCount > 0)
                {
                newHostApi.setConnection(*oldHostApi.getConnection(0), EChild);
                childCount--;
                }
                
	        //relinquishfocus or else pointer is left in roster, even though memory for it
	        //might be released. Must be called before connection removed.
            if (myControl->Focus())
                {
                myControl->RelinquishFocus();
                }
                
            // Move new control under the old control's parent and remove old control from the parent.
            if(myControl->Host())
                {
                CAlfWidgetControl* parent = dynamic_cast<CAlfWidgetControl*>(myControl->Host());
                if(parent)
                    {
                    IAlfHostAPI& parentHostApi = parent->hostAPI();
                    parentHostApi.setConnection(*aControl, EChild);
                    parentHostApi.removeConnection(*myControl);
                    }
                }                
            }
                
        // Set the owner widget of the control to point to this widget
        aControl->setOwnerWidget(this);
        
        // Remove reference to this widget from the previous control
        removeReferenceFromControl();               
        }
    mImpl->setControl(aControl, aDeletePreviousControl);
    }

OSN_EXPORT IAlfModel* AlfWidget::model()
    {
    return  mImpl->model();
    }

// ---------------------------------------------------------------------------
// Sets the new model for this widget. If a control exists, it is automatically
// added as an observer for the model and notified for the model change.
// The old model is released.
// ---------------------------------------------------------------------------
//
OSN_EXPORT void AlfWidget::setModel( IAlfModel* aModel,bool aTakeOwnerShip)
    {
    mImpl->setModel( aModel ,aTakeOwnerShip);
    }


OSN_EXPORT const char* AlfWidget::widgetName() const
    {
    return mImpl->widgetName().getUtf8();
    }

// ---------------------------------------------------------------------------
// From class MAlfInterfaceBase.
// Static getter for interfaces provided by the widget, the control, or the model.
// ---------------------------------------------------------------------------
//
OSN_EXPORT IAlfInterfaceBase* AlfWidget::makeInterface( AlfWidget* aWidget, const IfId& aType )
    {
    if ( !aWidget )
        {
        return NULL;
        }
    else
        {
        return aWidget->makeInterface( aType );
        }
    }

// ---------------------------------------------------------------------------
// From class IAlfInterfaceBase.
// Getter for interfaces provided by the widget.
// ---------------------------------------------------------------------------
//
OSN_EXPORT IAlfInterfaceBase* AlfWidget::makeInterface( const IfId& aType )
    {
    UString param(aType.mImplementationId);
    if ( param == IAlfWidget::type().mImplementationId )
        {
        return static_cast<IAlfWidget*>(this);
        }
    else if (param == IAlfAttributeOwner::type().mImplementationId )
        {
        return static_cast<IAlfAttributeOwner*>(mImpl->getAttributeOwner());
        }
    else if (param == IAlfContainerWidget::type().mImplementationId )
        {
        return static_cast<IAlfContainerWidget*>(this);
        }
    IAlfInterfaceBase* result = NULL;
    if (control())
        {
        result = control()->makeInterface(aType);
        }
    if (!result && model())
        {
        result = model()->makeInterface(aType);
        }
    return result;
    }

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
//
OSN_EXPORT int AlfWidget::widgetCount() const
    {
    return mImpl->widgetCount();
    }

// ---------------------------------------------------------------------------
// From class IAlfContainerWidget
// ---------------------------------------------------------------------------
OSN_EXPORT void AlfWidget::addWidget(IAlfWidget& aWidget)
    {
    // There should never be a situation where add widget is called on a
    // widget without a control.
    assert(aWidget.control() != 0);
    assert(control() != 0);
    assert(control()->ControlGroup() != 0);

    // Throw an exception if widget is added to itself.
    IAlfWidget* self = static_cast<IAlfWidget*>(this);
    if(self == &aWidget)
        {
        ALF_THROW(AlfException, EInvalidArgument, "Tried to add a widget to itself.");
        }

    // Throw an exception if added widget is a view widget.
    IAlfViewWidget* view = aWidget.makeInterface<IAlfViewWidget>(&aWidget);
    if(view != 0)
        {
        ALF_THROW(AlfException, EInvalidArgument, "Attempted to add a view widget into a container widget.");
        }        

    // Bail out if the given widget is already added in this widget.
    if(mImpl->findWidget(static_cast<AlfWidget*>(&aWidget)) != -1)
        {
        return;
        }

    // Append the added widget and its children to widget's control group.
    aWidget.control()->resetHierarchyControlGroup(*control()->ControlGroup());

    // Append widget to widget array and remove widget from previous container's widget array.
    mImpl->addWidget(static_cast<AlfWidget*>(&aWidget));
    CAlfWidgetControl* parentControl = dynamic_cast<CAlfWidgetControl*>(aWidget.control()->Host());
    if( parentControl )
        {
        parentControl->widget()->removeWidget(aWidget);
        }

    // Set connection to added widget's control
    CAlfWidgetControl* cntrl = control();
    if (cntrl)
        {
        IAlfHostAPI& hostApi = cntrl->hostAPI();
        try
            {
            hostApi.setConnection(*aWidget.control(), EChild);
            }
        catch (AlfException &e)
            {
            removeWidget(aWidget);
            // Attempt to add it back to the old.
            if(parentControl)
                {
                parentControl->widget()->mImpl->addWidget(static_cast<AlfWidget*>(&aWidget));
                hostApi.setConnection(*parentControl, EChild);
                }
            throw(e);
            }
        }
    }
	
OSN_EXPORT IAlfWidget* AlfWidget::getWidget(int aIndex) const
    {
    return mImpl->getWidget(aIndex);
    }
    
OSN_EXPORT int AlfWidget::getWidgetIndex(IAlfWidget& aWidget) const
    {
    return mImpl->findWidget(static_cast<AlfWidget*>(&aWidget));
    }

OSN_EXPORT void AlfWidget::removeWidget(int aIndex)
    {
    IAlfWidget* widget = getWidget(aIndex); //get the widget
    CAlfWidgetControl* cntrl = control();
    if (widget && cntrl)
        {
        CAlfWidgetControl* childcontrol = widget->control();
        if(childcontrol)
            {
            if (childcontrol->Focus())
                {
                try
                    {
                    childcontrol->RelinquishFocus();
                    }
                 catch(...)
                    {
                    // ignore any problems with getting rid of focus
                    }
                }
            else if(childcontrol->isContainer())
                {
                CAlfWidgetControl* focused = 
                        dynamic_cast<CAlfWidgetControl*>(childcontrol->FocusedConnection());                    
                if(focused)
                    {
                    try
                        {
                        control()->processEvent(TAlfEvent(EEventFocusNextWidget));
                        }
                    catch(...)
                        {
                        // cannot fail because of event processing to get rid of focus
                        }
                    }
                }
            IAlfHostAPI& hostApi = cntrl->hostAPI();
            hostApi.removeConnection(*childcontrol); //remove from hierarchy
            }
        }
    mImpl->removeWidget(aIndex); //remove it from array
    }

OSN_EXPORT void AlfWidget::applyLayout(IAlfLayoutManager& aLayout)
    {
    CAlfWidgetControl* cntrl = control();
    if (cntrl)
        {
        IAlfHostAPI& hostApi = cntrl->hostAPI();
      
        //remove connections first
        for (int i=0 ; i< widgetCount() ; i++)
            {
            IAlfWidget* widget = getWidget(i);
            hostApi.removeConnection(*widget->control());
            }

        hostApi.setBaseLayout(aLayout);    
        
        //add connections again, when new layout has been set.
        for (int i=0 ; i< widgetCount() ; i++)
            {
            IAlfWidget* widget = getWidget(i);
            hostApi.setConnection(*(widget->control()),EChild);
            }
        }
    }

OSN_EXPORT void AlfWidget::setChildFocus(bool /*aFocus*/)
    {

    }
    
OSN_EXPORT void AlfWidget::setPresentation(const char* /*aFilePath*/)
    {
    }
    
    
OSN_EXPORT void AlfWidget::removeWidget(IAlfWidget& aWidget)
    {
    for(int i = 0; i < mImpl->widgetCount(); ++i)
        {
        if(mImpl->getWidget(i) == &aWidget)
            {
            mImpl->removeWidget(i);
            break;
            }
        }
    }
    
    }//namespace Alf