widgetmodel/alfwidgetmodel/src/alfwidget.cpp
branchRCL_3
changeset 26 0e9bb658ef58
parent 0 e83bab7cf002
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/widgetmodel/alfwidgetmodel/src/alfwidget.cpp	Wed Sep 01 12:23:18 2010 +0100
@@ -0,0 +1,498 @@
+/*
+* 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
+
+