src/hbcore/vkbhosts/hbabstractvkbhost.cpp
changeset 34 ed14f46c0e55
parent 6 c3690ec91ef8
--- a/src/hbcore/vkbhosts/hbabstractvkbhost.cpp	Mon Oct 04 17:49:30 2010 +0300
+++ b/src/hbcore/vkbhosts/hbabstractvkbhost.cpp	Mon Oct 18 18:23:13 2010 +0300
@@ -22,158 +22,59 @@
 ** Nokia at developer.feedback@nokia.com.
 **
 ****************************************************************************/
+
 #include "hbabstractvkbhost.h"
 #include "hbabstractvkbhost_p.h"
+#include "private/hbvkbgeometrylogic_p.h"
+#include "hbvkbhostcontainerwidget_p.h"
 #include "hbinputvirtualkeyboard.h"
 #include "hbinputsettingproxy.h"
 #include "hbinputvkbhostbridge.h"
+#include "hbvkbconstants_p.h"
+#include "hbwidgetfeedback.h"
 #include "hbinputmethod.h"
 #include "hbdeviceprofile.h"
+#include "hbscrollarea.h"
 #include "hbmainwindow.h"
+#include "hbpopup_p.h"
 #include "hbpopup.h"
 #include "hbview.h"
-#include "hbwidgetfeedback.h"
 #include "hbinstance.h"
 
 #include <QTextEdit>
 
-const int HbAnimationTime = 200;
-const qreal HbEditorExtraMargin = 5.0;
-const qreal HbCursorLineMargin = 15.0;
-const qreal HbContainerBorderMargin = 20.0;
-const qreal HbHeightVerticalFactor = 0.5;
-const qreal HbHeightHorizFactor = 0.7;
 const QString KHandWritingName("Handwriting");
 // see hbpopup.cpp for this
 extern const char* KPositionManagedByVKB;
 
-/// @cond
-
-HbVkbHostContainerWidget::HbVkbHostContainerWidget(QObject *containterWidget)
-    : mContainerWidget(containterWidget)
-{
-}
-
-// sets container widgets position to new position.
-void HbVkbHostContainerWidget::setPos(QPointF newPosition)
-{
-    if (mContainerWidget) {
-        QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject *>(mContainerWidget);
-        if (graphicsObject) {
-            graphicsObject->setPos(newPosition);
-            return;
-        }
+/*!
+@stable
+@hbcore
+\class HbAbstractVkbHost
+\brief The default virtual keyboard host
 
-        QWidget *qWidget = qobject_cast<QWidget *>(mContainerWidget);
-        if (qWidget) {
-#ifdef Q_WS_WIN
-            QPoint finalPosition = newPosition.toPoint();
-            finalPosition -= qWidget->geometry().topLeft() - qWidget->frameGeometry().topLeft();
-            qWidget->move(finalPosition);
-#else
-            qWidget->move(newPosition.toPoint());
-#endif
-            return;
-        }
-    }
-}
-
-// returns the global position, if container widget is a QGraphicsObject, it returns
-// scene position. In case the widget is QWidget it returns global co-ordinates
-QPointF HbVkbHostContainerWidget::pos()
-{
-    if (mContainerWidget) {
-        QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject *>(mContainerWidget);
-        if (graphicsObject) {
-            return graphicsObject->pos();;
-        }
-
-        QWidget *qWidget = qobject_cast<QWidget *>(mContainerWidget);
-        if (qWidget) {
-            return qWidget->mapToGlobal(QPoint(0, 0));
-        }
-    }
-
-    return QPointF(0, 0);
-}
-
-// returns the bounding rect in global co-ordinate, if container widget is a QGraphicsObject
-// it returns in scene co-ordinate, incase widget is QWidget it returns in global co-ordinate
-QRectF HbVkbHostContainerWidget::sceneBoundingRect()
-{
-    if (mContainerWidget) {
-        QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject *>(mContainerWidget);
-        if (graphicsObject) {
-            return graphicsObject->sceneBoundingRect();;
-        }
+This class implements the default virtual keyboard host. A virtual keyboard
+host is responsible for the interaction between application background
+and the virtual keyboard widget when a virtual keyboard becomes visible.
 
-        QWidget *qWidget = qobject_cast<QWidget *>(mContainerWidget);
-        if (qWidget) {
-            return QRectF(qWidget->mapToGlobal(QPoint(0, 0)), qWidget->size());
-        }
-    }
-
-    return QRectF(0, 0, 0, 0);
-}
+Its main task is to guarantee that editor's cursor line remains visible
+and that the virtual keyboard widget doesn't cover it.
 
-// connect container specific signals here.
-void HbVkbHostContainerWidget::connectSignals(QObject *receiver)
-{
-    if (qobject_cast<QGraphicsObject *> (mContainerWidget)) {
-        QObject::connect(mContainerWidget, SIGNAL(yChanged()),
-                         receiver, SLOT(ensureCursorVisibility()));
-    }
-
-    HbPopup *popup = qobject_cast<HbPopup *>(mContainerWidget);
-    if (popup) {
-        QObject::connect(popup, SIGNAL(aboutToHide()), receiver, SLOT(containerAboutToClose()));
-    }
-
-    HbView *view = qobject_cast<HbView *>(mContainerWidget);
-    if (view) {
-        QObject::connect(view->mainWindow(), SIGNAL(currentViewChanged(HbView *)),
-                         receiver, SLOT(currentViewChanged(HbView *)));
-    }
-}
+The abstract vkb host does this by moving the editor container around in suitable way.
 
-// disconnect container specific signals here.
-void HbVkbHostContainerWidget::disconnectSignals(QObject *receiver)
-{
-    if (qobject_cast<QGraphicsObject *> (mContainerWidget)) {
-        QObject::disconnect(mContainerWidget, SIGNAL(yChanged()),
-                            receiver, SLOT(ensureCursorVisibility()));
-    }
-
-    HbPopup *popup = qobject_cast<HbPopup *>(mContainerWidget);
-    if (popup) {
-        QObject::disconnect(popup, SIGNAL(aboutToHide()), receiver, SLOT(containerAboutToClose()));
-    }
+See \ref vkbHandling "virtual keyboard handling guide" for more information
 
-    HbPopup *view = qobject_cast<HbPopup *>(mContainerWidget);
-    if (view) {
-        QObject::disconnect(view->mainWindow(), SIGNAL(currentViewChanged(HbView *)),
-                            receiver, SLOT(currentViewChanged(HbView *)));
-    }
-}
-
-/// @endcond
-
-/*!
-\proto
-\class HbAbstractVkbHost
-\brief Base class for HbCore's virtual keyboard hosts.
-
-This class contains common code for HbCore's virtual keyboard hosts.
+\sa HbVkbHost
+\sa HbShrinkingVkbHost
+\sa HbStaticVkbHost
 */
 
-/// @cond
-
 HbAbstractVkbHostPrivate::HbAbstractVkbHostPrivate(HbAbstractVkbHost *myHost, QObject *containerWidget)
     : q_ptr(myHost),
       mCallback(0),
       mKeypad(0),
       mContainerWidget(new HbVkbHostContainerWidget(containerWidget)),
-      mTimeLine(HbAnimationTime),
+      mTimeLine(HbVkbAnimationTime),
       mKeypadStatus(HbVkbHost::HbVkbStatusClosed),
       mKeypadOperationOngoing(false),
       mOriginalContainerPosition(QPointF(0, 0)),
@@ -182,9 +83,13 @@
       mKeypadMovementStartingPoint(QPointF(0, 0)),
       mKeypadMovementVector(QPointF(0, 0)),
       mInputMethod(0),
-      mKeypadStatusBeforeOrientationChange(HbVkbHost::HbVkbStatusClosed)
+      mKeypadStatusBeforeOrientationChange(HbVkbHost::HbVkbStatusClosed),
+      mTitleBarHiddenByVkbHost(false),
+      mStatusBarHiddenByVkbHost(false),
+      mMarginInPixels(0)
 {
     mTimeLine.setUpdateInterval(16);
+    mMarginInPixels = HbDeviceProfile::current().unitValue() * HbVkbHostMargin;
 }
 
 HbAbstractVkbHostPrivate::~HbAbstractVkbHostPrivate()
@@ -192,149 +97,164 @@
     delete mContainerWidget;
 }
 
+/*!
+\internal
+Initializes starting values to parameters needed for running the keypad and
+container widget animation effects.
+*/
 void HbAbstractVkbHostPrivate::prepareAnimationsCommon()
 {
-    if (mContainerWidget->widgetObject() && mKeypad) {
+    // Initialize movement variables to starting values. These will
+    // be fine tuned later.
+    mKeypadMovementVector = QPointF(0, 0);
+    mContainerMovementVector = QPointF(0, 0);
+    mContainerMovementStartingPoint = QPointF();
+    mKeypadMovementStartingPoint = QPointF();
+    mScrollAreaRect = QRectF();
+
+    if (mContainerWidget && mContainerWidget->widgetObject() && mKeypad) {
         // If the keyboard is not already open, remember the original position.
         // That is where the container will eventually be returned to.
         if (mKeypadStatus == HbVkbHost::HbVkbStatusClosed) {
             mOriginalContainerPosition = mContainerWidget->pos();
         }
 
-        // Initialize movement variables to starting values. These will
-        // be fine tuned later.
-        mKeypadMovementVector = QPointF(0, 0);
-        mContainerMovementVector = QPointF(0, 0);
         mContainerMovementStartingPoint = mContainerWidget->pos();
         mKeypadMovementStartingPoint = mKeypad->pos();
     }
 
     mScreenSize = screenSize();
+
+    // Make sure that the editor is completely visible inside a scroll area.
+    ensureVisibilityInsideScrollArea();
 }
 
+/*!
+\internal
+Sets up view and focus object variables.
+*/
+bool HbAbstractVkbHostPrivate::getViewAndFocusObjects(HbView*& currentView, HbInputFocusObject*& focusObject)
+{
+    if (!mKeypad || !mInputMethod || !mContainerWidget ) {
+        return false;
+    }
+
+    HbMainWindow* window = mainWindow();
+    if (!window) {
+        return false;
+    }
+
+    // Update margin pixel value while you're at it.
+    mMarginInPixels = HbDeviceProfile::profile(window).unitValue() * HbVkbHostMargin;
+
+    currentView = window->currentView();
+    if (!currentView) {
+        return false;
+    }
+
+    focusObject = mInputMethod->focusObject();
+    if (!focusObject) {
+        return false;
+    }
+
+    return true;
+}
+
+/*!
+\internal
+Sets up the container widget animation effect.
+*/
 bool HbAbstractVkbHostPrivate::prepareContainerAnimation(HbVkbHost::HbVkbStatus status)
 {
-    if (!mKeypad || !mContainerWidget->widgetObject() || !mInputMethod || !mInputMethod->focusObject()) {
+    // Init and check main objects
+    HbView* currentView = 0;
+    HbInputFocusObject* focusObject = 0;
+    if (!getViewAndFocusObjects(currentView, focusObject)) {
         return false;
     }
 
-    if (status == HbVkbHost::HbVkbStatusOpened) {
-        // Calculate the area that remains visible when the keypad is open.
-        QRectF visibleArea = QRectF(0.0, 0.0, mScreenSize.width(), mScreenSize.height() - mKeypad->size().height());
-
-        // Find out the container area.
-        QRectF containerArea = mContainerWidget->sceneBoundingRect();
-        containerArea.adjust(0.0, -HbContainerBorderMargin, 0.0, HbContainerBorderMargin);
+    bool result = false;
 
-        if (visibleArea.contains(containerArea)) {
-            // The whole container is already inside the visible area, nothing to do.
-            return false;
-        }
+    if (status == HbVkbHost::HbVkbStatusOpened) {
+        // Init parameters before calling.
+        QSizeF keypadSize = mKeypad->size();
+        QRectF viewRect = currentView->sceneBoundingRect();
+        bool isPopupType = qobject_cast<HbPopup *>(mContainerWidget->widgetObject()) != 0;
+        bool vkbOpen = mKeypadStatus == HbVkbHost::HbVkbStatusOpened;
+        QRectF containerRect = mContainerWidget->sceneBoundingRect();
+        QRectF editorRect = findEditorRect(focusObject);
+        QRectF cursorRect = focusObject->microFocus();
+        QPointF fixedMovement = mContainerWidget->fixedContainerMovement();
 
-        if (visibleArea.height() >= containerArea.height()) {
-            // It isn't in the visible area yet but fits there. Let's move it there.
-            mContainerMovementVector = QPointF(0.0, visibleArea.bottom() - containerArea.bottom());
-            return true;
+        // We know that the container will be moved at least the amount of
+        // fixed movement vector (which typically, if non-zero, is the
+        // height of the title bar). So we reduce the keypad area
+        // to make the calculations match (fixed movement points
+        // to negative direction, that's why addition).
+        if (!vkbOpen) {
+            keypadSize.setHeight(keypadSize.height() + fixedMovement.y());
         }
 
-        // Find out the editor bounding box and add a small margin to height.
-        QRectF editorGeometry = mInputMethod->focusObject()->editorGeometry();
-        editorGeometry.adjust(0.0, -HbCursorLineMargin, 0.0, HbCursorLineMargin);
+        // Initialize geometry calculation unit to handle all geometry calculations.
+        HbVkbGeometryLogicPrivate unit = HbVkbGeometryLogicPrivate(
+                mScreenSize,
+                keypadSize,
+                viewRect,
+                isPopupType,
+                vkbOpen,
+                containerRect,
+                editorRect,
+                cursorRect,
+                mMarginInPixels);
 
-        // Then see if the editor is already inside the visible area.
-        // If it isn't, see if it would fit there.
-        if (!visibleArea.contains(editorGeometry)) {
-            if (editorGeometry.width() <= visibleArea.width() &&
-                editorGeometry.height() <= visibleArea.height()) {
-                // Yes, it fits into visible area, let's move it there so that
-                // the whole editor area is in use right away.
-                // First check if we want to move it to upper or lower
-                // part of the visible area.
-                if (editorGeometry.top() <= visibleArea.top()) {
-                    // It goes to the upper part of the visible area.
-                    mContainerMovementVector = QPointF(0.0, -editorGeometry.top());
-                } else {
-                    mContainerMovementVector = QPointF(0.0, visibleArea.bottom() - editorGeometry.bottom());
+        result = unit.calculateContainerMovement(mContainerMovementVector);
+        if (!vkbOpen) {
+            // Apply fixed movement only if the keyboard is not already open.
+            // Fixed movement is used for hiding the title bar.
+            mContainerMovementVector = selectLongestVerticalVector(fixedMovement, mContainerMovementVector);
+        }
+    } else if (status == HbVkbHost::HbVkbStatusClosed) {
+        if (mContainerMovementStartingPoint != mOriginalContainerPosition) {
+           mContainerMovementVector = mOriginalContainerPosition - mContainerMovementStartingPoint;
+           result = true;
+        }
+    }
+
+    return result;
+}
+
+/*!
+\internal
+Sets up the keypad widget animation effect.
+*/
+bool HbAbstractVkbHostPrivate::prepareKeypadAnimation(HbVkbHost::HbVkbStatus status)
+{
+    if (mKeypad) {
+        if (status == HbVkbHost::HbVkbStatusOpened) {
+            if (mKeypadStatus == HbVkbHost::HbVkbStatusClosed) {
+                // Set up keyboard open animation.
+                mKeypadMovementStartingPoint.setY(mScreenSize.height());
+                mKeypadMovementVector.setY(-mKeypad->size().height());
+                if (!disableCursorShift()) {
+                    // Initialize keypad position
+                    mKeypad->setPos(mKeypadMovementStartingPoint);
                 }
-
                 return true;
             }
-        }
-
-        // The editor is either already inside the visible area or doesn't fit there.
-        // Let's see if the cursor is visble.
-        // First find out micro focus rectangle and increase the height by a small margin.
-        QRectF microFocus = mInputMethod->focusObject()->microFocus();
-        microFocus.setTop(microFocus.top() - HbEditorExtraMargin);
-        microFocus.setBottom(microFocus.bottom() + HbEditorExtraMargin);
-
-        // Check whether the cursor rectangle is inside visible area.
-        if (!visibleArea.contains(microFocus)) {
-            QRectF realEditorGeometry = editorGeometry;
-            realEditorGeometry.adjust(0.0, HbCursorLineMargin, 0.0, -HbCursorLineMargin);
-            if (!realEditorGeometry.contains(microFocus)) {
-                // A sanity check. If the microFocus rectangle is outside the editor
-                // bounding rect, don't do anything. The situation in editor widget is not
-                // up to date.
-                return false;
-            }
-            // The cursor is outside the visible area. Figure out how much and
-            // to which direction the container has to be moved.
-            if (microFocus.bottom() <= visibleArea.top()) {
-                // First see what would happen if we returned the container to original position.
-                // Is the cursor visible then?
-                // This is always preferred, use it if possible.
-                QPointF toOriginalPos = mOriginalContainerPosition - mContainerWidget->pos();
-                QRectF translatedMicroFocus = microFocus.translated(toOriginalPos);
-                if (visibleArea.contains(translatedMicroFocus)) {
-                    mContainerMovementVector = toOriginalPos;
-                } else {
-                    // It goes to the upper part of the visible area.
-                    mContainerMovementVector = QPointF(0.0, HbCursorLineMargin - microFocus.top());
-                }
-            } else {
-                mContainerMovementVector = QPointF(0.0, visibleArea.bottom() - HbCursorLineMargin - microFocus.bottom());
-            }
-
+        } else {
+            // It is going to be closed.
+            mKeypadMovementVector = QPointF(0, mKeypad->size().height());
             return true;
         }
-    } else {
-        // It is going to be closed or minimized.
-        mContainerMovementVector = mOriginalContainerPosition - mContainerMovementStartingPoint;
-        return true;
     }
 
     return false;
 }
 
-bool HbAbstractVkbHostPrivate::prepareKeypadAnimation(HbVkbHost::HbVkbStatus status)
-{
-    if (status == HbVkbHost::HbVkbStatusOpened) {
-        if (mKeypadStatus == HbVkbHost::HbVkbStatusClosed) {
-            // Set up keyboard open animation.
-            mKeypadMovementStartingPoint.setY(mScreenSize.height());
-            mKeypadMovementVector.setY(-mKeypad->size().height());
-            if (!disableCursorShift()) {
-                // Initialize keypad position
-                mKeypad->setPos(mKeypadMovementStartingPoint);
-            }
-            return true;
-        } else if (mKeypadStatus == HbVkbHost::HbVkbStatusMinimized && mCallback) {
-            mKeypadMovementVector.setY(-(mKeypad->size().height() - mCallback->minimizedKeyboardSize().height()));
-            return true;
-        }
-    } else if (status == HbVkbHost::HbVkbStatusMinimized && mCallback) {
-        mKeypadMovementVector = QPointF(0, mKeypad->size().height() - mCallback->minimizedKeyboardSize().height());
-        return true;
-    } else {
-        // It is going to be closed.
-        mKeypadMovementVector = QPointF(0, mKeypad->size().height());
-        return true;
-    }
-
-    return false;
-}
-
+/*!
+\internal
+Sets up all the animation effects.
+*/
 bool HbAbstractVkbHostPrivate::prepareAnimations(HbVkbHost::HbVkbStatus status)
 {
     prepareAnimationsCommon();
@@ -353,6 +273,10 @@
     return (containerResult | prepareKeypadAnimation(status));
 }
 
+/*!
+\internal
+Connects orientation change, view switching and possible other related signals.
+*/
 void HbAbstractVkbHostPrivate::connectSignals()
 {
     mContainerWidget->connectSignals(q_ptr);
@@ -362,10 +286,14 @@
     if (mainWindow) {
         q_ptr->connect(mainWindow, SIGNAL(aboutToChangeOrientation()), q_ptr, SLOT(orientationAboutToChange()));
         q_ptr->connect(mainWindow, SIGNAL(orientationChanged(Qt::Orientation)), q_ptr, SLOT(orientationChanged(Qt::Orientation)));
-        q_ptr->connect(mainWindow, SIGNAL(currentViewChanged(HbView *)), q_ptr, SLOT(currentViewChanged(HbView *)));
+        q_ptr->connect(mainWindow, SIGNAL(aboutToChangeView(HbView *, HbView *)), q_ptr, SLOT(aboutToChangeView(HbView *, HbView *)));
     }
 }
 
+/*!
+\internal
+Disconnects orientation change, view switching and possible other related signals.
+*/
 void HbAbstractVkbHostPrivate::disconnectSignals()
 {
     mContainerWidget->disconnectSignals(q_ptr);
@@ -375,10 +303,14 @@
     if (mainWindow) {
         q_ptr->disconnect(mainWindow, SIGNAL(aboutToChangeOrientation()), q_ptr, SLOT(orientationAboutToChange()));
         q_ptr->disconnect(mainWindow, SIGNAL(orientationChanged(Qt::Orientation)), q_ptr, SLOT(orientationChanged(Qt::Orientation)));
-        q_ptr->disconnect(mainWindow, SIGNAL(currentViewChanged(HbView *)), q_ptr, SLOT(currentViewChanged(HbView *)));
+        q_ptr->disconnect(mainWindow, SIGNAL(aboutToChangeView(HbView *, HbView *)), q_ptr, SLOT(aboutToChangeView(HbView *, HbView *)));
     }
 }
 
+/*!
+\internal
+Opens the keypad widget with animation effect.
+*/
 void HbAbstractVkbHostPrivate::openKeypad()
 {
     if (mContainerWidget->widgetObject()) {
@@ -390,7 +322,9 @@
             }
 
             if (mKeypadStatus != HbVkbHost::HbVkbStatusOpened) {
-                mCallback->aboutToOpen(q_ptr);
+                if (mCallback) {
+                    mCallback->aboutToOpen(q_ptr);
+                }
                 q_ptr->resizeKeyboard(); // Make sure that the keyboard doesn't exceed given boundaries.
             }
 
@@ -403,15 +337,16 @@
     }
 }
 
+/*!
+\internal
+Closes the keypad with animation effect.
+*/
 void HbAbstractVkbHostPrivate::closeKeypad()
-{
-    // Since the keypad is already in a minimized state we should not play animation.
-    if (mKeypadStatus == HbVkbHost::HbVkbStatusMinimized) {
-        closeKeypadWithoutAnimation();
-    }
-
+{  
     if (mKeypadStatus != HbVkbHost::HbVkbStatusClosed) {
-        mCallback->aboutToClose(q_ptr);
+        if (mCallback) {
+            mCallback->aboutToClose(q_ptr);
+        }
 
         if (prepareAnimations(HbVkbHost::HbVkbStatusClosed)) {
             mKeypadStatus = HbVkbHost::HbVkbStatusClosed;
@@ -420,19 +355,10 @@
     }
 }
 
-void HbAbstractVkbHostPrivate::minimizeKeypad()
-{
-    if (mCallback && mKeypadStatus != HbVkbHost::HbVkbStatusMinimized) {
-        mCallback->aboutToClose(q_ptr);
-        if (mContainerWidget->widgetObject()) {
-            if (prepareAnimations(HbVkbHost::HbVkbStatusMinimized)) {
-                mKeypadStatus = HbVkbHost::HbVkbStatusMinimized;
-                mTimeLine.start();
-            }
-        }
-    }
-}
-
+/*!
+\internal
+Opens the keypad widget without animation effect.
+*/
 void HbAbstractVkbHostPrivate::openKeypadWithoutAnimation()
 {
     HbMainWindow *mainWin = mainWindow();
@@ -443,7 +369,9 @@
         }
 
         if (mKeypadStatus != HbVkbHost::HbVkbStatusOpened) {
-            mCallback->aboutToOpen(q_ptr);
+            if (mCallback) {
+                mCallback->aboutToOpen(q_ptr);
+            }
             q_ptr->resizeKeyboard(); // Make sure that the keyboard doesn't exceed given boundaries.
         }
         if (prepareAnimations(HbVkbHost::HbVkbStatusOpened)) {
@@ -456,48 +384,32 @@
             }
 
             mKeypadStatus = HbVkbHost::HbVkbStatusOpened;
-            mCallback->keyboardOpened(q_ptr);
+            if (mCallback) {
+                mCallback->keyboardOpened(q_ptr);
+            }
         }
     }
+
+    ensureVisibilityInsideScrollArea();
+    ensureVisibilityInsideVisibleArea();
 }
 
-void HbAbstractVkbHostPrivate::openMinimizedKeypad()
-{
-    // No need of any animation as this minimized keypad is very small to be a candidate for an
-    // animation.
-    HbMainWindow *mainWin = mainWindow();
-    if (mainWin && mKeypad && mContainerWidget->widgetObject()) {
-        if (mKeypad->scene() != mainWin->scene()) {
-            // Add item to scene if it is not already in there.
-            mainWin->scene()->addItem(mKeypad);
-        }
-
-        if (mKeypadStatus != HbVkbHost::HbVkbStatusMinimized) {
-            mCallback->aboutToOpen(q_ptr);
-            q_ptr->resizeKeyboard(); // Make sure that the keyboard doesn't exceed given boundaries.
-        }
-
-        if (prepareAnimations(HbVkbHost::HbVkbStatusMinimized)) {
-            if (!disableCursorShift()) {
-                mKeypad->setPos(0.0, mScreenSize.height() - mCallback->minimizedKeyboardSize().height());
-            }
-            mKeypadStatus = HbVkbHost::HbVkbStatusMinimized;
-            mCallback->keyboardMinimized(q_ptr);
-        }
-    }
-}
-
+/*!
+\internal
+Closes the keypad widget without animating it.
+*/
 void HbAbstractVkbHostPrivate::closeKeypadWithoutAnimation()
 {
-    if (mKeypadStatus != HbVkbHost::HbVkbStatusClosed && mKeypad) {
+    if (mKeypadStatus != HbVkbHost::HbVkbStatusClosed && mKeypad && mCallback) {
         mCallback->aboutToClose(q_ptr);
+
         // Set original content widget position
         mKeypadStatus = HbVkbHost::HbVkbStatusClosed;
 
         if (!disableCursorShift()) {
             // Return the container widget to original position.
             mContainerWidget->setPos(mOriginalContainerPosition);
-            mContainerWidget->widgetObject()->setProperty(KPositionManagedByVKB, false );
+            mContainerWidget->widgetObject()->setProperty(KPositionManagedByVKB, false);
         }
 
         // Hide the keypad
@@ -507,35 +419,18 @@
     }
 }
 
-void HbAbstractVkbHostPrivate::minimizeKeypadWithoutAnimation()
-{
-    HbMainWindow *mainWin = mainWindow();
-    if (mKeypadStatus != HbVkbHost::HbVkbStatusMinimized && mKeypad && mainWin) {
-        mCallback->aboutToClose(q_ptr);
-        if (mKeypad->scene() != mainWin->scene()) {
-            // Add item to scene if it is not already in there.
-            mainWin->scene()->addItem(mKeypad);
-        }
-
-        mKeypadStatus = HbVkbHost::HbVkbStatusMinimized;
-        if (!disableCursorShift()) {
-            // Return the container widget to original position.
-            mContainerWidget->setPos(mOriginalContainerPosition);
-
-            // Set the keypad to minimized position.
-            mKeypad->setPos(QPointF(0.0, mScreenSize.height() - mCallback->minimizedKeyboardSize().height()));
-        }
-    }
-}
-
+/*!
+\internal
+Cancels the ongoing keypad animation and resets the timeline timer.
+*/
 void HbAbstractVkbHostPrivate::cancelAnimationAndHideVkbWidget()
 {
     if (mTimeLine.state() == QTimeLine::Running) {
         mTimeLine.stop();
 
-        if (!disableCursorShift()) {
+        if (!disableCursorShift() && mContainerWidget && mContainerWidget->widgetObject()) {
             mContainerWidget->setPos(mOriginalContainerPosition);
-            mContainerWidget->widgetObject()->setProperty(KPositionManagedByVKB, false );
+            mContainerWidget->widgetObject()->setProperty(KPositionManagedByVKB, false);
         }
 
         if (mKeypad) {
@@ -551,6 +446,10 @@
     }
 }
 
+/*!
+\internal
+Returns pointer to container's main window (if one exists).
+*/
 HbMainWindow *HbAbstractVkbHostPrivate::mainWindow() const
 {
     HbWidget *hbWidget = qobject_cast<HbWidget *>(mContainerWidget->widgetObject());
@@ -568,6 +467,10 @@
     return 0;
 }
 
+/*!
+\internal
+Returns screen size.
+*/
 QSizeF HbAbstractVkbHostPrivate::screenSize() const
 {
     HbMainWindow *mainWin = mainWindow();
@@ -592,7 +495,6 @@
 
 bool HbAbstractVkbHostPrivate::disableCursorShift()
 {
-
     if (!mInputMethod
         || mainWindow()) {
         return false;
@@ -607,9 +509,177 @@
     return false;
 }
 
+/*!
+\internal
+Closes the keypad. This slot is connected to various signals from 
+different container classes.
+*/
+void HbAbstractVkbHostPrivate::_q_containerAboutToClose()
+{
+    Q_Q(HbAbstractVkbHost);
+    q->closeKeypad();
+}
 
-/// @endcond
+/*!
+\internal
+Finds out if given editor is inside a scroll area and makes sure the cursor position is visible inside the
+scroll area.
+*/
+void HbAbstractVkbHostPrivate::ensureVisibilityInsideScrollArea() const
+{
+    if (mInputMethod && mInputMethod->focusObject()) {
+        HbInputFocusObject *fo = mInputMethod->focusObject();
+        HbScrollArea *scrollArea = 0;
+
+        QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject *>(fo->object());
+        if (graphicsObject) {
+            for (QGraphicsWidget *parent = graphicsObject->parentWidget(); parent; parent = parent->parentWidget()) {
+                scrollArea = qobject_cast<HbScrollArea*>(parent);
+                if (scrollArea) {
+                    break;
+                }
+            }
+        }
+
+        if (scrollArea && scrollArea->contentWidget()) {
+            QRectF scrollRect = scrollArea->sceneBoundingRect();
+            mScrollAreaRect = scrollRect;
+            QRectF editorRect = fo->editorGeometry();
+
+            if (!scrollRect.contains(editorRect)) {
+                // The editor is not visible inside a scroll area.
+                // Calculate how much the area needs to be scrolled
+                // to make the cursor line visible inside the scroll
+                // area. The call scroll area's ensure visibility and
+                // return the calculated value (it needs to be factored in
+                // to container animation calculations).                            
+                if (editorRect.height() < scrollRect.height()) {
+                    // Whole editor rect fits into scroll area. Move it there.
+                    if (editorRect.bottom() > scrollRect.bottom()) {
+                        // Scroll upwards.                    
+                        scrollArea->ensureVisible(scrollArea->contentWidget()->mapFromScene(editorRect.bottomLeft()), 0.0, mMarginInPixels);
+                    } else {
+                        // Scroll downwards.                        
+                        scrollArea->ensureVisible(scrollArea->contentWidget()->mapFromScene(editorRect.topLeft()), 0.0, mMarginInPixels);
+                    }
+                } else {
+                    // Whole editor doesn't fit into scroll area. Used micro focus position instead.
+                    QRectF microFocus = fo->microFocus();
+                    if (microFocus.bottom() > scrollRect.bottom()) {
+                        // Scroll upwards.
+                        scrollArea->ensureVisible(scrollArea->contentWidget()->mapFromScene(microFocus.bottomLeft()), 0.0, mMarginInPixels);
+                    } else {
+                        // Scroll downwards.
+                        scrollArea->ensureVisible(scrollArea->contentWidget()->mapFromScene(microFocus.topLeft()), 0.0, mMarginInPixels);
+                    }
+                }
+            }
+        }
+    }
+}
+
+/*!
+\internal
+Finds out if given editor is inside a scroll area and makes sure the cursor position is visible inside the
+visible area.
+*/
+void HbAbstractVkbHostPrivate::ensureVisibilityInsideVisibleArea() const
+{
+    Q_Q(const HbAbstractVkbHost);
+    if (mInputMethod && mInputMethod->focusObject()) {
+        HbInputFocusObject *fo = mInputMethod->focusObject();
+        HbScrollArea *scrollArea = 0;
+
+        QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject *>(fo->object());
+        if (graphicsObject) {
+            for (QGraphicsWidget *parent = graphicsObject->parentWidget(); parent; parent = parent->parentWidget()) {
+                scrollArea = qobject_cast<HbScrollArea*>(parent);
+                if (scrollArea) {
+                    break;
+                }
+            }
+        }
 
+        if (scrollArea && scrollArea->contentWidget()) {
+            QRectF editorRect = fo->editorGeometry();
+            QRectF visibleArea = q->applicationArea();
+            if (!visibleArea.isValid() && mContainerWidget) {
+                visibleArea = mContainerWidget->sceneBoundingRect();
+            }
+
+            if (!visibleArea.contains(editorRect)) {
+                // Editor is inside scroll area but not on visible area so scroll it to be visible
+                if (editorRect.bottom() > visibleArea.bottom()) {
+                    // Scroll upwards.
+                    QPointF point = QPointF(0.0, -scrollArea->contentWidget()->pos().y() + (editorRect.bottom() - visibleArea.bottom()) + mMarginInPixels);
+                    scrollArea->scrollContentsTo(point);
+                } else {
+                    // Scroll downwards.
+                    QPointF point = QPointF(0.0, -scrollArea->contentWidget()->pos().y() + editorRect.y() - mMarginInPixels);
+                    scrollArea->scrollContentsTo(point);
+                }
+            }
+        }
+    }
+}
+
+/*!
+\internal
+Returns the editor bounding rect. If the editor is inside a scroll area, then we actually
+need to use the intersection of scroll area bounding rect and the editor rect in
+our calculations.
+*/
+QRectF HbAbstractVkbHostPrivate::findEditorRect(HbInputFocusObject* fo) const
+{
+    if (fo) {      
+        QRectF editorRect = fo->editorGeometry();
+        if (!mScrollAreaRect.isEmpty()) {
+            QRectF adjustedSrcollArea = mScrollAreaRect;
+            // Cancel out the to-be-added margin
+            adjustedSrcollArea.adjust(0, mMarginInPixels, 0, -mMarginInPixels);
+            return editorRect.intersected(adjustedSrcollArea);
+        }
+        return editorRect;
+    }
+
+    return QRectF();
+}
+
+/*!
+\internal
+Returns true if the container is a popup and it is still running its opening animation
+when the open keypad call comes in.
+*/
+bool HbAbstractVkbHostPrivate::popupAnimationInProgress() const
+{
+    HbPopup *popup = qobject_cast<HbPopup *>(mContainerWidget->widgetObject());
+    if (popup) {
+        HbPopupPrivate *popupPrivate = HbPopupPrivate::d_ptr(popup);
+        return popupPrivate->showingInProgress;
+    }
+
+    return false;
+}
+
+/*!
+\internal
+From two given vector, returns the longest along the y-axis that points to the direction defined
+by v1.
+*/
+QPointF HbAbstractVkbHostPrivate::selectLongestVerticalVector(const QPointF &v1, const QPointF &v2) const
+{
+    if (v1.y() * v2.y() < 0) {
+        // They point to opposite directions.
+        return v1;
+    }
+
+    if (qAbs(v2.y()) > qAbs(v1.y())) {
+        // v2 is longer.
+        return v2;
+    }
+
+    return v1;
+}
 
 HbAbstractVkbHost::HbAbstractVkbHost(HbWidget *containerWidget) : d_ptr(new HbAbstractVkbHostPrivate(this, containerWidget))
 {
@@ -617,6 +687,9 @@
 
     setParent(containerWidget);
     HbVkbHost::attachHost(this, containerWidget);
+    if (containerWidget) {
+        containerWidget->setFlag(QGraphicsItem::ItemSendsGeometryChanges);
+    }
 
     connect(&d->mTimeLine, SIGNAL(finished()), this, SLOT(animationFinished()));
     connect(&d->mTimeLine, SIGNAL(valueChanged(qreal)), this, SLOT(animValueChanged(qreal)));
@@ -639,6 +712,9 @@
 
     setParent(containerWidget);
     HbVkbHost::attachHost(this, containerWidget);
+    if (containerWidget) {
+        containerWidget->setFlag(QGraphicsItem::ItemSendsGeometryChanges);
+    }
 
     connect(&d->mTimeLine, SIGNAL(finished()), this, SLOT(animationFinished()));
     connect(&d->mTimeLine, SIGNAL(valueChanged(qreal)), this, SLOT(animValueChanged(qreal)));
@@ -650,6 +726,9 @@
 
     setParent(containerWidget);
     HbVkbHost::attachHost(this, containerWidget);
+    if (containerWidget) {
+        containerWidget->setFlag(QGraphicsItem::ItemSendsGeometryChanges);
+    }
 
     connect(&d->mTimeLine, SIGNAL(finished()), this, SLOT(animationFinished()));
     connect(&d->mTimeLine, SIGNAL(valueChanged(qreal)), this, SLOT(animValueChanged(qreal)));
@@ -701,10 +780,9 @@
         d->mInputMethod = owner;
     }
 
-    if ((d->mKeypadStatus != HbVkbStatusMinimized) && (!vkb || !owner)) {
+    if (!vkb || !owner) {
         // The caller is opening the keypad for the first time but didn't supply
-        // all the needed parameters. Null parameters are ok only if minimized
-        // keypad is reopened.
+        // all the needed parameters.
         return;
     }
 
@@ -717,6 +795,16 @@
         return;
     }
 
+    if (d->popupAnimationInProgress()) {
+        // The container is a popup and it is still running its opening animation.
+        // delay.
+        connect(d->mContainerWidget->widgetObject(), SIGNAL(popupReady()), this, SLOT(stateTransitionCompleted()));
+        d->mPendingCall.vkb = vkb;
+        d->mPendingCall.animationAllowed = animationAllowed;
+        d->mPendingCall.popupOpening = true;
+        return;
+    }
+
     if (!d->mKeypadOperationOngoing) {
         d->mKeypadOperationOngoing = true;
 
@@ -736,7 +824,7 @@
         emit aboutToOpen();
 
         if (d->mContainerWidget && d->mContainerWidget->widgetObject()) {
-            d->mContainerWidget->widgetObject()->setProperty(KPositionManagedByVKB, true );
+            d->mContainerWidget->widgetObject()->setProperty(KPositionManagedByVKB, true);
         }
 
         if (animationAllowed) {
@@ -788,15 +876,16 @@
         // Move the container.
         if (d->mContainerWidget->widgetObject()) {
             d->mContainerWidget->setPos(d->mContainerMovementStartingPoint + (d->mContainerMovementVector * value));
-        }
 
-        // Move keypad
-        if (d->mKeypad) {
-            d->mKeypad->setPos(d->mKeypadMovementStartingPoint + (d->mKeypadMovementVector * value));
+            // Move keypad
+            if (d->mKeypad) {
+                QPointF keypadPos = d->mKeypadMovementStartingPoint + (d->mKeypadMovementVector * value);
+                d->mKeypad->setPos(keypadPos);
+            }
         }
     }
 
-    if (d->mCallback && d->mKeypad) {
+    if (d->mCallback) {
         d->mCallback->keyboardAnimationFrame(HbVirtualKeyboard::HbVkbAnimOpen, value);
     }
 }
@@ -827,23 +916,28 @@
                     textEdit->ensureCursorVisible();
                 }
             }
+            d->ensureVisibilityInsideScrollArea();
+            d->ensureVisibilityInsideVisibleArea();
 
             // Make sure the keypad never steals focus.
             d->mKeypad->setFlag(QGraphicsItem::ItemIsPanel, true);
-            d->mKeypad->setActive(false);
+            if (d->mKeypad->isActive()) {
+                d->mKeypad->setActive(false);
+            }
             emit keypadOpened();
-        } else if (d->mKeypadStatus == HbVkbHost::HbVkbStatusMinimized) {
-            d->mCallback->keyboardMinimized(this);
-            emit keypadClosed();
         } else {
             // It was closed. Hide the keyboard.
             d->mKeypad->hide();
             // Return the container where it was.
             d->mContainerWidget->setPos(d->mOriginalContainerPosition);
-            d->mContainerWidget->widgetObject()->setProperty(KPositionManagedByVKB, false );
+            d->mContainerWidget->widgetObject()->setProperty(KPositionManagedByVKB, false);
             d->mCallback->keyboardClosed(this);
             emit keypadClosed();
-            HbVkbHostBridge::instance()->connectHost(0);
+
+            // Keyboard might be opened again due to pending open call
+            if (d->mKeypadStatus == HbVkbHost::HbVkbStatusClosed) {
+                HbVkbHostBridge::instance()->connectHost(0);
+            }
         }
     }
 }
@@ -907,8 +1001,7 @@
     Q_D(HbAbstractVkbHost);
 
     if ((d->mTimeLine.state() == QTimeLine::Running) ||
-        (d->mKeypadStatus == HbVkbStatusClosed) ||
-        (d->mKeypadStatus == HbVkbStatusMinimized) ||
+        (d->mKeypadStatus == HbVkbStatusClosed) ||        
         !d->mContainerWidget->widgetObject()) {
         return;
     }
@@ -926,15 +1019,11 @@
     Q_D(const HbAbstractVkbHost);
 
     HbMainWindow *mainWindow = d->mainWindow();
-    if (d->mContainerWidget->widgetObject() && mainWindow && d->mCallback) {
+    if (d->mContainerWidget && d->mContainerWidget->widgetObject() && mainWindow && d->mCallback) {
         QSizeF vpSize = d->screenSize();
         QRectF viewport = QRectF(QPointF(0.0, 0.0), QPointF(vpSize.width(), vpSize.height()));
 
-        if (d->mKeypadStatus == HbVkbStatusMinimized) {
-            viewport.setHeight(viewport.height() - d->mCallback->minimizedKeyboardSize().height());
-        } else {
-            viewport.setHeight(viewport.height() - confirmedKeyboardSize().height());
-        }
+        viewport.setHeight(viewport.height() - confirmedKeyboardSize().height());
         return viewport;
     }
 
@@ -949,7 +1038,7 @@
 {
     Q_D(const HbAbstractVkbHost);
 
-    if (d->mCallback && d->mKeypad) {
+    if (d->mCallback) {
         QSizeF kbArea = keyboardArea();
         QSizeF confirmed = d->mCallback->preferredKeyboardSize();
 
@@ -990,8 +1079,7 @@
 {
     Q_D(const HbAbstractVkbHost);
 
-    if (d->mKeypadStatus == HbVkbStatusOpened ||
-        d->mKeypadStatus == HbVkbStatusMinimized) {
+    if (d->mKeypadStatus == HbVkbStatusOpened) {
         return activeViewRect();
     }
 
@@ -1001,55 +1089,6 @@
 /*!
 \reimp
 */
-void HbAbstractVkbHost::minimizeKeypad(bool animationAllowed)
-{
-    Q_D(HbAbstractVkbHost);
-    if (d->mKeypadStatus != HbVkbStatusClosed && !d->mKeypadOperationOngoing) {
-        d->mKeypadOperationOngoing = true;
-
-        if (animationAllowed) {
-            d->minimizeKeypad();
-        } else {
-            d->minimizeKeypadWithoutAnimation();
-        }
-
-        d->mKeypadOperationOngoing = false;
-    }
-}
-
-/*!
-\reimp
-*/
-void HbAbstractVkbHost::openMinimizedKeypad(HbVirtualKeyboard *vkb, HbInputMethod *owner)
-{
-    Q_D(HbAbstractVkbHost);
-    d->mInputMethod = owner;
-
-    if (!d->mKeypadOperationOngoing) {
-        d->mKeypadOperationOngoing = true;
-
-        if (d->mCallback != vkb || !d->mKeypad) {
-            // This keypad is opened for the first time or it was opened before but some other keypad
-            // was opened in between.
-            d->mCallback = vkb;
-            d->mKeypad = vkb->asGraphicsWidget();
-        }
-
-        if (!d->mKeypad) {
-            // Keyboard widget creation failed for some reason, can't go on.
-            d->mCallback = 0;
-            return;
-        }
-
-        d->openMinimizedKeypad();
-        d->connectSignals();
-        d->mKeypadOperationOngoing = false;
-    }
-}
-
-/*!
-\reimp
-*/
 HbVkbHost::HbVkbStatus HbAbstractVkbHost::keypadStatusBeforeOrientationChange() const
 {
     Q_D(const HbAbstractVkbHost);
@@ -1057,23 +1096,12 @@
 }
 
 /*!
-This slot is called when active HbView changes.
+\deprecated HbAbstractVkbHost::currentViewChanged(HbView *view)
+    is deprecated.
 */
 void HbAbstractVkbHost::currentViewChanged(HbView *view)
 {
-    Q_D(HbAbstractVkbHost);
-
-    if (view != d->mContainerWidget->widgetObject()) {
-        if (d->mTimeLine.state() == QTimeLine::Running) {
-            d->cancelAnimationAndHideVkbWidget();
-            if (d->mCallback) {
-                d->mCallback->keyboardClosed(this);
-            }
-        } else if (d->mKeypadStatus != HbVkbStatusClosed) {
-            d->closeKeypadWithoutAnimation();
-            emit keypadClosed();
-        }
-    }
+    Q_UNUSED(view);
 }
 
 /*!
@@ -1110,7 +1138,11 @@
 {
     Q_D(HbAbstractVkbHost);
 
-    disconnect(HbVkbHostBridge::instance(), SIGNAL(stateTransitionCompleted()), this, SLOT(stateTransitionCompleted()));
+    if (!d->mPendingCall.popupOpening) {
+        disconnect(HbVkbHostBridge::instance(), SIGNAL(stateTransitionCompleted()), this, SLOT(stateTransitionCompleted()));
+    } else {
+        disconnect(d->mContainerWidget->widgetObject(), SIGNAL(popupReady()), this, SLOT(stateTransitionCompleted()));
+    }
 
     if (d->mPendingCall.vkb) {
         // There was an open call pending. Do it now.
@@ -1120,4 +1152,26 @@
     }
 }
 
+/*!
+This slot is called when change in active HbView starts.
+*/
+void HbAbstractVkbHost::aboutToChangeView(HbView *oldView, HbView *newView)
+{
+    Q_D(HbAbstractVkbHost);
+
+    if (oldView != newView) {
+        if (d->mTimeLine.state() == QTimeLine::Running) {
+            d->cancelAnimationAndHideVkbWidget();
+            if (d->mCallback) {
+                d->mCallback->keyboardClosed(this);
+            }
+        } else if (d->mKeypadStatus != HbVkbStatusClosed) {
+            d->closeKeypadWithoutAnimation();
+            emit keypadClosed();
+        }
+    }
+}
+
+#include "moc_hbabstractvkbhost.cpp"
+
 // End of file