src/hbcore/layouts/hbanchorlayout.cpp
changeset 6 c3690ec91ef8
parent 5 627c4a0fd0e7
child 7 923ff622b8b9
--- a/src/hbcore/layouts/hbanchorlayout.cpp	Fri Jun 11 13:58:22 2010 +0300
+++ b/src/hbcore/layouts/hbanchorlayout.cpp	Wed Jun 23 18:33:25 2010 +0300
@@ -29,64 +29,76 @@
 #include "hbanchorlayoutengine_p.h"
 
 #include <QLayout>
+#include <QDebug>
 
 #include "hblayoututils_p.h"
 
+
 //Uncomment next define in order to get more debug prints.
 //Similar define exists also in the engine side.
 //#define HBANCHORLAYOUT_DEBUG
 
-#include <QDebug>
+#ifdef HBANCHORLAYOUT_DEBUG
+#ifndef Q_WS_S60
+#include "hbspaceritem_p.h"
+#endif
+#endif
 
 /*!
-    @stable
-    @hbcore
     \class HbAnchorLayout
-    \brief HbAnchorLayout manages geometries of its child items with anchors that
+    \brief HbAnchorLayout manages geometries of its child items with anchors
     that connect the layout items with each other.
 
-    The anchors have a start edge, an end edge and a value. The start and
-    end edges are defined by (layout item, edge) pairs. See setAnchor() for
-    more details.
+    It also allows layout items to be missing and can fix anchor attachments.
+    Here are some simple rules how anchor fixation can be created (the example
+    is only for horizontal direction - the same needs to be done for portrait as well).
 
-    If anchors set allow ambiguos positioning of items, then layout tries to set items size as 
+    If anchors set allow ambiguos positioning of items, then layout tries to set items size as
     close to preferred as possible.
 
-    Example code:
-    \snippet{anchorlayoutsample.cpp,1}
+    \image html hbmeshlayout1.png
+
+    From the image above, we have decided that the green node is always present. This
+    means that all the other nodes in the horizontal graph can be optional.
+
+    \image html hbmeshlayout2.png
+
+    Then, we create the anchors starting from the non-optional node and point towards
+    the edges of the layout. The mesh layout definition in the WidgetML would look like:
+
+    \code
 
-    The picture below illustrates the anchors defined by the above example code.
+    <meshitem src="green_item" srcEdge="LEFT" dst="blue_item" dstEdge="RIGHT" />
+    <meshitem src="blue_item" srcEdge="LEFT" dst="" dstEdge="LEFT" />
+    <meshitem src="green_item" srcEdge="RIGHT" dst="red_item" dstEdge="LEFT" />
+    <meshitem src="red_item" srcEdge="RIGHT" dst="yellow_item" dstEdge="LEFT" />
+    <meshitem src="yellow_item" srcEdge="RIGHT" dst="" dstEdge="RIGHT" />
+
+    \endcode
 
-    \image html hbanchorlayout.png
+    As mentioned, the green node needs be present always. In practice, this means that the
+    parent widget, which owns this anchor layout, needs to have a child widget with item
+    name "green_item". \c HbStyle::setItemName for more details.
+
+    If an optional node is missing, the anchors pointing to the node are
+    changed to point to the node after (=towards the parent layout) the missing one - this
+    is called "fixing the mesh".
+
+    \image html hbmeshlayout3.png
+
+    In the picture above, the blue and yellow items are missing. The anchor is fixed by removing
+    the anchor definitions starting from the missing nodes.
+
+    \stable
 */
 
 /*!
-    \enum Hb::Edge
+    \enum HbAnchorLayout::Edge
 
     This enum defines the edges of a layout item.
 */
 
-/*!
-    \var HbAnchorLayout::Left
-    Left edge.
-*/
-
-/*!
-    \var HbAnchorLayout::Top
-    Top edge.
-*/
-
-/*!
-    \var HbAnchorLayout::Right
-    Right edge.
-*/
-
-/*!
-    \var HbAnchorLayout::Bottom
-    Bottom edge.
-*/
-
-/*!
+/*
     \enum EdgeType
     \internal
 */
@@ -95,6 +107,112 @@
     Vertical
 };
 
+/*
+    Type for mapping from layout item to node identifier.
+    \internal
+*/
+typedef QMap<QGraphicsLayoutItem*, QString> HbMeshItemMap;
+typedef HbMeshItemMap::iterator HbMeshItemMapIterator;
+typedef HbMeshItemMap::const_iterator HbMeshItemMapConstIterator;
+
+
+/*
+    Result of findEndItem.
+*/
+struct HbMeshEndItemResult
+{
+    QGraphicsLayoutItem *mItem;
+    HbAnchorLayout::Edge mEdge;
+    qreal mValue;
+};
+
+class HbAnchorLayoutPrivate
+{
+public:
+    Q_DECLARE_PUBLIC( HbAnchorLayout )
+
+    HbAnchorLayoutPrivate();
+    ~HbAnchorLayoutPrivate();
+
+    void addItemIfNeeded(QGraphicsLayoutItem *item);
+
+    static EdgeType edgeType( HbAnchorLayout::Edge edge );
+    void setItemGeometries();
+    void updateAnchorsAndItems();
+
+    void createEquations( EdgeType type );
+
+    int getEdgeIndex(QGraphicsLayoutItem *item, Hb::Edge edge);
+
+    bool findEndItem(
+        QList<HbMeshEndItemResult> &resultList,
+        const HbAnchor *anchor,
+        QStringList &ids) const;
+    void resolveAnchors();
+    void removeItemIfNeeded( QGraphicsLayoutItem *item );
+
+    bool setAnchor( HbAnchor *anchor );
+
+    void setSizeProp( SizeProperty *v, QGraphicsLayoutItem *item, EdgeType type );
+    GraphVertex *createCenterEdge( EdgeType type, QGraphicsLayoutItem *item,  Hb::Edge edge );
+    void defineNextGeometry( const int itemIndexStart, const int itemIndexEnd, const int anchorIndex, const int definedItemIndex );
+
+
+    QSizeF sizeHint(Qt::SizeHint which);
+
+public:
+    HbAnchorLayout * q_ptr;
+
+    bool mEquationsDirty; // if true, we needed to re-create the equations (e.g. when new anchor is set)
+    bool mValid;          // result of the calculations. false, if the equations cannot be solved.
+    bool mInvalidateCalled; // set true in ::invalidate() and cleared after geometry is set in ::setGeometry
+    bool mWrongAnchors;
+
+    QList<HbAnchor*> mAllAnchors; // anchors that are set by user
+    QList<HbAnchor*> mResolvedDynamicAnchors; //  references to generated anchors
+    QList<HbAnchor*> mResolvedStaticAnchors; // references to anchors, that remains the same after resolving
+    QList<HbAnchor*> mResolvedAnchors; // anchors that are passed to engine
+
+    // mesh layout data
+    QList<QGraphicsLayoutItem*> mItems; // for addItem
+    QList<QGraphicsLayoutItem*> mActualItems; // layouted items
+    HbMeshItemMap mMeshMap;
+
+    QRectF mUsedRect;
+
+    // new items
+
+    QList<GraphEdge*> mEdgesVertical;
+    QList<GraphEdge*> mEdgesHorizontal;
+    QList<GraphVertex*> mVerticesVertical;
+    QList<GraphVertex*> mVerticesHorizontal;
+
+    QList<Expression*> mEquationsHorizontal;
+    QList<Expression*> mEquationsVertical;
+    VariableSet mVariablesHorizontal;
+    VariableSet mVariablesVertical;
+
+    Variable *mLayoutVarH;
+    Variable *mLayoutVarV;
+
+    QVector< bool > mAnchorsVisited;
+    QVector< bool > mGeometryDefinedH;
+    QVector< bool > mGeometryDefinedV;
+    typedef struct {
+        qreal x1, y1, x2, y2;
+    } ItemGeometry;
+
+    QVector< ItemGeometry > mItemsGeometry;
+
+    Solution mSolutionHorizontal;
+    Solution mSolutionVertical;
+
+};
+
+
+
+
+
 
 /*!
     \internal
@@ -111,8 +229,10 @@
 HbAnchor::HbAnchor(const HbAnchor &anchor)
 : mStartItem(anchor.mStartItem),
   mStartEdge(anchor.mStartEdge),
+  mStartId(anchor.mStartId),
   mEndItem(anchor.mEndItem),
   mEndEdge(anchor.mEndEdge),
+  mEndId(anchor.mEndId),
   mValue(anchor.mValue)
 {
 }
@@ -135,8 +255,10 @@
 {
     if (this != &anchor) {
         mStartItem = anchor.mStartItem;
+        mStartId = anchor.mStartId;
         mStartEdge = anchor.mStartEdge;
         mEndItem = anchor.mEndItem;
+        mEndId = anchor.mEndId;
         mEndEdge = anchor.mEndEdge;
         mValue = anchor.mValue;
     }
@@ -144,85 +266,38 @@
 }
 
 
-class HbAnchorLayoutPrivate
-{
-public:
-    Q_DECLARE_PUBLIC( HbAnchorLayout )
-
-    HbAnchorLayoutPrivate();
-    ~HbAnchorLayoutPrivate();
-
-    void addItemIfNeeded( QGraphicsLayoutItem *item );
-    EdgeType edgeType( const Hb::Edge edge ) const;
-    HbAnchor* getAnchor( QGraphicsLayoutItem *startItem,
-                         Hb::Edge startEdge,
-                         QGraphicsLayoutItem *endItem,
-                         Hb::Edge endEdge );
-
-    void setItemGeometries();
-
-    void createEquations( EdgeType type );
-    void setSizeProp( SizeProperty *v, QGraphicsLayoutItem *item, EdgeType type );
-    GraphVertex *createCenterEdge( EdgeType type, QGraphicsLayoutItem *item,  Hb::Edge edge );
-    void defineNextGeometry( const int itemIndexStart, const int itemIndexEnd, 
-        const int anchorIndex, const int definedItemIndex );
-
-    QSizeF sizeHint( Qt::SizeHint which );
-
-public:
-    HbAnchorLayout * q_ptr;
-    QList<QGraphicsLayoutItem*> mItems;
-    QList<HbAnchor*> mAnchors;
-    bool mEquationsDirty; // if true, we needed to re-create the equations (e.g. when new anchor is set)
-    bool mValid;          // result of the calculations. false, if the equations cannot be solved.
-    bool mWrongAnchors;    // need to recreate anchors, these ones are unsolvable with any layout geometry
-    bool mInvalidateCalled; // set true in ::invalidate() and cleared after geometry is set in ::setGeometry
 
 
-    QRectF mUsedRect;
-
-    QList<GraphEdge*> mEdgesVertical;
-    QList<GraphEdge*> mEdgesHorizontal;
-    QList<GraphVertex*> mVerticesVertical;
-    QList<GraphVertex*> mVerticesHorizontal;
-
-    QList<Expression*> mEquationsHorizontal;
-    QList<Expression*> mEquationsVertical;
-    VariableSet mVariablesHorizontal;
-    VariableSet mVariablesVertical;
-
-    Variable *mLayoutVarH;
-    Variable *mLayoutVarV;
-
-    QVector<bool> mAnchorsVisited;
-    QVector< bool > mGeometryDefinedH;
-    QVector< bool > mGeometryDefinedV;
-    typedef struct {
-        qreal x1, y1, x2, y2;
-    } ItemGeometry;
-
-    QVector< ItemGeometry > mItemsGeometry;
-
-    Solution mSolutionHorizontal;
-    Solution mSolutionVertical;
-};
 
 /*!
     \internal
 */
-HbAnchorLayoutPrivate::HbAnchorLayoutPrivate() : 
-    mEquationsDirty( false ), mValid( true ), mWrongAnchors( false ), mInvalidateCalled(false),
-                                                    mLayoutVarH( 0 ), mLayoutVarV( 0 )
+QList<HbAnchor*> HbAnchorLayoutDebug::getAnchors( HbAnchorLayout* layout )
+{
+    layout->d_ptr->resolveAnchors();
+    return layout->d_ptr->mResolvedAnchors;
+}
+
+QList<HbAnchor*> HbAnchorLayoutDebug::getOriginalAnchors( HbAnchorLayout* layout )
+{
+    return layout->d_ptr->mAllAnchors;
+}
+
+/*
+    \class HbAnchorLayoutPrivate
+    \internal
+*/
+HbAnchorLayoutPrivate::HbAnchorLayoutPrivate() : mEquationsDirty(false), mValid(true), mInvalidateCalled( false ), mWrongAnchors( false ),
+                                                mUsedRect( 0, 0, 0, 0 ), mLayoutVarH( 0 ), mLayoutVarV( 0 )
+
 {
 }
 
-/*!
+/*
     \internal
 */
 HbAnchorLayoutPrivate::~HbAnchorLayoutPrivate()
 {
-    qDeleteAll( mAnchors );
-
 
     qDeleteAll( mEdgesVertical );
     qDeleteAll( mEdgesHorizontal );
@@ -231,58 +306,312 @@
 
     qDeleteAll( mEquationsHorizontal );
     qDeleteAll( mEquationsVertical );
+
+    qDeleteAll( mAllAnchors );
+    qDeleteAll( mResolvedDynamicAnchors );
 }
 
-/*!
+/*
     \internal
 */
-void HbAnchorLayoutPrivate::addItemIfNeeded( QGraphicsLayoutItem *item )
-{
-    Q_Q(HbAnchorLayout);
-    if ( item != q && !mItems.contains(item) ) {
-        HbLayoutUtils::addChildItem(q, item);
-
-        mItems.append( item );
-    }
-}
-
-/*!
-    \internal
-*/
-EdgeType HbAnchorLayoutPrivate::edgeType( const Hb::Edge edge ) const
+EdgeType HbAnchorLayoutPrivate::edgeType( HbAnchorLayout::Edge edge )
 {
     EdgeType type( Horizontal );
-    if ( edge == Hb::TopEdge || edge == Hb::BottomEdge || edge == Hb::CenterVEdge) {
+    if( edge == Hb::TopEdge || edge == Hb::BottomEdge || edge == Hb::CenterVEdge ) {
         type = Vertical;
     }
     return type;
 }
 
-/*!
+#ifdef HBANCHORLAYOUT_DEBUG
+/*
+    Returns string representation of value in \c Edge enumeration.
+    \internal
+*/
+static QString edgeAsText(HbAnchorLayout::Edge edge)
+{
+    QString result;
+    switch (edge) {
+    case Hb::LeftEdge:
+        result = "LEFT";
+        break;
+
+    case Hb::RightEdge:
+        result = "RIGHT";
+        break;
+
+    case Hb::CenterHEdge:
+        result = "CENTERH";
+        break;
+
+    case Hb::TopEdge:
+        result = "TOP";
+        break;
+
+    case Hb::BottomEdge:
+        result = "BOTTOM";
+        break;
+
+    case Hb::CenterVEdge:
+        result = "CENTERV";
+        break;
+
+    default:
+        result = "<UNDEFINED>";
+        break;
+    }
+
+    return result;
+}
+
+static QString itemAsText(QGraphicsLayoutItem* item, QGraphicsLayout *layout)
+{
+    QString result = "<emtpy>";
+    if ( item ) {
+        result = (item == layout) ? "HbAnchorLayout" : "<unknown>";
+        QGraphicsItem *gItem = item->graphicsItem();
+        if (gItem) {
+            if (gItem->isWidget()) {
+                result = static_cast<QGraphicsWidget*>(gItem)->metaObject()->className();
+            }
+#ifndef Q_WS_S60
+        } else {
+            HbSpacerItem *spacer = dynamic_cast<HbSpacerItem *>(item);
+            if ( spacer ) {
+                result = "HbSpacerItem";
+            }
+#endif
+        }
+    }
+    return result;
+}
+
+#endif // HBANCHORLAYOUT_DEBUG
+
+/*
     \internal
 */
-HbAnchor* HbAnchorLayoutPrivate::getAnchor(
-    QGraphicsLayoutItem *startItem,
-    Hb::Edge startEdge,
-    QGraphicsLayoutItem *endItem,
-    Hb::Edge endEdge )
+void HbAnchorLayoutPrivate::updateAnchorsAndItems()
 {
-    for ( int i = mAnchors.count()-1 ; i >= 0; i-- ) {
-        HbAnchor* anchor = mAnchors.at(i);
-        if ( anchor->mStartItem == startItem &&
-             anchor->mStartEdge == startEdge &&
-             anchor->mEndItem == endItem &&
-             anchor->mEndEdge == endEdge ) {
-                return anchor;
+    Q_Q(HbAnchorLayout);
+    resolveAnchors();
+
+#ifdef HBANCHORLAYOUT_DEBUG
+    QGraphicsWidget* w = HbLayoutUtils::parentWidget( q );
+    if ( w ) {
+        qDebug() << "MeshLayout: Mesh anchors for" << w->metaObject()->className();
+    }
+    const QString parentId =
+        mMeshMap.contains(q) ? mMeshMap.value(q) : QString();
+    qDebug() << "-- -- resolved";
+    qDebug() << "-- count: " << mResolvedAnchors.size() << ", parent: " << parentId;
+    foreach (const HbAnchor *item, mResolvedAnchors) {
+        const QString itemTemplate("-- (%1 [%2], %3) - (%4 [%5], %6) = %7");
+        qDebug() <<
+            itemTemplate
+            .arg(item->mStartId)
+            .arg(itemAsText(item->mStartItem, q))
+            .arg(edgeAsText(item->mStartEdge))
+            .arg(item->mEndId)
+            .arg(itemAsText(item->mEndItem, q))
+            .arg(edgeAsText(item->mEndEdge))
+            .arg(item->mValue).toAscii().data();
+    }
+    qDebug() << "-- -- all";
+    qDebug() << "-- count: " << mAllAnchors.size() << ", parent: " << parentId;
+    foreach (const HbAnchor *item, mAllAnchors) {
+        const QString itemTemplate("-- (%1 [%2], %3) - (%4 [%5], %6) = %7");
+        qDebug() <<
+            itemTemplate
+            .arg(item->mStartId)
+            .arg(itemAsText(item->mStartItem, q))
+            .arg(edgeAsText(item->mStartEdge))
+            .arg(item->mEndId)
+            .arg(itemAsText(item->mEndItem, q))
+            .arg(edgeAsText(item->mEndEdge))
+            .arg(item->mValue).toAscii().data();
+    }
+    qDebug() << "-- ";
+#endif // HBANCHORLAYOUT_DEBUG
+
+    // HbAnchorLayout will only touch items that have anchors defined.
+    mActualItems.clear();
+    for (QList<HbAnchor*>::const_iterator it = mResolvedAnchors.constBegin();
+         it != mResolvedAnchors.constEnd();
+         ++it) {
+
+        const HbAnchor* item = *it;
+
+        if (item->mStartItem != q && !mActualItems.contains(item->mStartItem)) {
+            mActualItems.append(item->mStartItem);
+        }
+        if (item->mEndItem != q && !mActualItems.contains(item->mEndItem)) {
+            mActualItems.append(item->mEndItem);
         }
     }
-    return 0;
+
+}
+
+
+void HbAnchorLayoutPrivate::setSizeProp( SizeProperty *v, QGraphicsLayoutItem *item, EdgeType type )
+{
+    if( type == Vertical ) {
+        const QSizePolicy::Policy verticalPolicy = item->sizePolicy().verticalPolicy();
+
+        if ( verticalPolicy & QSizePolicy::ShrinkFlag ) {
+            v->min = item->minimumHeight();
+        } else {
+            v->min = item->preferredHeight();
+        }
+
+        if ( verticalPolicy & (QSizePolicy::GrowFlag | QSizePolicy::ExpandFlag) ) {
+            v->max = item->maximumHeight();
+        } else {
+            v->max = item->preferredHeight();
+        }
+
+        v->pref = qBound( v->min, item->preferredHeight(), v->max );
+
+        v->flags |= (v->min == v->max) ? SizeProperty::FlagFixed : 0;
+        v->flags |= (verticalPolicy & QSizePolicy::ExpandFlag) ? SizeProperty::FlagExpanding : 0;
+
+        if( verticalPolicy & QSizePolicy::IgnoreFlag ) {
+            v->pref = v->min;
+            v->flags |= SizeProperty::FlagExpanding;
+        }
+    } else {
+        const QSizePolicy::Policy horizontalPolicy = item->sizePolicy().horizontalPolicy();
+
+        if ( horizontalPolicy & QSizePolicy::ShrinkFlag ) {
+            v->min = item->minimumWidth();
+        } else {
+            v->min = item->preferredWidth();
+        }
+
+        if ( horizontalPolicy & (QSizePolicy::GrowFlag | QSizePolicy::ExpandFlag) ) {
+            v->max = item->maximumWidth();
+        } else {
+            v->max = item->preferredWidth();
+        }
+
+        v->pref = qBound( v->min, item->preferredWidth(), v->max );
+
+        v->flags |= (v->min == v->max) ? SizeProperty::FlagFixed : 0;
+        v->flags |= (horizontalPolicy & QSizePolicy::ExpandFlag) ? SizeProperty::FlagExpanding : 0;
+
+        if( horizontalPolicy & QSizePolicy::IgnoreFlag ) {
+            v->pref = v->min;
+            v->flags |= SizeProperty::FlagExpanding;
+        }
+    }
 }
 
-void HbAnchorLayoutPrivate::defineNextGeometry( 
-    const int itemIndexStart, 
-    const int itemIndexEnd, 
-    const int anchorIndex, 
+
+GraphVertex *HbAnchorLayoutPrivate::createCenterEdge( EdgeType type, QGraphicsLayoutItem *item,  Hb::Edge edge )
+{
+    GraphVertex *middle;
+    GraphVertex *start = 0;
+    GraphVertex *end = 0;
+
+    QList<GraphEdge*> *edges = &mEdgesHorizontal;
+    QList<GraphVertex*> *vertices = &mVerticesHorizontal;
+
+    if( type == Vertical ) {
+        if( edge != Hb::CenterVEdge ) {
+            qWarning() << "HbAnchorLayout: something wrong " << __LINE__;
+            return 0;
+        }
+
+        edges = &mEdgesVertical;
+        vertices = &mVerticesVertical;
+
+        for( int j = 0; j < vertices->size(); j++ ) {
+            GraphVertex *current = vertices->at(j);
+            if( current->itemRef == item ) {
+                if( current->itemSide == Hb::TopEdge ) {
+                    start = current;
+                } else if( current->itemSide == Hb::BottomEdge ) {
+                    end = current;
+                }
+            }
+        }
+    } else {
+        if( edge != Hb::CenterHEdge ) {
+            qWarning() << "HbAnchorLayout: something wrong " << __LINE__;
+            return 0;
+        }
+
+        for( int j = 0; j < vertices->size(); j++ ) {
+            GraphVertex *current = vertices->at(j);
+            if( current->itemRef == item ) {
+                if( current->itemSide == Hb::LeftEdge ) {
+                    start = current;
+                } else if( current->itemSide == Hb::RightEdge ) {
+                    end = current;
+                }
+            }
+        }
+    }
+
+    if( !( start && end ) ) {
+        qWarning() << "HbAnchorLayout: something wrong " << __LINE__;
+        return 0;
+    }
+
+    GraphEdge *oldEdge = 0;
+
+    for( int i = 0; i < edges->size(); i++ ) {
+        oldEdge = edges->at(i);
+        if( ( oldEdge->ref == item ) && ( oldEdge->startVertex == start ) && ( oldEdge->endVertex == end ) ){
+            break;
+        }
+    }
+
+    if( !oldEdge ) {
+        qWarning() << "HbAnchorLayout: something wrong " << __LINE__;
+        return 0;
+    }
+
+    middle = new GraphVertex();
+    middle->itemRef = ( void* )item;
+    middle->itemSide =  edge;
+    middle->special = false;
+
+    GraphEdge *newEdge1 = new GraphEdge();
+    GraphEdge *newEdge2 = new GraphEdge();
+
+    newEdge1->startVertex = start;
+    newEdge1->endVertex = middle;
+    newEdge1->ref = ( void* )item;
+
+    newEdge1->expr->plusExpression( oldEdge->expr );
+    newEdge1->expr->multiply( 0.5 );
+
+
+    newEdge2->startVertex = middle;
+    newEdge2->endVertex = end;
+    newEdge2->ref = ( void* )item;
+    newEdge2->expr->plusExpression( oldEdge->expr );
+    newEdge2->expr->multiply( 0.5 );
+
+
+    middle->edges.append( newEdge1 );
+    start->edges.append( newEdge1 );
+    middle->edges.append( newEdge2 );
+    end->edges.append( newEdge2 );
+
+    edges->append( newEdge1 );
+    edges->append( newEdge2 );
+    vertices->append( middle );
+
+
+    return middle;
+}
+
+void HbAnchorLayoutPrivate::defineNextGeometry(
+    const int itemIndexStart,
+    const int itemIndexEnd,
+    const int anchorIndex,
     const int definedItemIndex )
 {
     ItemGeometry *knownItemGeom, *unKnownItemGeom;
@@ -290,7 +619,7 @@
     int sign;
     qreal itemSize;
     bool isHorizontal;
-    HbAnchor *anchor = mAnchors.at( anchorIndex );
+    HbAnchor *anchor = mResolvedAnchors.at( anchorIndex );
     qreal leftPoint(0), rightPoint(0), sourcePoint(0), dstPointLeft(0);
 
     mAnchorsVisited[ anchorIndex ] = true;
@@ -310,12 +639,10 @@
 
         if( isHorizontal ) {
             mGeometryDefinedH[itemIndexEnd] = true;
-            itemSize = mSolutionHorizontal.value( 
-                mVariablesHorizontal.findVariable( mItems.at(itemIndexEnd) ) );
+            itemSize = mSolutionHorizontal.value( mVariablesHorizontal.findVariable( mActualItems.at(itemIndexEnd) ) );
         } else {
             mGeometryDefinedV[itemIndexEnd] = true;
-            itemSize = mSolutionVertical.value( 
-                mVariablesVertical.findVariable( mItems.at(itemIndexEnd) ) );
+            itemSize = mSolutionVertical.value( mVariablesVertical.findVariable( mActualItems.at(itemIndexEnd) ) );
         }
 
         sign = 1;
@@ -328,12 +655,10 @@
 
         if( isHorizontal ) {
             mGeometryDefinedH[itemIndexStart] = true;
-            itemSize = mSolutionHorizontal.value( 
-                mVariablesHorizontal.findVariable( mItems.at(itemIndexStart) ) );
+            itemSize = mSolutionHorizontal.value( mVariablesHorizontal.findVariable( mActualItems.at(itemIndexStart) ) );
         } else {
             mGeometryDefinedV[itemIndexStart] = true;
-            itemSize = mSolutionVertical.value(
-                mVariablesVertical.findVariable( mItems.at(itemIndexStart) ) );
+            itemSize = mSolutionVertical.value( mVariablesVertical.findVariable( mActualItems.at(itemIndexStart) ) );
         }
 
         sign = -1;
@@ -401,7 +726,8 @@
 
 }
 
-/*!
+
+/*
     \internal
 */
 void HbAnchorLayoutPrivate::setItemGeometries()
@@ -409,16 +735,18 @@
     Q_Q(HbAnchorLayout);
     const QRectF newRect = q->geometry();
 
-    if( mWrongAnchors || ( mItems.isEmpty() ) ) {
+    if( mWrongAnchors || ( mActualItems.isEmpty() ) ) {
         return;
     }
 
 
-    if ( (newRect != mUsedRect) || mInvalidateCalled ) {
+    if( (newRect != mUsedRect) || mInvalidateCalled ) {
 
+        mInvalidateCalled = false;
         mUsedRect = newRect;
 
         if ( mEquationsDirty ) {
+            updateAnchorsAndItems();
             createEquations( Horizontal );
             createEquations( Vertical );
             mEquationsDirty = false;
@@ -498,25 +826,27 @@
                 mGeometryDefinedV[i] = false;
             }
 
-            int layoutIndex = mItems.size();
+            int layoutIndex = mActualItems.size();
 
-            mItemsGeometry[ layoutIndex ].x1 = 0;
-            mItemsGeometry[ layoutIndex ].x2 = newRect.width();
-            mItemsGeometry[ layoutIndex ].y1 = 0;
-            mItemsGeometry[ layoutIndex ].y2 = newRect.height();
+            mItemsGeometry[ layoutIndex ].x1 = 0;//newRect.left();
+            mItemsGeometry[ layoutIndex ].x2 = newRect.width();//newRect.right();
+            mItemsGeometry[ layoutIndex ].y1 = 0;//newRect.top();
+            mItemsGeometry[ layoutIndex ].y2 = newRect.height();//newRect.bottom();
+            mGeometryDefinedH[ layoutIndex ] = true;
+            mGeometryDefinedV[ layoutIndex ] = true;
 
 
             for( int i = 0; i < mAnchorsVisited.size(); i++ ) {
 
-                HbAnchor *anchor = mAnchors.at(i);
+                HbAnchor *anchor = mResolvedAnchors.at(i);
 
 
                 if( ( anchor->mStartItem != q ) && ( anchor->mEndItem != q ) ) {
                     continue;
                 }
 
-                int startIndex = mItems.indexOf( anchor->mStartItem ); // returns -1 if not found => this is layout
-                int endIndex = mItems.indexOf( anchor->mEndItem );
+                int startIndex = mActualItems.indexOf( anchor->mStartItem ); // returns -1 if not found => this is layout
+                int endIndex = mActualItems.indexOf( anchor->mEndItem );
 
                 mAnchorsVisited[i] = true; // Temporary overkill, if both anchors connected to layout. Must be restricted on setAnchor() level
 
@@ -555,10 +885,10 @@
                     if( mAnchorsVisited.at(i) ) {
                         continue;
                     }
-                    HbAnchor *anchor = mAnchors.at(i);
+                    HbAnchor *anchor = mResolvedAnchors.at(i);
 
-                    startIndex = mItems.indexOf( anchor->mStartItem );
-                    endIndex = mItems.indexOf( anchor->mEndItem );
+                    startIndex = mActualItems.indexOf( anchor->mStartItem );
+                    endIndex = mActualItems.indexOf( anchor->mEndItem );
 #ifdef HBANCHORLAYOUT_DEBUG
                     qDebug() << "startIndex:" << startIndex << "  endIndex" << endIndex;
 #endif //HBANCHORLAYOUT_DEBUG
@@ -580,9 +910,16 @@
                 }
             }
 
+#ifdef HBANCHORLAYOUT_DEBUG
+            QGraphicsWidget* w = HbLayoutUtils::parentWidget( q );
+            if ( w ) {
+                qDebug() << "Items of " << w->metaObject()->className();
+            }
+#endif
+
 
             Qt::LayoutDirection layoutDir = HbLayoutUtils::visualDirection(q);
-            for( int i = 0; i < layoutIndex; i++ ) {
+            for( int i = 0; i < mActualItems.size(); i++ ) {
                 QRectF geom;
                 ItemGeometry calcGeom = mItemsGeometry.at(i);
                 if( mGeometryDefinedH.at(i) ) {
@@ -590,197 +927,28 @@
                     geom.setRight( mUsedRect.left() + calcGeom.x2 );
                 } else {
                     geom.setLeft( mUsedRect.left() );
-                    geom.setRight( mUsedRect.left() + mItems.at(i)->preferredWidth() );
+                    geom.setRight( mUsedRect.left() + mActualItems.at(i)->preferredWidth() );
                 }
                 if( mGeometryDefinedV.at(i) ) {
                     geom.setTop( mUsedRect.top() + calcGeom.y1 );
                     geom.setBottom( mUsedRect.top() + calcGeom.y2 );
                 } else {
                     geom.setTop( mUsedRect.top() );
-                    geom.setBottom( mUsedRect.top() + mItems.at(i)->preferredHeight() );
+                    geom.setBottom( mUsedRect.top() + mActualItems.at(i)->preferredHeight() );
                 }
 
-                HbLayoutUtils::visualRect(layoutDir, geom, newRect);
+                HbLayoutUtils::visualRect( layoutDir, geom, newRect );
 
 #ifdef HBANCHORLAYOUT_DEBUG
                 qDebug( "Item %d: (%lf, %lf) : (%lf %lf)", i, calcGeom.x1, calcGeom.y1, calcGeom.x2, calcGeom.y2 );
+        //        qDebug() << "Item " <<  i << "(" << ((QGraphicsWidget*)mActualItems.at(i))->metaObject()->className() << ")" << " geom " << geom;
 #endif // HBANCHORLAYOUT_DEBUG
-
-                mItems.at(i)->setGeometry( geom );
+                mActualItems.at(i)->setGeometry( geom );
             }
         }
     }
 }
 
-void HbAnchorLayoutPrivate::setSizeProp( SizeProperty *v, QGraphicsLayoutItem *item, EdgeType type )
-{
-    if( type == Vertical ) {
-        const QSizePolicy::Policy verticalPolicy = item->sizePolicy().verticalPolicy();
-
-        if ( verticalPolicy & QSizePolicy::ShrinkFlag ) {
-            v->min = item->minimumHeight();
-        } else {
-            v->min = item->preferredHeight();
-        }
-
-        if ( verticalPolicy & (QSizePolicy::GrowFlag | QSizePolicy::ExpandFlag) ) {
-            v->max = item->maximumHeight();
-        } else {
-            v->max = item->preferredHeight();
-        }
-
-        v->pref = qBound( v->min, item->preferredHeight(), v->max );
-
-        v->flags |= (v->min == v->max) ? SizeProperty::FlagFixed : 0;
-        v->flags |= (verticalPolicy & QSizePolicy::ExpandFlag) ? SizeProperty::FlagExpanding : 0;
-
-        if( verticalPolicy & QSizePolicy::IgnoreFlag ) {
-            v->pref = v->min;
-            v->flags |= SizeProperty::FlagExpanding;
-        }
-    } else {
-        const QSizePolicy::Policy horizontalPolicy = item->sizePolicy().horizontalPolicy();
-
-        if ( horizontalPolicy & QSizePolicy::ShrinkFlag ) {
-            v->min = item->minimumWidth();
-        } else {
-            v->min = item->preferredWidth();
-        }
-
-        if ( horizontalPolicy & (QSizePolicy::GrowFlag | QSizePolicy::ExpandFlag) ) {
-            v->max = item->maximumWidth();
-        } else {
-            v->max = item->preferredWidth();
-        }
-
-        v->pref = qBound( v->min, item->preferredWidth(), v->max );
-
-        v->flags |= (v->min == v->max) ? SizeProperty::FlagFixed : 0;
-        v->flags |= (horizontalPolicy & QSizePolicy::ExpandFlag) ? SizeProperty::FlagExpanding : 0;
-
-        if( horizontalPolicy & QSizePolicy::IgnoreFlag ) {
-            v->pref = v->min;
-            v->flags |= SizeProperty::FlagExpanding;
-        }
-    }
-}
-
-
-GraphVertex *HbAnchorLayoutPrivate::createCenterEdge( 
-    EdgeType type, QGraphicsLayoutItem *item,  Hb::Edge edge )
-{
-    GraphVertex *middle;
-    GraphVertex *start = 0;
-    GraphVertex *end = 0;
-
-    QList<GraphEdge*> *edges = &mEdgesHorizontal;
-    QList<GraphVertex*> *vertices = &mVerticesHorizontal;
-
-    if( type == Vertical ) {
-        if( edge != Hb::CenterVEdge ) {
-#ifdef HBANCHORLAYOUT_DEBUG
-            qDebug() << "something wrong " << __LINE__;
-#endif //HBANCHORLAYOUT_DEBUG
-            return 0;
-        }
-
-        edges = &mEdgesVertical;
-        vertices = &mVerticesVertical;
-
-        for( int j = 0; j < vertices->size(); j++ ) {
-            GraphVertex *current = vertices->at(j);
-            if( current->itemRef == item ) {
-                if( current->itemSide == Hb::TopEdge ) {
-                    start = current;
-                } else if( current->itemSide == Hb::BottomEdge ) {
-                    end = current;
-                }
-            }
-        }
-    } else {
-        if( edge != Hb::CenterHEdge ) {
-#ifdef HBANCHORLAYOUT_DEBUG
-            qDebug() << "something wrong " << __LINE__;
-#endif //HBANCHORLAYOUT_DEBUG
-            return 0;
-        }
-
-        for( int j = 0; j < vertices->size(); j++ ) {
-            GraphVertex *current = vertices->at(j);
-            if( current->itemRef == item ) {
-                if( current->itemSide == Hb::LeftEdge ) {
-                    start = current;
-                } else if( current->itemSide == Hb::RightEdge ) {
-                    end = current;
-                }
-            }
-        }
-    }
-
-    if( !( start && end ) ) {
-#ifdef HBANCHORLAYOUT_DEBUG
-        qDebug() << "something wrong " << __LINE__;
-#endif //HBANCHORLAYOUT_DEBUG
-        return 0;
-    }
-
-    GraphEdge *oldEdge = 0;
-
-    for( int i = 0; i < edges->size(); i++ ) {
-        oldEdge = edges->at(i);
-        if( oldEdge->ref == item ) {
-            if( ( oldEdge->startVertex == start ) && ( oldEdge->endVertex == end ) ){
-/*                edges->removeOne( oldEdge );
-                start->edges.removeOne( oldEdge );
-                end->edges.removeOne( oldEdge );*/
-                break;
-            }
-        }
-    }
-
-    if( !oldEdge ) {
-#ifdef HBANCHORLAYOUT_DEBUG
-        qDebug() << "something wrong " << __LINE__;
-#endif //HBANCHORLAYOUT_DEBUG
-        return 0;
-    }
-
-    middle = new GraphVertex();
-    middle->itemRef = ( void* )item;
-    middle->itemSide =  edge;
-    middle->special = false;
-
-    GraphEdge *newEdge1 = new GraphEdge();
-    GraphEdge *newEdge2 = new GraphEdge();
-
-    newEdge1->startVertex = start;
-    newEdge1->endVertex = middle;
-    newEdge1->ref = ( void* )item;
-
-    newEdge1->expr->plusExpression( oldEdge->expr );
-    newEdge1->expr->multiply( 0.5 );
-
-
-    newEdge2->startVertex = middle;
-    newEdge2->endVertex = end;
-    newEdge2->ref = ( void* )item;
-    newEdge2->expr->plusExpression( oldEdge->expr );
-    newEdge2->expr->multiply( 0.5 );
-
-
-    middle->edges.append( newEdge1 );
-    start->edges.append( newEdge1 );
-    middle->edges.append( newEdge2 );
-    end->edges.append( newEdge2 );
-
-    edges->append( newEdge1 );
-    edges->append( newEdge2 );
-    vertices->append( middle );
-
-
-    return middle;
-}
-
 /*!
     \internal
 */
@@ -845,8 +1013,8 @@
         }
 
 
-        for ( int i = 0; i < mItems.count(); i++ ) {
-            QGraphicsLayoutItem *item = mItems.at( i );
+        for ( int i = 0; i < mActualItems.count(); i++ ) {
+            QGraphicsLayoutItem *item = mActualItems.at( i );
             itemStart = new GraphVertex();
             itemEnd = new GraphVertex();
             newEdge = new GraphEdge();
@@ -891,16 +1059,16 @@
         v1->sizeProp.flags = SizeProperty::FlagFixed;
 
 
-        for( int i = 0; i < mAnchors.count(); i++) {
-            HbAnchor* anchor = mAnchors.at(i);
+        for( int i = 0; i < mResolvedAnchors.count(); i++) {
+            HbAnchor* anchor = mResolvedAnchors.at(i);
             if ( edgeType( anchor->mStartEdge ) == type ) {
                 itemStart = 0;
                 itemEnd = 0;
                 for( int j = 0; j < vertices->size(); j++ ) {
-                    if( ( vertices->at(j)->itemRef == anchor->mStartItem ) && 
+                    if( ( vertices->at(j)->itemRef == anchor->mStartItem ) &&
                             ( vertices->at(j)->itemSide == anchor->mStartEdge ) ) {
                         itemStart = vertices->at(j);
-                    } else if( ( vertices->at(j)->itemRef == anchor->mEndItem ) && 
+                    } else if( ( vertices->at(j)->itemRef == anchor->mEndItem ) &&
                         ( vertices->at(j)->itemSide == anchor->mEndEdge ) ) {
                         itemEnd = vertices->at(j);
                     }
@@ -913,6 +1081,19 @@
                     itemEnd = createCenterEdge( type, anchor->mEndItem,  anchor->mEndEdge );
                 }
 
+                if( !itemStart ){
+                    qWarning() << "HbAnchorLayout: internal error, line " << __LINE__;
+                    mWrongAnchors = true;
+                    AnchorLayoutEngine::instance()->cleanUp( layoutStart, layoutMiddle, layoutEnd, edges, vertices, el );
+                    return;
+                }
+                if( !itemEnd ) {
+                    qWarning() << "HbAnchorLayout: internal error, line " << __LINE__;
+                    mWrongAnchors = true;
+                    AnchorLayoutEngine::instance()->cleanUp( layoutStart, layoutMiddle, layoutEnd, edges, vertices, el );
+                    return;
+                }
+
                 newEdge = new GraphEdge();
                 itemStart->edges.append( newEdge );
                 itemEnd->edges.append( newEdge );
@@ -965,11 +1146,10 @@
 
         if( ! AnchorLayoutEngine::instance()->processItems( edges, vertices, vs, el ) ) {
             mWrongAnchors = true;
-            AnchorLayoutEngine::instance()->cleanUp( 
-                layoutStart, layoutMiddle, layoutEnd, edges, vertices, el );
-//#ifdef HBANCHORLAYOUT_DEBUG
-            qDebug() << "FAIL line:" << __LINE__;
-//#endif //HBANCHORLAYOUT_DEBUG
+            AnchorLayoutEngine::instance()->cleanUp( layoutStart, layoutMiddle, layoutEnd, edges, vertices, el );
+#ifdef HBANCHORLAYOUT_DEBUG
+            qDebug() << "FAIL! " << __LINE__;
+#endif //HBANCHORLAYOUT_DEBUG
             return;
         }
 
@@ -1000,16 +1180,16 @@
         layoutVar->sizeProp.pref = 100;
         layoutVar->sizeProp.flags = 0;
 
-        AnchorLayoutEngine::instance()->attachToLayout( 
+        AnchorLayoutEngine::instance()->attachToLayout(
             layoutStart, layoutMiddle, layoutEnd, layoutVar, el );
-        AnchorLayoutEngine::instance()->cleanUp( 
+        AnchorLayoutEngine::instance()->cleanUp(
             layoutStart, layoutMiddle, layoutEnd, edges, vertices, el );
 
 
-        mAnchorsVisited.resize( mAnchors.size() * sizeof( bool ) );
-        mGeometryDefinedH.resize( mItems.size() * sizeof( bool ) );
-        mGeometryDefinedV.resize( mItems.size() * sizeof( bool ) );
-        mItemsGeometry.resize( ( mItems.size() + 1 ) * sizeof( ItemGeometry ) );
+        mAnchorsVisited.resize( mResolvedAnchors.size() * sizeof( bool ) );
+        mGeometryDefinedH.resize( ( mActualItems.size() + 1  ) * sizeof( bool ) );
+        mGeometryDefinedV.resize( ( mActualItems.size() + 1 ) * sizeof( bool ) );
+        mItemsGeometry.resize( ( mActualItems.size() + 1 ) * sizeof( ItemGeometry ) );
 
         if( type == Vertical ) {
             mLayoutVarV = layoutVar;
@@ -1019,15 +1199,231 @@
     }
 }
 
+/*
+    Finds new end item for problematic anchor.
 
-/*!
-    \internal
+    Follows the anchor that have the same start edge
+    as the problematic anchor.
+
+    Invariant:
+        \a ids must be the exactly same in return. It is the array
+        which nodes have already been visited - so in order to avoid
+        infinite recursion, don't visit already visited.
+*/
+bool HbAnchorLayoutPrivate::findEndItem(
+    QList<HbMeshEndItemResult> &resultList,
+    const HbAnchor *problem,
+    QStringList &ids) const
+{
+    HbMeshEndItemResult result;
+    bool found = false;
+
+    for (QList<HbAnchor*>::const_iterator it = mAllAnchors.constBegin();
+         it != mAllAnchors.constEnd();
+         ++it) {
+
+        const HbAnchor* currentItem = *it;
+
+        if (!currentItem->mStartId.isNull() &&
+            currentItem->mStartId == problem->mEndId &&
+            currentItem->mStartEdge == problem->mStartEdge &&
+            !ids.contains(currentItem->mStartId)) {
+
+            qreal currentSpacing = currentItem->mValue;
+
+            QGraphicsLayoutItem *item = currentItem->mEndItem;
+
+
+            if (item) {
+                found = true;
+                result.mEdge = currentItem->mEndEdge;
+                result.mItem = item;
+                result.mValue = currentSpacing;
+                resultList.append( result );
+            } else {
+                ids.append(currentItem->mStartId);
+                found |= findEndItem(resultList, currentItem, ids);
+                ids.takeLast();
+            }
+            /*
+            if (found) {
+                // We have found an end item. There can be multiple end items,
+                // but (for now) the first one is selected.
+                return true;
+            }*/
+        }
+    }
+
+    return found;
+}
+
+/*
+    Resolves anchors to be used in anchor layout calculations.
+
+    For each anchor x with start id, start edge, end id, end edge:
+
+    If there is layout items corresponding to both start id and end id,
+    anchor is used automatically.
+    If there is layout item corresponding to start id, then we try to
+    "fix" anchor by looking for a path of anchors (same direction, with spacing defined)
+    from anchor x's end id as starting point to such end id that has layout item.
+    If found, anchor is fixed by replacing end id with found end id.
+
+    So direction of anchors affect this resolution process, but not in the
+    anchor layout calculations.
+
+    \sa findEndItem
 */
-QList<HbAnchor*> HbAnchorLayoutDebug::getAnchors( HbAnchorLayout* layout )
+void HbAnchorLayoutPrivate::resolveAnchors()
+{
+    HbAnchor *item;
+
+    qDeleteAll( mResolvedDynamicAnchors );
+    mResolvedDynamicAnchors.clear();
+    mResolvedStaticAnchors.clear();
+
+    for ( int i = 0; i < mAllAnchors.size(); i++ ) {
+
+        HbAnchor *anchor = mAllAnchors.at(i);
+
+        if( ( anchor->mStartItem ) && ( anchor->mEndItem ) ) {
+            mResolvedStaticAnchors.append( anchor );
+            continue;
+        }
+
+        if (anchor->mStartItem && !anchor->mEndId.isNull()) {
+            QList<HbMeshEndItemResult> resultList;
+
+            QStringList ids;
+            ids.append(anchor->mStartId);
+
+            if (findEndItem(resultList, anchor, ids)) {
+                for( int j = 0; j < resultList.size(); j++ ) {
+                    item = new HbAnchor();
+                    item->mStartItem = anchor->mStartItem;
+                    item->mStartId = anchor->mStartId;
+                    item->mStartEdge = anchor->mStartEdge;
+                    item->mEndEdge = resultList.at(j).mEdge;
+                    item->mEndItem = resultList.at(j).mItem;
+                    item->mValue = resultList.at(j).mValue;
+                    mResolvedDynamicAnchors.append(item);
+                }
+            }
+        } else {
+            // Nothing needed.
+        }
+    }
+
+    mResolvedAnchors = mResolvedDynamicAnchors + mResolvedStaticAnchors;
+}
+
+bool HbAnchorLayoutPrivate::setAnchor( HbAnchor *anchor )
 {
-    return layout->d_ptr->mAnchors;
+    // This method is called from HbAnchorLayout::setAnchor.
+
+    if (HbAnchorLayoutPrivate::edgeType(anchor->mStartEdge) !=
+        HbAnchorLayoutPrivate::edgeType(anchor->mEndEdge)) {
+        qWarning() << "HbAnchorLayout::setAnchor : You can't connect different type of edges";
+        return false;
+    }
+
+    if ( ( anchor->mStartId.isNull() && ( anchor->mStartItem == 0 ) ) ||
+        ( anchor->mEndId.isNull() && ( anchor->mEndItem == 0 ) ) ){
+        qWarning() << "HbAnchorLayout::setAnchor : Both ids must be valid";
+        return false;
+    }
+
+    if ( ( anchor->mStartId == anchor->mEndId ) && ( ( anchor->mStartItem == anchor->mEndItem ) ) &&
+        ( anchor->mStartEdge == anchor->mEndEdge ) ) {
+        qWarning() << "HbAnchorLayout::setAnchor : You cannot set anchor between the same edge";
+        return false;
+    }
+
+    bool modified = false;
+
+    const int count = mAllAnchors.size();
+    for (int i = 0; i < count; ++i) {
+        HbAnchor *item = mAllAnchors.at(i);
+
+
+        bool idConditionStartStart = ( !item->mStartId.isNull() ) && ( item->mStartId == anchor->mStartId );
+        bool idConditionEndEnd = ( !item->mEndId.isNull() ) && ( item->mEndId == anchor->mEndId );
+        bool idConditionStartEnd = ( !item->mStartId.isNull() ) && ( item->mStartId == anchor->mEndId );
+        bool idConditionEndStart = ( !item->mEndId.isNull() ) && ( item->mEndId == anchor->mStartId );
+
+        bool itemConditionStartStart = ( item->mStartItem != 0 ) && ( item->mStartItem == anchor->mStartItem );
+        bool itemConditionEndEnd = ( item->mEndItem != 0 ) && ( item->mEndItem == anchor->mEndItem );
+        bool itemConditionStartEnd = ( item->mStartItem != 0 ) && ( item->mStartItem == anchor->mEndItem );
+        bool itemConditionEndStart = ( item->mEndItem != 0 ) && ( item->mEndItem == anchor->mStartItem );
+
+        bool edgeConditionStartStart = item->mStartEdge == anchor->mStartEdge;
+        bool edgeConditionEndEnd = item->mEndEdge == anchor->mEndEdge;
+        bool edgeConditionStartEnd = item->mStartEdge == anchor->mEndEdge;
+        bool edgeConditionEndStart = item->mEndEdge == anchor->mStartEdge;
+
+
+        if((idConditionStartStart || itemConditionStartStart) &&
+            (idConditionEndEnd || itemConditionEndEnd) &&
+            (edgeConditionStartStart) &&
+            (edgeConditionEndEnd) ){
+                modified = true;
+                item->mValue = anchor->mValue;
+                delete anchor;
+                break;
+        } else if( (idConditionStartEnd || itemConditionStartEnd) &&
+            (idConditionEndStart || itemConditionEndStart) &&
+            (edgeConditionStartEnd) &&
+            (edgeConditionEndStart) ){
+                modified = true;
+                item->mValue = -anchor->mValue;
+                delete anchor;
+                break;
+        }
+    }
+
+    if (!modified) {
+        if( anchor->mStartItem != 0 ){
+            anchor->mStartId = mMeshMap.value( anchor->mStartItem );
+        } else if( ! anchor->mStartId.isNull() ) {
+            anchor->mStartItem = mMeshMap.key( anchor->mStartId );
+        }
+
+        if( anchor->mEndItem != 0 ){
+            anchor->mEndId = mMeshMap.value( anchor->mEndItem );
+        } else if( ! anchor->mEndId.isNull() ) {
+            anchor->mEndItem = mMeshMap.key( anchor->mEndId );
+        }
+
+        addItemIfNeeded( anchor->mStartItem );
+        addItemIfNeeded( anchor->mEndItem );
+
+        mAllAnchors.append(anchor);
+    }
+
+    return true;
 }
 
+void HbAnchorLayoutPrivate::removeItemIfNeeded( QGraphicsLayoutItem *item )
+{
+    Q_Q( HbAnchorLayout );
+
+    if( ( item == 0 ) || ( item == q ) ) {
+        return;
+    }
+
+    for ( int i = 0; i < mAllAnchors.size(); i++ ) {
+        HbAnchor *anchor = mAllAnchors.at(i);
+        if ( ( anchor->mStartItem == item ) || ( anchor->mEndItem == item ) ) {
+            return;
+        }
+    }
+
+    item->setParentLayoutItem( 0 );
+    mItems.removeAt(q->indexOf( item ));
+}
+
+
+
 /*!
     Constructor.
 */
@@ -1062,6 +1458,7 @@
     delete d_ptr;
 }
 
+
 /*!
     Creates an anchor, or updates an existing one, between the edges described by
     (\a startItem, \a startEdge) and (\a endItem, \a endEdge).
@@ -1071,9 +1468,9 @@
     That is, it is not allowed to connect e.g. top edge of an item to the
     left edge of another one. Also there are horizontal and vertical center edges.
 
-    The distance between the two edges is defined by \a value.
-    If \a value is positive the end edge is to the right or below the start edge.
-    If \a value is negative the end edge is to the left or above the start edge.
+    The distance between the two edges is defined by \a length.
+    If \a length is positive the end edge is to the right or below the start edge.
+    If \a length is negative the end edge is to the left or above the start edge.
 
     Anchors can be created between the parent layout and a child layout item,
     or between two child layout items, or even between two edges of the same
@@ -1092,48 +1489,95 @@
     \param startEdge source edge.
     \param endItem target item.
     \param endEdge target edge.
-    \param value spacing (in pixels).
+    \param length spacing (in pixels).
     \return true if anchor was successfully added, false otherwise
 */
-bool HbAnchorLayout::setAnchor( QGraphicsLayoutItem *startItem,
-                             Hb::Edge startEdge,
-                             QGraphicsLayoutItem *endItem,
-                             Hb::Edge endEdge,
-                             qreal value )
+bool HbAnchorLayout::setAnchor( QGraphicsLayoutItem *startItem, Edge startEdge, QGraphicsLayoutItem *endItem, Edge endEdge, qreal length )
 {
     Q_D( HbAnchorLayout );
-    if ( d->edgeType(startEdge) != d->edgeType(endEdge) ) {
-        qWarning() << "HbAnchorLayout::setAnchor : You can't connect different type of edges";
-        return false;
-    }
 
-    if ( !startItem || !endItem ) {
-        qWarning() << "HbAnchorLayout::setAnchor : One of the items is NULL";
-        return false;
+    HbAnchor *anchor = new HbAnchor();
+    anchor->mStartItem = startItem;
+    anchor->mStartEdge = startEdge;
+    anchor->mEndItem = endItem;
+    anchor->mEndEdge = endEdge;
+    anchor->mValue = length;
+
+    if (d->setAnchor(anchor)) {
+        invalidate();
+        return true;
     }
 
-    if ( ( startItem == endItem ) && ( startEdge == endEdge ) ) {
-        qWarning() << "HbAnchorLayout::setAnchor : You cannot set anchor between the same edge";
-        return false;
+    delete anchor;
+
+    return false;
+}
+
+/*!
+    Same as previous, but here it operates with node ids, instead of items itself.
+
+    \param startId start id.
+    \param startEdge start edge.
+    \param endId end id.
+    \param endEdge end edge.
+    \param length spacing value for all edges starting from (\a startId, \a startEdge).
+    \return true if success, false otherwise.
+*/
+bool HbAnchorLayout::setAnchor( const QString& startId, Edge startEdge, const QString& endId, Edge endEdge, qreal length )
+{
+    Q_D( HbAnchorLayout );
+
+    HbAnchor *anchor = new HbAnchor();
+    anchor->mStartId = startId;
+    anchor->mStartEdge = startEdge;
+    anchor->mEndId = endId;
+    anchor->mEndEdge = endEdge;
+    anchor->mValue = length;
+
+    if (d->setAnchor(anchor)) {
+        invalidate();
+        return true;
     }
 
-    d->addItemIfNeeded(startItem);
-    d->addItemIfNeeded(endItem);
+    delete anchor;
 
-    HbAnchor* anchor = d->getAnchor(startItem, startEdge, endItem, endEdge);
-    HbAnchor* anchor2 = d->getAnchor(endItem, endEdge, startItem, startEdge);
+    return false;
+}
+
+
+/*!
+    Removes anchor (\a startId, \a startEdge, \a endNodeId, \a endEdge).
 
-    if ( anchor ) {
-        anchor->mValue = value;
-    } else if ( anchor2 ) {
-        anchor2->mValue = -value;
-    } else {
-        anchor = new HbAnchor(startItem, startEdge, endItem, endEdge, value);
-        d->mAnchors.append(anchor);
+    \param startId start id.
+    \param startEdge start edge.
+    \param endId end id.
+    \param endEdge end edge.
+    \return true if success, false otherwise.
+*/
+bool HbAnchorLayout::removeAnchor( const QString& startNodeId, Edge startEdge, const QString& endNodeId, Edge endEdge )
+{
+    Q_D( HbAnchorLayout );
+    bool modified = false;
+
+    for (int i = d->mAllAnchors.size() - 1; i >= 0; --i) {
+        HbAnchor* anchor = d->mAllAnchors[i];
+        if( ( anchor->mStartId == startNodeId && anchor->mStartEdge == startEdge &&
+                anchor->mEndId == endNodeId && anchor->mEndEdge == endEdge ) ||
+            ( anchor->mStartId == endNodeId && anchor->mStartEdge == endEdge &&
+                anchor->mEndId == startNodeId && anchor->mEndEdge == startEdge ) ){
+            delete d->mAllAnchors.takeAt(i);
+            modified = true;
+            break;
+        }
     }
 
-    invalidate();
-    return true;
+    if (modified) {
+        d->removeItemIfNeeded( d->mMeshMap.key( startNodeId ) );
+        d->removeItemIfNeeded( d->mMeshMap.key( endNodeId ) );
+        invalidate();
+        return true;
+    }
+    return false;
 }
 
 /*!
@@ -1150,95 +1594,284 @@
     \param edge2 second edge.
     \return true if anchor was successfully removed, false otherwise
 */
-bool HbAnchorLayout::removeAnchor( QGraphicsLayoutItem *item1,
-                                   Hb::Edge edge1,
-                                   QGraphicsLayoutItem *item2,
-                                   Hb::Edge edge2 )
+bool HbAnchorLayout::removeAnchor( QGraphicsLayoutItem *startItem, Edge startEdge, QGraphicsLayoutItem *endItem, Edge endEdge )
+{
+    Q_D( HbAnchorLayout );
+    bool modified = false;
+
+    for (int i = d->mAllAnchors.size() - 1; i >= 0; --i) {
+        HbAnchor* anchor = d->mAllAnchors[i];
+        if( ( anchor->mStartItem == startItem && anchor->mStartEdge == startEdge &&
+                anchor->mEndItem == endItem && anchor->mEndEdge == endEdge ) ||
+                ( anchor->mStartItem == endItem && anchor->mStartEdge == endEdge &&
+                anchor->mEndItem == startItem && anchor->mEndEdge == startEdge ) ){
+            delete d->mAllAnchors.takeAt(i);
+            modified = true;
+            break;
+        }
+    }
+
+    if (modified) {
+        d->removeItemIfNeeded( startItem );
+        d->removeItemIfNeeded( endItem );
+        invalidate();
+        return true;
+    }
+    return false;
+}
+
+
+
+/*!
+    Removes all anchors starting or ending to \a nodeId.
+    Same is done with associated item
+
+    \param id id to be removed.
+    \return true if success, false otherwise.
+*/
+bool HbAnchorLayout::removeNodeId( const QString& nodeId )
 {
     Q_D( HbAnchorLayout );
-    HbAnchor *anchor = d->getAnchor( item1, edge1, item2, edge2 );
-    if( !anchor ) {
-        anchor = d->getAnchor( item2, edge2, item1, edge1 );
-    }
-    if ( anchor ) {
-        d->mAnchors.removeAll( anchor );
+    bool modified = false;
+
+    // if association, do removal
+
+    for (int i = d->mAllAnchors.size() - 1; i >= 0; --i) {
+        HbAnchor *anchor = d->mAllAnchors.at(i);
+        if (anchor->mStartId == nodeId || anchor->mEndId == nodeId) {
+            QGraphicsLayoutItem *startItem = anchor->mStartItem;
+            QGraphicsLayoutItem *endItem = anchor->mEndItem;
 
-        // Remove non-anchored items
-        bool startFound = false;
-        bool endFound = false;
-        for ( int i = d->mAnchors.count() - 1; i >= 0; i-- ) {
-            if ( d->mAnchors.at(i)->mStartItem == item1 ||
-                 d->mAnchors.at(i)->mEndItem == item1 ) {
-                    startFound = true;
-            }
-            if ( d->mAnchors.at(i)->mStartItem == item2 ||
-                 d->mAnchors.at(i)->mEndItem == item2 ) {
-                    endFound = true;
-            }
+            delete d->mAllAnchors.takeAt(i);
+            d->removeItemIfNeeded( startItem );
+            d->removeItemIfNeeded( endItem );
+
+            modified = true;
         }
-        if ( !startFound && item1 != this ) {
-            item1->setParentLayoutItem( 0 );
-            d->mItems.removeAt(indexOf(item1));
-        }
-        if ( !endFound && item2 != this) {
-            item2->setParentLayoutItem( 0 );
-            d->mItems.removeAt(indexOf(item2));
-        }
-        delete anchor;
+    }
+
+    removeMapping( nodeId );
+
+    if (modified) {
         invalidate();
         return true;
-    } else {
-        return false;
+    }
+    return false;
+}
+
+/*!
+    Clears all anchors.
+    Note that this does not affect on mappings.
+*/
+void HbAnchorLayout::removeAnchors()
+{
+    Q_D( HbAnchorLayout );
+
+    if( d->mAllAnchors.size() ) {
+        qDeleteAll( d->mResolvedDynamicAnchors );
+        qDeleteAll( d->mAllAnchors );
+        d->mResolvedDynamicAnchors.clear();
+        d->mResolvedStaticAnchors.clear();
+        d->mResolvedAnchors.clear();
+        d->mAllAnchors.clear();
+        invalidate();
     }
 }
 
 /*!
-    From QGraphicsLayoutItem.
-    Sets the geometry of all the child items of this layout.
-
-    In case the layout is not valid geometry will not be set
-    to any of the child items.
-
-    \param rect rectangle for this layout.
-    \sa isValid
+    Sets identifier for \a item.
+    \param item layout item.
+    \param nodeId new id corresponding to \a item.
+    \return true if success, false otherwise.
 */
-void HbAnchorLayout::setGeometry(const QRectF &rect)
+bool HbAnchorLayout::setMapping( QGraphicsLayoutItem *item, const QString& nodeId )
 {
     Q_D( HbAnchorLayout );
 
-    QGraphicsLayout::setGeometry(rect);
-    d->setItemGeometries();
-    d->mInvalidateCalled = false;
+    bool modified = false;
+
+    if ( !nodeId.isNull() && ( item != 0 ) ) {
+
+        for( int i = 0; i < d->mAllAnchors.size(); i++ ) {
+            HbAnchor *anchor = d->mAllAnchors.at(i);
+            if( anchor->mStartItem == item ) {
+                anchor->mStartId = nodeId;
+                modified = true;
+            } else if( anchor->mStartId == nodeId ) {
+                anchor->mStartItem = item;
+                modified = true;
+            }
+
+            if( anchor->mEndItem == item ) {
+                anchor->mEndId = nodeId;
+                modified = true;
+            } else if( anchor->mEndId == nodeId ) {
+                anchor->mEndItem = item;
+                modified = true;
+            }
+
+        }
+
+        // Remove previous item -> id.
+        HbMeshItemMapIterator it = d->mMeshMap.begin();
+        while ( it != d->mMeshMap.end() ) {
+            if ( it.value() == nodeId ) {
+                it = d->mMeshMap.erase( it );
+            } else {
+                ++it;
+            }
+        }
+        d->addItemIfNeeded( item );
+        d->mMeshMap.insert( item, nodeId );
+    } else {
+        return false;
+    }
+
+    if( modified ){
+        invalidate();
+    }
+    return true;
+}
+
+/*!
+    Resets mapping for \a item. All anchors are updated after that.
+
+    item <=> "someId"  ---->  item <=> null
+
+    \param item layout item.
+    \return true if success, false otherwise.
+*/
+bool HbAnchorLayout::removeMapping( QGraphicsLayoutItem *item )
+{
+    Q_D( HbAnchorLayout );
+
+    bool modified = false;
+
+    if( ! item ) {
+        return false;
+    }
+
+    for( int i = 0; i < d->mAllAnchors.size(); i++ ) {
+        HbAnchor *anchor = d->mAllAnchors.at(i);
+
+        if( anchor->mStartItem == item ) {
+            anchor->mStartId = QString();
+            modified = true;
+        }
+
+        if( anchor->mEndItem == item ) {
+            anchor->mEndId = QString();
+            modified = true;
+        }
+    }
+
+
+    d->mMeshMap.remove(item);
+
+    if( modified ){
+        invalidate();
+    }
+    return true;
 }
 
 /*!
-    From QGraphicsLayoutItem.
-    Removes the item at index, \a index, without destroying it.
+    Resets mapping for \a nodeId. All anchors are updated after that.
+
+    item <=> "nodeId"  ---->  0 <=> "nodeId"
 
-    Removes all the anchors connected to the removed item.
-
-    \param index index of item to be removed.
+    \param nodeId node id
+    \return true if success, false otherwise.
 */
-void HbAnchorLayout::removeAt(int index)
+bool HbAnchorLayout::removeMapping( const QString& nodeId )
 {
     Q_D( HbAnchorLayout );
-    if ( index < 0 || index > d->mItems.count()-1 ) {
+
+    bool modified = false;
+
+    if( nodeId.isNull() ) {
+        return false;
+    }
+
+    for( int i = 0; i < d->mAllAnchors.size(); i++ ) {
+        HbAnchor *anchor = d->mAllAnchors.at(i);
+
+        if( anchor->mStartId == nodeId ) {
+            anchor->mStartItem = 0;
+            modified = true;
+        }
+
+        if( anchor->mEndId == nodeId ) {
+            anchor->mEndItem = 0;
+            modified = true;
+        }
+    }
+
+
+    HbMeshItemMapIterator it = d->mMeshMap.begin();
+    while ( it != d->mMeshMap.end() ) {
+        if ( it.value() == nodeId ) {
+            it = d->mMeshMap.erase( it );
+        } else {
+            ++it;
+        }
+    }
+
+    if( modified ){
+        invalidate();
+    }
+    return true;
+}
+
+
+/*!
+    Clears all item id mappings.
+*/
+void HbAnchorLayout::removeMappings()
+{
+    Q_D( HbAnchorLayout );
+    d->mMeshMap.clear();
+
+    for( int i = 0; i < d->mAllAnchors.size(); i++ ) {
+        HbAnchor *anchor = d->mAllAnchors.at(i);
+
+        if( !anchor->mStartId.isNull() ) {
+            anchor->mStartItem = 0;
+        }
+
+        if( !anchor->mEndId.isNull() ) {
+            anchor->mEndItem = 0;
+        }
+
+    }
+}
+
+/*!
+    Adds \a item.
+
+    \param item item to be added.
+    \param id id of this item.
+*/
+void HbAnchorLayoutPrivate::addItemIfNeeded(QGraphicsLayoutItem *item)
+{
+    Q_Q(HbAnchorLayout);
+
+    if (!item) {
+        //qWarning() << "HbAnchorLayout::addItemIfNeeded : item is NULL";
         return;
     }
-    QGraphicsLayoutItem *item = itemAt( index );
-    if ( item ) {
-        for ( int i = d->mAnchors.count() - 1; i >= 0; i-- ) {
-            if ( d->mAnchors.at(i)->mStartItem == item ||
-                 d->mAnchors.at(i)->mEndItem == item ) {
-                    d->mAnchors.removeAt(i);
-            }
-        }
 
-        item->setParentLayoutItem( 0 );
-        d->mItems.removeAt(index);
+    if (item == q) {
+        //qWarning() << "HbAnchorLayout::addItemIfNeeded : layout cannot be added";
+        return;
     }
 
-    invalidate();
+    if (mItems.contains(item)) {
+        //qWarning() << "HbAnchorLayout::addItemIfNeeded : item is already in layout";
+        return;
+    }
+
+    HbLayoutUtils::addChildItem(q, item);
+    mItems.append(item);
 }
 
 /*!
@@ -1247,35 +1880,12 @@
 
     \param item item to be removed.
 */
-void HbAnchorLayout::removeItem(QGraphicsLayoutItem* item)
+void HbAnchorLayout::removeItem(QGraphicsLayoutItem *item)
 {
     removeAt(indexOf(item));
 }
 
 /*!
-    From QGraphicsLayoutItem.
-    Returns the count of the child items in anchor layout.
-    \return amount of items in this layout.
-*/
-int HbAnchorLayout::count() const
-{
-    Q_D( const HbAnchorLayout );
-    return d->mItems.count();
-}
-
-/*!
-    From QGraphicsLayoutItem.
-    Returns a pointer to the item at an index \a index.
-    \param index position of desired item.
-    \return item at specified index.
-*/
-QGraphicsLayoutItem *HbAnchorLayout::itemAt(int index) const
-{
-    Q_D( const HbAnchorLayout );
-    return d->mItems.value(index);
-}
-
-/*!
     Returns the index of given layout \a item, or -1 if not found.
     \param item item to look for.
     \return index of item or -1 if not found.
@@ -1283,8 +1893,8 @@
 int HbAnchorLayout::indexOf(const QGraphicsLayoutItem* item) const
 {
     Q_D( const HbAnchorLayout );
-    for ( int i=0; i< d->mItems.count(); i++) {
-        if ( d->mItems.at(i) == item ) {
+    for (int i=0; i < d->mItems.count(); i++) {
+        if (d->mItems.at(i) == item) {
             return i;
         }
     }
@@ -1303,14 +1913,117 @@
     return ( d->mValid && ( ! d->mWrongAnchors ) );
 }
 
+
 /*!
-    From QGraphicsLayoutItem.
+    Returns node id for given item, or default constructed string if no mapping exist.
+    \param item item to check.
+    \return node id for given item.
+*/
+QString HbAnchorLayout::nodeId( QGraphicsLayoutItem *item ) const
+{
+    Q_D( const HbAnchorLayout );
+    if( d->mMeshMap.contains( item ) ) {
+        return d->mMeshMap.value( item );
+    }
+    return QString();
+}
+
+/*!
+    Returns list of node ids that are mentioned in anchors list.
+    \return list of node ids.
+*/
+QStringList HbAnchorLayout::nodeIds() const
+{
+    Q_D( const HbAnchorLayout );
+    QStringList list;
+    int c = d->mAllAnchors.count();
+    while (c--) {
+        QString id = d->mAllAnchors.at(c)->mStartId;
+        if (!list.contains(id) && !id.isNull()) {
+            list.append(id);
+        }
+        id = d->mAllAnchors.at(c)->mEndId;
+        if (!list.contains(id) && !id.isNull()) {
+            list.append(id);
+        }
+    }
+    return list;
+}
+
+/*!
+    Returns item reference for given node id, or zero if no mapping exist.
+    \param nodeId node id to check.
+    \return item reference for given item.
+*/
+QGraphicsLayoutItem *HbAnchorLayout::itemByNodeId( const QString& nodeId ) const
+{
+    Q_D( const HbAnchorLayout );
+    return d->mMeshMap.key( nodeId );
+}
+
+
+/*!
+    \reimp
+*/
+void HbAnchorLayout::removeAt(int index)
+{
+    Q_D( HbAnchorLayout );
+    if ( index < 0 || index > d->mItems.count()-1 ) {
+        return;
+    }
+    QGraphicsLayoutItem *item = itemAt( index );
+    if ( item ) {
+        for ( int i = d->mAllAnchors.count() - 1; i >= 0; i-- ) {
+            if ( ( ( d->mAllAnchors.at(i)->mStartItem == item ) && ( d->mAllAnchors.at(i)->mStartId.isNull() ) ) ||
+                 ( ( d->mAllAnchors.at(i)->mEndItem == item ) && ( d->mAllAnchors.at(i)->mEndId.isNull() ) ) ) {
+                    delete d->mAllAnchors.takeAt(i);
+            }
+        }
+
+        removeMapping( d->mMeshMap.value(item) );
+        item->setParentLayoutItem( 0 );
+        d->mItems.removeAt( index );
+    }
+
+    invalidate();
+}
+
+/*!
+    \reimp
+*/
+void HbAnchorLayout::setGeometry(const QRectF &rect)
+{
+    Q_D( HbAnchorLayout );
+    QGraphicsLayout::setGeometry(rect);
+    d->setItemGeometries();
+}
+
+/*!
+    \reimp
+*/
+int HbAnchorLayout::count() const
+{
+    Q_D( const HbAnchorLayout );
+    return d->mItems.count();
+}
+
+/*!
+    \reimp
+*/
+QGraphicsLayoutItem *HbAnchorLayout::itemAt(int index) const
+{
+    Q_D( const HbAnchorLayout );
+    return d->mItems.value(index);
+}
+
+/*!
+    \reimp
 */
 void HbAnchorLayout::invalidate()
 {
     Q_D( HbAnchorLayout );
+    d->mInvalidateCalled = true;
     d->mWrongAnchors = false;
-    d->mInvalidateCalled = true;
     d->mEquationsDirty = true;
     QGraphicsLayout::invalidate();
 }
@@ -1322,9 +2035,8 @@
 {
     QGraphicsLayout::widgetEvent(e);
 }
-
 /*!
-    From QGraphicsLayoutItem. If size hint for certain set of items cannot be defined, 
+    From QGraphicsLayoutItem. If size hint for certain set of items cannot be defined,
     then it returns default size hint (0/100/1000)
     \param which desired size hint.
     \param constraint optional constraint.
@@ -1338,15 +2050,15 @@
     return const_cast<HbAnchorLayoutPrivate*>(d)->sizeHint( which );
 }
 
-QSizeF HbAnchorLayoutPrivate::sizeHint( Qt::SizeHint which )
+QSizeF HbAnchorLayoutPrivate::sizeHint(Qt::SizeHint which)
 {
     if ( mEquationsDirty ) {
-        mEquationsDirty = false;
+        updateAnchorsAndItems();
         createEquations( Horizontal );
         createEquations( Vertical );
+        mEquationsDirty = false;
     }
 
-
     if( mLayoutVarH && mLayoutVarV ) {
 
         QSizeF res;
@@ -1386,4 +2098,3 @@
         }
     }
 }
-