[meego-commits] 5584: Changes to Trunk:Testing/meegotouch-inputmethodkeyboard

Kaitlin Rupert kaitlin.rupert at intel.com
Mon Jul 12 18:31:52 UTC 2010


Hi,
I have made the following changes to meegotouch-inputmethodkeyboard in project Trunk:Testing. Please review and accept ASAP.

Thank You,
Kaitlin Rupert

[This message was auto-generated]

---

Request #5584:

  submit:   devel:nokia:trunk/meegotouch-inputmethodkeyboard(r3) -> Trunk:Testing/meegotouch-inputmethodkeyboard


Message:
    Update to release tag 0.4.8-2.  This update is dependent on the libmeegotouch u
pdate.

State:   new          2010-07-12T06:26:52 krupert
Comment: None



changes files:
--------------
--- meegotouch-inputmethodkeyboard.changes
+++ meegotouch-inputmethodkeyboard.changes
@@ -0,0 +1,3 @@
+* Thu Jul 08 2010 Kaitlin Rupert <kaitlin.rupert at intel.com> - 0.4.8
+- Update to release tag 0.4.8-2
+

old:
----
  meegotouch-inputmethodkeyboard-0.4.2.1.tar.bz2

new:
----
  meegotouch-inputmethodkeyboard-0.4.8.tar.bz2

spec files:
-----------
--- meegotouch-inputmethodkeyboard.spec
+++ meegotouch-inputmethodkeyboard.spec
@@ -1,13 +1,13 @@
 # 
 # Do not Edit! Generated by:
-# spectacle version 0.17
+# spectacle version 0.18
 # 
 # >> macros
 # << macros
 
 Name:       meegotouch-inputmethodkeyboard
 Summary:    MeeGo Virtual Keyboard
-Version:    0.4.2.1
+Version:    0.4.8
 Release:    1
 Group:      System/GUI/Other
 License:    LGPL v2.1
@@ -24,10 +24,9 @@
 BuildRequires:  pkgconfig(QtNetwork)
 BuildRequires:  pkgconfig(QtGui)
 BuildRequires:  pkgconfig(meegotouch)
-BuildRequires:  meegotouch-inputmethodframework-devel
-BuildRequires:  meegotouch-inputmethodengine-devel
-BuildRequires:  meegotouch-feedback-devel
-BuildRequires:  meegotouch-feedbackreactionmaps-devel
+BuildRequires:  pkgconfig(MeegoImFramework)
+BuildRequires:  pkgconfig(MeegoImEngine)
+BuildRequires:  pkgconfig(meegotouch-feedbackreactionmaps)
 Provides:   duikeyboard >= 0.4.0
 Provides:   meegokeyboard > 0.4.2
 Obsoletes:   duikeyboard < 0.4.0
@@ -105,15 +104,17 @@
 %{_libdir}/meego-im-plugins/*.so
 %{_libdir}/qt4/plugins/tasfixtures/libfixture_virtualkeyboard.so
 %{_datadir}/gconf/schemas/meego-keyboard.schemas
-%{_datadir}/meegotouch/virtual-keyboard/*
+%{_datadir}/meegotouch/virtual-keyboard
+%{_datadir}/l10n/meegotouch/virtual-keyboard.qm
+%{_datadir}/themes/base/meegotouch/libmeego-keyboard/style/libmeego-keyboard.css
+%{_datadir}/themes/base/meegotouch/svg/meegotouch-keyboard.svg
 # << files
 
 %files devel
 %defattr(-,root,root,-)
 # >> files devel
-%{_includedir}/meego-keyboard/*
-%{_libdir}/meego-keyboard-tests/*
-%{_datadir}/meego-keyboard-tests/*
+%{_includedir}/meego-keyboard
+%{_libdir}/meego-keyboard-tests
+%{_datadir}/meego-keyboard-tests
 # << files devel
 
-

other changes:
--------------

++++++ meegotouch-inputmethodkeyboard-0.4.2.1.tar.bz2 -> meegotouch-inputmethodkeyboard-0.4.8.tar.bz2
--- debian/api
+++ debian/api
+interface: libmeego-keyboard
+type: library
+scope: Platform
+state: unstable
+libs-pkg: meego-keyboard
+dev-pkg: meego-keyboard-dev
--- debian/changelog
+++ debian/changelog
@@ -1,3 +1,66 @@
+meego-keyboard (0.4.8-2) unstable; urgency=low
+
+  * Hide the opened settings dialog when its parent item is hidden
+
+ -- Ning Chi <ext-chi.ning at nokia.com>  Sat, 03 Jul 2010 15:39:20 +0300
+
+meego-keyboard (0.4.8-1) unstable; urgency=low
+
+  * Reduced the number of selected default languages
+  * Popup to appear immediately when button is pressed
+  * Fixed copy/paste button styling
+  * Layouts to use endonyms for language names
+
+ -- Pekka Vuorela <pekka.ta.vuorela at nokia.com>  Fri, 02 Jul 2010 12:34:40 +0300
+
+meego-keyboard (0.4.7-1) unstable; urgency=low
+
+  * Fixed vkb crashing when en_gb is not selected to be used
+  * Better implementation for relocation workaround
+
+ -- Pekka Vuorela <pekka.ta.vuorela at nokia.com>  Thu, 01 Jul 2010 10:15:00 +0300
+
+meego-keyboard (0.4.6-1) unstable; urgency=low
+
+  * Replaced layoutmenu with framework settings
+
+ -- Pekka Vuorela <pekka.ta.vuorela at nokia.com>  Tue, 29 Jun 2010 11:47:12 +0300
+
+meego-keyboard (0.4.5-1) unstable; urgency=low
+
+  * Symbol view is toggled by clicking sym button
+  * Fixes: NB#173809, New: custom autorepeat setup
+  * Fixes: NB#168702, commit preedit in vkb->hwkbd transition
+  * Fixes delete on hardware keyboard
+  * Changes: correct language code in xml file and layoutmanager
+  * Changes: support icon_id for custom toolbar
+  * Implemented SWP#TINME-790, SWP#TINME-941, SWP#TINME-835, SWP#TINME-967, SWP#TINME-908 
+
+ -- Pekka Vuorela <pekka.ta.vuorela at nokia.com>  Wed, 23 Jun 2010 11:13:18 +0300
+
+meego-keyboard (0.4.4-1) unstable; urgency=low
+
+  * Uses toolbar API from im framework
+  * Uses MeegoImEngine instead of Dui prefixed
+  * Implemented direct mode gesture
+  * Implemented direct mode for hardware keyboard
+  * Fixes: NB#170644, hwkbd: send release events for all press events
+  * Fixes: NB#161309, Keyboard sends Key-Events during "swipe-gesture"
+  * Dead keys to stay pressed when selected
+
+ -- Pekka Vuorela <pekka.ta.vuorela at nokia.com>  Wed, 16 Jun 2010 17:37:39 +0300
+
+meego-keyboard (0.4.3-1) unstable; urgency=low
+
+  * Implemented multitouch support (not yet enabled as default)
+  * Better swipe gesture recognition
+  * Error correction disabled as default
+  * Fixed error correction candidate width
+  * Separate package for fixtures required by Matti
+  * Misc fixes
+
+ -- Pekka Vuorela <pekka.ta.vuorela at nokia.com>  Thu, 10 Jun 2010 13:54:59 +0300
+
 meego-keyboard (0.4.2-1) unstable; urgency=low
 
   * Fixed autocapitalization for plain qt apps
--- debian/control
+++ debian/control
@@ -2,7 +2,7 @@
 Section: libs
 Priority: extra
 Maintainer: Mohammad Anwari <Mohammad.Anwari at nokia.com> 
-Build-Depends: debhelper (>= 5), libqt4-dev (>= 4.6) | libqt4-maemo5-dev (>= 4.6), doxygen, libduiimenginewords-dev (>= 0.1.8), libmeegoimframework-dev (>= 0.19.2~1), libmeegotouch-dev (>= 0.20), libmeegoreactionmap-dev (>= 0.14.0-1)
+Build-Depends: debhelper (>= 5), libqt4-dev (>= 4.6) | libqt4-maemo5-dev (>= 4.6), doxygen, libmeegoimenginewords-dev (>= 0.1.13), libmeegoimframework-dev (>= 0.19.6), libmeegotouch-dev (>= 0.20), libmeegoreactionmap-dev (>= 0.14.0-1)
 Standards-Version: 3.7.2
 
 Package: meego-keyboard
@@ -27,9 +27,15 @@
 
 Package: meego-keyboard-tests
 Architecture: any
-Depends:  testrunner, libduiimengine-dummydriver, meego-keyboard (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends}
+Depends:  testrunner, libmeegoimengine-dummydriver, meego-keyboard (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends}
 XB-Maemo-CI-Packages: meego-keyboard 
 XB-Maemo-CI-Stage: fast, staging
 Description: MeegoTouch Input Method Keyboard unit test suite 
  MeegoTouch Keyboard unit test suite.
 
+Package: meego-keyboard-fixtures
+Architecture: any
+Depends:  meego-keyboard (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends}
+XB-Maemo-CI-Packages: meego-keyboard
+XB-Maemo-CI-Stage: fast, staging
+Description: MeegoTouch Input Method Keyboard Fixtures used by matti
--- debian/meego-keyboard-fixtures.install
+++ debian/meego-keyboard-fixtures.install
+usr/lib/qt4/plugins/tasfixtures/
--- debian/meego-keyboard-tests.install
+++ debian/meego-keyboard-tests.install
@@ -1,3 +1,2 @@
 usr/share/meego-keyboard-tests/
 usr/lib/meego-keyboard-tests/
-usr/lib/qt4/plugins/tasfixtures/
--- debian/meego-keyboard.install
+++ debian/meego-keyboard.install
@@ -1,3 +1,5 @@
 usr/lib/meego-im-plugins/
 usr/share/meegotouch/virtual-keyboard
+usr/share/themes/base
 usr/share/gconf
+usr/share/l10n/meegotouch/virtual-keyboard.qm
--- doc/doc.pri
+++ doc/doc.pri
@@ -1,13 +1,14 @@
 DOXYGEN_BIN=doxygen
 
-QMAKE_EXTRA_UNIX_TARGETS += doc
+QMAKE_EXTRA_TARGETS += doc
 doc.target = doc
+
 isEmpty(DOXYGEN_BIN) {
     doc.commands = @echo "Unable to detect doxygen in PATH"
 } else {
   doc.commands = mkdir -p $${OUT_PWD}/doc/html/ ;
-  doc.commands+= ( cat $${IN_PWD}/mdoxy.cfg.in | \
-      perl -pe \"s:\@M_SRC_DIR\@:$${IN_PWD}:\" > $${OUT_PWD}/doc/mdoxy.cfg );
+  doc.commands += ( cat $${IN_PWD}/mdoxy.cfg.in | \
+      perl -pe \"s:\\@M_SRC_DIR\\@:$${IN_PWD}:\" > $${OUT_PWD}/doc/mdoxy.cfg );
 
   doc.commands+= ( cd doc ; $${DOXYGEN_BIN} mdoxy.cfg );
   doc.commands+= ( cd doc ; $${IN_PWD}/xmlize.pl );
--- fixture_virtualkeyboard/fixture_virtualkeyboard.cpp
+++ fixture_virtualkeyboard/fixture_virtualkeyboard.cpp
@@ -35,7 +35,9 @@
 FixtureVirtualKeyboard::~FixtureVirtualKeyboard()
 {
 }
-
+/*!
+ *  \brief execute is called when implementing a fixture from ruby matti
+ */
 bool FixtureVirtualKeyboard::execute(void *objectInstance, 
                                      const QString &actionName,
                                      const QHash<QString, QString> &parameters,
@@ -49,7 +51,7 @@
     }
 
     QGraphicsItem *gItem = (QGraphicsItem*)objectInstance;
-    const SingleWidgetButtonArea* const widget =  static_cast<SingleWidgetButtonArea*>((QGraphicsWidget*)gItem);
+    const SingleWidgetButtonArea *const widget =  qgraphicsitem_cast<SingleWidgetButtonArea *>(gItem);
 
     if (!widget) {
         stdOut = "This fixture can be called for Keybuttonarea only!";
@@ -63,6 +65,13 @@
         }
     }
 
+    else if (actionName == "isAccurateMode") {
+
+        stdOut = widget->isAccurateMode() ? "true": "false";
+
+        return true;
+    }
+
     const IKeyButton *button = 0;
     const QString key = QString(parameters.value("key"));
 
--- m-keyboard.pro
+++ m-keyboard.pro
@@ -4,6 +4,7 @@
 SUBDIRS = m-keyboard \
       unit_test \
       fixture_virtualkeyboard \
+      translations \
 
 include (doc/doc.pri)
 
--- m-keyboard/common/common.pri
+++ m-keyboard/common/common.pri
@@ -11,14 +11,12 @@
     $$COMMON_DIR/layoutdata.h \
     $$COMMON_DIR/layoutsmanager.h \
     $$COMMON_DIR/limitedtimer.h \
-    $$COMMON_DIR/toolbardata.h \
-    $$COMMON_DIR/toolbarwidget.h \
-    $$COMMON_DIR/toolbarmanager.h \
     $$COMMON_DIR/vkbdatakey.h \
     $$COMMON_DIR/mxkb.h \
     $$COMMON_DIR/mhardwarekeyboard.h \
     $$COMMON_DIR/hwkbcharloops.h \
     $$COMMON_DIR/hwkbcharloopsmanager.h \
+    $$COMMON_DIR/keyeventhandler.h \
 
 SOURCES += \
     $$COMMON_DIR/keyboarddata.cpp\
@@ -26,14 +24,12 @@
     $$COMMON_DIR/layoutdata.cpp\
     $$COMMON_DIR/layoutsmanager.cpp\
     $$COMMON_DIR/limitedtimer.cpp\
-    $$COMMON_DIR/toolbardata.cpp\
-    $$COMMON_DIR/toolbarwidget.cpp \
-    $$COMMON_DIR/toolbarmanager.cpp\
     $$COMMON_DIR/vkbdatakey.cpp\
     $$COMMON_DIR/mxkb.cpp \
     $$COMMON_DIR/mhardwarekeyboard.cpp \
     $$COMMON_DIR/hwkbcharloops.cpp \
     $$COMMON_DIR/hwkbcharloopsmanager.cpp \
+    $$COMMON_DIR/keyeventhandler.cpp \
 
 INCLUDEPATH += $$COMMON_DIR
 DEPENDPATH += $$COMMON_DIR
--- m-keyboard/common/hwkbcharloopsmanager.cpp
+++ m-keyboard/common/hwkbcharloopsmanager.cpp
@@ -203,8 +203,8 @@
     const QString name = element.attribute(HWKBTagName);
     if (charLoops.contains(language)) {
         //if already contains, overwrite.
-        params.currentCharLoop->loops.clear();
         params.currentCharLoop = charLoops[language];
+        params.currentCharLoop->loops.clear();
     } else {
         params.currentCharLoop = new HwKbCharacterLoops(language, name);
         charLoops.insert(language, params.currentCharLoop);
--- m-keyboard/common/keyboarddata.cpp
+++ m-keyboard/common/keyboarddata.cpp
@@ -472,13 +472,3 @@
         result = KeyBinding::ActionInsert;
     return result;
 }
-
-bool KeyboardData::isLanguageLongFormat(const QString &language)
-{
-    return (language.length() > 2 && language.at(2) == '_');
-}
-
-QString KeyboardData::convertLanguageToShortFormat(const QString &language)
-{
-    return language.left(2).toLower();
-}
--- m-keyboard/common/keyboarddata.h
+++ m-keyboard/common/keyboarddata.h
@@ -75,15 +75,6 @@
     const LayoutData *layout(LayoutData::LayoutType type, M::Orientation orientation,
                              bool portraitFallback = true) const;
 
-    /*! \brief Determines whether given language is of "en_GB" style as opposed to "en".
-     */
-    static bool isLanguageLongFormat(const QString &language);
-
-    /*!
-     * \brief Converts "en_GB" style language string to shorter "en" style.
-     */
-    static QString convertLanguageToShortFormat(const QString &language);
-
 private:
     /*!
     * \brief Implements keyboard loading
--- m-keyboard/common/keyeventhandler.cpp
+++ m-keyboard/common/keyeventhandler.cpp
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+
+#include "keyeventhandler.h"
+#include "keyevent.h"
+#include "ikeybutton.h"
+#include "keybuttonarea.h"
+
+#include <QDebug>
+
+KeyEventHandler::KeyEventHandler(QObject *parent)
+    : QObject(parent),
+      shiftHeldDown(false),
+      ignoreShiftClick(false)
+{
+}
+
+void KeyEventHandler::addEventSource(KeyButtonArea *eventSource)
+{
+    bool ok = false;
+
+    ok = connect(eventSource, SIGNAL(keyPressed(const IKeyButton *, const QString &, bool)),
+                 this, SLOT(handleKeyPress(const IKeyButton *, const QString &, bool)));
+    Q_ASSERT(ok);
+
+    ok = connect(eventSource, SIGNAL(keyReleased(const IKeyButton *, const QString &, bool)),
+                 this, SLOT(handleKeyRelease(const IKeyButton *, const QString &, bool)));
+    Q_ASSERT(ok);
+
+    ok = connect(eventSource, SIGNAL(keyClicked(const IKeyButton *, const QString &, bool)),
+                 this, SLOT(handleKeyClick(const IKeyButton *, const QString &, bool)));
+    Q_ASSERT(ok);
+}
+
+void KeyEventHandler::handleKeyPress(const IKeyButton *key, const QString &accent, bool upperCase)
+{
+    const KeyEvent event = keyToKeyEvent(*key, QEvent::KeyPress, accent, upperCase);
+    emit keyPressed(event);
+
+    if (event.qtKey() == Qt::Key_Shift) {
+        shiftHeldDown = true;
+        emit shiftPressed(true);
+    } else if (shiftHeldDown) {
+        ignoreShiftClick = true;
+    }
+}
+
+void KeyEventHandler::handleKeyRelease(const IKeyButton *key, const QString &accent, bool upperCase)
+{
+    const KeyEvent event = keyToKeyEvent(*key, QEvent::KeyRelease, accent, upperCase);
+
+    emit keyReleased(event);
+
+    if (event.qtKey() == Qt::Key_Shift && shiftHeldDown) {
+        shiftHeldDown = false;
+        emit shiftPressed(false);
+    }
+}
+
+void KeyEventHandler::handleKeyClick(const IKeyButton *key, const QString &accent, bool upperCase)
+{
+    const KeyEvent event = keyToKeyEvent(*key, QEvent::KeyRelease, accent, upperCase);
+
+    if (event.qtKey() == Qt::Key_Shift && ignoreShiftClick) {
+        ignoreShiftClick = false; // ignore this event
+    } else {
+        emit keyClicked(event);
+    }
+}
+
+KeyEvent KeyEventHandler::keyToKeyEvent(const IKeyButton &key, QKeyEvent::Type eventType,
+                                         const QString &accent, bool upperCase) const
+{
+    KeyEvent event;
+
+    if (accent.isEmpty()) {
+        event = key.key().toKeyEvent(eventType, upperCase);
+    } else {
+        event = key.key().toKeyEvent(eventType, accent.at(0), upperCase);
+    }
+
+    return event;
+}
+
--- m-keyboard/common/keyeventhandler.h
+++ m-keyboard/common/keyeventhandler.h
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+
+#ifndef KEYEVENTHANDLER_H
+#define KEYEVENTHANDLER_H
+
+#include <QObject>
+#include <QKeyEvent>
+
+class KeyButtonArea;
+class KeyEvent;
+class IKeyButton;
+class QString;
+
+/*!
+ * \class KeyEventHandler
+ * \brief Logic class to convert signals generated by buttons from
+ * raw information into KeyEvent. Also filters clicks from shift button.
+ */
+class KeyEventHandler : public QObject
+{
+    Q_OBJECT
+
+public:
+    //! Constructs new instance of KeyEventHandler with given \a parent
+    explicit KeyEventHandler(QObject *parent = 0);
+
+    //! Connects this object to signals from given \a source
+    void addEventSource(KeyButtonArea *eventSource);
+
+signals:
+    /*!
+     * \brief Emitted when key is pressed
+     *
+     * Note that this happens also when user keeps finger down/mouse
+     * button pressed and moves over another key (event is about the new key)
+     * \param event key event
+     */
+    void keyPressed(const KeyEvent &event);
+
+    /*!
+     * \brief Emitted when key is released
+     *
+     * Note that this happens also when user keeps finger down/mouse
+     * button pressed and moves over another key (event is about the old key)
+     * \param event key event
+     */
+    void keyReleased(const KeyEvent &event);
+
+    /*!
+     * \brief Emitted when user releases mouse button/lifts finger
+     *
+     * Except when done on a dead key
+     * \param event key event
+     */
+    void keyClicked(const KeyEvent &event);
+
+    /*!
+     * \brief Emitted when shift key is pressed or released
+     * \param state Contains true is key is pressed
+     */
+    void shiftPressed(bool state);
+
+private slots:
+    /*!
+     * \brief Generates KeyEvent for given \a key and emits keyPressed
+     */
+    void handleKeyPress(const IKeyButton *key, const QString &accent, bool upperCase);
+
+    /*!
+     * \brief Generates KeyEvent for given \a key and emits keyReleased
+     */
+    void handleKeyRelease(const IKeyButton *key, const QString &accent, bool upperCase);
+
+    /*!
+     * \brief Generates KeyEvent for given \a key and emits keyClicked
+     */
+    void handleKeyClick(const IKeyButton *key, const QString &accent, bool upperCase);
+
+private:
+    //! Turn key button into a KeyEvent, considering current accent and modifier state
+    KeyEvent keyToKeyEvent(const IKeyButton &key, QKeyEvent::Type eventType,
+                           const QString &accent, bool upperCase) const;
+
+private:
+    //! Keeps track of shift up/down status.
+    bool shiftHeldDown;
+
+    //! When this is set true the next shift click is ignored.
+    bool ignoreShiftClick;
+
+#ifdef UNIT_TEST
+    friend class Ut_KeyEventHandler;
+#endif
+};
+
+#endif
+
--- m-keyboard/common/layoutdata.cpp
+++ m-keyboard/common/layoutdata.cpp
@@ -30,6 +30,8 @@
 }
 
 LayoutData::LayoutData()
+    : layoutOrientation(M::Landscape),
+      layoutType(General)
 {
 }
 
@@ -66,7 +68,10 @@
 LayoutSection::LayoutSection()
     : m_maxColumns(0),
       maxRows(0),
-      sectionName("")
+      movable(false),
+      m_verticalAlignment(Qt::AlignVCenter),
+      m_horizontalAlignment(Qt::AlignHCenter),
+      sectionType(Sloppy)
 {
 }
 
--- m-keyboard/common/layoutsmanager.cpp
+++ m-keyboard/common/layoutsmanager.cpp
@@ -29,7 +29,7 @@
     const QString SystemDisplayLanguage("/meegotouch/i18n/language");
     const QString DefaultNumberFormat("latin");
     const QString LayoutFileExtension(".xml");
-    const QString FallbackLanguage("en");
+    const QString FallbackLanguage("en_gb");
     const QString NumberKeyboardFileArabic("number_ar.xml");
     const QString NumberKeyboardFileLatin("number.xml");
     const QString PhoneNumberKeyboardFileArabic("phonenumber_ar.xml");
@@ -163,11 +163,7 @@
     bool loaded = keyboard->loadNokiaKeyboard(language + LayoutFileExtension);
 
     if (!loaded) {
-        // In case of "en_GB" we'll try to load en.xml.
-        if (KeyboardData::isLanguageLongFormat(language)) {
-            loaded = keyboard->loadNokiaKeyboard(
-                         KeyboardData::convertLanguageToShortFormat(language) + LayoutFileExtension);
-        }
+        loaded = keyboard->loadNokiaKeyboard(QString(language.toLower() + LayoutFileExtension));
     }
 
     if (!loaded) {
@@ -177,9 +173,9 @@
     }
 
     // Make sure entry for language exists. Create if it doesn't.
-    kbIterator = keyboards.find(language);
+    kbIterator = keyboards.find(language.toLower());
     if (kbIterator == keyboards.end()) {
-        kbIterator = keyboards.insert(language, 0);
+        kbIterator = keyboards.insert(language.toLower(), 0);
     }
 
     if (*kbIterator) {
@@ -243,7 +239,7 @@
 
         foreach(QString language, newLanguages) {
             // Existing languages are not reloaded.
-            if (!keyboards.contains(language)) {
+            if (!keyboards.contains(language.toLower())) {
                 // Add new language
                 if (!loadLanguage(language)) {
                     qWarning() << __PRETTY_FUNCTION__
@@ -281,8 +277,6 @@
     bool val = false;
 
     QString shortFormatLanguage = language;
-    if (KeyboardData::isLanguageLongFormat(language))
-        shortFormatLanguage = KeyboardData::convertLanguageToShortFormat(language);
     if (shortFormatLanguage == "ru"    // Russian
             || shortFormatLanguage == "pl" // Polish
             || shortFormatLanguage == "bg" // Bulgaria
--- m-keyboard/common/mhardwarekeyboard.cpp
+++ m-keyboard/common/mhardwarekeyboard.cpp
@@ -28,6 +28,8 @@
 #undef KeyPress
 #undef KeyRelease
 #include <X11/XKBlib.h>
+#define XK_MISCELLANY
+#include <X11/keysymdef.h>
 
 #define ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
 
@@ -39,6 +41,9 @@
     const unsigned int SymModifierMask = Mod4Mask;
     const unsigned int FnModifierMask = Mod5Mask;
     const unsigned int longPressTime = 600; // in milliseconds
+
+    const unsigned short RepeatDelay(660);   // in milliseconds
+    const unsigned short RepeatInterval(25); // in milliseconds
 };
 
 MHardwareKeyboard::MHardwareKeyboard(MInputContextConnection& icConnection, QObject *parent)
@@ -96,51 +101,113 @@
     return currentKeyboardType;
 }
 
-void MHardwareKeyboard::focusChanged(bool focusIn)
+
+void MHardwareKeyboard::toggleCustomAutoRepeat(const bool enable)
 {
-    qDebug() << __PRETTY_FUNCTION__ << ":" << focusIn;
-    if (focusIn) {
-        // TODO: this is a temporary hack until we have proper autorepeat setup
-        XAutoRepeatOff(QX11Info::display());
-
-        shiftShiftCapsLock = false;
-        shiftsPressed = 0;
-        pressedKeys.clear();
-        autoCaps = false;
+    XkbDescPtr description(XkbAllocKeyboard());
+    if (!description) {
+        qWarning() << "Unable to allocate Xkb keyboard description for autorepeat setup.";
+        return;
+    }
+
+    const unsigned int neededControls(XkbRepeatKeysMask | XkbPerKeyRepeatMask);
+    if (Success != XkbGetControls(QX11Info::display(), neededControls, description)) {
+        qWarning() << "Failure to query Xkb server controls for autorepeat setup.";
+        XkbFreeKeyboard(description, 0, True);
+        return;
+    }
+
+    if (!description->ctrls) {
+        qWarning() << "Unable to query Xkb server controls for autorepeat setup.";
+        XkbFreeKeyboard(description, 0, True);
+        return;
+    }
+
+    if (False == XkbChangeEnabledControls(QX11Info::display(), XkbUseCoreKbd,
+                                          XkbRepeatKeysMask, XkbRepeatKeysMask)) {
+        qWarning() << "Unable to enable controls for autorepeat.";
+        XkbFreeKeyboard(description, 0, True);
+        return;
+    }
+
+    description->ctrls->repeat_delay = RepeatDelay;
+    description->ctrls->repeat_interval = RepeatInterval;
+
+    std::fill(description->ctrls->per_key_repeat,
+              description->ctrls->per_key_repeat + XkbPerKeyBitArraySize, enable ? 0 : 0xff);
 
-        // We reset state without using latch/lockModifiers in order to force notification
-        // (to make sure whoever is listening is in sync with us).
-        currentLatchedMods = 0;
-        mXkb.latchModifiers(ShiftMask | FnModifierMask, 0);
-        emit modifierStateChanged(Qt::ShiftModifier, ModifierClearState);
-        switch (currentKeyboardType) {
-        case M::NumberContentType:
-        case M::PhoneNumberContentType:
-            // With number and phone number content type Fn must be permanently locked
-            currentLockedMods = FnModifierMask;
-            mXkb.lockModifiers(FnModifierMask, FnModifierMask);
-            emit modifierStateChanged(FnLevelModifier, ModifierLockedState);
-            stateTransitionsDisabled = true;
-            break;
-        default:
-            stateTransitionsDisabled = false;
-            // clear locked modifiers for other keyboard types.
-            currentLockedMods = 0;
-            mXkb.lockModifiers(LockMask | FnModifierMask, 0);
-            emit modifierStateChanged(FnLevelModifier, ModifierClearState);
-            break;
+    if (enable) {
+        static const KeySym repeatableKeys[] = { XK_BackSpace, XK_Left, XK_Up, XK_Right, XK_Down };
+
+        for (unsigned int i = 0; i < ELEMENTS(repeatableKeys); ++i) {
+            const KeyCode repeatableKeyCode(XKeysymToKeycode(QX11Info::display(), repeatableKeys[i]));
+            if (repeatableKeyCode) {
+                description->ctrls->per_key_repeat[repeatableKeyCode >> 3] |= 1 << (repeatableKeyCode & 7);
+            } else {
+                qWarning() << "Unable to make keysym" << repeatableKeys[i] << "repeatable: no keycode found.";
+            }
         }
+    }
 
-        inputContextConnection.setRedirectKeys(true);
-    } else {
-        inputContextConnection.setRedirectKeys(false);
-        // Unlock and unlatch everything.  If for example non-Qt X application gets focus
-        // after this focus out, there is no way to unlock Lock modifier using the
-        // physical keyboard.  So better clear the state a well as we can.
-        lockModifiers(LockMask | FnModifierMask, 0);
-        latchModifiers(ShiftMask | FnModifierMask, 0);
-        XAutoRepeatOn(QX11Info::display());
+    if (False == XkbSetControls(QX11Info::display(), neededControls, description)) {
+        qWarning() << "Unable to set Xkb server controls for autorepeat setup.";
     }
+
+    XkbFreeKeyboard(description, 0, True);
+
+    inputContextConnection.setDetectableAutoRepeat(enable);
+}
+
+void MHardwareKeyboard::enable()
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    toggleCustomAutoRepeat(true);
+
+    shiftShiftCapsLock = false;
+    shiftsPressed = 0;
+    pressedKeys.clear();
+    autoCaps = false;
+
+    // We reset state without using latch/lockModifiers in order to force notification
+    // (to make sure whoever is listening is in sync with us).
+    currentLatchedMods = 0;
+    mXkb.latchModifiers(ShiftMask | FnModifierMask, 0);
+    emit modifierStateChanged(Qt::ShiftModifier, ModifierClearState);
+    switch (currentKeyboardType) {
+    case M::NumberContentType:
+    case M::PhoneNumberContentType:
+        // With number and phone number content type Fn must be permanently locked
+        currentLockedMods = FnModifierMask;
+        mXkb.lockModifiers(FnModifierMask, FnModifierMask);
+        emit modifierStateChanged(FnLevelModifier, ModifierLockedState);
+        stateTransitionsDisabled = true;
+        break;
+    default:
+        stateTransitionsDisabled = false;
+        // clear locked modifiers for other keyboard types.
+        currentLockedMods = 0;
+        mXkb.lockModifiers(LockMask | FnModifierMask, 0);
+        emit modifierStateChanged(FnLevelModifier, ModifierClearState);
+        break;
+    }
+
+    inputContextConnection.setRedirectKeys(true);
+}
+
+
+void MHardwareKeyboard::disable()
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    inputContextConnection.setRedirectKeys(false);
+    // Unlock and unlatch everything.  If for example non-Qt X application gets focus
+    // after this focus out, there is no way to unlock Lock modifier using the
+    // physical keyboard.  So better clear the state a well as we can.
+    lockModifiers(LockMask | FnModifierMask, 0);
+    latchModifiers(ShiftMask | FnModifierMask, 0);
+
+    toggleCustomAutoRepeat(false);
 }
 
 
@@ -280,6 +347,18 @@
                       keyCode == Qt::Key_Delete ? "\b" : text, autoRepeat, count));
         eaten = true;
     }
+    // Delete is generated by pressing Shift+Backspace.  This results to an event with
+    // shift modifier and Delete key code, which can be interpreted as the cut shortcut
+    // even though user intended just delete action.  Shift+Del shouldn't be cut shortcut
+    // on our platform but Qt is not going to change that, so we work around the problem
+    // by removing the shift modifier.
+    else if (shiftsPressed && (keyCode == Qt::Key_Delete)) {
+        inputContextConnection.sendKeyEvent(
+            QKeyEvent(QEvent::KeyPress, keyCode,
+                      modifiers & ~Qt::KeyboardModifiers(Qt::ShiftModifier),
+                      text, autoRepeat, count));
+        eaten = true;
+    }
 
     // Relatch modifiers, X unlatches them on press but we want to unlatch on release
     // (and not even always on release, e.g. with Sym+aaab we unlatch only after the
@@ -296,11 +375,23 @@
                                          quint32 nativeScanCode, quint32 nativeModifiers)
 {
     bool eaten = false;
+    const bool keyWasPressed(pressedKeys.contains(nativeScanCode));
 
-    if (nativeModifiers & SymModifierMask) {
+    // Relock modifiers; X seems to unlock Fn automatically on Fn release, which is not
+    // desired at least with [phone] number content type.
+    if (currentLockedMods) {
+        mXkb.lockModifiers(currentLockedMods, currentLockedMods);
+    }
+
+    if (keyWasPressed && (nativeModifiers & SymModifierMask)) {
         eaten = handleReleaseWithSymModifier(keyCode, text);
     }
 
+    const Qt::KeyboardModifiers filteredModifiers(
+        ((currentLatchedMods & ShiftMask) && !shiftsPressed)
+        ? (modifiers & ~Qt::KeyboardModifiers(Qt::ShiftModifier))
+        : modifiers);
+
     if (keyCode == Qt::Key_Shift) {
         if (!shiftShiftCapsLock) {
             handleCyclableModifierRelease(Qt::Key_Shift, LockMask, ShiftMask, FnModifierMask,
@@ -313,18 +404,13 @@
         handleCyclableModifierRelease(FnLevelKey, FnModifierMask, FnModifierMask, LockMask,
                                       ShiftMask);
     } else if (!eaten && !passKeyOnPress(keyCode, text, nativeScanCode)) {
-        const bool keyWasPressed(pressedKeys.contains(nativeScanCode));
         if (keyWasPressed) {
             inputContextConnection.sendKeyEvent(
-                QKeyEvent(QEvent::KeyPress, keyCode,
-                          ((currentLatchedMods & ShiftMask) && !shiftsPressed)
-                          ? (modifiers & ~Qt::KeyboardModifiers(Qt::ShiftModifier))
-                          : modifiers,
-                          text, false, 1));
-            // TODO: should we send release too?  MTextEdit seems to be happy with
-            // just press but what about others?
-            eaten = true;
+                QKeyEvent(QEvent::KeyPress, keyCode, filteredModifiers, text, false, 1));
+            inputContextConnection.sendKeyEvent(
+                QKeyEvent(QEvent::KeyRelease, keyCode, filteredModifiers, text, false, 1));
         }
+        eaten = true;
 
         if (!autoCaps) {
             latchModifiers(FnModifierMask | ShiftMask, 0);
@@ -332,10 +418,17 @@
     }
     // This case works around the problem of host calling setAutoCapitalization()
     // after backspace press event but before backspace release.  That turns the
-    // release event into a Delete release!  We eat backspace releases for consistency
-    // as well.  If the answer the the above "should we send release too?" question is
-    // "yes", presumably we need other kind of trickery here.
-    else if ((keyCode == Qt::Key_Backspace) || (keyCode == Qt::Key_Delete)) {
+    // release event into a Delete release!
+    else if (!shiftsPressed && (keyCode == Qt::Key_Delete)) {
+        inputContextConnection.sendKeyEvent(
+            QKeyEvent(QEvent::KeyRelease, Qt::Key_Backspace, filteredModifiers, "\b", false, 1));
+        eaten = true;
+    }
+    // See the same case in filterKeyPress
+    else if (shiftsPressed && (keyCode == Qt::Key_Delete)) {
+        inputContextConnection.sendKeyEvent(
+            QKeyEvent(QEvent::KeyRelease, keyCode,
+                      modifiers & ~Qt::KeyboardModifiers(Qt::ShiftModifier), text, false, 1));
         eaten = true;
     }
 
@@ -408,6 +501,9 @@
         inputContextConnection.sendKeyEvent(
             QKeyEvent(QEvent::KeyPress, static_cast<Qt::Key>(QKeySequence(text)[0]), Qt::NoModifier,
                       text, false, 1));
+        inputContextConnection.sendKeyEvent(
+            QKeyEvent(QEvent::KeyRelease, static_cast<Qt::Key>(QKeySequence(text)[0]), Qt::NoModifier,
+                      text, false, 1));
         latchModifiers(FnModifierMask | ShiftMask, 0);
         pressedKeys.remove(longPressKey);
     }
@@ -418,7 +514,7 @@
 {
     if ((lastKeyCode == SymKey) && (keyCode == SymKey)) {
         emit symbolKeyClicked();
-        return true;            // TODO: or false?
+        return false;
     }
 
     if ((characterLoopIndex != -1) && ((lastSymText != text) || (keyCode == SymKey))) {
--- m-keyboard/common/mhardwarekeyboard.h
+++ m-keyboard/common/mhardwarekeyboard.h
@@ -67,16 +67,22 @@
     //! Set auto capitalization state.
     void setAutoCapitalization(bool state);
 
-    /*! \brief Notify hardware keyboard about changed focus
+    /*! \brief Enable MHardwareKeyboard functionality
      *
-     *  From the point of view of MHardwareKeyboard focus leaves a widget also when host's
-     *  state is changed from Hardware to OnScreen.  If focus enters a widget while host's
-     *  state is OnScreen, MHardwareKeyboard won't be informed unless state changes from
-     *  OnScreen to Hardware.
+     * This implies that autorepeat is configured, modifier and other state is reset and
+     * key event redirection from input context is enabled.
      *
-     *  \param focusIn true - focus has entered a widget, false - focus has left a widget
+     * You can call enable() again after enable() without calling disable() in between.
+     * This could be done e.g. when focus is changed from one widget to another.
      */
-    void focusChanged(bool focusIn);
+    void enable();
+
+    /*! \brief Disable MHardwareKeyboard functionality
+     *
+     * This implies that autorepeat is enabled, modifier state is reset and key event
+     * redirection from input context is disabled.
+     */
+    void disable();
 
     /*! \brief Reset internal state of the hardware keyboard code.
      * \post modifiers in clear state
@@ -207,6 +213,18 @@
                           const QString &text,
                           quint32 nativeScanCode, quint32 nativeModifiers);
 
+
+    //! \brief Toggle custom autorepeat if \a enable is true, disable it otherwise
+    //!
+    //! Custom autorepeat means that only backspace and arrow keys have autorepeat
+    //! functionality.  This also sets hardwired key repeat rate and delay and enables
+    //! detectable autorepeat (see \a MInputContextConnection::setDetectableAutoRepeat).
+    //!
+    //! Note: this doesn't aim to save and restore autorepeat configuration.  With false
+    //! parameter autorepeat is simply enabled for all keys and detectable autorepeat is
+    //! disabled.
+    void toggleCustomAutoRepeat(bool enable);
+
     M::TextContentType currentKeyboardType;
     MXkb mXkb;
     bool autoCaps;
@@ -218,8 +236,6 @@
     //! An attribute of the last key event passed to filterKeyEvent.
     Qt::Key lastKeyCode;
 
-    // TODO: this isn't used at the moment but might serve as a starting point
-    // for the key filtering feature later
     typedef QHash<quint32, bool> PressedKeyMap; // key is native scan code / X keycode
     PressedKeyMap pressedKeys;
 
--- m-keyboard/common/mxkb.cpp
+++ m-keyboard/common/mxkb.cpp
@@ -38,7 +38,6 @@
         return;
     }
 
-    XSynchronize(display, 1);
     // TODO: XkbUseCoreKbd may change in the device and it should be queried from xkb.
     deviceSpec = XkbUseCoreKbd;
 }
--- m-keyboard/common/toolbardata.cpp
+++ m-keyboard/common/toolbardata.cpp
-/* * This file is part of meego-keyboard *
- *
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
- * All rights reserved.
- * Contact: Nokia Corporation (directui at nokia.com)
- *
- * If you have questions regarding the use of this file, please contact
- * Nokia at directui at nokia.com.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * and appearing in the file LICENSE.LGPL included in the packaging
- * of this file.
- */
-
-
-
-#include "toolbardata.h"
-
-#include <QFile>
-#include <QFileInfo>
-#include <QDomDocument>
-#include <QDebug>
-
-namespace
-{
-    const QString ToolbarConfigurationPath = "/usr/share/meegotouch/imtoolbars/";
-    const QString ImTagToolbar               = QString("toolbar");
-    const QString ImTagButton                = QString("button");
-    const QString ImTagLabel                 = QString("label");
-    const QString ImTagActions               = QString("actions");
-    const QString ImTagName                  = QString("name");
-    const QString ImTagGroup                 = QString("group");
-    const QString ImTagPriority              = QString("priority");
-    const QString ImTagOrientation           = QString("orientation");
-    const QString ImTagShowOn                = QString("showon");
-    const QString ImTagHideOn                = QString("hideon");
-    const QString ImTagAlignment             = QString("alignment");
-    const QString ImTagIcon                  = QString("icon");
-    const QString ImTagSize                  = QString("size");
-    const QString ImTagText                  = QString("text");
-    const QString ImTagTextId                = QString("text_id");
-    const QString ImTagToggle                = QString("toggle");
-    const QString ImTagPressed               = QString("pressed");
-    const QString ImTagSelectedText          = QString("selectedtext");
-    const QString ImTagAlways                = QString("always");
-    const QString ImTagLeft                  = QString("left");
-    const QString ImTagRight                 = QString("right");
-    const QString ImTagSendKeySequence       = QString("sendkeysequence");
-    const QString ImTagSendString            = QString("sendstring");
-    const QString ImTagSendCommand           = QString("sendcommand");
-    const QString ImTagCopy                  = QString("copy");
-    const QString ImTagPaste                 = QString("paste");
-    const QString ImTagShowGroup             = QString("showgroup");
-    const QString ImTagHideGroup             = QString("hidegroup");
-    const QString ImTagKeySequence           = QString("keysequence");
-    const QString ImTagString                = QString("string");
-    const QString ImTagCommand               = QString("command");
-    const QString ImTagOrientationLandscape  = QString("landscape");
-    const QString ImTagOrientationPortrait   = QString("portrait");
-}
-
-struct TBParseParameters {
-    //! Contains true if current XML tag was successfully parsed
-    bool validTag;
-
-    QString fileName;
-
-    ToolbarWidget *currentWidget;
-
-    TBParseParameters();
-};
-
-struct TBParseStructure {
-    TBParseStructure(const QString &name, ToolbarData::TagParser p)
-        : tagName(name),
-          parser(p) {
-    };
-    QString tagName;
-    ToolbarData::TagParser parser;
-};
-
-TBParseParameters::TBParseParameters()
-    : validTag(true),
-      fileName(""),
-      currentWidget(0)
-{
-}
-
-ToolbarData::ToolbarData()
-{
-}
-
-ToolbarData::~ToolbarData()
-{
-}
-
-QString ToolbarData::fileName() const
-{
-    return toolbarFileName;
-}
-
-bool ToolbarData::equal(const QString &toolbar) const
-{
-    QString absoluteFileName = toolbar;
-    QFileInfo info(toolbar);
-    if (info.isRelative())
-        absoluteFileName = ToolbarConfigurationPath + info.fileName();
-    return (absoluteFileName == toolbarFileName);
-}
-
-bool ToolbarData::loadNokiaToolbarXml(const QString &fileName)
-{
-    QString absoluteFileName = fileName;
-    QFileInfo info(absoluteFileName);
-    if (info.isRelative())
-        absoluteFileName = ToolbarConfigurationPath + info.fileName();
-    if (!QFile::exists(absoluteFileName)) {
-        qDebug() << "can not find file:" << absoluteFileName;
-        return false;
-    }
-
-    TBParseParameters params;
-    params.fileName = absoluteFileName;
-    toolbarFileName = absoluteFileName;
-    bool valid = true;
-    QFile infile(absoluteFileName);
-    QString errorStr;
-    int errorLine;
-    int errorColumn;
-    QDomDocument doc;
-    if (!infile.open(QIODevice::ReadOnly)) {
-        qWarning() << "Unable to open toolbar xml file" << absoluteFileName;
-        return false;
-    }
-    if (!doc.setContent((QIODevice *)(&infile), true, &errorStr, &errorLine,
-                        &errorColumn)) {
-        qWarning() << __PRETTY_FUNCTION__ << "can not parse xml" << absoluteFileName
-                   << "error line:" << errorLine << ", column:" << errorColumn;
-        infile.close();
-        return false;
-    }
-
-    const QDomElement root = doc.documentElement();
-    //check the root tag
-    if (!root.isNull() && root.tagName() != ImTagToolbar) {
-        qWarning() << __PRETTY_FUNCTION__
-                   << "wrong format xml" << absoluteFileName << "for virtual keyboard tool bar";
-        valid = false;
-    } else {
-        const TBParseStructure parsers[2] = {TBParseStructure(ImTagButton, &ToolbarData::parseTagButton),
-                                             TBParseStructure(ImTagLabel, &ToolbarData::parseTagLabel)
-                                            };
-
-        parseChildren(root, params, parsers, 2);
-        valid = params.validTag;
-    }
-
-    infile.close();
-
-    return valid;
-}
-
-void ToolbarData::parseChildren(const QDomElement &element, TBParseParameters &params,
-                                const TBParseStructure *parserList, int parserCount)
-{
-    Q_ASSERT(parserCount > 0);
-
-    for (QDomNode child = element.firstChild(); !child.isNull() && params.validTag;
-            child = child.nextSibling()) {
-        if (child.isElement()) {
-            const QDomElement childElement = child.toElement();
-            bool found = false;
-            for (int i = 0; i < parserCount; ++i) {
-                if (childElement.tagName() == parserList[i].tagName) {
-                    (this->*(parserList[i].parser))(childElement, params);
-                    found = true;
-                    break;
-                }
-            }
-            if (!found) {
-                qWarning() << "Unexpected tag" << childElement.tagName() << "on line"
-                           << childElement.lineNumber() << "column" << childElement.columnNumber()
-                           << "in layout file" << params.fileName;
-                params.validTag = false;
-            }
-        }
-    }
-}
-
-Qt::Alignment ToolbarData::alignment(const QString &alignmentString)
-{
-    Qt::Alignment align = Qt::AlignRight;
-    if (alignmentString == ImTagLeft)
-        align = Qt::AlignLeft;
-    else if (alignmentString == ImTagRight)
-        align = Qt::AlignRight;
-    return align;
-}
-
-M::Orientation ToolbarData::orientation(const QString &orientationString)
-{
-    M::Orientation orient = M::Portrait;
-    if (orientationString == ImTagOrientationLandscape)
-        orient = M::Landscape;
-    return orient;
-}
-
-ToolbarWidget::VisibleType ToolbarData::visibleType(const QString &visibleTypeString)
-{
-    ToolbarWidget::VisibleType type = ToolbarWidget::Undefined;
-    if (visibleTypeString == ImTagSelectedText)
-        type = ToolbarWidget::WhenSelectingText;
-    else if (visibleTypeString == ImTagAlways)
-        type = ToolbarWidget::Always;
-    return type;
-}
-
-void ToolbarData::parseTagButton(const QDomElement &element, TBParseParameters &params)
-{
-    const QString name = element.attribute(ImTagName);
-    //check if the name is unique
-    foreach(ToolbarWidget *tw, widgets) {
-        if (tw->name().compare(name, Qt::CaseInsensitive) == 0) {
-            return;
-        }
-    }
-
-    ToolbarWidget *b = new ToolbarWidget(ToolbarWidget::Button);
-    b->widgetName = name;
-    b->group = element.attribute(ImTagGroup);
-    b->priority = element.attribute(ImTagPriority).toInt();
-    b->orientation = orientation(element.attribute(ImTagOrientation));
-    b->showOn = visibleType(element.attribute(ImTagShowOn));
-    b->hideOn = visibleType(element.attribute(ImTagHideOn));
-    b->alignment = alignment(element.attribute(ImTagAlignment));
-    b->text = element.attribute(ImTagText);
-    b->textId = element.attribute(ImTagTextId);
-    b->icon = element.attribute(ImTagIcon);
-    bool ok;
-    int size = element.attribute(ImTagSize).remove("%").toInt(&ok, 10);
-    if (ok) {
-        b->size = size;
-    } else {
-        b->size = 100;
-    }
-    b->toggle = (element.attribute(ImTagToggle) == "true") ? true : false;
-    b->pressed = (element.attribute(ImTagPressed) == "true") ? true : false;
-    widgets.append(b);
-    params.currentWidget = b;
-
-    const TBParseStructure parser(ImTagActions, &ToolbarData::parseTagActions);
-    parseChildren(element, params, &parser);
-}
-
-void ToolbarData::parseTagLabel(const QDomElement &element, TBParseParameters &params)
-{
-    const QString name = element.attribute(ImTagName);
-    //check if the name is unique
-    foreach(ToolbarWidget *tw, widgets) {
-        if (tw->name().compare(name, Qt::CaseInsensitive) == 0) {
-            return;
-        }
-    }
-
-    ToolbarWidget *label = new ToolbarWidget(ToolbarWidget::Label);
-    label->widgetName = name;
-    label->group = element.attribute(ImTagGroup);
-    label->priority = element.attribute(ImTagPriority).toInt();
-    label->orientation = orientation(element.attribute(ImTagOrientation));
-    label->showOn = visibleType(element.attribute(ImTagShowOn));
-    label->hideOn = visibleType(element.attribute(ImTagHideOn));
-    label->alignment = alignment(element.attribute(ImTagAlignment));
-    label->text = element.attribute(ImTagText);
-    label->textId = element.attribute(ImTagTextId);
-    widgets.append(label);
-    params.currentWidget = label;
-}
-
-void ToolbarData::parseTagActions(const QDomElement &element, TBParseParameters &params)
-{
-    if (!params.currentWidget && (params.currentWidget->type() != ToolbarWidget::Button))
-        return;
-    const TBParseStructure parsers[7] = {TBParseStructure(ImTagSendKeySequence, &ToolbarData::parseTagSendKeySequence),
-                                         TBParseStructure(ImTagSendString, &ToolbarData::parseTagSendString),
-                                         TBParseStructure(ImTagSendCommand, &ToolbarData::parseTagSendCommand),
-                                         TBParseStructure(ImTagCopy, &ToolbarData::parseTagCopy),
-                                         TBParseStructure(ImTagPaste, &ToolbarData::parseTagPaste),
-                                         TBParseStructure(ImTagShowGroup, &ToolbarData::parseTagShowGroup),
-                                         TBParseStructure(ImTagHideGroup, &ToolbarData::parseTagHideGroup)
-                                        };
-    parseChildren(element, params, parsers, 7);
-}
-
-void ToolbarData::parseTagSendKeySequence(const QDomElement &element, TBParseParameters &params)
-{
-    ToolbarWidget::Action *action = new ToolbarWidget::Action(ToolbarWidget::SendKeySequence);
-    action->keys = element.attribute(ImTagKeySequence);
-    (static_cast<ToolbarWidget *>(params.currentWidget))->actions.append(action);
-}
-
-void ToolbarData::parseTagSendString(const QDomElement &element, TBParseParameters &params)
-{
-    ToolbarWidget::Action *action = new ToolbarWidget::Action(ToolbarWidget::SendString);
-    action->text = element.attribute(ImTagString);
-    (static_cast<ToolbarWidget *>(params.currentWidget))->actions.append(action);
-}
-
-void ToolbarData::parseTagSendCommand(const QDomElement &element, TBParseParameters &params)
-{
-    ToolbarWidget::Action *action = new ToolbarWidget::Action(ToolbarWidget::SendCommand);
-    action->command = element.attribute(ImTagCommand);
-    (static_cast<ToolbarWidget *>(params.currentWidget))->actions.append(action);
-}
-
-void ToolbarData::parseTagCopy(const QDomElement &element, TBParseParameters &params)
-{
-    Q_UNUSED(element);
-    ToolbarWidget::Action *action = new ToolbarWidget::Action(ToolbarWidget::Copy);
-    (static_cast<ToolbarWidget *>(params.currentWidget))->actions.append(action);
-}
-
-void ToolbarData::parseTagPaste(const QDomElement &element, TBParseParameters &params)
-{
-    Q_UNUSED(element);
-    ToolbarWidget::Action *action = new ToolbarWidget::Action(ToolbarWidget::Paste);
-    (static_cast<ToolbarWidget *>(params.currentWidget))->actions.append(action);
-}
-
-void ToolbarData::parseTagShowGroup(const QDomElement &element, TBParseParameters &params)
-{
-    ToolbarWidget::Action *action = new ToolbarWidget::Action(ToolbarWidget::ShowGroup);
-    action->group = element.attribute(ImTagGroup);
-    (static_cast<ToolbarWidget *>(params.currentWidget))->actions.append(action);
-}
-
-void ToolbarData::parseTagHideGroup(const QDomElement &element, TBParseParameters &params)
-{
-    ToolbarWidget::Action *action = new ToolbarWidget::Action(ToolbarWidget::HideGroup);
-    action->group = element.attribute(ImTagGroup);
-    (static_cast<ToolbarWidget *>(params.currentWidget))->actions.append(action);
-}
--- m-keyboard/common/toolbardata.h
+++ m-keyboard/common/toolbardata.h
-/* * This file is part of meego-keyboard *
- *
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
- * All rights reserved.
- * Contact: Nokia Corporation (directui at nokia.com)
- *
- * If you have questions regarding the use of this file, please contact
- * Nokia at directui at nokia.com.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * and appearing in the file LICENSE.LGPL included in the packaging
- * of this file.
- */
-
-
-
-#ifndef TOOLBARDATA_H
-#define TOOLBARDATA_H
-
-#include <QObject>
-#include <QList>
-#include "toolbarwidget.h"
-
-class QDomElement;
-struct TBParseParameters;
-struct TBParseStructure;
-
-/*!
-  \brief ToolbarData corresponds to a toolbar defined in a XML file
- */
-class ToolbarData : public QObject
-{
-    Q_OBJECT
-    Q_DISABLE_COPY(ToolbarData)
-
-public:
-    /*!
-    * \brief Constructor
-    */
-    ToolbarData();
-
-    /*!
-    * \brief Destructor
-    */
-    ~ToolbarData();
-
-    /*!
-    * \brief Load a custom toolbar's content from \a fileName xml file.
-    * \a fileName is the xml file name (with ".xml" postfix). And \a fileName could have absolute path.
-    * If no absolute path specified, then it will be taken from the default path
-    * "/usr/share/meegotouch/imtoolbars/".
-    * \param fileName Name of the xml file which contains the content of a custom toolbar.
-    */
-    bool loadNokiaToolbarXml(const QString &fileName);
-
-    /*!
-    * \brief Returns the custom toolbar's xml file name.
-    */
-    QString fileName() const;
-
-    /*!
-     *\brief Returns true \a toolbar equal this custom toolbar.
-     * \a toolbar is the xml file name.
-     * \sa fileName(), \sa loadNokiaToolbarXml().
-     */
-    bool equal(const QString &toolbar) const;
-
-private:
-    /*!
-     * \brief Translate alignmentString to Qt::Alignment.
-     */
-    static Qt::Alignment alignment(const QString &alignmentString);
-
-    /*!
-    * \brief Translate orientationString to M::Orientation.
-    */
-    static M::Orientation orientation(const QString &orientationString);
-
-    /*!
-     * \brief Translate visibleTypeString to ToolbarWidget::VisibleType.
-     */
-    static ToolbarWidget::VisibleType visibleType(const QString &visibleTypeString);
-
-    //! Parse XML tag for button.
-    void parseTagButton(const QDomElement &element, TBParseParameters &params);
-
-    //! Parse XML tag for label.
-    void parseTagLabel(const QDomElement &element, TBParseParameters &params);
-
-    //! Parse XML tag for action.
-    void parseTagActions(const QDomElement &element, TBParseParameters &params);
-
-    //! Parse XML tag for SendKeySequence.
-    void parseTagSendKeySequence(const QDomElement &element, TBParseParameters &params);
-
-    //! Parse XML tag for SendString
-    void parseTagSendString(const QDomElement &element, TBParseParameters &params);
-
-    //! Parse XML tag for SendCommand
-    void parseTagSendCommand(const QDomElement &element, TBParseParameters &params);
-
-    //! Parse XML tag for Copy
-    void parseTagCopy(const QDomElement &element, TBParseParameters &params);
-
-    //! Parse XML tag for Paste
-    void parseTagPaste(const QDomElement &element, TBParseParameters &params);
-
-    //! Parse XML tag for ShowGroup
-    void parseTagShowGroup(const QDomElement &element, TBParseParameters &params);
-
-    //! Parse XML tag for HideGroup
-    void parseTagHideGroup(const QDomElement &element, TBParseParameters &params);
-
-    //! Type of tag parser methods
-    typedef void (ToolbarData::*TagParser)(const QDomElement &, TBParseParameters &);
-
-    /*!
-     * \brief Helper method for parsing children of an element
-     * \param element Element whose children are to be parsed
-     * \param params Parsing state
-     * \param parserList, a TBParseStructure array.
-     * \param parserCount, the number of TBParseStructure in the array.
-     */
-    void parseChildren(const QDomElement &element, TBParseParameters &params,
-                       const TBParseStructure *parserList, int parserCount = 1);
-protected:
-    QList<ToolbarWidget *> widgets;
-    QString toolbarFileName;
-    friend class ToolbarManager;
-    friend struct TBParseStructure;
-    friend class Ut_MImToolbar;
-};
-
-#endif //TOOLBAR_H
--- m-keyboard/common/toolbarmanager.cpp
+++ m-keyboard/common/toolbarmanager.cpp
-/* * This file is part of meego-keyboard *
- *
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
- * All rights reserved.
- * Contact: Nokia Corporation (directui at nokia.com)
- *
- * If you have questions regarding the use of this file, please contact
- * Nokia at directui at nokia.com.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * and appearing in the file LICENSE.LGPL included in the packaging
- * of this file.
- */
-
-
-
-#include "toolbarmanager.h"
-#include "toolbardata.h"
-#include "mtoolbarbutton.h"
-#include "mimtoolbar.h"
-#include <MGConfItem>
-#include <MButton>
-#include <MLabel>
-#include <MLocale>
-#include <QDebug>
-
-namespace
-{
-    const QString ObjectNameToolbarButton("VirtualKeyboardToolbarButton");
-    const QString ObjectNameToolbarLabel("VirtualKeyboardToolbarLabel");
-    const int MaximumToolbarCount = 10;
-}
-
-const int ToolbarManager::widgetNameDataKey(1000);
-const int ToolbarManager::widgetTypeDataKey(1001);
-ToolbarManager *ToolbarManager::toolbarMgrInstance = 0;
-
-ToolbarManager::ToolbarManager()
-    : current(cachedToolbars.end())
-{
-}
-
-ToolbarManager::~ToolbarManager()
-{
-    qDeleteAll(cachedToolbars.values());
-    cachedToolbars.clear();
-    cachedToolbarIds.clear();
-
-    qDeleteAll(toolbarWidgetPool);
-    toolbarWidgetPool.clear();
-}
-
-void ToolbarManager::createInstance()
-{
-    Q_ASSERT(!toolbarMgrInstance);
-    if (!toolbarMgrInstance) {
-        toolbarMgrInstance = new ToolbarManager;
-    }
-}
-
-void ToolbarManager::destroyInstance()
-{
-    Q_ASSERT(toolbarMgrInstance);
-    delete toolbarMgrInstance;
-    toolbarMgrInstance = 0;
-}
-
-int ToolbarManager::widgetCount() const
-{
-    if (current != cachedToolbars.end())
-        return current.value()->widgets.count();
-    else
-        return 0;
-}
-
-QList<ToolbarWidget *> ToolbarManager::widgetList() const
-{
-    QList<ToolbarWidget *> list;
-    if (current != cachedToolbars.end())
-        list = current.value()->widgets;
-
-    return list;
-}
-
-QList<ToolbarWidget *> ToolbarManager::widgetList(Qt::Alignment align) const
-{
-    QList<ToolbarWidget *> list;
-    if (current != cachedToolbars.end()) {
-        foreach(ToolbarWidget *tw, current.value()->widgets) {
-            if (tw->alignment == align) {
-                //sort according priority
-                bool inserted = false;
-                for (int i = 0; i < list.count(); ++i) {
-                    if (((align == Qt::AlignLeft) && (list[i]->priority < tw->priority))
-                            || ((align == Qt::AlignRight) && (list[i]->priority > tw->priority)))
-                        continue;
-                    else {
-                        inserted = true;
-                        list.insert(i, tw);
-                        break;
-                    }
-                }
-                if (!inserted) {
-                    list.append(tw);
-                    continue;
-                }
-            }
-        }
-    }
-    return list;
-}
-
-ToolbarWidget *ToolbarManager::toolbarWidget(qlonglong id, const QString &name) const
-{
-    if (current != cachedToolbars.end() && current.key() == id) {
-        return toolbarWidget(name);
-    } else {
-        CachedToolbarContainer::const_iterator iterator = cachedToolbars.find(id);
-        if (iterator != cachedToolbars.end()) {
-            foreach(ToolbarWidget *tw, iterator.value()->widgets) {
-                if (tw->name() == name)
-                    return tw;
-            }
-        }
-    }
-    return 0;
-}
-
-ToolbarWidget *ToolbarManager::toolbarWidget(const QString &name) const
-{
-    if (current != cachedToolbars.end()) {
-        foreach(ToolbarWidget *tw, current.value()->widgets) {
-            if (tw->name() == name)
-                return tw;
-        }
-    }
-    return 0;
-}
-
-ToolbarWidget *ToolbarManager::toolbarWidget(const MWidget *w) const
-{
-    if (w)
-        return toolbarWidget(w->data(widgetNameDataKey).toString());
-    return 0;
-}
-
-MWidget *ToolbarManager::widget(const QString &name) const
-{
-    MWidget *w = 0;
-    for (int i = 0; i < toolbarWidgetPool.count(); i++) {
-        if (toolbarWidgetPool[i] && toolbarWidgetPool[i]->data(widgetNameDataKey).toString() == name) {
-            w = toolbarWidgetPool[i];
-            break;
-        }
-    }
-    return w;
-}
-
-QList<qlonglong> ToolbarManager::toolbarList() const
-{
-    return cachedToolbars.keys();
-}
-
-qlonglong ToolbarManager::currentToolbar() const
-{
-    if (current != cachedToolbars.end())
-        return current.key();
-    return -1;
-}
-
-bool ToolbarManager::loadToolbar(qlonglong id)
-{
-    // sanity tests
-    if (!toolbars.contains(id)) {
-        qWarning() << "ToolbarsManager: toolbar load error: " << id;
-        reset();
-        return false;
-    }
-
-    //already load
-    if ((current != cachedToolbars.end()) && (current.key() == id) && validateWidgetPool()) {
-        return true;
-    }
-
-    current = cachedToolbars.find(id);
-    if (current == cachedToolbars.end()) {
-        ToolbarData * toolbarData = createToolbar(toolbars.value(id));
-        if (toolbarData) {
-            // if cached toolbars reach MaximumToolbarCount, then remove the most rarely used toolbar.
-            if (cachedToolbarIds.count() >= MaximumToolbarCount) {
-                // the last toolbar is the most rarely used one.
-                delete cachedToolbars.take(cachedToolbarIds.takeLast());
-            }
-            current = cachedToolbars.insert(id, toolbarData);
-            cachedToolbarIds.prepend(id);
-        }
-    } else {
-        //move current (toolbar) to the beginning of cahced toolbars.
-        cachedToolbarIds.move(cachedToolbarIds.indexOf(current.key()), 0);
-    }
-
-    if (current != cachedToolbars.end()) {
-        loadToolbarWidgets();
-        return true;
-    } else {
-        //can't find
-        return false;
-    }
-}
-
-ToolbarData *ToolbarManager::createToolbar(const QString &name)
-{
-    // load a toolbar
-    ToolbarData *toolbar = new ToolbarData;
-    const bool loaded = toolbar->loadNokiaToolbarXml(name);
-
-    if (!loaded) {
-        qWarning() << "ToolbarsManager: toolbar load error: "
-                   << name;
-        delete toolbar;
-        toolbar = 0;
-    }
-
-    return toolbar;
-}
-
-void ToolbarManager::reset()
-{
-    resetWidgetPool();
-    current = cachedToolbars.end();
-}
-
-void ToolbarManager::loadToolbarWidgets()
-{
-    qDebug() << __PRETTY_FUNCTION__;
-    resetWidgetPool();
-    foreach(const ToolbarWidget *tw, widgetList()) {
-        createWidget(tw);
-    }
-}
-
-void ToolbarManager::createWidget(const ToolbarWidget *tw)
-{
-    if (!tw)
-        return;
-
-    QPointer<MWidget> w = widget(tw->name());
-    //because name is the unique id, so if there is already created, then just use it
-    if (!w) {
-        //find the first unused pool item, or create a new one
-        for (int i = 0; i < toolbarWidgetPool.count(); i++) {
-            if (toolbarWidgetPool[i] && toolbarWidgetPool[i]->data(widgetNameDataKey).toString().isEmpty()
-                && toolbarWidgetPool[i]->data(widgetTypeDataKey).toInt() == tw->type()) {
-                w = toolbarWidgetPool[i];
-                break;
-            }
-        }
-        if (!w) {
-            switch (tw->type()) {
-            case ToolbarWidget::Button:
-                w = new MToolbarButton();
-                w->setObjectName(ObjectNameToolbarButton);
-                break;
-            case ToolbarWidget::Label:
-                w = new MLabel();
-                w->setObjectName(ObjectNameToolbarLabel);
-                break;
-            default:
-                //unknown widget type.
-                return;
-            }
-            toolbarWidgetPool.append(w);
-        }
-    }
-    w->setData(widgetNameDataKey, tw->name());
-    w->setData(widgetTypeDataKey, tw->type());
-
-    switch (tw->type()) {
-    case ToolbarWidget::Button: {
-        MToolbarButton *b = qobject_cast<MToolbarButton*>(w);
-        if (b) {
-            if (!tw->textId.isEmpty()) {
-                b->setText(qtTrId(tw->textId.toUtf8().data()));
-            } else {
-                b->setText(tw->text);
-            }
-            b->setIconFile(QString(tw->icon));
-            b->setIconPercent(tw->size);
-            b->setCheckable(tw->toggle);
-            if (tw->toggle) {
-                b->setChecked(tw->pressed);
-            }
-            connect(b, SIGNAL(clicked()), this, SLOT(handleButtonClick()));
-        }
-        break;
-    }
-    case ToolbarWidget::Label: {
-        MLabel *l = qobject_cast<MLabel*>(w);
-        if (!tw->textId.isEmpty()) {
-            l->setText(qtTrId(tw->textId.toUtf8().data()));
-        } else {
-            l->setText(tw->text);
-        }
-        break;
-    }
-    default:
-        break;
-    }
-}
-
-void ToolbarManager::resetWidgetPool()
-{
-    validateWidgetPool();
-    for (int i = 0; i < toolbarWidgetPool.count(); i++) {
-        toolbarWidgetPool[i]->setData(widgetNameDataKey, "");
-        toolbarWidgetPool[i]->setVisible(false);
-        toolbarWidgetPool[i]->disconnect();
-    }
-}
-
-bool ToolbarManager::validateWidgetPool()
-{
-    // Widgets in the widget pool could be destroyed outside by MImToolbar.
-    // But QPointer can safely promise the pointers are already set to 0,
-    // so remove all null widget from pool.
-    bool valid = (toolbarWidgetPool.removeAll(0) > 0) ? false : true;
-    return valid;
-}
-
-void ToolbarManager::handleButtonClick()
-{
-    const MButton *button = qobject_cast<MButton *>(this->sender());
-    Q_ASSERT(button);
-
-    ToolbarWidget *tw = toolbarWidget(button);
-    if (!tw)
-        return;
-    // records button's toggle state
-    if (tw->toggle) {
-        tw->pressed = button->isChecked();
-    }
-
-    emit buttonClicked(*tw);
-}
-
-void ToolbarManager::registerToolbar(qlonglong id, const QString &fileName)
-{
-    qDebug() << __PRETTY_FUNCTION__;
-    if ((id <= 0) || fileName.isEmpty() || toolbars.contains(id))
-        return;
-
-    toolbars.insert(id, fileName);
-
-    ToolbarData * toolbarData = createToolbar(fileName);
-    if (toolbarData) {
-        // if cached toolbars reach MaximumToolbarCount, then remove the most rarely used toolbar.
-        if (cachedToolbarIds.count() >= MaximumToolbarCount) {
-            // the last toolbar is the most rarely used one.
-            // FIXME: the removing of cached toolbar will lead to all the states changed by
-            // setToolbarItemAttribute be lost. Can we avoid it?
-            delete cachedToolbars.take(cachedToolbarIds.takeLast());
-        }
-        cachedToolbars.insert(id, toolbarData);
-        cachedToolbarIds.prepend(id);
-    }
-}
-
-void ToolbarManager::unregisterToolbar(qlonglong id)
-{
-    qDebug() << __PRETTY_FUNCTION__;
-    if (!toolbars.contains(id))
-        return;
-
-    if (cachedToolbars.contains(id)) {
-        if (id == currentToolbar()) {
-            reset();
-        }
-        delete cachedToolbars.take(id);
-        cachedToolbarIds.removeOne(id);
-    }
-    toolbars.remove(id);
-}
-
-void ToolbarManager::setToolbarItemAttribute(qlonglong id, const QString &item, const QString &attribute, const QVariant &value)
-{
-    qDebug() << __PRETTY_FUNCTION__;
-    if ((id <= 0) || item.isEmpty() || attribute.isEmpty() || value.isNull())
-        return;
-
-    ToolbarWidget *tw = toolbarWidget(id, item);
-    if (tw) {
-        switch (tw->type()) {
-        case ToolbarWidget::Button: {
-            MToolbarButton *button = qobject_cast<MToolbarButton *>(widget(item));
-            if (!button)
-                return;
-            if (attribute == "icon") {
-                button->setIconFile(value.toString());
-                tw->icon = value.toString();
-            } else if (attribute == "text") {
-                button->setText(value.toString());
-                tw->text = value.toString();
-            } else if (attribute == "textid") {
-                button->setText(qtTrId(value.toString().toUtf8().data()));
-                tw->textId = value.toString();
-            } else if (attribute == "pressed" && tw->toggle) {
-                button->setChecked(value.toBool());
-                tw->pressed = value.toBool();
-            }
-            break;
-        }
-        case ToolbarWidget::Label: {
-            MLabel *label = qobject_cast<MLabel *>(widget(item));
-            if (!label)
-                return;
-            if (attribute == "text") {
-                label->setText(value.toString());
-                tw->text = value.toString();
-            } else if (attribute == "textid") {
-                label->setText(qtTrId(value.toString().toUtf8().data()));
-                tw->textId = value.toString();
-            }
-            break;
-        }
-        default:
-            break;
-        }
-    }
-}
-
--- m-keyboard/common/toolbarmanager.h
+++ m-keyboard/common/toolbarmanager.h
-/* * This file is part of meego-keyboard *
- *
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
- * All rights reserved.
- * Contact: Nokia Corporation (directui at nokia.com)
- *
- * If you have questions regarding the use of this file, please contact
- * Nokia at directui at nokia.com.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * and appearing in the file LICENSE.LGPL included in the packaging
- * of this file.
- */
-
-
-#ifndef TOOLBARMANAGER_H
-#define TOOLBARMANAGER_H
-
-#include <QObject>
-#include <QHash>
-#include <QPointer>
-#include "toolbarwidget.h"
-#include <memory>
-
-class ToolbarData;
-class MGConfItem;
-class MWidget;
-
-/*!
- \brief The ToolbarManager class manager the virtual keyboard toolbar.
-
-  ToolbarManager loads and managers not only the toolbars which defined with GConf key
-  "/meegotouch/inputmethods/toolbars",
-  but also the copy/paste button and close button.
-*/
-class ToolbarManager : public QObject
-{
-    Q_OBJECT
-
-public:
-    /*!
-     *\brief Destructor.
-     */
-    virtual ~ToolbarManager();
-
-    //! \brief Get singleton instance
-    //! \return singleton instance
-    static ToolbarManager &instance();
-
-    //! \brief Create singleton
-    static void createInstance();
-
-    //! \brief Destroy singleton
-    static void destroyInstance();
-
-    /*!
-     * \brief Register an input method toolbar which is defined in \a fileName with the unique identifier \a id.
-     * ToolbarManager can load a custom toolbar's content according \a id and \a fileName, and cache it for the
-     * future use. The \a id should be unique, and the \a fileName is the absolute file name of the custom toolbar.
-     */
-    void registerToolbar(qlonglong id, const QString &fileName);
-
-    /*!
-     * \brief Unregister an input method \a toolbar which unique identifier is \a id.
-     * ToolbarManager will remove the cached toolbar according \a id.
-     */
-    void unregisterToolbar(qlonglong id);
-
-    /*!
-     * \brief Sets the \a attribute for the \a item in the custom toolbar which has the unique \a id to \a value.
-     */
-    void setToolbarItemAttribute(qlonglong id, const QString &item, const QString &attribute, const QVariant &value);
-
-    QRegion region(bool includeToolbar = true) const;
-    /*!
-     *\brief Returns the widget count in current loaded customized toolbar.
-     */
-    int widgetCount() const;
-
-    /*!
-     *\brief Returns the widget list in current loaded customized toolbar.
-     */
-    QList<ToolbarWidget *> widgetList() const;
-
-    /*!
-     *\brief Returns the widget list with \a align in current loaded customized toolbar.
-     * And the widget list is already sorted by priorities
-     */
-    QList<ToolbarWidget *> widgetList(Qt::Alignment align) const;
-
-    /*!
-     *\brief Returns a ToolbarWidget pointer to the widget with \a name in cached customized toolbar with \a id.
-     */
-    ToolbarWidget *toolbarWidget(qlonglong id, const QString &name) const;
-
-    /*!
-     *\brief Returns a ToolbarWidget pointer to the widget with \a name in current loaded customized toolbar.
-     */
-    ToolbarWidget *toolbarWidget(const QString &name) const;
-
-    /*!
-     *\brief Returns a ToolbarWidget pointer to the widget with \a widget in current loaded customized toolbar.
-     */
-    ToolbarWidget *toolbarWidget(const MWidget *widget) const;
-
-    /*!
-     *\brief Returns a MWidget pointer to the widget with \a name in current loaded customized toolbar.
-     */
-    MWidget *widget(const QString &name) const;
-
-    /*!
-     *\brief Returns current loaded toolbar's identifier.
-     */
-    qlonglong currentToolbar() const;
-
-    /*!
-     * \brief Loads the toolbar according the unique \a id.
-     * The \a uuid must be registered before by registerToolbar().
-     * \return true if the toolbar \a name is loaded successfully or already cached before.
-     * \sa registerToolbar().
-     */
-    bool loadToolbar(qlonglong id);
-
-    /*!
-     *\brief Reset current loaded customized toolbar to 0.
-     */
-    void reset();
-
-signals:
-    //! Emitted when a button is clicked
-    void buttonClicked(const ToolbarWidget &);
-
-private slots:
-    void loadToolbarWidgets();
-
-    void handleButtonClick();
-
-public:
-    static const int widgetNameDataKey;
-    static const int widgetTypeDataKey;
-
-private:
-    /*!
-     * \brief Default constructor.
-     */
-    ToolbarManager();
-
-    /*!
-     *\brief Returns a list of the name for all toolbars.
-     */
-    QList<qlonglong> toolbarList() const;
-
-    const QString *widgetName(const MWidget *) const;
-
-    void resetWidgetPool();
-
-    bool validateWidgetPool();
-
-    ToolbarData *createToolbar(const QString &name);
-
-    void createWidget(const ToolbarWidget *b);
-
-    typedef QHash<qlonglong, QString> ToolbarContainer;
-    //! all registered toolbars
-    ToolbarContainer toolbars;
-
-    typedef QHash<qlonglong, ToolbarData *> CachedToolbarContainer;
-    //! cached toolbars
-    CachedToolbarContainer cachedToolbars;
-
-    //! the list of identifier of the cached toolbars, sorted by used frequency.
-    QList<qlonglong> cachedToolbarIds;
-
-    //! current used toolbar iterator
-    CachedToolbarContainer::const_iterator current;
-
-    QList< QPointer<MWidget> > toolbarWidgetPool;
-
-    //! Singleton instance
-    static ToolbarManager *toolbarMgrInstance;
-
-    friend class Ut_MImToolbar;
-    friend class Ut_ToolbarManager;
-};
-
-inline ToolbarManager &ToolbarManager::instance()
-{
-    Q_ASSERT(toolbarMgrInstance);
-    return *toolbarMgrInstance;
-}
-
-#endif
--- m-keyboard/common/toolbarwidget.cpp
+++ m-keyboard/common/toolbarwidget.cpp
-/* * This file is part of meego-keyboard *
- *
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
- * All rights reserved.
- * Contact: Nokia Corporation (directui at nokia.com)
- *
- * If you have questions regarding the use of this file, please contact
- * Nokia at directui at nokia.com.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * and appearing in the file LICENSE.LGPL included in the packaging
- * of this file.
- */
-
-
-
-#include <QtAlgorithms>
-#include "toolbarwidget.h"
-
-ToolbarWidget::ToolbarWidget(WidgetType t)
-    : widgetType(t),
-      orientation(M::Portrait),
-      showOn(Always),
-      hideOn(Undefined),
-      alignment(Qt::AlignRight),
-      visible(false),
-      toggle(false),
-      pressed(false)
-{
-}
-
-ToolbarWidget::Action::Action(ToolbarWidget::ActionType t)
-    : type(t)
-{
-}
-
-ToolbarWidget::~ToolbarWidget()
-{
-    qDeleteAll(actions);
-}
-
-ToolbarWidget::WidgetType ToolbarWidget::type() const
-{
-    return widgetType;
-}
-
-QString ToolbarWidget::name() const
-{
-    return widgetName;
-}
-
-bool ToolbarWidget::isVisible() const
-{
-    return visible;
-}
-
-void ToolbarWidget::setVisible(bool v)
-{
-    visible = v;
-}
--- m-keyboard/common/toolbarwidget.h
+++ m-keyboard/common/toolbarwidget.h
-/* * This file is part of meego-keyboard *
- *
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
- * All rights reserved.
- * Contact: Nokia Corporation (directui at nokia.com)
- *
- * If you have questions regarding the use of this file, please contact
- * Nokia at directui at nokia.com.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * and appearing in the file LICENSE.LGPL included in the packaging
- * of this file.
- */
-
-
-#ifndef TOOLBARWIDGET_H
-#define TOOLBARWIDGET_H
-
-#include <MNamespace>
-#include <QList>
-#include <QString>
-#include <QStringList>
-/*!
- * \brief ToolbarWidget represents a named widget in a customized toolbar for virtual keyboard.
- */
-class ToolbarWidget
-{
-    Q_DISABLE_COPY(ToolbarWidget)
-
-public:
-    //! Type of toolbar widget
-    enum WidgetType {
-        Button,
-        Label,
-        UndefinedWidgetType
-    };
-
-    //! Type of visible premiss for toolbar button
-    enum VisibleType {
-        WhenSelectingText,
-        Always,
-        Undefined
-    };
-
-    //! Type of action
-    enum ActionType {
-        SendKeySequence,
-        SendString,
-        SendCommand,
-        Copy,
-        Paste,
-        ShowGroup,
-        HideGroup,
-        Unknown
-    };
-
-    /*!
-    * \brief Constructor
-    */
-    ToolbarWidget(WidgetType type = UndefinedWidgetType);
-
-    /*!
-    * \brief Destructor
-    */
-    virtual ~ToolbarWidget();
-
-    /*!
-     * \brief Returns the WidgetType of the widget.
-     * \sa WidgetType.
-     */
-    WidgetType type() const;
-
-    /*!
-     * \brief Returns the name of the widget.
-     */
-    QString name() const;
-
-    /*!
-    * \brief Returns visibility of the widget.
-    */
-    bool isVisible() const;
-
-    /*!
-    * \brief Sets the visibility of the widget.
-    */
-    void setVisible(bool);
-
-protected:
-    WidgetType widgetType;
-    //! The NAME attribute should be unique and it is used as a reference in the toolbar system.
-    QString widgetName;
-    //! The group name which the button belongs to
-    QString group;
-    int priority;
-    M::Orientation orientation;
-    VisibleType showOn;
-    VisibleType hideOn;
-    Qt::Alignment alignment;
-    QString text;
-    QString textId;
-    bool visible;
-
-    struct Action {
-        Action(ActionType = Unknown);
-        ActionType type;
-        QString keys;
-        QString text;
-        QString command;
-        QString group;
-    };
-
-    // below attributes are only valid for Button
-    bool toggle;
-    bool pressed;
-    QString icon;
-    int size;
-    //! actions when clicking the widget
-    QList<Action *> actions;
-
-    friend class ToolbarData;
-    friend class ToolbarManager;
-    friend class MImToolbar;
-    friend class ParseParameters;
-    friend class Ut_MImToolbar;
-};
-
-#endif
--- m-keyboard/layouts/ar.xml
+++ m-keyboard/layouts/ar.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
-<keyboard version="1.0" title="الْعَرَبيّة" language="ar_SA" catalog="ar_SA">
+<keyboard version="1.0" title="العربية" language="ar" catalog="ar">
     <layout type="general" orientation="landscape">
         <section id="main" movable="false" vertical_alignment="center" horizontal_alignment="center">
           <row>
--- m-keyboard/layouts/cs.xml
+++ m-keyboard/layouts/cs.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
-<keyboard title="Czech" version="1.0" catalog="cs" language="cs">
+<keyboard title="Čeština" version="1.0" catalog="cs" language="cs">
     <layout type="general" orientation="landscape">
         <section id="main" movable="false" vertical_alignment="center" horizontal_alignment="center">
             <row>
--- m-keyboard/layouts/da.xml
+++ m-keyboard/layouts/da.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
-<keyboard title="Danish" version="1.0" catalog="da" language="da">
+<keyboard title="Dansk" version="1.0" catalog="da" language="da">
     <layout type="general" orientation="landscape">
         <section id="main" movable="false" vertical_alignment="center" horizontal_alignment="center">
           <row>
--- m-keyboard/layouts/de.xml
+++ m-keyboard/layouts/de.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
-<keyboard title="Germany" version="1.0" catalog="de" language="de">
+<keyboard title="Deutsch" version="1.0" catalog="de" language="de">
     <layout type="general" orientation="landscape">
         <section id="main" movable="false" vertical_alignment="center" horizontal_alignment="center">
           <row>
--- m-keyboard/layouts/en.xml
+++ m-keyboard/layouts/en.xml
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
-<keyboard title="English (US)" version="1.0" catalog="en_US" language="en_US">
-    <import file="en_default.xml"/>
-    <import file="en_customer.xml"/>
-</keyboard>
--- m-keyboard/layouts/en_default.xml
+++ m-keyboard/layouts/en_default.xml
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
-<keyboard title="English (US)" version="1.0" catalog="en_US" language="en_US">
-    <layout type="general" orientation="landscape">
-        <section id="main" movable="false" vertical_alignment="center" horizontal_alignment="center">
-          <row>
-            <key>
-              <binding label="q"/>
-              <binding shift="true" label="Q"/>
-            </key>
-            <key>
-              <binding label="w"/>
-              <binding shift="true" label="W"/>
-            </key>
-            <key>
-              <binding label="e"/>
-              <binding shift="true" label="E"/>
-            </key>
-            <key>
-              <binding label="r"/>
-              <binding shift="true" label="R"/>
-            </key>
-            <key>
-              <binding label="t"/>
-              <binding shift="true" label="T"/>
-            </key>
-            <key>
-              <binding label="y"/>
-              <binding shift="true" label="Y"/>
-            </key>
-            <key>
-              <binding label="u"/>
-              <binding shift="true" label="U"/>
-            </key>
-            <key>
-              <binding label="i"/>
-              <binding shift="true" label="I"/>
-            </key>
-            <key>
-              <binding label="o"/>
-              <binding shift="true" label="O"/>
-            </key>
-            <key>
-              <binding label="p"/>
-              <binding shift="true" label="P"/>
-            </key>
-          </row>
-          <row>
-            <key>
-              <binding label="a"/>
-              <binding shift="true" label="A"/>
-            </key>
-            <key>
-              <binding label="s"/>
-              <binding shift="true" label="S"/>
-            </key>
-            <key>
-              <binding label="d"/>
-              <binding shift="true" label="D"/>
-            </key>
-            <key>
-              <binding label="f"/>
-              <binding shift="true" label="F"/>
-            </key>
-            <key>
-              <binding label="g"/>
-              <binding shift="true" label="G"/>
-            </key>
-            <key>
-              <binding label="h"/>
-              <binding shift="true" label="H"/>
-            </key>
-            <key>
-              <binding label="j"/>
-              <binding shift="true" label="J"/>
-            </key>
-            <key>
-              <binding label="k"/>
-              <binding shift="true" label="K"/>
-            </key>
-            <key>
-              <binding label="l"/>
-              <binding shift="true" label="L"/>
-            </key>
-          </row>
-          <row>
-            <key>
-              <binding label="z"/>
-              <binding shift="true" label="Z"/>
-            </key>
-            <key>
-              <binding label="x"/>
-              <binding shift="true" label="X"/>
-            </key>
-            <key>
-              <binding label="c"/>
-              <binding shift="true" label="C"/>
-            </key>
-            <key>
-              <binding label="v"/>
-              <binding shift="true" label="V"/>
-            </key>
-            <key>
-              <binding label="b"/>
-              <binding shift="true" label="B"/>
-            </key>
-            <key>
-              <binding label="n"/>
-              <binding shift="true" label="N"/>
-            </key>
-            <key>
-              <binding label="m"/>
-              <binding shift="true" label="M"/>
-            </key>
-          </row>
-        </section>
-        <section id="functionkey" movable="false" horizontal_alignment="left" vertical_alignment="center">
-          <row>
-            <key>
-              <binding action="shift" label=""/>
-            </key>
-            <key>
-              <binding action="sym" label="Sym" secondary_label="áçè"/>
-              <binding shift="true" action="layout_menu" label=""/>
-            </key>
-            <key>
-              <binding label="-"/>
-              <binding shift="true" label="'"/>
-            </key>
-            <key>
-              <binding action="space" label=""/>
-              <binding shift="true" action="return" label=""/>
-            </key>
-            <key>
-              <binding label="?"/>
-              <binding shift="true" label="!"/>
-            </key>
-            <key>
-              <binding label="."/>
-              <binding shift="true" label=","/>
-            </key>
-            <key>
-              <binding action="backspace" label=""/>
-            </key>
-          </row>
-        </section>
-    </layout>
-    <layout type="general" orientation="portrait">
-        <section id="functionkey" movable="false" horizontal_alignment="left" vertical_alignment="center">
-          <row>
-            <key>
-              <binding action="shift" label=""/>
-            </key>
-            <key>
-              <binding action="sym" label="Sym" secondary_label="áçè"/>
-              <binding shift="true" action="layout_menu" label=""/>
-            </key>
-            <key>
-              <binding action="space" label=""/>
-              <binding shift="true" action="return" label=""/>
-            </key>
-            <key>
-              <binding label="."/>
-              <binding shift="true" label=","/>
-            </key>
-            <key>
-              <binding action="backspace" label=""/>
-            </key>
-          </row>
-        </section>
-    </layout>
-    <import file="symbols_en_us.xml"/>
-</keyboard>
--- m-keyboard/layouts/en_gb.xml
+++ m-keyboard/layouts/en_gb.xml
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
+<keyboard title="English (UK)" version="1.0" catalog="en_gb" language="en_gb">
+    <import file="en_gb_default.xml"/>
+    <import file="en_gb_customer.xml"/>
+</keyboard>
--- m-keyboard/layouts/en_gb_default.xml
+++ m-keyboard/layouts/en_gb_default.xml
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
+<keyboard title="English (UK)" version="1.0" catalog="en_gb" language="en_gb">
+    <layout type="general" orientation="landscape">
+        <section id="main" movable="false" vertical_alignment="center" horizontal_alignment="center">
+          <row>
+            <key>
+              <binding label="q"/>
+              <binding shift="true" label="Q"/>
+            </key>
+            <key>
+              <binding label="w"/>
+              <binding shift="true" label="W"/>
+            </key>
+            <key>
+              <binding label="e"/>
+              <binding shift="true" label="E"/>
+            </key>
+            <key>
+              <binding label="r"/>
+              <binding shift="true" label="R"/>
+            </key>
+            <key>
+              <binding label="t"/>
+              <binding shift="true" label="T"/>
+            </key>
+            <key>
+              <binding label="y"/>
+              <binding shift="true" label="Y"/>
+            </key>
+            <key>
+              <binding label="u"/>
+              <binding shift="true" label="U"/>
+            </key>
+            <key>
+              <binding label="i"/>
+              <binding shift="true" label="I"/>
+            </key>
+            <key>
+              <binding label="o"/>
+              <binding shift="true" label="O"/>
+            </key>
+            <key>
+              <binding label="p"/>
+              <binding shift="true" label="P"/>
+            </key>
+          </row>
+          <row>
+            <key>
+              <binding label="a"/>
+              <binding shift="true" label="A"/>
+            </key>
+            <key>
+              <binding label="s"/>
+              <binding shift="true" label="S"/>
+            </key>
+            <key>
+              <binding label="d"/>
+              <binding shift="true" label="D"/>
+            </key>
+            <key>
+              <binding label="f"/>
+              <binding shift="true" label="F"/>
+            </key>
+            <key>
+              <binding label="g"/>
+              <binding shift="true" label="G"/>
+            </key>
+            <key>
+              <binding label="h"/>
+              <binding shift="true" label="H"/>
+            </key>
+            <key>
+              <binding label="j"/>
+              <binding shift="true" label="J"/>
+            </key>
+            <key>
+              <binding label="k"/>
+              <binding shift="true" label="K"/>
+            </key>
+            <key>
+              <binding label="l"/>
+              <binding shift="true" label="L"/>
+            </key>
+          </row>
+          <row>
+            <key>
+              <binding label="z"/>
+              <binding shift="true" label="Z"/>
+            </key>
+            <key>
+              <binding label="x"/>
+              <binding shift="true" label="X"/>
+            </key>
+            <key>
+              <binding label="c"/>
+              <binding shift="true" label="C"/>
+            </key>
+            <key>
+              <binding label="v"/>
+              <binding shift="true" label="V"/>
+            </key>
+            <key>
+              <binding label="b"/>
+              <binding shift="true" label="B"/>
+            </key>
+            <key>
+              <binding label="n"/>
+              <binding shift="true" label="N"/>
+            </key>
+            <key>
+              <binding label="m"/>
+              <binding shift="true" label="M"/>
+            </key>
+          </row>
+        </section>
+        <section id="functionkey" movable="false" horizontal_alignment="left" vertical_alignment="center">
+          <row>
+            <key>
+              <binding action="shift" label=""/>
+            </key>
+            <key>
+              <binding action="sym" label="Sym" secondary_label="áçè"/>
+              <binding shift="true" action="layout_menu" label=""/>
+            </key>
+            <key>
+              <binding label="-"/>
+              <binding shift="true" label="'"/>
+            </key>
+            <key>
+              <binding action="space" label=""/>
+              <binding shift="true" action="return" label=""/>
+            </key>
+            <key>
+              <binding label="?"/>
+              <binding shift="true" label="!"/>
+            </key>
+            <key>
+              <binding label="."/>
+              <binding shift="true" label=","/>
+            </key>
+            <key>
+              <binding action="backspace" label=""/>
+            </key>
+          </row>
+        </section>
+    </layout>
+    <layout type="general" orientation="portrait">
+        <section id="functionkey" movable="false" horizontal_alignment="left" vertical_alignment="center">
+          <row>
+            <key>
+              <binding action="shift" label=""/>
+            </key>
+            <key>
+              <binding action="sym" label="Sym" secondary_label="áçè"/>
+              <binding shift="true" action="layout_menu" label=""/>
+            </key>
+            <key>
+              <binding action="space" label=""/>
+              <binding shift="true" action="return" label=""/>
+            </key>
+            <key>
+              <binding label="."/>
+              <binding shift="true" label=","/>
+            </key>
+            <key>
+              <binding action="backspace" label=""/>
+            </key>
+          </row>
+        </section>
+    </layout>
+    <import file="symbols.xml"/>
+</keyboard>
--- m-keyboard/layouts/en_us.xml
+++ m-keyboard/layouts/en_us.xml
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
+<keyboard title="English (US)" version="1.0" catalog="en_us" language="en_us">
+    <import file="en_us_default.xml"/>
+    <import file="en_us_customer.xml"/>
+</keyboard>
--- m-keyboard/layouts/en_us_default.xml
+++ m-keyboard/layouts/en_us_default.xml
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
+<keyboard title="English (US)" version="1.0" catalog="en_us" language="en_us">
+    <layout type="general" orientation="landscape">
+        <section id="main" movable="false" vertical_alignment="center" horizontal_alignment="center">
+          <row>
+            <key>
+              <binding label="q"/>
+              <binding shift="true" label="Q"/>
+            </key>
+            <key>
+              <binding label="w"/>
+              <binding shift="true" label="W"/>
+            </key>
+            <key>
+              <binding label="e"/>
+              <binding shift="true" label="E"/>
+            </key>
+            <key>
+              <binding label="r"/>
+              <binding shift="true" label="R"/>
+            </key>
+            <key>
+              <binding label="t"/>
+              <binding shift="true" label="T"/>
+            </key>
+            <key>
+              <binding label="y"/>
+              <binding shift="true" label="Y"/>
+            </key>
+            <key>
+              <binding label="u"/>
+              <binding shift="true" label="U"/>
+            </key>
+            <key>
+              <binding label="i"/>
+              <binding shift="true" label="I"/>
+            </key>
+            <key>
+              <binding label="o"/>
+              <binding shift="true" label="O"/>
+            </key>
+            <key>
+              <binding label="p"/>
+              <binding shift="true" label="P"/>
+            </key>
+          </row>
+          <row>
+            <key>
+              <binding label="a"/>
+              <binding shift="true" label="A"/>
+            </key>
+            <key>
+              <binding label="s"/>
+              <binding shift="true" label="S"/>
+            </key>
+            <key>
+              <binding label="d"/>
+              <binding shift="true" label="D"/>
+            </key>
+            <key>
+              <binding label="f"/>
+              <binding shift="true" label="F"/>
+            </key>
+            <key>
+              <binding label="g"/>
+              <binding shift="true" label="G"/>
+            </key>
+            <key>
+              <binding label="h"/>
+              <binding shift="true" label="H"/>
+            </key>
+            <key>
+              <binding label="j"/>
+              <binding shift="true" label="J"/>
+            </key>
+            <key>
+              <binding label="k"/>
+              <binding shift="true" label="K"/>
+            </key>
+            <key>
+              <binding label="l"/>
+              <binding shift="true" label="L"/>
+            </key>
+          </row>
+          <row>
+            <key>
+              <binding label="z"/>
+              <binding shift="true" label="Z"/>
+            </key>
+            <key>
+              <binding label="x"/>
+              <binding shift="true" label="X"/>
+            </key>
+            <key>
+              <binding label="c"/>
+              <binding shift="true" label="C"/>
+            </key>
+            <key>
+              <binding label="v"/>
+              <binding shift="true" label="V"/>
+            </key>
+            <key>
+              <binding label="b"/>
+              <binding shift="true" label="B"/>
+            </key>
+            <key>
+              <binding label="n"/>
+              <binding shift="true" label="N"/>
+            </key>
+            <key>
+              <binding label="m"/>
+              <binding shift="true" label="M"/>
+            </key>
+          </row>
+        </section>
+        <section id="functionkey" movable="false" horizontal_alignment="left" vertical_alignment="center">
+          <row>
+            <key>
+              <binding action="shift" label=""/>
+            </key>
+            <key>
+              <binding action="sym" label="Sym" secondary_label="áçè"/>
+              <binding shift="true" action="layout_menu" label=""/>
+            </key>
+            <key>
+              <binding label="-"/>
+              <binding shift="true" label="'"/>
+            </key>
+            <key>
+              <binding action="space" label=""/>
+              <binding shift="true" action="return" label=""/>
+            </key>
+            <key>
+              <binding label="?"/>
+              <binding shift="true" label="!"/>
+            </key>
+            <key>
+              <binding label="."/>
+              <binding shift="true" label=","/>
+            </key>
+            <key>
+              <binding action="backspace" label=""/>
+            </key>
+          </row>
+        </section>
+    </layout>
+    <layout type="general" orientation="portrait">
+        <section id="functionkey" movable="false" horizontal_alignment="left" vertical_alignment="center">
+          <row>
+            <key>
+              <binding action="shift" label=""/>
+            </key>
+            <key>
+              <binding action="sym" label="Sym" secondary_label="áçè"/>
+              <binding shift="true" action="layout_menu" label=""/>
+            </key>
+            <key>
+              <binding action="space" label=""/>
+              <binding shift="true" action="return" label=""/>
+            </key>
+            <key>
+              <binding label="."/>
+              <binding shift="true" label=","/>
+            </key>
+            <key>
+              <binding action="backspace" label=""/>
+            </key>
+          </row>
+        </section>
+    </layout>
+    <import file="symbols_en_us.xml"/>
+</keyboard>
--- m-keyboard/layouts/es.xml
+++ m-keyboard/layouts/es.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
-<keyboard title="Spanish" version="1.0" catalog="es" language="es">
+<keyboard title="Español" version="1.0" catalog="es" language="es">
     <layout type="general" orientation="landscape">
         <section id="main" movable="false" vertical_alignment="center" horizontal_alignment="center">
           <row>
--- m-keyboard/layouts/fr.xml
+++ m-keyboard/layouts/fr.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
-<keyboard title="French" version="1.0" catalog="fr" language="fr">
+<keyboard title="Français" version="1.0" catalog="fr" language="fr">
     <layout type="general" orientation="landscape">
         <section id="main" movable="false" vertical_alignment="center" horizontal_alignment="center">
           <row>
--- m-keyboard/layouts/fr_CA.xml
+++ m-keyboard/layouts/fr_CA.xml
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
-<keyboard title="French (Canadian)" version="1.0" catalog="fr_CA" language="fr_CA">
-    <layout type="general" orientation="landscape">
-        <section id="main" movable="false" vertical_alignment="center" horizontal_alignment="center">
-          <row>
-            <key>
-              <binding label="q"/>
-              <binding shift="true" label="Q"/>
-            </key>
-            <key>
-              <binding label="w"/>
-              <binding shift="true" label="W"/>
-            </key>
-            <key>
-              <binding accented_labels="èéêë" accents="`´^¨" label="e"/>
-              <binding shift="true" accented_labels="ÈÉÊË" accents="`´^¨" label="E"/>
-            </key>
-            <key>
-              <binding label="r"/>
-              <binding shift="true" label="R"/>
-            </key>
-            <key>
-              <binding label="t"/>
-              <binding shift="true" label="T"/>
-            </key>
-            <key>
-              <binding accented_labels="ýÿ" accents="´¨" label="y"/>
-              <binding shift="true" accented_labels="ÝŸ" accents="´¨" label="Y"/>
-            </key>
-            <key>
-              <binding accented_labels="ùúûü" accents="`´^¨" label="u"/>
-              <binding shift="true" accented_labels="ÙÚÛÜ" accents="`´^¨" label="U"/>
-            </key>
-            <key>
-              <binding accented_labels="ìíîï" accents="`´^¨" label="i"/>
-              <binding shift="true" accented_labels="ÌÍÎÏ" accents="`´^¨" label="I"/>
-            </key>
-            <key>
-              <binding accented_labels="òóôö" accents="`´^¨" label="o"/>
-              <binding shift="true" accented_labels="ÒÓÔÖ" accents="`´^¨" label="O"/>
-            </key>
-            <key>
-              <binding label="p"/>
-              <binding shift="true" label="P"/>
-            </key>
-            <key>
-              <binding dead="true" label="¨"/>
-            </key>
-          </row>
-          <row>
-            <key>
-              <binding accented_labels="àáâä" accents="`´^¨" label="a"/>
-              <binding shift="true" accented_labels="ÀÁÂÄ" accents="`´^¨" label="A"/>
-            </key>
-            <key>
-              <binding label="s"/>
-              <binding shift="true" label="S"/>
-            </key>
-            <key>
-              <binding label="d"/>
-              <binding shift="true" label="D"/>
-            </key>
-            <key>
-              <binding label="f"/>
-              <binding shift="true" label="F"/>
-            </key>
-            <key>
-              <binding label="g"/>
-              <binding shift="true" label="G"/>
-            </key>
-            <key>
-              <binding label="h"/>
-              <binding shift="true" label="H"/>
-            </key>
-            <key>
-              <binding label="j"/>
-              <binding shift="true" label="J"/>
-            </key>
-            <key>
-              <binding label="k"/>
-              <binding shift="true" label="K"/>
-            </key>
-            <key>
-              <binding label="l"/>
-              <binding shift="true" label="L"/>
-            </key>
-            <key>
-              <binding dead="true" label="^"/>
-            </key>
-          </row>
-          <row>
-            <key>
-              <binding label="z"/>
-              <binding shift="true" label="Z"/>
-            </key>
-            <key>
-              <binding label="x"/>
-              <binding shift="true" label="X"/>
-            </key>
-            <key>
-              <binding label="c"/>
-              <binding shift="true" label="C"/>
-            </key>
-            <key>
-              <binding label="v"/>
-              <binding shift="true" label="V"/>
-            </key>
-            <key>
-              <binding label="b"/>
-              <binding shift="true" label="B"/>
-            </key>
-            <key>
-              <binding label="n"/>
-              <binding shift="true" label="N"/>
-            </key>
-            <key>
-              <binding label="m"/>
-              <binding shift="true" label="M"/>
-            </key>
-            <key>
-              <binding label="ç"/>
-              <binding shift="true" label="Ç"/>
-            </key>
-            <key>
-              <binding dead="true" label="´"/>
-            </key>
-            <key>
-              <binding dead="true" label="`"/>
-            </key>
-          </row>
-        </section>
-        <section id="functionkey" movable="false" horizontal_alignment="left" vertical_alignment="center">
-          <row>
-            <key>
-              <binding action="shift" label=""/>
-            </key>
-            <key>
-              <binding action="sym" label="Sym" secondary_label="áçè"/>
-              <binding shift="true" action="layout_menu" label=""/>
-            </key>
-            <key>
-              <binding label="-"/>
-              <binding shift="true" label="'"/>
-            </key>
-            <key>
-              <binding action="space" label=""/>
-              <binding shift="true" action="return" label=""/>
-            </key>
-            <key>
-              <binding label="?"/>
-              <binding shift="true" label="!"/>
-            </key>
-            <key>
-              <binding label="."/>
-              <binding shift="true" label=","/>
-            </key>
-            <key>
-              <binding action="backspace" label=""/>
-            </key>
-          </row>
-        </section>
-    </layout>
-    <layout type="general" orientation="portrait">
-        <section id="functionkey" movable="false" horizontal_alignment="left" vertical_alignment="center">
-          <row>
-            <key>
-              <binding action="shift" label=""/>
-            </key>
-            <key>
-              <binding action="sym" label="Sym" secondary_label="áçè"/>
-              <binding shift="true" action="layout_menu" label=""/>
-            </key>
-            <key>
-              <binding action="space" label=""/>
-              <binding shift="true" action="return" label=""/>
-            </key>
-            <key>
-              <binding label="."/>
-              <binding shift="true" label=","/>
-            </key>
-            <key>
-              <binding action="backspace" label=""/>
-            </key>
-          </row>
-        </section>
-    </layout>
-    <import file="symbols.xml"/>
-</keyboard>
--- m-keyboard/layouts/fr_ca.xml
+++ m-keyboard/layouts/fr_ca.xml
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
+<keyboard title="Français (Canada)" version="1.0" catalog="fr_CA" language="fr_CA">
+    <layout type="general" orientation="landscape">
+        <section id="main" movable="false" vertical_alignment="center" horizontal_alignment="center">
+          <row>
+            <key>
+              <binding label="q"/>
+              <binding shift="true" label="Q"/>
+            </key>
+            <key>
+              <binding label="w"/>
+              <binding shift="true" label="W"/>
+            </key>
+            <key>
+              <binding accented_labels="èéêë" accents="`´^¨" label="e"/>
+              <binding shift="true" accented_labels="ÈÉÊË" accents="`´^¨" label="E"/>
+            </key>
+            <key>
+              <binding label="r"/>
+              <binding shift="true" label="R"/>
+            </key>
+            <key>
+              <binding label="t"/>
+              <binding shift="true" label="T"/>
+            </key>
+            <key>
+              <binding accented_labels="ýÿ" accents="´¨" label="y"/>
+              <binding shift="true" accented_labels="ÝŸ" accents="´¨" label="Y"/>
+            </key>
+            <key>
+              <binding accented_labels="ùúûü" accents="`´^¨" label="u"/>
+              <binding shift="true" accented_labels="ÙÚÛÜ" accents="`´^¨" label="U"/>
+            </key>
+            <key>
+              <binding accented_labels="ìíîï" accents="`´^¨" label="i"/>
+              <binding shift="true" accented_labels="ÌÍÎÏ" accents="`´^¨" label="I"/>
+            </key>
+            <key>
+              <binding accented_labels="òóôö" accents="`´^¨" label="o"/>
+              <binding shift="true" accented_labels="ÒÓÔÖ" accents="`´^¨" label="O"/>
+            </key>
+            <key>
+              <binding label="p"/>
+              <binding shift="true" label="P"/>
+            </key>
+            <key>
+              <binding dead="true" label="¨"/>
+            </key>
+          </row>
+          <row>
+            <key>
+              <binding accented_labels="àáâä" accents="`´^¨" label="a"/>
+              <binding shift="true" accented_labels="ÀÁÂÄ" accents="`´^¨" label="A"/>
+            </key>
+            <key>
+              <binding label="s"/>
+              <binding shift="true" label="S"/>
+            </key>
+            <key>
+              <binding label="d"/>
+              <binding shift="true" label="D"/>
+            </key>
+            <key>
+              <binding label="f"/>
+              <binding shift="true" label="F"/>
+            </key>
+            <key>
+              <binding label="g"/>
+              <binding shift="true" label="G"/>
+            </key>
+            <key>
+              <binding label="h"/>
+              <binding shift="true" label="H"/>
+            </key>
+            <key>
+              <binding label="j"/>
+              <binding shift="true" label="J"/>
+            </key>
+            <key>
+              <binding label="k"/>
+              <binding shift="true" label="K"/>
+            </key>
+            <key>
+              <binding label="l"/>
+              <binding shift="true" label="L"/>
+            </key>
+            <key>
+              <binding dead="true" label="^"/>
+            </key>
+          </row>
+          <row>
+            <key>
+              <binding label="z"/>
+              <binding shift="true" label="Z"/>
+            </key>
+            <key>
+              <binding label="x"/>
+              <binding shift="true" label="X"/>
+            </key>
+            <key>
+              <binding label="c"/>
+              <binding shift="true" label="C"/>
+            </key>
+            <key>
+              <binding label="v"/>
+              <binding shift="true" label="V"/>
+            </key>
+            <key>
+              <binding label="b"/>
+              <binding shift="true" label="B"/>
+            </key>
+            <key>
+              <binding label="n"/>
+              <binding shift="true" label="N"/>
+            </key>
+            <key>
+              <binding label="m"/>
+              <binding shift="true" label="M"/>
+            </key>
+            <key>
+              <binding label="ç"/>
+              <binding shift="true" label="Ç"/>
+            </key>
+            <key>
+              <binding dead="true" label="´"/>
+            </key>
+            <key>
+              <binding dead="true" label="`"/>
+            </key>
+          </row>
+        </section>
+        <section id="functionkey" movable="false" horizontal_alignment="left" vertical_alignment="center">
+          <row>
+            <key>
+              <binding action="shift" label=""/>
+            </key>
+            <key>
+              <binding action="sym" label="Sym" secondary_label="áçè"/>
+              <binding shift="true" action="layout_menu" label=""/>
+            </key>
+            <key>
+              <binding label="-"/>
+              <binding shift="true" label="'"/>
+            </key>
+            <key>
+              <binding action="space" label=""/>
+              <binding shift="true" action="return" label=""/>
+            </key>
+            <key>
+              <binding label="?"/>
+              <binding shift="true" label="!"/>
+            </key>
+            <key>
+              <binding label="."/>
+              <binding shift="true" label=","/>
+            </key>
+            <key>
+              <binding action="backspace" label=""/>
+            </key>
+          </row>
+        </section>
+    </layout>
+    <layout type="general" orientation="portrait">
+        <section id="functionkey" movable="false" horizontal_alignment="left" vertical_alignment="center">
+          <row>
+            <key>
+              <binding action="shift" label=""/>
+            </key>
+            <key>
+              <binding action="sym" label="Sym" secondary_label="áçè"/>
+              <binding shift="true" action="layout_menu" label=""/>
+            </key>
+            <key>
+              <binding action="space" label=""/>
+              <binding shift="true" action="return" label=""/>
+            </key>
+            <key>
+              <binding label="."/>
+              <binding shift="true" label=","/>
+            </key>
+            <key>
+              <binding action="backspace" label=""/>
+            </key>
+          </row>
+        </section>
+    </layout>
+    <import file="symbols.xml"/>
+</keyboard>
--- m-keyboard/layouts/it.xml
+++ m-keyboard/layouts/it.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
-<keyboard title="Italian" version="1.0" catalog="it" language="it">
+<keyboard title="Italiano" version="1.0" catalog="it" language="it">
     <layout type="general" orientation="landscape">
         <section id="main" movable="false" vertical_alignment="center" horizontal_alignment="center">
           <row>
--- m-keyboard/layouts/nl.xml
+++ m-keyboard/layouts/nl.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
-<keyboard title="Dutch" version="1.0" catalog="nl" language="nl">
+<keyboard title="Nederlands" version="1.0" catalog="nl" language="nl">
     <layout type="general" orientation="landscape">
         <section id="main" movable="false" vertical_alignment="center" horizontal_alignment="center">
           <row>
--- m-keyboard/layouts/no.xml
+++ m-keyboard/layouts/no.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
-<keyboard title="Norwegian" version="1.0" catalog="no" language="no">
+<keyboard title="Norsk" version="1.0" catalog="no" language="no">
     <layout type="general" orientation="landscape">
         <section id="main" movable="false" vertical_alignment="center" horizontal_alignment="center">
           <row>
--- m-keyboard/layouts/pl.xml
+++ m-keyboard/layouts/pl.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
-<keyboard title="Polish" version="1.0" catalog="pl" language="pl">
+<keyboard title="Polski" version="1.0" catalog="pl" language="pl">
     <layout type="general" orientation="landscape">
         <section id="main" movable="false" vertical_alignment="center" horizontal_alignment="center">
           <row>
--- m-keyboard/layouts/pt.xml
+++ m-keyboard/layouts/pt.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
-<keyboard title="Portuguese" version="1.0" catalog="pt" language="pt">
+<keyboard title="Português" version="1.0" catalog="pt" language="pt">
     <layout type="general" orientation="landscape">
         <section id="main" movable="false" vertical_alignment="center" horizontal_alignment="center">
           <row>
--- m-keyboard/layouts/ru.xml
+++ m-keyboard/layouts/ru.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
-<keyboard title="Russian" version="1.0" catalog="ru" language="ru">
+<keyboard title="Русский" version="1.0" catalog="ru" language="ru">
     <layout type="general" orientation="landscape">
         <section id="main" movable="false" vertical_alignment="center" horizontal_alignment="center">
           <row>
--- m-keyboard/layouts/sv.xml
+++ m-keyboard/layouts/sv.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
-<keyboard title="Swedish" version="1.0" catalog="sv" language="sv">
+<keyboard title="Svenska" version="1.0" catalog="sv" language="sv">
     <layout type="general" orientation="landscape">
         <section id="main" movable="false" vertical_alignment="center" horizontal_alignment="center">
           <row>
--- m-keyboard/m-keyboard.pro
+++ m-keyboard/m-keyboard.pro
@@ -9,7 +9,7 @@
 # we have this line temporarily until new libmeegotouch without rpath is integrated
 QT += xml
 
-CONFIG += plugin meegotouch duiimengine duiimenginewords meegoimframework meegoreactionmap
+CONFIG += plugin meegotouch meegoimengine meegoimenginewords meegoimframework meegoreactionmap
 #CONFIG += mcontrolpanel
 DEFINES += NOCONTROLPANEL
 
@@ -35,10 +35,12 @@
 
 HEADERS += \
     mkeyboardhost.h \
+    mkeyboardsettings.h \
     mkeyboardplugin.h \
 
 SOURCES += \
     mkeyboardhost.cpp \
+    mkeyboardsettings.cpp \
     mkeyboardplugin.cpp \
 
 target.path += /usr/lib/meego-im-plugins
--- m-keyboard/mkeyboardhost.cpp
+++ m-keyboard/mkeyboardhost.cpp
@@ -17,6 +17,7 @@
 
 
 #include "mkeyboardhost.h"
+#include "mvirtualkeyboardstyle.h"
 #include "mvirtualkeyboard.h"
 #include "mhardwarekeyboard.h"
 #ifdef M_IM_DISABLE_TRANSLUCENCY
@@ -24,14 +25,13 @@
 #endif
 #include "mimcorrectioncandidatewidget.h"
 #include "keyboarddata.h"
-#include "layoutmenu.h"
 #include "layoutsmanager.h"
 #include "symbolview.h"
-#include "toolbarmanager.h"
 
-#include <duiimenginewords.h>
+#include <mimenginewords.h>
 #include <minputcontextconnection.h>
 #include <mplainwindow.h>
+#include <mtoolbardata.h>
 #include <mgconfitem.h>
 #include <mtheme.h>
 
@@ -50,8 +50,8 @@
 #include <MSceneWindow>
 #include <MInfoBanner>
 #include <MLibrary>
-M_LIBRARY // to avoid a crash from mtheme. FIXME - is this the proper way for us?
 
+M_LIBRARY
 
 namespace
 {
@@ -65,16 +65,16 @@
     const int AutoBackspaceDelay = 500;      // in ms
     const int BackspaceRepeatInterval = 100; // in ms
     const int MultitapTime = 1500;           // in ms
-    const char * const PixmapDirectory = "/usr/share/meegotouch/virtual-keyboard/images";
-    const QString CssFile("/usr/share/meegotouch/virtual-keyboard/css/%1x%2.css");
-    const QString DefaultCss = CssFile.arg(864).arg(480); // Default screen resolution is 864x480
     const Qt::KeyboardModifier FnLevelModifier = Qt::GroupSwitchModifier;
     const int ModifierLockOnInfoDuration = 1000;    // in ms
+    // This GConf item defines whether multitouch is enabled or disabled
+    const char * const MultitouchSettings = "/meegotouch/inputmethods/multitouch/enabled";
 }
 
 
 MKeyboardHost::MKeyboardHost(MInputContextConnection* icConnection, QObject *parent)
     : MInputMethodBase(icConnection, parent),
+      vkbStyleContainer(0),
       vkbWidget(0),
       symbolView(0),
       inputMethodCorrectionSettings(new MGConfItem(InputMethodCorrectionSetting)),
@@ -85,32 +85,26 @@
       correctionEnabled(false),
       feedbackPlayer(0),
       autoCapsEnabled(true),
+      upperCase(false),
       cursorPos(-1),
       inputMethodMode(M::InputMethodModeNormal),
       backSpaceTimer(this),
       multitapIndex(0),
+      shiftHeldDown(false),
       activeState(OnScreen),
       modifierLockOnInfoBanner(0),
       modifierLockOnTimer(this),
-      haveFocus(false)
+      haveFocus(false),
+      savedShiftState(ModifierClearState),
+      savedUpperCase(false),
+      enableMultiTouch(false)
 {
     displayHeight = MPlainWindow::instance()->visibleSceneSize(M::Landscape).height();
     displayWidth  = MPlainWindow::instance()->visibleSceneSize(M::Landscape).width();
 
-    //TODO get this from settings
-    MTheme *theme = MTheme::instance();
-    theme->addPixmapDirectory(PixmapDirectory);
-
-    QString css = CssFile.arg(displayWidth, displayHeight);
-
-    if (!QFile::exists(css)) {
-        css = DefaultCss;
-    }
-
-    theme->loadCSS(css);
+    enableMultiTouch = MGConfItem(MultitouchSettings).value().toBool();
 
     LayoutsManager::createInstance();
-    ToolbarManager::createInstance();
 
     sceneWindow = new MSceneWindow;
     sceneWindow->setManagedManually(true); // we want the scene window to remain in origin
@@ -132,7 +126,11 @@
     // 2) Add widgets directly to scene (detached from MSceneManager) and
     //    update their transformations by hand.
 
-    vkbWidget = new MVirtualKeyboard(LayoutsManager::instance(), sceneWindow);
+    vkbStyleContainer = new MVirtualKeyboardStyleContainer;
+    vkbStyleContainer->initialize("MVirtualKeyboard", "MVirtualKeyboardView", 0);
+
+    vkbWidget = new MVirtualKeyboard(LayoutsManager::instance(), vkbStyleContainer, sceneWindow);
+    vkbWidget->setInputMethodMode(static_cast<M::InputMethodMode>(inputMethodMode));
 
     connect(vkbWidget, SIGNAL(keyClicked(const KeyEvent &)),
             this, SLOT(handleKeyClick(const KeyEvent &)));
@@ -145,7 +143,7 @@
 
     connect(vkbWidget, SIGNAL(regionUpdated(const QRegion &)),
             this, SLOT(handleRegionUpdate(const QRegion &)));
-    connect(vkbWidget, SIGNAL(regionUpdated(const QRegion &)),
+    connect(vkbWidget, SIGNAL(inputMethodAreaUpdated(const QRegion &)),
             this, SLOT(handleInputMethodAreaUpdate(const QRegion &)));
 
     connect(vkbWidget, SIGNAL(userInitiatedHide()),
@@ -154,6 +152,7 @@
     connect(vkbWidget, SIGNAL(pluginSwitchRequired(M::InputMethodSwitchDirection)),
             this, SIGNAL(pluginSwitchRequired(M::InputMethodSwitchDirection)));
 
+    modifierLockOnTimer.setSingleShot(true);
     modifierLockOnTimer.setInterval(ModifierLockOnInfoDuration);
     connect(&modifierLockOnTimer, SIGNAL(timeout()), this, SLOT(hideLockOnInfoBanner()));
 
@@ -185,7 +184,7 @@
             SIGNAL(orientationChangeFinished(M::Orientation)),
             SLOT(finalizeOrientationChange()));
 
-    symbolView = new SymbolView(LayoutsManager::instance(), &vkbWidget->style(),
+    symbolView = new SymbolView(LayoutsManager::instance(), vkbStyleContainer,
                                 vkbWidget->selectedLanguage(), sceneWindow);
     connect(symbolView, SIGNAL(regionUpdated(const QRegion &)),
             this, SLOT(handleRegionUpdate(const QRegion &)));
@@ -208,19 +207,6 @@
     connect(hardwareKeyboard, SIGNAL(shiftStateChanged()),
             this, SLOT(updateSymbolViewLevel()));
 
-    // Construct layout menu dialog
-    layoutMenu = new LayoutMenu(&vkbWidget->style(), 0);
-
-    connect(layoutMenu, SIGNAL(errorCorrectionToggled(bool)),
-            this, SLOT(errorCorrectionToggled(bool)));
-
-    connect(layoutMenu, SIGNAL(regionUpdated(const QRegion &)),
-            this, SLOT(handleRegionUpdate(const QRegion &)));
-
-    connect(layoutMenu, SIGNAL(languageSelected(int)), vkbWidget, SLOT(setLanguage(int)));
-    // FIXME: connect something to layoutMenu::organizeContent()?
-    // layout menu done
-
     connect(vkbWidget, SIGNAL(copyPasteRequest(CopyPasteState)),
             this, SLOT(sendCopyPaste(CopyPasteState)));
     connect(vkbWidget, SIGNAL(sendKeyEventRequest(const QKeyEvent &)),
@@ -228,7 +214,7 @@
     connect(vkbWidget, SIGNAL(sendStringRequest(const QString &)),
             this, SLOT(sendString(const QString &)));
 
-    imCorrectionEngine = DuiImEngineWords::instance();
+    imCorrectionEngine = MImEngineWords::instance();
 
 
     if (!inputMethodCorrectionEngine->value().isNull()) {
@@ -258,7 +244,6 @@
     connect(symbolView, SIGNAL(hidden()), vkbWidget, SLOT(showMainArea()));
 }
 
-
 MKeyboardHost::~MKeyboardHost()
 {
     hideLockOnInfoBanner();
@@ -266,10 +251,14 @@
     hardwareKeyboard = 0;
     delete vkbWidget;
     vkbWidget = 0;
+    delete symbolView;
+    symbolView = 0;
     delete correctionCandidateWidget;
     correctionCandidateWidget = 0;
     delete sceneWindow;
     sceneWindow = 0;
+    delete vkbStyleContainer;
+    vkbStyleContainer = 0;
 #ifdef M_IM_DISABLE_TRANSLUCENCY
     delete correctionSceneWindow;
     correctionSceneWindow = 0;
@@ -280,9 +269,7 @@
     inputMethodCorrectionSettings = 0;
     //TODO imCorrectionEngine is not deleted. memory loss
     backSpaceTimer.stop();
-    delete layoutMenu;
     LayoutsManager::destroyInstance();
-    ToolbarManager::destroyInstance();
 }
 
 void MKeyboardHost::createCorrectionCandidateWidget()
@@ -331,7 +318,13 @@
 {
     haveFocus = focusIn;
     if (activeState == Hardware) {
-        hardwareKeyboard->focusChanged(focusIn);
+        if (inputMethodMode != M::InputMethodModeDirect) {
+            if (focusIn) {
+                hardwareKeyboard->enable();
+            } else {
+                hardwareKeyboard->disable();
+            }
+        }
         if (!focusIn) {
             sendInputModeIndicator(MInputMethodBase::NoIndicator);
         }
@@ -413,7 +406,15 @@
 
     const int inputMethodModeValue = inputContextConnection()->inputMethodMode(valid);
     if (valid) {
+        if (haveFocus && (activeState == Hardware) && (inputMethodMode != inputMethodModeValue)) {
+            if (inputMethodModeValue != M::InputMethodModeDirect) {
+                hardwareKeyboard->enable();
+            } else {
+                hardwareKeyboard->disable();
+            }
+        }
         inputMethodMode = inputMethodModeValue;
+        vkbWidget->setInputMethodMode(static_cast<M::InputMethodMode>(inputMethodMode));
     }
 }
 
@@ -423,6 +424,8 @@
     if (!autoCapsEnabled)
         return;
 
+    upperCase = false;
+
     // TODO: consider RTL language case
     // Capitalization is determined by preedit and Auto Capitalization.
     // If there are some preedit, it should be lower case.
@@ -430,15 +433,18 @@
     //   1. at the beginning of one paragraph
     //   2. after a sentence delimiter and one or more spaces
     static const QRegExp autoCapsTrigger("[" + AutoCapsSentenceDelimiters + "] +$");
-    const bool upperCase = ((preedit.length() == 0)
-                            && ((cursorPos == 0)
-                                || ((cursorPos > 0)
-                                    && (cursorPos <= surroundingText.length())
-                                    && surroundingText.left(cursorPos).contains(autoCapsTrigger))));
-
-    if ((activeState == OnScreen) && (vkbWidget->shiftStatus() != MVirtualKeyboard::ShiftLock)) {
+    upperCase = ((preedit.length() == 0)
+                 && ((cursorPos == 0)
+                     || ((cursorPos > 0)
+                         && (cursorPos <= surroundingText.length())
+                         && surroundingText.left(cursorPos).contains(autoCapsTrigger))));
+
+    if ((activeState == OnScreen)
+        && (vkbWidget->shiftStatus() != ModifierLockedState)
+        && (!enableMultiTouch || !shiftHeldDown
+            || (vkbWidget->shiftStatus() != ModifierLatchedState))) {
         vkbWidget->setShiftState(upperCase ?
-                                 MVirtualKeyboard::ShiftOn : MVirtualKeyboard::ShiftOff);
+                                 ModifierLatchedState : ModifierClearState);
     } else if ((activeState == Hardware) &&
                (hardwareKeyboard->modifierState(Qt::ShiftModifier) != ModifierLockedState)) {
         hardwareKeyboard->setAutoCapitalization(upperCase);
@@ -499,14 +505,14 @@
     // If correction candidate widget was open we need to reposition it.
     if (correctionCandidateWidget->isVisible()) {
         bool success = false;
-        QRect rect = inputContextConnection()->preeditRectangle(success);
+        const QRect rect = inputContextConnection()->preeditRectangle(success);
         QRect localRect;
         // Note: For Qt applications we don't have means to retrieve
         // the correct coordinates for pre-edit rectangle, so rect here
         // is null.
         if (success && !rect.isNull() && rotateRect(rect, localRect)) {
-            int bottomLimit = static_cast<int>(sceneWindow->mapRectFromScene(
-                                                   vkbWidget->region(false).boundingRect()).top());
+            const int bottomLimit = static_cast<int>(sceneWindow->mapRectFromScene(
+                                                         vkbWidget->region(false).boundingRect()).top());
 
             correctionCandidateWidget->setPosition(localRect, bottomLimit);
         } else {
@@ -594,7 +600,7 @@
     QRect localRect;
 
     // Bottom limit for positioning candidate list widget. Keep above keyboard.
-    int bottomLimit = static_cast<int>(vkbWidget->region(false).boundingRect().top());
+    const int bottomLimit = static_cast<int>(vkbWidget->region(false).boundingRect().top());
 
     // Use preeditRect if one was passed (not null).
     if (!preeditRect.isNull() && rotateRect(preeditRect, localRect)) {
@@ -665,16 +671,16 @@
     } else {
         static const KeyEvent event("\b", QEvent::KeyRelease, Qt::Key_Backspace,
                                     KeyEvent::NotSpecial,
-                                    vkbWidget->shiftStatus() != MVirtualKeyboard::ShiftOff
+                                    vkbWidget->shiftStatus() != ModifierClearState
                                     ? Qt::ShiftModifier : Qt::NoModifier);
         inputContextConnection()->sendKeyEvent(KeyEvent(event, QEvent::KeyPress).toQKeyEvent());
         inputContextConnection()->sendKeyEvent(event.toQKeyEvent());
     }
     // Backspace toggles shift off if it's on (not locked)
     // except if autoCaps is on and cursor is at 0 position.
-    if (vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOn
+    if (vkbWidget->shiftStatus() == ModifierLatchedState
         && (!autoCapsEnabled || cursorPos != 0)) {
-        vkbWidget->setShiftState(MVirtualKeyboard::ShiftOff);
+        vkbWidget->setShiftState(ModifierClearState);
     }
 }
 
@@ -686,6 +692,23 @@
 
 void MKeyboardHost::handleKeyPress(const KeyEvent &event)
 {
+    if (event.qtKey() == Qt::Key_Shift) {
+        if (shiftHeldDown) {
+            return; //ignore duplicated event
+        }
+
+        if (activeState == OnScreen && enableMultiTouch) {
+            shiftHeldDown = true;
+            savedShiftState = vkbWidget->shiftStatus();
+            savedUpperCase = upperCase;
+            // we need to invert shift state:
+            // * clear shift state if it is latched or locked, or
+            // * latch it, if it is cleared
+            const ModifierState newState = (savedShiftState == ModifierClearState) ? ModifierLatchedState : ModifierClearState;
+            vkbWidget->setShiftState(newState);
+        }
+    }
+
     if (((inputMethodMode == M::InputMethodModeDirect)
          && (event.specialKey() == KeyEvent::NotSpecial))
         || (event.qtKey() == Qt::Key_plusminus)) { // plusminus key makes an exception
@@ -699,6 +722,31 @@
 
 void MKeyboardHost::handleKeyRelease(const KeyEvent &event)
 {
+    if (event.qtKey() == Qt::Key_Shift) {
+        if (!shiftHeldDown) {
+            return; //ignore duplicated event
+        }
+
+        if (activeState == OnScreen && enableMultiTouch) {
+            ModifierState newState = ModifierClearState;
+
+            shiftHeldDown = false;
+            // we need to update shift status:
+            // * restore old value if character case was not toggled by auto caps
+            // * latch shift key if upper case was enabled by auto caps
+            // * otherwise clear shift key
+            if (savedUpperCase == upperCase) {
+                newState = savedShiftState;
+            } else if (upperCase) {
+                newState = ModifierLatchedState;
+            } else {
+                newState = ModifierClearState;
+            }
+
+            vkbWidget->setShiftState(newState);
+        }
+    }
+
     if (((inputMethodMode == M::InputMethodModeDirect)
          && (event.specialKey() == KeyEvent::NotSpecial))
         || (event.qtKey() == Qt::Key_plusminus)) { // plusminus key makes an exception
@@ -718,9 +766,7 @@
     }
 
     // Draw the reactive areas of first one of these who is visible.
-    if (layoutMenu->isActive()) {
-        layoutMenu->redrawReactionMaps();
-    } else if (correctionCandidateWidget->isVisible()) {
+    if (correctionCandidateWidget->isVisible()) {
         correctionCandidateWidget->redrawReactionMaps();
     } else if (symbolView->isFullyVisible()) {
         symbolView->redrawReactionMaps();
@@ -773,21 +819,33 @@
 {
     if (event.qtKey() == Qt::Key_Shift) {
         switch (vkbWidget->shiftStatus()) {
-        case MVirtualKeyboard::ShiftOn:
-            vkbWidget->setShiftState(MVirtualKeyboard::ShiftLock);
+        case ModifierLatchedState:
+            // If current ShiftOn state is due to autocaps, go back to ShiftOff.
+            // Otherwise, lock it.
+            if (upperCase) {
+                vkbWidget->setShiftState(ModifierClearState);
+            } else {
+                vkbWidget->setShiftState(ModifierLockedState);
+            }
             break;
-        case MVirtualKeyboard::ShiftOff:
-            vkbWidget->setShiftState(MVirtualKeyboard::ShiftOn);
+        case ModifierClearState:
+            vkbWidget->setShiftState(ModifierLatchedState);
             break;
-        case MVirtualKeyboard::ShiftLock:
-            vkbWidget->setShiftState(MVirtualKeyboard::ShiftOff);
+        case ModifierLockedState:
+            vkbWidget->setShiftState(ModifierClearState);
             break;
         }
-    } else if (vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOn
-               && (event.qtKey() != Qt::Key_Backspace)) {
+        upperCase = false;
+    } else if (vkbWidget->shiftStatus() == ModifierLatchedState
+               && (event.qtKey() != Qt::Key_Backspace)
+               && (event.specialKey() != KeyEvent::Sym)
+               && (!shiftHeldDown || upperCase)) {
         // Any key except shift toggles shift off if it's on (not locked).
-        // backspace toggles shift off is handled in doBackspace().
-        vkbWidget->setShiftState(MVirtualKeyboard::ShiftOff);
+        // Exceptions are:
+        // - backspace, toggles shift off is handled in doBackspace()
+        // - sym, pressing sym key keeps current shift state
+        // - shift, when held down don't bring level down, except with autocaps!
+        vkbWidget->setShiftState(ModifierClearState);
     }
 
     if (event.specialKey() == KeyEvent::LayoutMenu) {
@@ -940,17 +998,11 @@
 
     qDebug() << __PRETTY_FUNCTION__ << "- used language:" << language;
 
-    // TODO: wouldn't it be better if correction engine did this?
-    QString shortLanguage(language);
-    if (KeyboardData::isLanguageLongFormat(language)) {
-        shortLanguage = KeyboardData::convertLanguageToShortFormat(language);
-    }
-
-    if (engineReady && (shortLanguage != imCorrectionEngine->language())) {
+    if (engineReady) {
         // TODO: maybe we should check return values here and in case of failure
         // be always in accurate mode, for example
-        imCorrectionEngine->setKeyboardLayout(shortLanguage);
-        imCorrectionEngine->setLanguage(shortLanguage, Dui::LanguagePriorityPrimary);
+        imCorrectionEngine->setKeyboardLayout(language);
+        imCorrectionEngine->setLanguage(language, M::LanguagePriorityPrimary);
         synchronizeCorrectionSetting();
         imCorrectionEngine->disablePrediction();
         imCorrectionEngine->disableCompletion();
@@ -959,20 +1011,6 @@
     }
 }
 
-
-void MKeyboardHost::errorCorrectionToggled(bool on)
-{
-    if (engineReady && (on != imCorrectionEngine->correctionEnabled())) {
-        bool correction = true;
-        if (!inputMethodCorrectionSettings->value().isNull())
-            correction = inputMethodCorrectionSettings->value().toBool();
-        if (on != correction) {
-            inputMethodCorrectionSettings->set(QVariant(on));
-        }
-    }
-}
-
-
 void MKeyboardHost::synchronizeCorrectionSetting()
 {
     bool correction = true;
@@ -981,10 +1019,8 @@
 
     if (!correction) {
         imCorrectionEngine->disableCorrection();
-        layoutMenu->disableErrorCorrection();
     } else {
         imCorrectionEngine->enableCorrection();
-        layoutMenu->enableErrorCorrection();
     }
 
     updateCorrectionState();
@@ -1038,17 +1074,7 @@
 
 void MKeyboardHost::showLayoutMenu()
 {
-    const QStringList languageList = LayoutsManager::instance().languageList();
-    const int currentIndex = languageList.indexOf(vkbWidget->selectedLanguage());
-
-    // Update layout menu's list of language titles and current language.
-    QStringList titles;
-    foreach (const QString &language, languageList) {
-        titles << LayoutsManager::instance().keyboardTitle(language);
-    }
-
-    layoutMenu->setLanguageList(titles, currentIndex);
-    layoutMenu->show();
+    emit settingsRequested();
 }
 
 QRegion MKeyboardHost::combineRegionTo(RegionMap &regionStore,
@@ -1086,32 +1112,15 @@
     inputContextConnection()->sendCommitString(text);
 }
 
-void MKeyboardHost::registerToolbar(qlonglong id, const QString &fileName)
-{
-    ToolbarManager::instance().registerToolbar(id, fileName);
-}
-
-void MKeyboardHost::unregisterToolbar(qlonglong id)
+void MKeyboardHost::setToolbar(QSharedPointer<const MToolbarData> toolbar)
 {
-    ToolbarManager::instance().unregisterToolbar(id);
-}
-
-void MKeyboardHost::setToolbar(qlonglong id)
-{
-    qDebug() << __PRETTY_FUNCTION__ << id;
-    if (id >= 0) {
-        vkbWidget->showToolbarWidget(id);
+    if (toolbar) {
+        vkbWidget->showToolbarWidget(toolbar);
     } else {
         vkbWidget->hideToolbarWidget();
     }
 }
 
-void MKeyboardHost::setToolbarItemAttribute(qlonglong id, const QString &item,
-                                              const QString &attribute, const QVariant &value)
-{
-    ToolbarManager::instance().setToolbarItemAttribute(id, item, attribute, value);
-}
-
 void MKeyboardHost::processKeyEvent(QEvent::Type keyType, Qt::Key keyCode,
                                     Qt::KeyboardModifiers modifiers, const QString &text,
                                     bool autoRepeat, int count, quint32 nativeScanCode,
@@ -1149,6 +1158,10 @@
     if (activeState == actualState)
         return;
 
+    if ((activeState == OnScreen) && (correctedPreedit.length() > 0)) {
+        inputContextConnection()->sendCommitString(correctedPreedit);
+    }
+
     // Resets before changing the activeState to make sure clear.
     reset();
     activeState = actualState;
@@ -1161,8 +1174,8 @@
         sendInputModeIndicator(MInputMethodBase::NoIndicator);
         disconnect(hardwareKeyboard, SIGNAL(modifierStateChanged(Qt::KeyboardModifier, ModifierState)),
                    this, SLOT(handleModifierStateChanged(Qt::KeyboardModifier, ModifierState)));
-        if (haveFocus) {
-            hardwareKeyboard->focusChanged(false);
+        if (haveFocus && (inputMethodMode != M::InputMethodModeDirect)) {
+            hardwareKeyboard->disable();
         }
     } else {
         //TODO: this is a temporary method, should get the hw layout language, then find out the
@@ -1171,8 +1184,8 @@
         symbolView->hideFunctionRow();
         connect(hardwareKeyboard, SIGNAL(modifierStateChanged(Qt::KeyboardModifier, ModifierState)),
                 this, SLOT(handleModifierStateChanged(Qt::KeyboardModifier, ModifierState)));
-        if (haveFocus) {
-            hardwareKeyboard->focusChanged(true);
+        if (haveFocus && (inputMethodMode != M::InputMethodModeDirect)) {
+            hardwareKeyboard->enable();
         }
     }
 
@@ -1183,22 +1196,18 @@
 
 void MKeyboardHost::handleSymbolKeyClick()
 {
-    if (!symbolView->isActive()) {
+    if (((activeState == Hardware) && !hardwareKeyboard->symViewAvailable())
+        || !vkbWidget->symViewAvailable()) {
+        return;
+    }
 
-        if ((activeState == Hardware) && !hardwareKeyboard->symViewAvailable()) {
-            return;
-        } else if (!vkbWidget->symViewAvailable()) {
-            return;
-        }
+    // Toggle SymbolView.
+    if (!symbolView->isActive()) {
         symbolView->showSymbolView();
         //give the symbolview right shift level(for hardware state)
         updateSymbolViewLevel();
     } else {
-        if (symbolView->currentPage() < (symbolView->pageCount() - 1)) {
-            symbolView->switchToNextPage();
-        } else {
-            symbolView->hideSymbolView();
-        }
+        symbolView->hideSymbolView();
     }
 }
 
@@ -1207,23 +1216,14 @@
     if (!symbolView->isActive())
         return;
 
-    MVirtualKeyboard::ShiftLevel shiftLevel = MVirtualKeyboard::ShiftOff;
+    ModifierState shiftLevel = ModifierClearState;
     if (activeState == OnScreen) {
         shiftLevel = vkbWidget->shiftStatus();
     } else {
-        switch (hardwareKeyboard->modifierState(Qt::ShiftModifier)) {
-        case ModifierLatchedState:
-            shiftLevel = MVirtualKeyboard::ShiftOn;
-            break;
-        case ModifierLockedState:
-            shiftLevel = MVirtualKeyboard::ShiftLock;
-            break;
-        default:
-            break;
-        }
+        shiftLevel = hardwareKeyboard->modifierState(Qt::ShiftModifier);
     }
-    symbolView->switchLevel(shiftLevel > 0 ? 1 : 0,
-                            shiftLevel == MVirtualKeyboard::ShiftLock);
+    symbolView->switchLevel(shiftLevel > 0 ? 1 : 0);
+    symbolView->setShiftStatus(shiftLevel > 0, shiftLevel == ModifierLockedState);
 }
 
 void MKeyboardHost::showSymbolView()
@@ -1314,24 +1314,40 @@
         // notify the modifier is changed to locked state
         // number and phone number content type always force FN key to be locked,
         // don't need indicator lock notification.
-        if (modifierLockOnInfoBanner) {
-            modifierLockOnInfoBanner->setBodyText(lockOnNotificationLabel);
-            modifierLockOnTimer.start();
-        } else {
-            modifierLockOnInfoBanner = new MInfoBanner(MInfoBanner::Information);
-            modifierLockOnInfoBanner->setBodyText(lockOnNotificationLabel);
-            MPlainWindow::instance()->sceneManager()->appearSceneWindow(modifierLockOnInfoBanner,
-                    MSceneWindow::DestroyWhenDone);
-            modifierLockOnTimer.start();
-        }
+        showLockOnInfoBanner(lockOnNotificationLabel);
     } else if (modifierLockOnInfoBanner) {
-        hideLockOnInfoBanner();
+        hideLockOnInfoBanner(false);
     }
 }
 
-void MKeyboardHost::hideLockOnInfoBanner()
+void MKeyboardHost::showLockOnInfoBanner(const QString &notification)
 {
-    if (modifierLockOnInfoBanner)
+    // current region maybe empty, we should request 1 pixel to make infobanner visible.
+    // FIXME: this request 1 pixel looks like hack way.
+    // maybe we should request system notification instead of showing our own infobanner.
+    emit regionUpdated(combineRegionTo(widgetRegions, QRegion(0, 0, 1, 1), *this));
+
+    if (modifierLockOnInfoBanner) {
+        modifierLockOnInfoBanner->setBodyText(notification);
+        modifierLockOnTimer.start();
+    } else {
+        modifierLockOnInfoBanner = new MInfoBanner(MInfoBanner::Information);
+        modifierLockOnInfoBanner->setBodyText(notification);
+        MPlainWindow::instance()->sceneManager()->appearSceneWindow(modifierLockOnInfoBanner,
+                                                                    MSceneWindow::DestroyWhenDone);
+        modifierLockOnTimer.start();
+    }
+}
+
+void MKeyboardHost::hideLockOnInfoBanner(bool updateRegion)
+{
+    if (modifierLockOnInfoBanner) {
         MPlainWindow::instance()->sceneManager()->disappearSceneWindow(modifierLockOnInfoBanner);
+    }
     modifierLockOnInfoBanner = 0;
+    // some time we don't need to update region at once (e.g. during changing modifier state frequently)
+    // when modifierLockOnTimer is timeout, this method will be called to update region
+    if (updateRegion) {
+        emit regionUpdated(combineRegionTo(widgetRegions, QRegion(), *this));
+    }
 }
--- m-keyboard/mkeyboardhost.h
+++ m-keyboard/mkeyboardhost.h
@@ -32,10 +32,10 @@
 class MImCorrectionCandidateWidget;
 class MSceneWindow;
 class MVirtualKeyboard;
+class MVirtualKeyboardStyleContainer;
 class MHardwareKeyboard;
-class LayoutMenu;
 class SymbolView;
-class DuiImEngineWords;
+class MImEngineWords;
 class QWidget;
 class MInfoBanner;
 
@@ -59,11 +59,7 @@
     virtual void visualizationPriorityChanged(bool priority);
     virtual void appOrientationChanged(int angle);
     virtual void setCopyPasteState(bool copyAvailable, bool pasteAvailable);
-    virtual void registerToolbar(qlonglong id, const QString &fileName);
-    virtual void unregisterToolbar(qlonglong id);
-    virtual void setToolbar(qlonglong id);
-    virtual void setToolbarItemAttribute(qlonglong id, const QString &item,
-                                         const QString &attribute, const QVariant &value);
+    virtual void setToolbar(QSharedPointer<const MToolbarData> toolbar);
     virtual void setState(const QSet<MIMHandlerState> &state);
     virtual void processKeyEvent(QEvent::Type keyType, Qt::Key keyCode,
                                  Qt::KeyboardModifiers modifiers,
@@ -100,11 +96,6 @@
      */
     void updatePreedit(const QString &string);
 
-    /*!
-     * Turn error correction on/off
-     */
-    void errorCorrectionToggled(bool on);
-
     /*! \brief Prepares vkb for orientation change when application is about to rotate.
      *
      * This should hide vkb.
@@ -170,8 +161,11 @@
      */
     void handleModifierStateChanged(Qt::KeyboardModifier modifier, ModifierState state);
 
-    //! hide CapsLock infobanner
-    void hideLockOnInfoBanner();
+    //! show FN/Caps Lock infobanner
+    void showLockOnInfoBanner(const QString &notification);
+
+    //! hide FN/Caps Lock infobanner
+    void hideLockOnInfoBanner(bool updateRegion = true);
 
 private:
     void createCorrectionCandidateWidget();
@@ -227,13 +221,14 @@
     QString preedit;
     QString correctedPreedit;
 
+    MVirtualKeyboardStyleContainer *vkbStyleContainer;
+
     MImCorrectionCandidateWidget *correctionCandidateWidget;
     MVirtualKeyboard *vkbWidget;
     MHardwareKeyboard *hardwareKeyboard;
-    LayoutMenu *layoutMenu;
     SymbolView *symbolView;
 
-    DuiImEngineWords *imCorrectionEngine;
+    MImEngineWords *imCorrectionEngine;
     //! default input method error correction setting
     MGConfItem *inputMethodCorrectionSettings;
     MGConfItem *inputMethodCorrectionEngine;
@@ -255,6 +250,8 @@
 
     //! FIXME: should we provide such a flag to on/off auto caps
     bool autoCapsEnabled;
+    //! Contains true if autocapitalization decides to switch keyboard to upper case
+    bool upperCase;
     QString surroundingText;
     int cursorPos;
 
@@ -266,6 +263,9 @@
     QTime lastClickEventTime;
     unsigned int multitapIndex;
 
+    //! Keeps track of shift up/down status.
+    bool shiftHeldDown;
+
     MSceneWindow *sceneWindow;
 #ifdef M_IM_DISABLE_TRANSLUCENCY
     QWidget *correctionWindow;
@@ -288,6 +288,15 @@
     //! \sa focusChanged
     bool haveFocus;
 
+    //! Saved shift key state before moment when it was pressed
+    ModifierState savedShiftState;
+
+    //! Saved auto capitalization state before press on shift button
+    bool savedUpperCase;
+
+    //! Contains true if multi-touch is enabled
+    bool enableMultiTouch;
+
 #ifdef UNIT_TEST
     friend class Ut_MKeyboardHost;
 #endif
--- m-keyboard/mkeyboardplugin.cpp
+++ m-keyboard/mkeyboardplugin.cpp
@@ -16,13 +16,19 @@
 
 
 
+#include <MLocale>
 #include "mkeyboardplugin.h"
 #include "mkeyboardhost.h"
+#include "mkeyboardsettings.h"
 
 #include <QtPlugin>
 
 #include <mtimestamp.h>
 
+MKeyboardPlugin::MKeyboardPlugin()
+    : translationIsLoaded(false)
+{
+}
 
 QString MKeyboardPlugin::name() const
 {
@@ -39,12 +45,20 @@
 MInputMethodBase *
 MKeyboardPlugin::createInputMethod(MInputContextConnection *icConnection)
 {
+    loadTranslation();
     mTimestamp("MKeyboardPlugin", "start");
     MInputMethodBase *inputMethod = new MKeyboardHost(icConnection);
     mTimestamp("MKeyboardPlugin", "end");
     return inputMethod;
 }
 
+MInputMethodSettingsBase *MKeyboardPlugin::createInputMethodSettings()
+{
+    loadTranslation();
+    MInputMethodSettingsBase *inputMethodSettings = new MKeyboardSettings();
+    return inputMethodSettings;
+}
+
 QSet<MIMHandlerState> MKeyboardPlugin::supportedStates() const
 {
     QSet<MIMHandlerState> result;
@@ -53,5 +67,15 @@
     return result;
 }
 
-Q_EXPORT_PLUGIN2(mvirtualkeyboard, MKeyboardPlugin)
+void MKeyboardPlugin::loadTranslation()
+{
+    if (!translationIsLoaded) {
+        MLocale locale;
+        // add virtual-keyboard catalog for the settings translation.
+        locale.installTrCatalog("virtual-keyboard");
+        MLocale::setDefault(locale);
+        translationIsLoaded = true;
+    }
+}
 
+Q_EXPORT_PLUGIN2(meego-keyboard, MKeyboardPlugin)
--- m-keyboard/mkeyboardplugin.h
+++ m-keyboard/mkeyboardplugin.h
@@ -35,12 +35,20 @@
     Q_INTERFACES(MInputMethodPlugin)
 
 public:
+    MKeyboardPlugin();
+
     //! \reimp
     virtual QString name() const;
     virtual QStringList languages() const;
     virtual MInputMethodBase *createInputMethod(MInputContextConnection *icConnection);
+    virtual MInputMethodSettingsBase *createInputMethodSettings();
     virtual QSet<MIMHandlerState> supportedStates() const;
     //! \reimp_end
+
+private:
+    void loadTranslation();
+
+    bool translationIsLoaded;
 };
 
 #endif
--- m-keyboard/mkeyboardsettings.cpp
+++ m-keyboard/mkeyboardsettings.cpp
+/* * This file is part of m-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#include "mkeyboardsettings.h"
+#include "mkeyboardsettingswidget.h"
+#include "keyboarddata.h"
+
+#include <QObject>
+#include <QGraphicsWidget>
+#include <QDir>
+#include <QFileInfo>
+#include <QDebug>
+
+namespace {
+    const QString SettingsIMCorrectionSetting("/meegotouch/inputmethods/correctionenabled");
+    const QString InputMethodLanguages("/meegotouch/inputmethods/languages");
+    const QString VKBConfigurationPath("/usr/share/meegotouch/virtual-keyboard/layouts/");
+    const QString VKBLayoutsFilterRule("*.xml");
+    const QString VKBLayoutsIgnoreRules("number|test"); // use as regexp to ignore number and test layouts
+};
+
+MKeyboardSettings::MKeyboardSettings()
+    : keyboardErrorCorrectionConf(SettingsIMCorrectionSetting, this),
+      selectedKeyboardsConf(InputMethodLanguages, this)
+{
+    readAvailableKeyboards();
+    connect(&keyboardErrorCorrectionConf, SIGNAL(valueChanged()),
+            this, SIGNAL(errorCorrectionChanged()));
+    connect(&selectedKeyboardsConf, SIGNAL(valueChanged()),
+            this, SIGNAL(selectedKeyboardsChanged()));
+}
+
+MKeyboardSettings::~MKeyboardSettings()
+{
+}
+
+QGraphicsWidget *MKeyboardSettings::createContentWidget(QGraphicsWidget *parent)
+{
+    // the pointer of returned QGraphicsWidget is owned by the caller,
+    // so we just always create a new containerWidget.
+    return new MKeyboardSettingsWidget(this, parent);
+}
+
+QString MKeyboardSettings::title()
+{
+    //% "Virtual keyboards";
+    return qtTrId("qtn_txts_virtual_keyboards");;
+}
+
+QString MKeyboardSettings::icon()
+{
+    return "";
+}
+
+void MKeyboardSettings::readAvailableKeyboards()
+{
+    availableKeyboardInfos.clear();
+    // available keyboard languages are determined by xml layouts that can be found
+    const QDir layoutsDir(VKBConfigurationPath, VKBLayoutsFilterRule);
+    QRegExp ignoreExp(VKBLayoutsIgnoreRules, Qt::CaseInsensitive);
+
+    foreach (QFileInfo keyboardFileInfo, layoutsDir.entryInfoList()) {
+        if (keyboardFileInfo.fileName().contains(ignoreExp))
+            continue;
+        KeyboardData keyboard;
+        if (keyboard.loadNokiaKeyboard(keyboardFileInfo.fileName())) {
+            if (keyboard.language().isEmpty() || keyboard.title().isEmpty())
+                continue;
+            bool duplicated = false;
+            foreach (const KeyboardInfo &info, availableKeyboardInfos) {
+                if (info.language == keyboard.language()) {
+                    duplicated = true;
+                    break;
+                }
+            }
+            if (!duplicated) {
+                KeyboardInfo keyboardInfo;
+                keyboardInfo.fileName = keyboardFileInfo.fileName();
+                keyboardInfo.language = keyboard.language();
+                keyboardInfo.title = keyboard.title();
+                availableKeyboardInfos.append(keyboardInfo);
+            }
+        }
+    }
+}
+
+QMap<QString, QString> MKeyboardSettings::availableKeyboards() const
+{
+    QMap<QString, QString> keyboards;
+    foreach (const KeyboardInfo &keyboardInfo, availableKeyboardInfos) {
+        keyboards.insert(keyboardInfo.language, keyboardInfo.title);
+    }
+    return keyboards;
+}
+
+QMap<QString, QString> MKeyboardSettings::selectedKeyboards() const
+{
+    QMap<QString, QString> keyboards;
+    foreach (const QString language, selectedKeyboardsConf.value().toStringList()) {
+        keyboards.insert(language, keyboardTitle(language));
+    }
+    return keyboards;
+}
+
+void MKeyboardSettings::setSelectedKeyboards(const QStringList &keyboardTitles)
+{
+    QStringList languages;
+    foreach (const QString &title, keyboardTitles) {
+        QString language = keyboardLanguage(title);
+        if (!language.isEmpty() && !languages.contains(language)) {
+            languages.append(language);
+        }
+    }
+    selectedKeyboardsConf.set(languages);
+}
+
+QString MKeyboardSettings::keyboardTitle(const QString &language) const
+{
+    QString title;
+    foreach (const KeyboardInfo &keyboardInfo, availableKeyboardInfos) {
+        if (keyboardInfo.language == language) {
+            title = keyboardInfo.title;
+            break;
+        }
+    }
+    return title;
+}
+
+QString MKeyboardSettings::keyboardLanguage(const QString &title) const
+{
+    QString language;
+    foreach (const KeyboardInfo &keyboardInfo, availableKeyboardInfos) {
+        if (keyboardInfo.title == title) {
+            language = keyboardInfo.language;
+            break;
+        }
+    }
+    return language;
+}
+
+bool  MKeyboardSettings::errorCorrection() const
+{
+    return keyboardErrorCorrectionConf.value().toBool();
+}
+
+void  MKeyboardSettings::setErrorCorrection(bool enabled)
+{
+    if (keyboardErrorCorrectionConf.value().toBool() != enabled)
+        keyboardErrorCorrectionConf.set(enabled);
+}
--- m-keyboard/mkeyboardsettings.h
+++ m-keyboard/mkeyboardsettings.h
+/* * This file is part of m-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#ifndef MKEYBOARDSETTINGS_H
+#define MKEYBOARDSETTINGS_H
+
+#include <QObject>
+#include <MWidget>
+#include <MGConfItem>
+#include <minputmethodsettingsbase.h>
+
+class QGraphicsWidget;
+
+/*!
+ * \brief MKeyboardSettings is the implemetation of meego-keyboard setting.
+ * MKeyboardSettings implement MInputMethodSettingsBase and create the meego-keyboard
+ * setting. It provides below functionalities: get/set error corretion, get/set
+ * installed (selected) keyboards.
+ */
+class MKeyboardSettings: public QObject, public MInputMethodSettingsBase
+{
+    Q_OBJECT
+    Q_DISABLE_COPY(MKeyboardSettings)
+    friend class Ut_MKeyboardSettings;
+
+public:
+    MKeyboardSettings();
+
+    ~MKeyboardSettings();
+
+    //!\reimp
+    virtual QString title();
+    virtual QString icon();
+    virtual QGraphicsWidget *createContentWidget(QGraphicsWidget *parent = 0);
+    //! \reimp_end
+
+    //! Reads all available keyboards
+    void readAvailableKeyboards();
+
+    //! Returns a map with languages and titles for all available keyboards.
+    QMap<QString, QString> availableKeyboards() const;
+
+    //! Returns a map with languages and titles for all selected keyboards.
+    QMap<QString, QString> selectedKeyboards() const;
+
+    //! Sets selected keyboards with \a keyboardTitles.
+    void setSelectedKeyboards(const QStringList &keyboardTitles);
+
+    //! Returns the boolean value of error correction option.
+    bool errorCorrection() const;
+
+    //! Sets error correction option.
+    void setErrorCorrection(bool);
+
+Q_SIGNALS:
+    //! Emitted when selected keyboards are changed.
+    void selectedKeyboardsChanged();
+
+    //! Emitted when error correction option is changed.
+    void errorCorrectionChanged();
+
+private:
+    QString keyboardTitle(const QString &language) const;
+    QString keyboardLanguage(const QString &title) const;
+
+    struct KeyboardInfo {
+        QString fileName;
+        QString language;
+        QString title;
+    };
+
+    //! all available keyboards
+    QList<KeyboardInfo> availableKeyboardInfos;
+    MGConfItem keyboardErrorCorrectionConf;
+    MGConfItem selectedKeyboardsConf;
+};
+
+#endif
--- m-keyboard/theme/864x480.css
+++ m-keyboard/theme/864x480.css
- at const MARGIN_DOUBLE:    1.2mm;
- at const MARGIN_LARGE:     0.8mm;
- at const PADDING_MEDIUM:   0.6mm;
- at const PADDING_LARGE:    1.2mm;
-
-/*
-    FlickUpButtonStyle is only used in conjunction with real button widgets as keyboard keys.
-    This also applies to object names dedicated for these buttons such as #Backspace or #Enter.
-
-    Alternative styling is used when the keyboard keys are not actual widgets, i.e. the
-    "single widget" approach. These are defined in MVirtualKeyboardStyle.
-*/
-
-/*  FlickUpButton related styling */
-
-FlickUpButtonStyle {
-    background-image: "keyboard-key-background" 10px 10px 10px 10px;
-    font: "Nokia Sans Light" 24;
-    minimum-size: 30 56;
-    preferred-size: 8.2mm 5.6mm;
-    maximum-size: -1 -1;
-    icon: ;
-    releaseFeedback: ;
-    pressFeedback: ;
-    margin-top: 0;
-    margin-bottom: 0;
-    margin-left: 0;
-    margin-right: 0;
-
-    reactive-margin-left: 2;
-    reactive-margin-right: 2;
-    reactive-margin-top: 6;
-    reactive-margin-bottom: 6;
-
-    text-margin-left: 0;
-    text-margin-right: 0;
-}
-
-FlickUpButtonStyle:pressed {
-    background-image: "keyboard-key-background-pressed" 10px 10px 10px 10px;
-}
-
-FlickUpButtonStyle:selected {
-    background-image: "keyboard-key-background-selected" 10px 10px 10px 10px;
-}
-
-#Backspace {
-    icon-size: 48 26;
-    icon: "icon-m-keyboard-backspace";
-}
-
-#LayoutMenu {
-    icon-size: 64 33;
-    icon: "icon-m-keyboard-menu";
-}
-
-#Enter {
-    icon-size: 38 28;
-    icon: "icon-m-keyboard-enter";
-}
-
-#ShiftNormal {
-    icon-size: 38 38;
-    icon: "icon-m-shift-lowercase";
-}
-
-#ShiftLatched {
-    icon-size: 38 38;
-    icon: "icon-m-shift-uppercase";
-}
-
-#ShiftLocked {
-    icon-size: 38 38;
-    icon: "icon-m-keyboard-shift-capslock";
-}
-
-/* End of FlickUpButton related styling */
-
-#VirtualKeyboardSymTabs {
-    background-image: "keyboard-tabs-background" 10px 10px 10px 10px;
-}
-
-#VirtualKeyboardSymCloseButton {
-    preferred-size: 10.6mm 5.1mm;
-}
-
-#VirtualKeyboardSymTabsButton {
-    preferred-size: 100 48;
-    maximum-size: 100 48;
-    margin-left: 0;
-    margin-right: 0;
-    margin-top: 0;
-    margin-bottom: 0;
-    background-image: "keyboard-tab-optional" 10px 10px 10px 10px;
-}
-
-#VirtualKeyboardSymTabsButton:selected {
-    background-image: "keyboard-tab-active" 10px 10px 10px 10px;
-}
-
-MVirtualKeyboardStyle {
-    background-image: "keyboard-background" 10px 10px 10px 10px;
-    font: "Nokia Sans Light" 24;
-    font-opacity: 0.9;
-    font-color: #FFFFFF;
-    secondary-font: $FONT_SMALL;
-
-    padding-top: $PADDING_LARGE;
-    padding-bottom: $PADDING_LARGE;
-
-    spacing-vertical: $MARGIN_DOUBLE;
-    spacing-horizontal: 0.3mm;
-
-    deadkey-locked-color: #FFA500;
-
-    notification-font: "Nokia Sans Light" 24;
-    notification-border-color: #808080;
-    notification-background-color: #323232;
-    notification-text-color: #FFFFFF;
-    notification-opacity: 0.9;
-
-    toolbar-background-image: "keyboard-toolbar-background" 10px 10px 10px 10px;
-
-    releaseFeedback: ;
-    pressFeedback: ;
-
-    /* Single widget keyboard button styling */
-    key-background-id: "keyboard-key-background";
-    key-background-pressed-id: "keyboard-key-background-pressed";
-    key-background-selected-id: "keyboard-key-background-selected";
-
-    key-backspace-icon-size: 48 48;
-    key-backspace-icon-id: "icon-m-common-backspace";
-
-    key-menu-icon-size: 48 48;
-    key-menu-icon-id: "icon-m-input-methods-menu";
-
-    key-enter-icon-size: 48 48;
-    key-enter-icon-id: "icon-m-input-methods-enter";
-
-    key-shift-icon-size: 48 48;
-    key-shift-icon-id: "icon-m-input-methods-shift";
-    key-shift-uppercase-icon-id: "icon-m-input-methods-capslock";
-    /* End of single widget keyboard button styling */
-}
-
-MVirtualKeyboardStyle.Portrait {
-    keyboard-area-size: 480 280;
-    
-    label-margin-top: 2mm;
-    label-margin-left-with-secondary: 4.6mm;
-    secondary-label-separation: 0.9mm;
-
-    padding-left: $PADDING_MEDIUM;
-    padding-right: 0.7mm;
-
-    tab-button-size: 91 70;
-    menu-size: 470 342;
-
-    /* Single widget keyboard button styling */
-    key-normal-size: 4.4mm 8mm;
-    key-phone-number-normal-size: 15.3mm 8mm;
-    key-function-normal-size: 8mm 8mm;
-    key-function-large-size: 8mm 8mm;
-    key-number-backspace-size: 15.3mm 8mm;
-    key-sym-normal-size: 7.5mm 8mm;
-    /* End of single widget keyboard button styling */
-
-    key-background-sym-indicator-sym: "keyboard-key-sym-selected-portrait";
-    key-background-sym-indicator-ace: "keyboard-key-ace-selected-portrait";
-}
-
-MVirtualKeyboardStyle.Landscape {
-    keyboard-area-size: 864 280;
-    
-    label-margin-top: $MARGIN_LARGE;
-    label-margin-left-with-secondary: -1; /* not used, labels are centered horizontally */
-    secondary-label-separation: 0;
-
-    padding-left: $PADDING_LARGE;
-    padding-right: 0.9mm;
-
-    tab-button-size: 108 70;
-
-    menu-size: 790 342;
-
-    /* Single widget keyboard button styling */
-    key-normal-size: 8.2mm 5.6mm;
-    key-phone-number-normal-size: 8.2mm 8.4mm;
-    key-function-normal-size: 8.2mm 5.6mm;
-    key-function-large-size: 12.4mm 5.6mm;
-    key-number-backspace-size: 12.4mm 5.6mm;
-    key-sym-normal-size: 8.2mm 5.6mm;
-    /* End of single widget keyboard button styling */
-
-    key-background-sym-indicator-sym: "keyboard-key-sym-selected-landscape";
-    key-background-sym-indicator-ace: "keyboard-key-ace-selected-landscape";
-}
-
-
-#MenuToggleButton {
-    background-image: "Toggle-btn-normal" 0 0 0 0;
-    background-opacity: 1.0;
-    background-color: #000000;
-    text-color: #FFFFFF;
-}
-
-
-#MenuToggleButton:pressed {
-    background-image: "Toggle-btn-selected" 0 0 0 0;
-    background-opacity: 1.0;
-    background-color: #F9A427;
-    text-color: #555555;    
-}
-
-
-#MenuLanguageList {
-    background-image: "Single-line-input-field" 0 0 0 0;
-    text-left-offset: 12;
-    text-right-offset: 12;
-
-    font: "Nokia Sans" 20;
-    text-color: #000000;
-
-    preferred-size: 414 56;
-    minimum-size: 414 56;
-    maximum-size: 414 56;
-}
-
-#VirtualKeyboardToolbarButton {
-    background-image: "keyboard-toolbar-button-background" 10px 10px 10px 10px;
-    margin-left: 0;
-    margin-right: 0;
-    margin-top: 0;
-    margin-bottom: 0;
-    preferred-size: 100 48;
-    maximum-size: 100 48;
-    reactive-margin-left: 2;
-    reactive-margin-right: 2;
-    reactive-margin-top: 5;
-    reactive-margin-bottom: 5;
-}
-
-#VirtualKeyboardToolbarButton:pressed {
-    background-image: "keyboard-toolbar-button-background-pressed" 10px 10px 10px 10px;
-}
-
-#VirtualKeyboardToolbarButton:selected {
-    background-image: "keyboard-toolbar-button-background-pressed" 10px 10px 10px 10px;
-}
-
-WidgetBarStyle {
-    margin-left: 0;
-    margin-top: 0;
-    margin-right: 0;
-    margin-bottom: 0;
-
-    padding-top: 3;
-    padding-left: 3;
-    padding-right: 3;
-}
-
-#CorrectionCandidateList {
-    margin-left: 0;
-    margin-top: 0;
-    margin-right: 0;
-    margin-bottom: 0;
-}
-
-#CorrectionCandidateItem {
-    preferred-size: -1 6.4mm;
-    minimum-size: 10mm 6.4mm;
-    maximum-size: 100% 6.4mm;
-
-    title-object-name: "CorrectionCandidateItemTitle";
-}
-#CorrectionCandidateItemTitle {
-    margin-left:   2.4mm;
-    margin-right:  2.4mm;
-}
--- m-keyboard/theme/libmeego-keyboard.css
+++ m-keyboard/theme/libmeego-keyboard.css
+ at const MARGIN_DOUBLE:    1.2mm;
+ at const MARGIN_LARGE:     0.8mm;
+ at const PADDING_MEDIUM:   0.6mm;
+ at const PADDING_LARGE:    1.2mm;
+
+/*
+    FlickUpButtonStyle is only used in conjunction with real button widgets as keyboard keys.
+    This also applies to object names dedicated for these buttons such as #Backspace or #Enter.
+
+    Alternative styling is used when the keyboard keys are not actual widgets, i.e. the
+    "single widget" approach. These are defined in MVirtualKeyboardStyle.
+*/
+
+/*  FlickUpButton related styling */
+
+FlickUpButtonStyle {
+    background-image: "keyboard-key" 10px 10px 10px 10px;
+    font: "Nokia Sans Light" 24;
+    minimum-size: 30 56;
+    preferred-size: 8.2mm 5.6mm;
+    maximum-size: -1 -1;
+    icon: ;
+    releaseFeedback: ;
+    pressFeedback: ;
+    margin-top: 0;
+    margin-bottom: 0;
+    margin-left: 0;
+    margin-right: 0;
+
+    reactive-margin-left: 2;
+    reactive-margin-right: 2;
+    reactive-margin-top: 6;
+    reactive-margin-bottom: 6;
+
+    text-margin-left: 0;
+    text-margin-right: 0;
+}
+
+FlickUpButtonStyle:pressed {
+    background-image: "keyboard-key-pressed" 10px 10px 10px 10px;
+}
+
+FlickUpButtonStyle:selected {
+    background-image: "keyboard-key-selected" 10px 10px 10px 10px;
+}
+
+#Backspace {
+    icon-size: 48 26;
+    icon: "icon-m-keyboard-backspace";
+}
+
+#LayoutMenu {
+    icon-size: 64 33;
+    icon: "icon-m-keyboard-menu";
+}
+
+#Enter {
+    icon-size: 38 28;
+    icon: "icon-m-keyboard-enter";
+}
+
+#ShiftNormal {
+    icon-size: 38 38;
+    icon: "icon-m-shift-lowercase";
+}
+
+#ShiftLatched {
+    icon-size: 38 38;
+    icon: "icon-m-shift-uppercase";
+}
+
+#ShiftLocked {
+    icon-size: 38 38;
+    icon: "icon-m-keyboard-shift-capslock";
+}
+
+/* End of FlickUpButton related styling */
+
+#VirtualKeyboardSymTabs {
+    /* id missing or needs renaming? */
+    background-image: "keyboard-tabs-background" 10px 10px 10px 10px;
+}
+
+#VirtualKeyboardSymCloseButton {
+    preferred-size: 10.6mm 5.1mm;
+}
+
+#VirtualKeyboardSymTabsButton {
+    preferred-size: 100 48;
+    maximum-size: 100 48;
+    margin-left: 0;
+    margin-right: 0;
+    margin-top: 0;
+    margin-bottom: 0;
+    /* id missing or needs renaming? */
+    background-image: "keyboard-tab-optional" 10px 10px 10px 10px;
+}
+
+#VirtualKeyboardSymTabsButton:selected {
+    /* id missing or needs renaming? */
+    background-image: "keyboard-tab-active" 10px 10px 10px 10px;
+}
+
+MVirtualKeyboardStyle {
+    background-image: "meegotouch-keyboard-background" 10px 10px 10px 10px;
+    font: "Nokia Sans Light" 28;
+    font-opacity: 0.9;
+    font-color: #000000;
+
+    secondary-font: $FONT_SMALL;
+
+    padding-top: $PADDING_LARGE;
+    padding-bottom: $PADDING_LARGE;
+
+    spacing-vertical: $MARGIN_DOUBLE;
+    spacing-horizontal: 0.3mm;
+
+    deadkey-locked-color: #FFA500;
+
+    notification-font: "Nokia Sans Light" 24;
+    notification-border-color: #808080;
+    notification-background-color: #323232;
+    notification-text-color: #FFFFFF;
+    notification-opacity: 0.9;
+
+    toolbar-background-image: "meegotouch-keyboard-toolbar-background" 10px 10px 10px 10px;
+
+    releaseFeedback: ;
+    pressFeedback: ;
+
+    /* Single widget keyboard button styling */
+    key-background-border-left: 10;
+    key-background-border-right: 10;
+    key-background-border-top: 10;
+    key-background-border-bottom: 10;
+
+    key-backspace-icon-id: "icon-m-input-methods-backspace";
+    key-backspace-icon-size: 48 48;
+
+    key-menu-icon-size: 48 48;
+    key-menu-icon-id: "icon-m-input-methods-menu";
+
+    key-enter-icon-size: 48 48;
+    key-enter-icon-id: "icon-m-input-methods-enter";
+
+    key-shift-icon-size: 48 48;
+    key-shift-icon-id: "icon-m-input-methods-shift";
+    key-shift-uppercase-icon-id: "icon-m-input-methods-capslock";
+    /* End of single widget keyboard button styling */
+}
+
+MVirtualKeyboardStyle.Portrait {
+    keyboard-area-size: 480 280;
+    
+    label-margin-top: 2.4mm;
+    label-margin-left-with-secondary: 4.6mm;
+    secondary-label-separation: 0.9mm;
+
+    padding-left: $PADDING_MEDIUM;
+    padding-right: 0.7mm;
+
+    tab-button-size: 91 70;
+    menu-size: 470 342;
+
+    /* Single widget keyboard button styling */
+    key-background-id: "meegotouch-keyboard-key-portrait";
+    key-background-pressed-id: "meegotouch-keyboard-key-pressed-portrait";
+    key-background-selected-id: "meegotouch-keyboard-key-selected-portrait";
+
+    key-normal-size: 4.4mm 8mm;
+
+    key-phone-number-normal-size: 15.3mm 8mm;
+    key-function-normal-size: 8mm 8mm;
+    key-function-large-size: 8mm 8mm;
+    key-number-backspace-size: 15.3mm 8mm;
+    key-sym-normal-size: 7.5mm 8mm;
+    /* End of single widget keyboard button styling */
+
+    key-background-sym-indicator-sym: "meegotouch-keyboard-key-sym-selected-portrait";
+    key-background-sym-indicator-ace: "meegotouch-keyboard-key-ace-selected-portrait";
+    key-background-sym-indicator-sym-pressed: "meegotouch-keyboard-key-sym-pressed-portrait";
+    key-background-sym-indicator-ace-pressed: "meegotouch-keyboard-key-ace-pressed-portrait";
+}
+
+MVirtualKeyboardStyle.Landscape {
+    keyboard-area-size: 864 280;
+    
+    label-margin-top: 1.2mm;
+    label-margin-left-with-secondary: -1; /* not used, labels are centered horizontally */
+    secondary-label-separation: 0;
+
+    padding-left: $PADDING_LARGE;
+    padding-right: 0.9mm;
+
+    tab-button-size: 108 70;
+
+    menu-size: 790 342;
+
+    /* Single widget keyboard button styling */
+    key-background-id: "meegotouch-keyboard-key-landscape";
+    key-background-pressed-id: "meegotouch-keyboard-key-pressed-landscape";
+    key-background-selected-id: "meegotouch-keyboard-key-selected-landscape";
+
+    key-normal-size: 8.2mm 5.6mm;
+
+    key-phone-number-normal-size: 8.2mm 8.4mm;
+    key-function-normal-size: 8.2mm 5.6mm;
+    key-function-large-size: 12.4mm 5.6mm;
+    key-number-backspace-size: 12.4mm 5.6mm;
+    key-sym-normal-size: 8.2mm 5.6mm;
+    /* End of single widget keyboard button styling */
+
+    key-background-sym-indicator-sym: "meegotouch-keyboard-key-sym-selected-landscape";
+    key-background-sym-indicator-ace: "meegotouch-keyboard-key-ace-selected-landscape";
+    key-background-sym-indicator-sym-pressed: "meegotouch-keyboard-key-sym-pressed-landscape";
+    key-background-sym-indicator-ace-pressed: "meegotouch-keyboard-key-ace-pressed-landscape";
+}
+
+#InvisibleHandle.Portrait {
+    preferred-size: 480 2.5mm;
+    minimum-size:   480 2.5mm;
+    maximum-size:   480 2.5mm;
+}
+
+#InvisibleHandle.Landscape {
+    preferred-size: 864 2.5mm;
+    minimum-size:   480 2.5mm;
+    maximum-size:   864 2.5mm;
+}
+
+#KeyboardToolbarHandle {
+    background-image: "meegotouch-keyboard-handle-background";
+}
+
+#KeyboardToolbarHandle.Portrait {
+    preferred-size: 480 0.6mm;
+    minimum-size: 480 0.6mm;
+    maximum-size: 480 0.6mm;
+}
+
+#KeyboardToolbarHandle.Landscape {
+    preferred-size: 864 0.6mm;
+    minimum-size: 480 0.6mm;
+    maximum-size: 864 0.6mm;
+}
+
+#KeyboardHandle {
+    background-image: "meegotouch-keyboard-handle-background";
+}
+
+#KeyboardHandle.Landscape {
+    preferred-size: 864 0.6mm;
+    minimum-size: 480 0.6mm;
+    maximum-size: 864 0.6mm;
+}
+
+#KeyboardHandle.Portrait {
+    preferred-size: 480 0.6mm;
+    minimum-size: 480 0.6mm;
+    maximum-size: 480 0.6mm;
+}
+
+#MenuToggleButton {
+    background-image: "Toggle-btn-normal" 0 0 0 0;
+    background-opacity: 1.0;
+    background-color: #000000;
+    text-color: #FFFFFF;
+}
+
+
+#MenuToggleButton:pressed {
+    background-image: "Toggle-btn-selected" 0 0 0 0;
+    background-opacity: 1.0;
+    background-color: #F9A427;
+    text-color: #555555;    
+}
+
+
+#MenuLanguageList {
+    background-image: "Single-line-input-field" 0 0 0 0;
+    text-left-offset: 12;
+    text-right-offset: 12;
+
+    font: "Nokia Sans" 20;
+    text-color: #000000;
+
+    preferred-size: 414 56;
+    minimum-size: 414 56;
+    maximum-size: 414 56;
+}
+
+MToolbarButtonStyle {
+    background-image: "meegotouch-keyboard-toolbar-button" 10px 10px 10px 10px;
+    margin-left: 0;
+    margin-right: 0;
+    margin-top: 0;
+    margin-bottom: 0;
+    preferred-size: 100 48;
+    maximum-size: 100 48;
+    reactive-margin-left: 2;
+    reactive-margin-right: 2;
+    reactive-margin-top: 5;
+    reactive-margin-bottom: 5;
+}
+
+MToolbarButtonStyle:pressed {
+    background-image: "meegotouch-keyboard-toolbar-button-pressed" 10px 10px 10px 10px;
+}
+
+MToolbarButtonStyle:selected {
+    background-image: "meegotouch-keyboard-toolbar-button-selected" 10px 10px 10px 10px;
+}
+
+WidgetBarStyle {
+    margin-left: 0;
+    margin-top: 0;
+    margin-right: 0;
+    margin-bottom: 0;
+
+    padding-top: 3;
+    padding-left: 3;
+    padding-right: 3;
+}
+
+#CorrectionCandidateList {
+    margin-left: 0;
+    margin-top: 0;
+    margin-right: 0;
+    margin-bottom: 0;
+}
+
+#CorrectionCandidateItem {
+    preferred-size: -1 6.4mm;
+    minimum-size: 10mm 6.4mm;
+    maximum-size: 100% 6.4mm;
+
+    title-object-name: "CorrectionCandidateItemTitle";
+}
+#CorrectionCandidateItemTitle {
+    margin-left:   2.4mm;
+    margin-right:  2.4mm;
+}
--- m-keyboard/theme/meegotouch-keyboard.svg
+++ m-keyboard/theme/meegotouch-keyboard.svg
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="meegotouch-keyboard-layer" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+	 x="0px" y="0px" width="500px" height="480px" viewBox="0 0 500 480" style="enable-background:new 0 0 500 480;"
+	 xml:space="preserve">
+<g id="meegotouch-keyboard">
+	<g id="virtualmeegotouch-keyboardThemeTemplateHelper">
+		<g id="vkbhelperBackground">
+			<g>
+				<path style="fill:#B3B3B3;" d="M16,479c-8.271,0-15-6.729-15-15V16C1,7.729,7.729,1,16,1h468c8.271,0,15,6.729,15,15v448
+					c0,8.271-6.729,15-15,15H16z"/>
+				<g>
+					<path d="M484,2c7.72,0,14,6.28,14,14v448c0,7.72-6.28,14-14,14H16c-7.72,0-14-6.28-14-14V16C2,8.28,8.28,2,16,2H484 M484,0H16
+						C7.2,0,0,7.2,0,16v448c0,8.8,7.2,16,16,16h468c8.8,0,16-7.2,16-16V16C500,7.2,492.8,0,484,0L484,0z"/>
+				</g>
+			</g>
+		</g>
+		<g>
+			<path style="fill:#010101;" d="M145.746,43.409l-5.634-20.794h3.138l4.352,17.307l4.561-17.307h2.72l-5.83,20.794H145.746z"/>
+			<path style="fill:#010101;" d="M160.417,43.409h-2.971V29.128h-1.855v-1.938h4.826V43.409z M158.939,21.499
+				c0.456,0,0.849,0.167,1.179,0.502s0.495,0.729,0.495,1.186c0,0.465-0.163,0.862-0.488,1.192c-0.326,0.33-0.721,0.495-1.186,0.495
+				c-0.474,0-0.874-0.165-1.199-0.495c-0.326-0.33-0.488-0.728-0.488-1.192c0-0.474,0.163-0.874,0.488-1.2
+				C158.065,21.662,158.465,21.499,158.939,21.499z"/>
+			<path style="fill:#010101;" d="M166.303,27.189l0.683,2.705c0.902-1.906,2.473-2.859,4.714-2.859
+				c0.298,0,0.516,0.015,0.656,0.043v2.705c-0.232-0.019-0.581-0.027-1.046-0.027c-1.274,0-2.208,0.305-2.803,0.913
+				c-0.595,0.608-0.893,1.56-0.893,2.853v9.888h-2.971v-16.22H166.303z"/>
+			<path style="fill:#010101;" d="M178.98,43.633c-1.265,0-2.19-0.295-2.775-0.887c-0.586-0.59-0.879-1.531-0.879-2.824V29.128
+				h-2.134v-1.116l4.337-4.421h0.767v3.599h3.947v1.938h-3.947v10.307c0,0.884,0.144,1.467,0.433,1.75
+				c0.288,0.284,0.725,0.425,1.311,0.425c0.604,0,1.422-0.134,2.455-0.404v1.926C181.249,43.465,180.077,43.633,178.98,43.633z"/>
+			<path style="fill:#010101;" d="M189.65,43.633c-1.655,0-2.894-0.431-3.717-1.291c-0.823-0.859-1.234-2.149-1.234-3.869V27.189
+				h2.971v10.767c0,1.218,0.214,2.132,0.642,2.741c0.428,0.608,1.074,0.912,1.938,0.912c1.079,0,1.913-0.408,2.503-1.227
+				s0.886-1.883,0.886-3.193v-10h2.971v16.22h-1.646l-0.6-2.399C193.332,42.758,191.761,43.633,189.65,43.633z"/>
+			<path style="fill:#010101;" d="M209.078,41.066c-1.004,1.711-2.566,2.566-4.686,2.566c-1.479,0-2.629-0.416-3.452-1.248
+				c-0.823-0.832-1.234-1.997-1.234-3.494c0-1.543,0.423-2.693,1.269-3.452c0.846-0.757,1.859-1.231,3.041-1.423
+				c1.181-0.189,2.617-0.285,4.31-0.285v-1.911c0-1.888-1.009-2.831-3.026-2.831c-1.163,0-2.581,0.246-4.254,0.739v-2.078
+				c1.683-0.465,3.282-0.697,4.797-0.697c1.786,0,3.141,0.431,4.066,1.29c0.925,0.859,1.388,2.127,1.388,3.801v11.366h-1.618
+				L209.078,41.066z M208.325,35.502h-1.66c-1.33,0-2.327,0.281-2.992,0.844c-0.665,0.562-0.997,1.4-0.997,2.517
+				c0,0.911,0.202,1.593,0.606,2.044s1.011,0.676,1.82,0.676c1.022,0,1.815-0.325,2.378-0.977c0.562-0.65,0.844-1.533,0.844-2.649
+				V35.502z"/>
+			<path style="fill:#010101;" d="M215.298,43.409V21.332h2.971v22.077H215.298z"/>
+			<path style="fill:#010101;" d="M235.242,34.246l5.914,9.163h-3.515l-5.579-8.828v8.828h-2.971V21.332h2.971v13.193l5.495-7.336
+				h3.25L235.242,34.246z"/>
+			<path style="fill:#010101;" d="M253.066,40.927v2.022c-1.461,0.455-2.971,0.684-4.533,0.684c-2.269,0-3.966-0.684-5.091-2.051
+				s-1.688-3.473-1.688-6.318c0-2.5,0.544-4.512,1.632-6.031c1.088-1.521,2.641-2.28,4.658-2.28c1.636,0,2.866,0.435,3.689,1.304
+				c0.822,0.869,1.35,1.934,1.582,3.193c0.232,1.261,0.35,2.76,0.35,4.498h-8.759c0,1.889,0.335,3.304,1.004,4.247
+				c0.669,0.944,1.673,1.415,3.012,1.415C250.058,41.609,251.438,41.383,253.066,40.927z M244.907,34.121h5.844
+				c0-1.962-0.232-3.348-0.697-4.156s-1.134-1.214-2.008-1.214c-0.976,0-1.723,0.419-2.238,1.255
+				C245.291,30.844,244.991,32.215,244.907,34.121z"/>
+			<path style="fill:#010101;" d="M259.578,42.81l-4.435-15.62h3.054l3.543,13.444l3.695-13.444h2.678l-5.076,17.195
+				c-0.391,1.293-0.939,2.244-1.646,2.854c-0.706,0.607-1.627,0.912-2.761,0.912c-0.781,0-1.646-0.098-2.595-0.292v-2.05
+				c0.855,0.167,1.636,0.25,2.343,0.25c0.642,0,1.164-0.216,1.569-0.648c0.404-0.432,0.792-1.299,1.165-2.601H259.578z"/>
+			<path style="fill:#010101;" d="M273.303,21.332v7.363c1.06-1.162,2.375-1.743,3.947-1.743c1.812,0,3.174,0.669,4.086,2.009
+				c0.911,1.338,1.367,3.347,1.367,6.024s-0.614,4.774-1.842,6.29c-1.227,1.516-2.914,2.273-5.062,2.273
+				c-2.111,0-3.933-0.094-5.467-0.279V21.332H273.303z M273.303,35.236v6.15c0.864,0.111,1.637,0.168,2.314,0.168
+				c1.367,0,2.376-0.5,3.027-1.5c0.65-0.999,0.977-2.717,0.977-5.152c0-1.972-0.256-3.45-0.768-4.436
+				c-0.512-0.986-1.273-1.479-2.287-1.479c-0.986,0-1.716,0.298-2.189,0.893c-0.475,0.596-0.772,1.318-0.893,2.169
+				C273.363,32.9,273.303,33.963,273.303,35.236z"/>
+			<path style="fill:#010101;" d="M291.922,43.633c-2.186,0-3.822-0.717-4.91-2.148s-1.631-3.58-1.631-6.443
+				c0-2.492,0.564-4.463,1.693-5.913c1.131-1.45,2.746-2.176,4.848-2.176c2.119,0,3.739,0.716,4.859,2.147
+				c1.121,1.432,1.682,3.432,1.682,5.997c0,2.642-0.523,4.724-1.569,6.249C295.848,42.87,294.189,43.633,291.922,43.633z
+				 M291.922,41.722c1.143,0,2.006-0.519,2.586-1.556c0.582-1.036,0.873-2.772,0.873-5.209c0-1.72-0.299-3.163-0.893-4.33
+				c-0.596-1.166-1.451-1.75-2.566-1.75c-1.135,0-1.994,0.525-2.58,1.576s-0.879,2.552-0.879,4.504c0,2.195,0.293,3.871,0.879,5.028
+				S290.787,41.722,291.922,41.722z"/>
+			<path style="fill:#010101;" d="M310.233,41.066c-1.004,1.711-2.566,2.566-4.687,2.566c-1.479,0-2.629-0.416-3.451-1.248
+				c-0.823-0.832-1.234-1.997-1.234-3.494c0-1.543,0.423-2.693,1.27-3.452c0.846-0.757,1.859-1.231,3.04-1.423
+				c1.181-0.189,2.617-0.285,4.31-0.285v-1.911c0-1.888-1.01-2.831-3.026-2.831c-1.163,0-2.581,0.246-4.254,0.739v-2.078
+				c1.683-0.465,3.282-0.697,4.798-0.697c1.785,0,3.141,0.431,4.065,1.29s1.388,2.127,1.388,3.801v11.366h-1.618L310.233,41.066z
+				 M309.48,35.502h-1.66c-1.33,0-2.326,0.281-2.991,0.844s-0.997,1.4-0.997,2.517c0,0.911,0.202,1.593,0.606,2.044
+				s1.011,0.676,1.82,0.676c1.022,0,1.815-0.325,2.378-0.977c0.562-0.65,0.844-1.533,0.844-2.649V35.502z"/>
+			<path style="fill:#010101;" d="M318.113,27.189l0.684,2.705c0.901-1.906,2.473-2.859,4.713-2.859
+				c0.299,0,0.517,0.015,0.656,0.043v2.705c-0.232-0.019-0.581-0.027-1.046-0.027c-1.274,0-2.208,0.305-2.804,0.913
+				c-0.595,0.608-0.893,1.56-0.893,2.853v9.888h-2.971v-16.22H318.113z"/>
+			<path style="fill:#010101;" d="M336.383,43.409l-0.627-1.994c-0.855,1.478-2.32,2.218-4.394,2.218
+				c-1.925,0-3.373-0.682-4.345-2.043c-0.971-1.363-1.457-3.49-1.457-6.381c0-2.428,0.518-4.41,1.555-5.949
+				c1.037-1.538,2.508-2.308,4.414-2.308c1.562,0,2.734,0.47,3.516,1.409v-7.029h2.971v22.077H336.383z M335.143,36.018
+				l-0.015-0.921c0-2.417-0.272-4.049-0.815-4.896c-0.545-0.846-1.318-1.269-2.322-1.269c-1.115,0-1.953,0.517-2.511,1.548
+				c-0.558,1.032-0.837,2.58-0.837,4.645c0,2.166,0.27,3.789,0.809,4.867s1.349,1.617,2.428,1.617c1.051,0,1.856-0.39,2.42-1.171
+				C334.861,39.658,335.143,38.184,335.143,36.018z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-handle-decoration">
+		<circle style="fill:#6E6F71;" cx="96" cy="377.999" r="2"/>
+		<circle style="fill:#6E6F71;" cx="104.167" cy="377.999" r="2"/>
+		<circle style="fill:#6E6F71;" cx="112.337" cy="377.999" r="2"/>
+		<circle style="fill:#6E6F71;" cx="120.505" cy="377.999" r="2"/>
+		<circle style="fill:#6E6F71;" cx="128.675" cy="377.999" r="2"/>
+		<circle style="fill:#6E6F71;" cx="136.843" cy="377.999" r="2"/>
+		<circle style="fill:#6E6F71;" cx="145.013" cy="377.999" r="2"/>
+		<circle style="fill:#6E6F71;" cx="153.181" cy="377.999" r="2"/>
+		<circle style="fill:#6E6F71;" cx="161.351" cy="377.999" r="2"/>
+	</g>
+	<g id="meegotouch-keyboard-handle-background">
+		<rect x="94" y="389.999" style="fill:#F2F2F2;" width="64" height="6"/>
+	</g>
+	<g id="meegotouch-keyboard-background">
+		<rect x="20" y="80" style="fill:#F2F2F2;" width="64" height="64"/>
+	</g>
+	<g id="meegotouch-keyboard-toolbar-background">
+		<rect x="20" y="154" style="fill:#F2F2F2;" width="64" height="64"/>
+	</g>
+	<g id="meegotouch-keyboard-toolbar-button-pressed-selected">
+		<g>
+			<path style="fill:#333333;" d="M94,311.999c0-5.5,4.5-10,10-10h44c5.5,0,10,4.5,10,10v29c0,5.5-4.5,10-10,10h-44
+				c-5.5,0-10-4.5-10-10V311.999z"/>
+		</g>
+		<g style="opacity:0.8;">
+			<path style="fill:#FFFFFF;" d="M94,313.999c0-5.5,4.5-10,10-10h44c5.5,0,10,4.5,10,10v29c0,5.5-4.5,10-10,10h-44
+				c-5.5,0-10-4.5-10-10V313.999z"/>
+		</g>
+		<g>
+			<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="125.9995" y1="351.999" x2="125.9995" y2="302.999">
+				<stop  offset="0" style="stop-color:#2AAAE2"/>
+				<stop  offset="1" style="stop-color:#1F749A"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_1_);" d="M158,341.999c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10v-29c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V341.999z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-toolbar-button-selected">
+		<g>
+			<path style="fill:#333333;" d="M158,269c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10v-29c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V269z"/>
+		</g>
+		<g>
+			<path style="fill:#CCCCCC;" d="M158,267c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10v-29c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V267z"/>
+		</g>
+		<g>
+			<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="125.9995" y1="278" x2="125.9995" y2="229.0005">
+				<stop  offset="0" style="stop-color:#2AAAE2"/>
+				<stop  offset="1" style="stop-color:#83D5F7"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_2_);" d="M158,268c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10v-29c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V268z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-toolbar-button-pressed">
+		<g>
+			<path style="fill:#333333;" d="M94,164c0-5.5,4.5-10,10-10h44c5.5,0,10,4.5,10,10v29c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10
+				V164z"/>
+		</g>
+		<g>
+			<path style="fill:#FFFFFF;" d="M94,166c0-5.5,4.5-10,10-10h44c5.5,0,10,4.5,10,10v29c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10
+				V166z"/>
+		</g>
+		<g>
+			<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="125.9995" y1="155" x2="125.9995" y2="204">
+				<stop  offset="0" style="stop-color:#4D4D4D"/>
+				<stop  offset="1" style="stop-color:#B3B3B3"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_3_);" d="M158,194c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10v-29c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V194z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-toolbar-button">
+		<g>
+			<path style="fill:#808080;" d="M158,121c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10V92c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V121z"/>
+		</g>
+		<g>
+			<path style="fill:#FFFFFF;" d="M158,119c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10V90c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V119z"/>
+		</g>
+		<g>
+			<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="125.9995" y1="81" x2="125.9995" y2="130">
+				<stop  offset="0" style="stop-color:#F2F2F2"/>
+				<stop  offset="1" style="stop-color:#D2D3D3"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_4_);" d="M158,120c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10V91c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V120z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-key-pressed-selected-portrait">
+		<g>
+			<path style="fill:#333333;" d="M238,355.999c0-5.5,4.5-10,10-10h44c5.5,0,10,4.5,10,10v58c0,5.5-4.5,10-10,10h-44
+				c-5.5,0-10-4.5-10-10V355.999z"/>
+		</g>
+		<g style="opacity:0.8;">
+			<path style="fill:#FFFFFF;" d="M238,357.999c0-5.5,4.5-10,10-10h44c5.5,0,10,4.5,10,10v58c0,5.5-4.5,10-10,10h-44
+				c-5.5,0-10-4.5-10-10V357.999z"/>
+		</g>
+		<g>
+			<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="270" y1="424.999" x2="270" y2="346.999">
+				<stop  offset="0" style="stop-color:#2AAAE2"/>
+				<stop  offset="1" style="stop-color:#1F749A"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_5_);" d="M302,414.999c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10v-58c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V414.999z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-key-selected-portrait">
+		<g>
+			<path style="fill:#333333;" d="M302,329c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10v-58c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V329z"/>
+		</g>
+		<g>
+			<path style="fill:#CCCCCC;" d="M302,327c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10v-58c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V327z"/>
+		</g>
+		<g>
+			<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="270" y1="338" x2="270" y2="260">
+				<stop  offset="0" style="stop-color:#2AAAE2"/>
+				<stop  offset="1" style="stop-color:#83D5F7"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_6_);" d="M302,328c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10v-58c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V328z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-key-pressed-portrait">
+		<g>
+			<path style="fill:#333333;" d="M238,178c0-5.5,4.5-10,10-10h44c5.5,0,10,4.5,10,10v58c0,5.5-4.5,10-10,10h-44
+				c-5.5,0-10-4.5-10-10V178z"/>
+		</g>
+		<g>
+			<path style="fill:#FFFFFF;" d="M238,180c0-5.5,4.5-10,10-10h44c5.5,0,10,4.5,10,10v58c0,5.5-4.5,10-10,10h-44
+				c-5.5,0-10-4.5-10-10V180z"/>
+		</g>
+		<g>
+			<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="270" y1="169" x2="270" y2="247.0005">
+				<stop  offset="0" style="stop-color:#4D4D4D"/>
+				<stop  offset="1" style="stop-color:#B3B3B3"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_7_);" d="M302,237c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10v-58c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V237z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-key-portrait">
+		<g>
+			<path style="fill:#808080;" d="M302,150c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10V92c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V150z"/>
+		</g>
+		<g>
+			<path style="fill:#FFFFFF;" d="M302,148c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10V90c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V148z"/>
+		</g>
+		<g>
+			<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="270" y1="81" x2="270" y2="159">
+				<stop  offset="0" style="stop-color:#F2F2F2"/>
+				<stop  offset="1" style="stop-color:#D2D3D3"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_8_);" d="M302,149c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10V91c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V149z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-key-sym-selected-landscape">
+		<g>
+			<path style="fill:#CCCCCC;" d="M473.996,170h-61.992c-5.503,0-10.004,4.406-10.004,9.792v19.228h82v-19.228
+				C484,174.406,479.498,170,473.996,170z"/>
+			<linearGradient id="SVGID_9_" gradientUnits="userSpaceOnUse" x1="443" y1="199.0195" x2="443" y2="170.9795">
+				<stop  offset="0" style="stop-color:#2AAAE2"/>
+				<stop  offset="1" style="stop-color:#83D5F7"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_9_);" d="M473.996,170.979h-61.992c-5.503,0-10.004,4.406-10.004,9.792v18.248h82v-18.248
+				C484,175.386,479.498,170.979,473.996,170.979z"/>
+		</g>
+		<g>
+			<path style="fill:#808080;" d="M402,199.02v17.189c0,5.385,4.501,9.791,10.004,9.791h61.992c5.502,0,10.004-4.406,10.004-9.791
+				V199.02H402z"/>
+			<linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="443" y1="199.0195" x2="443" y2="225.0215">
+				<stop  offset="0" style="stop-color:#F2F2F2"/>
+				<stop  offset="1" style="stop-color:#D2D3D3"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_10_);" d="M402,199.02v16.209c0,5.387,4.501,9.793,10.004,9.793h61.992
+				c5.502,0,10.004-4.406,10.004-9.793V199.02H402z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-key-ace-selected-landscape">
+		<g>
+			<path style="fill:#FFFFFF;" d="M473.998,81h-61.996C406.5,81,402,85.406,402,90.793v19.227h82V90.793
+				C484,85.406,479.498,81,473.998,81z"/>
+			<linearGradient id="SVGID_11_" gradientUnits="userSpaceOnUse" x1="443" y1="81.9785" x2="443" y2="110.0195">
+				<stop  offset="0" style="stop-color:#F2F2F2"/>
+				<stop  offset="1" style="stop-color:#D2D3D3"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_11_);" d="M473.998,81.979h-61.996c-5.502,0-10.002,4.407-10.002,9.793v18.248h82V91.771
+				C484,86.386,479.498,81.979,473.998,81.979z"/>
+		</g>
+		<g>
+			<path style="fill:#333333;" d="M402,110.02v17.188c0,5.387,4.5,9.793,10.002,9.793h61.996c5.5,0,10.002-4.406,10.002-9.793
+				V110.02H402z"/>
+			<linearGradient id="SVGID_12_" gradientUnits="userSpaceOnUse" x1="443" y1="136.0215" x2="443" y2="110.0195">
+				<stop  offset="0" style="stop-color:#2AAAE2"/>
+				<stop  offset="1" style="stop-color:#83D5F7"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_12_);" d="M402,110.02v16.209c0,5.386,4.5,9.793,10.002,9.793h61.996
+				c5.5,0,10.002-4.407,10.002-9.793V110.02H402z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-key-sym-selected-portrait">
+		<g>
+			<path style="fill:#CCCCCC;" d="M382,170h-60c-5.5,0-10,4.5-10,10v29h80v-29C392,174.5,387.5,170,382,170z"/>
+			<linearGradient id="SVGID_13_" gradientUnits="userSpaceOnUse" x1="352" y1="209" x2="352" y2="171">
+				<stop  offset="0" style="stop-color:#2AAAE2"/>
+				<stop  offset="1" style="stop-color:#83D5F7"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_13_);" d="M382,171h-60c-5.5,0-10,4.5-10,10v28h80v-28C392,175.5,387.5,171,382,171z"/>
+		</g>
+		<g>
+			<path style="fill:#808080;" d="M312,209v31.001c0,5.5,4.5,9.999,10,9.999h60c5.5,0,10-4.499,10-9.999V209H312z"/>
+			<linearGradient id="SVGID_14_" gradientUnits="userSpaceOnUse" x1="352" y1="209" x2="352" y2="249.0005">
+				<stop  offset="0" style="stop-color:#F2F2F2"/>
+				<stop  offset="1" style="stop-color:#D2D3D3"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_14_);" d="M312,209v30.001c0,5.5,4.5,9.999,10,9.999h60c5.5,0,10-4.499,10-9.999V209H312z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-key-ace-selected-portrait">
+		<g>
+			<path style="fill:#FFFFFF;" d="M382,80h-60c-5.5,0-10,4.5-10,10v29h80V90C392,84.5,387.5,80,382,80z"/>
+			<linearGradient id="SVGID_15_" gradientUnits="userSpaceOnUse" x1="352" y1="81" x2="352" y2="119">
+				<stop  offset="0" style="stop-color:#F2F2F2"/>
+				<stop  offset="1" style="stop-color:#D2D3D3"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_15_);" d="M382,81h-60c-5.5,0-10,4.5-10,10v28h80V91C392,85.5,387.5,81,382,81z"/>
+		</g>
+		<g>
+			<path style="fill:#333333;" d="M312,119v31c0,5.5,4.5,10,10,10h60c5.5,0,10-4.5,10-10v-31H312z"/>
+			<linearGradient id="SVGID_16_" gradientUnits="userSpaceOnUse" x1="352" y1="159" x2="352" y2="119">
+				<stop  offset="0" style="stop-color:#2AAAE2"/>
+				<stop  offset="1" style="stop-color:#83D5F7"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_16_);" d="M312,119v30c0,5.5,4.5,10,10,10h60c5.5,0,10-4.5,10-10v-30H312z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-key-sym-pressed-landscape">
+		<g>
+			<path style="fill:#333333;" d="M473.969,349H412c-5.5,0-10,4.5-10,10v19.635h81.969V359C483.969,353.5,479.469,349,473.969,349z"
+				/>
+			<linearGradient id="SVGID_17_" gradientUnits="userSpaceOnUse" x1="442.9844" y1="378.6348" x2="442.9844" y2="350">
+				<stop  offset="0" style="stop-color:#2AAAE2"/>
+				<stop  offset="1" style="stop-color:#1F749A"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_17_);" d="M473.969,350H412c-5.5,0-10,4.5-10,10v18.635h81.969V360
+				C483.969,354.5,479.469,350,473.969,350z"/>
+		</g>
+		<g>
+			<path style="fill:#333333;" d="M402,378.635v17.553c0,5.5,4.5,10,10,10h61.969c5.5,0,10-4.5,10-10v-17.553H402z"/>
+			<linearGradient id="SVGID_18_" gradientUnits="userSpaceOnUse" x1="442.9844" y1="378.6348" x2="442.9844" y2="405.1875">
+				<stop  offset="0" style="stop-color:#4D4D4D"/>
+				<stop  offset="1" style="stop-color:#B3B3B3"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_18_);" d="M402,378.635v16.553c0,5.5,4.5,10,10,10h61.969c5.5,0,10-4.5,10-10v-16.553H402z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-key-ace-pressed-landscape">
+		<g>
+			<path style="fill:#333333;" d="M473.998,260h-61.996C406.5,260,402,264.406,402,269.793v19.227h82v-19.227
+				C484,264.406,479.498,260,473.998,260z"/>
+			<linearGradient id="SVGID_19_" gradientUnits="userSpaceOnUse" x1="443" y1="260.9785" x2="443" y2="289.0195">
+				<stop  offset="0" style="stop-color:#4D4D4D"/>
+				<stop  offset="1" style="stop-color:#B3B3B3"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_19_);" d="M473.998,260.979h-61.996c-5.502,0-10.002,4.407-10.002,9.793v18.248h82v-18.248
+				C484,265.386,479.498,260.979,473.998,260.979z"/>
+		</g>
+		<g>
+			<path style="fill:#333333;" d="M402,289.02v17.188c0,5.387,4.5,9.793,10.002,9.793h61.996c5.5,0,10.002-4.406,10.002-9.793
+				V289.02H402z"/>
+			<linearGradient id="SVGID_20_" gradientUnits="userSpaceOnUse" x1="443" y1="315.0215" x2="443" y2="289.0195">
+				<stop  offset="0" style="stop-color:#2AAAE2"/>
+				<stop  offset="1" style="stop-color:#1F749A"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_20_);" d="M402,289.02v16.209c0,5.386,4.5,9.793,10.002,9.793h61.996
+				c5.5,0,10.002-4.407,10.002-9.793V289.02H402z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-key-sym-pressed-portrait">
+		<g>
+			<path style="fill:#333333;" d="M382,349h-60c-5.5,0-10,4.5-10,10v29h80v-29C392,353.5,387.5,349,382,349z"/>
+			<linearGradient id="SVGID_21_" gradientUnits="userSpaceOnUse" x1="352" y1="388" x2="352" y2="350">
+				<stop  offset="0" style="stop-color:#2AAAE2"/>
+				<stop  offset="1" style="stop-color:#1F749A"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_21_);" d="M382,350h-60c-5.5,0-10,4.5-10,10v28h80v-28C392,354.5,387.5,350,382,350z"/>
+		</g>
+		<g>
+			<path style="fill:#333333;" d="M312,388v31c0,5.5,4.5,10,10,10h60c5.5,0,10-4.5,10-10v-31H312z"/>
+			<linearGradient id="SVGID_22_" gradientUnits="userSpaceOnUse" x1="352" y1="388" x2="352" y2="428">
+				<stop  offset="0" style="stop-color:#4D4D4D"/>
+				<stop  offset="1" style="stop-color:#B3B3B3"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_22_);" d="M312,388v30c0,5.5,4.5,10,10,10h60c5.5,0,10-4.5,10-10v-30H312z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-key-ace-pressed-portrait">
+		<g>
+			<path style="fill:#333333;" d="M382,260h-60c-5.5,0-10,4.5-10,10v29h80v-29C392,264.5,387.5,260,382,260z"/>
+			<linearGradient id="SVGID_23_" gradientUnits="userSpaceOnUse" x1="352" y1="261" x2="352" y2="299">
+				<stop  offset="0" style="stop-color:#4D4D4D"/>
+				<stop  offset="1" style="stop-color:#B3B3B3"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_23_);" d="M382,261h-60c-5.5,0-10,4.5-10,10v28h80v-28C392,265.5,387.5,261,382,261z"/>
+		</g>
+		<g>
+			<path style="fill:#333333;" d="M312,299v31c0,5.5,4.5,10,10,10h60c5.5,0,10-4.5,10-10v-31H312z"/>
+			<linearGradient id="SVGID_24_" gradientUnits="userSpaceOnUse" x1="352" y1="339" x2="352" y2="299">
+				<stop  offset="0" style="stop-color:#2AAAE2"/>
+				<stop  offset="1" style="stop-color:#1F749A"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_24_);" d="M312,299v30c0,5.5,4.5,10,10,10h60c5.5,0,10-4.5,10-10v-30H312z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-key-pressed-selected-landscape">
+		<g>
+			<path style="fill:#333333;" d="M165,311.999c0-5.5,4.5-10,10-10h44c5.5,0,10,4.5,10,10v34c0,5.5-4.5,10-10,10h-44
+				c-5.5,0-10-4.5-10-10V311.999z"/>
+		</g>
+		<g style="opacity:0.8;">
+			<path style="fill:#FFFFFF;" d="M165,313.999c0-5.5,4.5-10,10-10h44c5.5,0,10,4.5,10,10v34c0,5.5-4.5,10-10,10h-44
+				c-5.5,0-10-4.5-10-10V313.999z"/>
+		</g>
+		<g>
+			<linearGradient id="SVGID_25_" gradientUnits="userSpaceOnUse" x1="196.9995" y1="356.999" x2="196.9995" y2="302.999">
+				<stop  offset="0" style="stop-color:#2AAAE2"/>
+				<stop  offset="1" style="stop-color:#1F749A"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_25_);" d="M229,346.999c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10v-34c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V346.999z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-key-selected-landscape">
+		<g>
+			<path style="fill:#333333;" d="M229,274c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10v-34c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V274z"/>
+		</g>
+		<g>
+			<path style="fill:#CCCCCC;" d="M229,272c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10v-34c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V272z"/>
+		</g>
+		<g>
+			<linearGradient id="SVGID_26_" gradientUnits="userSpaceOnUse" x1="196.9995" y1="283" x2="196.9995" y2="229.0005">
+				<stop  offset="0" style="stop-color:#2AAAE2"/>
+				<stop  offset="1" style="stop-color:#83D5F7"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_26_);" d="M229,273c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10v-34c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V273z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-key-pressed-landscape">
+		<g>
+			<path style="fill:#333333;" d="M165,164c0-5.5,4.5-10,10-10h44c5.5,0,10,4.5,10,10v34c0,5.5-4.5,10-10,10h-44
+				c-5.5,0-10-4.5-10-10V164z"/>
+		</g>
+		<g>
+			<path style="fill:#FFFFFF;" d="M165,166c0-5.5,4.5-10,10-10h44c5.5,0,10,4.5,10,10v34c0,5.5-4.5,10-10,10h-44
+				c-5.5,0-10-4.5-10-10V166z"/>
+		</g>
+		<g>
+			<linearGradient id="SVGID_27_" gradientUnits="userSpaceOnUse" x1="196.9995" y1="155" x2="196.9995" y2="209">
+				<stop  offset="0" style="stop-color:#4D4D4D"/>
+				<stop  offset="1" style="stop-color:#B3B3B3"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_27_);" d="M229,199c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10v-34c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V199z"/>
+		</g>
+	</g>
+	<g id="meegotouch-keyboard-key-landscape">
+		<g>
+			<path style="fill:#808080;" d="M229,126c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10V92c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V126z"/>
+		</g>
+		<g>
+			<path style="fill:#FFFFFF;" d="M229,124c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10V90c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V124z"/>
+		</g>
+		<g>
+			<linearGradient id="SVGID_28_" gradientUnits="userSpaceOnUse" x1="196.9995" y1="81" x2="196.9995" y2="135">
+				<stop  offset="0" style="stop-color:#F2F2F2"/>
+				<stop  offset="1" style="stop-color:#D2D3D3"/>
+			</linearGradient>
+			<path style="fill:url(#SVGID_28_);" d="M229,125c0,5.5-4.5,10-10,10h-44c-5.5,0-10-4.5-10-10V91c0-5.5,4.5-10,10-10h44
+				c5.5,0,10,4.5,10,10V125z"/>
+		</g>
+	</g>
+</g>
+</svg>
--- m-keyboard/theme/theme.pri
+++ m-keyboard/theme/theme.pri
@@ -1,9 +1,9 @@
-IMAGES_DATA = theme/*.svg
-images_data.path = /usr/share/meegotouch/virtual-keyboard/images
+IMAGES_DATA = theme/meegotouch-keyboard.svg
+images_data.path = /usr/share/themes/base/meegotouch/svg
 images_data.files = $$IMAGES_DATA
 
-CSS_DATA = theme/*.css
-css_data.path = /usr/share/meegotouch/virtual-keyboard/css
+CSS_DATA = theme/libmeego-keyboard.css
+css_data.path = /usr/share/themes/base/meegotouch/libmeego-keyboard/style
 css_data.files = $$CSS_DATA
 
 INSTALLS += \
--- m-keyboard/widgets/flickgesture.cpp
+++ m-keyboard/widgets/flickgesture.cpp
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#include "flickgesture.h"
+
+FlickGesture::FlickGesture(QObject *parent)
+    : QGesture(parent)
+{
+}
+
+FlickGesture::~FlickGesture()
+{
+}
+
+QPointF FlickGesture::positionDifference() const
+{
+    return endStartDifference;
+}
+
+void FlickGesture::setPositionDifference(const QPointF &positionDifference)
+{
+    endStartDifference = positionDifference;
+}
+
+FlickGesture::Direction FlickGesture::direction() const
+{
+    return gestureDirection;
+}
+
+void FlickGesture::setDirection(const Direction newDirection)
+{
+    gestureDirection = newDirection;
+}
+
--- m-keyboard/widgets/flickgesture.h
+++ m-keyboard/widgets/flickgesture.h
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#ifndef FLICKGESTURE_H
+#define FLICKGESTURE_H
+
+#include <QGesture>
+#include <QPointF>
+
+/*!
+  \brief Meego keyboard flick gesture.
+
+  Flick gestures are simple swipe gestures, made with just one finger.
+*/
+class FlickGesture : public QGesture
+{
+    Q_OBJECT
+
+public:
+    //! Possible gesture directions
+    enum Direction {
+        Left,
+        Right,
+        Up,
+        Down
+    };
+
+    //! Constructor
+    FlickGesture(QObject *parent = 0);
+
+    //! Destructor
+    virtual ~FlickGesture();
+
+    //! \return difference between end and start points
+    QPointF positionDifference() const;
+
+    //! Set difference between end and start points
+    void setPositionDifference(const QPointF &positionDifference);
+
+    //! \return gesture direction as determined from the position difference by the
+    //! recognizer.  Detailed x & y movement can be inspected via positionDifference().
+    Direction direction() const;
+
+    //! Set gesture direction
+    void setDirection(Direction newDirection);
+
+private:
+    //! Difference between end and start points
+    QPointF endStartDifference;
+
+    Direction gestureDirection;
+};
+
+#endif
--- m-keyboard/widgets/grip.cpp
+++ m-keyboard/widgets/grip.cpp
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#include "grip.h"
+#include "mvirtualkeyboardstyle.h"
+
+Grip::Grip(QGraphicsWidget *parent)
+    : Handle(parent)
+{
+    // TODO: decoration and spacers when we get the correct graphics
+}
+
+Grip::~Grip()
+{
+}
--- m-keyboard/widgets/grip.h
+++ m-keyboard/widgets/grip.h
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#ifndef GRIP_H
+#define GRIP_H
+
+#include "handle.h"
+
+class QGraphicsWidget;
+
+/*!
+  \brief Handle with a visual representation of a grip
+*/
+class Grip : public Handle
+{
+    Q_OBJECT
+
+public:
+    /*!
+     * \brief Constructor
+     * \param parent Parent object.
+     */
+    explicit Grip(QGraphicsWidget *parent = 0);
+
+    //! Destructor
+    virtual ~Grip();
+};
+
+#endif
--- m-keyboard/widgets/handle.cpp
+++ m-keyboard/widgets/handle.cpp
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#include "handle.h"
+#include <QGraphicsSceneMouseEvent>
+#include "flickgesture.h"
+
+#include <QDebug>
+#include <QGraphicsLinearLayout>
+
+Handle::Handle(QGraphicsWidget *parent)
+    : MStylableWidget(parent),
+      mainLayout(*new QGraphicsLinearLayout(Qt::Vertical, this))
+{
+    setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
+    mainLayout.setContentsMargins(0, 0, 0, 0);
+}
+
+Handle::~Handle()
+{
+}
+
+bool Handle::event(QEvent *e)
+{
+    const QGraphicsSceneMouseEvent *ev(dynamic_cast<const QGraphicsSceneMouseEvent *>(e));
+
+    if (e->type() == QEvent::GraphicsSceneMousePress) {
+        e->setAccepted(true);
+        startPosition = ev->pos();
+        return true;
+    } else if (e->type() == QEvent::GraphicsSceneMouseRelease) {
+        e->setAccepted(true);
+
+        const qreal MovementTresholdX(20);
+        const qreal MovementTresholdY(20);
+        const QPointF diff(ev->pos() - startPosition);
+
+        FlickGesture gesture;
+        gesture.setPositionDifference(diff);
+
+        if ((abs(diff.x()) > MovementTresholdX)
+            && (abs(diff.x()) > abs(diff.y()))) {
+            gesture.setDirection(diff.x() > 0 ? FlickGesture::Right : FlickGesture::Left);
+            flickGestureEvent(gesture);
+        } else if ((abs(diff.y()) > MovementTresholdY)) {
+            gesture.setDirection(diff.y() > 0 ? FlickGesture::Down : FlickGesture::Up);
+            flickGestureEvent(gesture);
+        }
+
+        return true;
+    }
+    return MStylableWidget::event(e);
+}
+
+void Handle::setChild(QGraphicsLayoutItem *widget)
+{
+    if (mainLayout.itemAt(0)) {
+        mainLayout.removeAt(0);
+    }
+    mainLayout.insertItem(0, widget);
+}
+
+typedef void (Handle::*FlickEmitter)(const FlickGesture &gesture);
+
+void Handle::flickGestureEvent(FlickGesture &gesture)
+{
+    static const FlickEmitter emitters[4] = { &Handle::flickLeft, &Handle::flickRight,
+                                              &Handle::flickUp, &Handle::flickDown };
+    (this->*emitters[static_cast<int>(gesture.direction())])(gesture);
+}
--- m-keyboard/widgets/handle.h
+++ m-keyboard/widgets/handle.h
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#ifndef HANDLE_H
+#define HANDLE_H
+
+#include "handlestyle.h"
+#include <MStylableWidget>
+
+class QGraphicsLinearLayout;
+class FlickGesture;
+
+/*!
+  \brief Handle is a wrapper widget of zero or one child that reacts to flick gestures.
+
+  Handle doesn't have any non-default content except the child if one is set.
+*/
+class Handle : public MStylableWidget
+{
+    Q_OBJECT
+
+public:
+    /*!
+     * \brief Constructor
+     * \param parent Parent object.
+     */
+    explicit Handle(QGraphicsWidget *parent = 0);
+
+    //! Destructor
+    virtual ~Handle();
+
+    //! Set the one child object that Handle can contain.
+    void setChild(QGraphicsLayoutItem *widget);
+
+    //! \reimp
+    bool event(QEvent *e);
+    //! \reimp_end
+
+signals:
+    void flickUp(const FlickGesture &gesture);
+    void flickDown(const FlickGesture &gesture);
+    void flickLeft(const FlickGesture &gesture);
+    void flickRight(const FlickGesture &gesture);
+
+protected:
+    M_STYLABLE_WIDGET(HandleStyle)
+
+private:
+    void flickGestureEvent(FlickGesture &gesture);
+
+private:
+    QGraphicsLinearLayout &mainLayout;
+
+    QPointF startPosition;         // TODO: temporary
+};
+
+#endif
--- m-keyboard/widgets/handlestyle.h
+++ m-keyboard/widgets/handlestyle.h
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#ifndef HANDLESTYLE_H
+#define HANDLESTYLE_H
+
+#include <MWidgetStyle>
+
+/*!
+ * \brief This defines style that is common to all Handle class based widgets.
+ */
+class M_EXPORT HandleStyle : public MWidgetStyle
+{
+    Q_OBJECT
+    M_STYLE(HandleStyle)
+};
+
+class M_EXPORT HandleStyleContainer : public MWidgetStyleContainer
+{
+    M_STYLE_CONTAINER(HandleStyle)
+
+    M_STYLE_MODE(Landscape)
+    M_STYLE_MODE(Portrait)
+
+    friend class Handle;
+};
+
+
+#endif
--- m-keyboard/widgets/horizontalswitcher.cpp
+++ m-keyboard/widgets/horizontalswitcher.cpp
@@ -52,7 +52,7 @@
     slides.clear();
 }
 
-void HorizontalSwitcher::switchTo(Direction direction)
+void HorizontalSwitcher::switchTo(SwitchDirection direction)
 {
     if (isRunning())
         finishAnimation();
@@ -110,31 +110,7 @@
     animTimeLine.start();
 }
 
-void HorizontalSwitcher::switchTo(int index)
-{
-    if (slides.count() > 1) {
-        if (!isVisible()) {
-            setCurrent(index);
-        } else if (index == currentIndex - 1)
-            switchTo(Left);
-        else if (index == currentIndex + 1)
-            switchTo(Right);
-        else if (index != currentIndex) {
-            // TODO: support animated switching over multiple slides?
-            setCurrent(index);
-        }
-    } else {
-        setCurrent(index);
-    }
-}
-
-void HorizontalSwitcher::switchTo(QGraphicsWidget *widget)
-{
-    Q_ASSERT(widget && slides.contains(widget));
-    switchTo(slides.indexOf(widget));
-}
-
-bool HorizontalSwitcher::isAtBoundary(Direction direction) const
+bool HorizontalSwitcher::isAtBoundary(SwitchDirection direction) const
 {
     if (direction == Right) {
         if (currentIndex == slides.count() - 1) {
@@ -157,21 +133,24 @@
 
 void HorizontalSwitcher::setCurrent(int index)
 {
-    if (index >= 0 && index < slides.count() && index != currentIndex) {
+    if (isValidIndex(index) && index != currentIndex) {
         int oldIndex = -1;
-        QGraphicsWidget *old = NULL;
-        if (currentIndex >= 0 && currentIndex < slides.count()) {
+        QGraphicsWidget *old = 0;
+
+        if (isValidIndex(currentIndex)) {
             oldIndex = currentIndex;
             old = slides.at(currentIndex);
         }
+
         currentIndex = index;
+
         QGraphicsWidget *widget = slides.at(index);
         widget->setPos(0, 0);
         widget->resize(size());
         widget->show();
-        emit switchStarting(oldIndex, currentIndex);
-        emit switchStarting(old, widget);
-        emit switchDone(oldIndex, currentIndex);
+
+        // Ultimately might lead to a reaction map update in MKeyboardHost,
+        // has no other purpose:
         emit switchDone(old, widget);
 
         updateGeometry();
@@ -234,24 +213,10 @@
 
         slides.append(widget);
         widget->hide();
-    }
-}
 
-void HorizontalSwitcher::removeWidget(QGraphicsWidget *widget)
-{
-    if (widget && slides.contains(widget)) {
-        if (widget->isVisible() && isRunning())
-            finishAnimation();
-
-        widget->setParentItem(0);
-        if (widget->scene())
-            widget->scene()->removeItem(widget);
-        slides.removeOne(widget);
-
-        if (!slides.isEmpty()) {
-            if (--currentIndex < 0)
-                currentIndex += slides.count();
-            setCurrent(currentIndex);
+        // HS was empty before, this was the first widget added:
+        if (slides.size() == 1) {
+            setCurrent(0);
         }
     }
 }
@@ -260,10 +225,14 @@
 {
     foreach(QGraphicsWidget * slide, slides) {
         slide->setParentItem(0);
-        if (slide->scene())
+
+        if (slide->scene()) {
             slide->scene()->removeItem(slide);
+        }
     }
+
     slides.clear();
+    currentIndex = -1;
     updateGeometry();
 }
 
@@ -325,3 +294,8 @@
     emit switchDone(oldIndex, currentIndex);
     emit switchDone(old, slides.at(currentIndex));
 }
+
+bool HorizontalSwitcher::isValidIndex(int index) const
+{
+    return (index >= 0 && index < slides.size());
+}
--- m-keyboard/widgets/horizontalswitcher.h
+++ m-keyboard/widgets/horizontalswitcher.h
@@ -28,11 +28,9 @@
     Q_OBJECT
 
 public:
-    /*! SwitchDirection tells which direction we want to
-     *  move the "camera", that is, the contents will
-     *  slide in opposite direction.
-     */
-    enum Direction {
+    //! SwitchDirection tells which neighbour should be shown next.
+    //! \sa switchTo()
+    enum SwitchDirection {
         Left, Right
     };
 
@@ -44,21 +42,14 @@
     //! Does nothing if less than two widgets added.
     //! Does not loop by default if end reached. You can use setLooping()
     //! method to change this behaviour.
-    void switchTo(Direction direction);
-
-    //! \brief Slide from current widget to one with given index.
-    void switchTo(int index);
-
-    //! \brief Slide from current widget to the given widget.
-    //!        Widget must exist in the switcher.
-    void switchTo(QGraphicsWidget *widget);
+    void switchTo(SwitchDirection direction);
 
     /*!
      * \brief Returns true if it is not possible to switch to the next
      * widget of current with given direction without looping.
      * \param direction Direction of switching
      */
-    bool isAtBoundary(Direction direction) const;
+    bool isAtBoundary(SwitchDirection direction) const;
 
     //! \brief Show given widget without animation.
     //!        The widget must be already added.
@@ -92,15 +83,18 @@
     //! \brief Add widget to switcher. Takes ownership.
     //!
     //! Indices for widgets are added in the order they were added.
+    //! If the container was empty (index at -1), then addWidget updates the
+    //! current index to point to widget and shows it.
     void addWidget(QGraphicsWidget *widget);
 
-    //! \brief Remove widget from switcher. Ownership changed to caller.
-    void removeWidget(QGraphicsWidget *widget);
-
     //! \brief Remove all widgets. Ownership changed to caller.
+    //!
+    //! Sets current index to -1.
     void removeAll();
 
-    /// \brief Deletes all widgets
+    //! \brief Deletes all widgets
+    //!
+    //! Sets current index to -1.
     void deleteAll();
 
 signals:
@@ -133,6 +127,8 @@
     void finishAnimation();
 
 private:
+    bool isValidIndex(int index) const;
+
     int currentIndex;
     QList<QGraphicsWidget *> slides;
     QGraphicsItemAnimation enterAnim;
--- m-keyboard/widgets/keybuttonarea.cpp
+++ m-keyboard/widgets/keybuttonarea.cpp
@@ -25,6 +25,8 @@
 #include <MApplication>
 #include <MComponentData>
 #include <MFeedbackPlayer>
+#include <MSceneManager>
+#include <MGConfItem>
 #include <QDebug>
 #include <QEvent>
 #include <QGraphicsLinearLayout>
@@ -35,45 +37,49 @@
 
 namespace
 {
-    const int FlickTime     = 150;
-    const int LongPressTime = 1000;
-
-    const int FlickDownThreshold = 50;
-    const int FlickUpThreshold = 50;
-    const int FlickLeftRightVerticalThreshold = 50;
-    const int FlickLeftRightHorizontalThreshold = 50;
+    const int GestureTimeOut = 1000;
+    const int LongPressTime  = 0;
+    const qreal ZValueButtons = 0.0;
 
     // Minimal distinguishable cursor/finger movement
     const qreal MovementThreshold = 5.0;
 
-    const qreal ZValueButtons = 0.0;
-};
+    // For gesture thresholds: How many pixels translate to one counted move event.
+    const qreal PixelsToMoveEventsFactor = 0.02;
+
+    // This GConf item defines whether multitouch is enabled or disabled
+    const char * const MultitouchSettings = "/meegotouch/inputmethods/multitouch/enabled";
+}
+
+int KeyButtonArea::swipeGestureTouchPoints = 1;
+
+M::InputMethodMode KeyButtonArea::InputMethodMode;
 
-KeyButtonArea::KeyButtonArea(MVirtualKeyboardStyleContainer *style,
+KeyButtonArea::KeyButtonArea(const MVirtualKeyboardStyleContainer *style,
                              QSharedPointer<const LayoutSection> sectionModel,
                              ButtonSizeScheme buttonSizeScheme,
                              bool usePopup,
                              QGraphicsWidget *parent)
     : MWidget(parent),
-      shiftButton(0),
       currentLevel(0),
       popup(PopupFactory::instance()->createPopup(*style, this)),
       styleContainer(style),
-      flickTimer(new LimitedTimer(this)),
+      newestTouchPointId(-1),
       longPressTimer(new LimitedTimer(this)),
       accurateMode(false),
-      flicked(false),
+      wasGestureTriggered(false),
+      enableMultiTouch(MGConfItem(MultitouchSettings).value().toBool()),
       activeDeadkey(0),
-      activeKey(0),
-      flickedKey(0),
       feedbackPlayer(0),
       section(sectionModel),
       buttonSizeScheme(buttonSizeScheme),
-      usePopup(usePopup)
+      usePopup(usePopup),
+      swipeGestureCount(0)
 {
-    flickTimer->setSingleShot(true);
-    flickTimer->setInterval(FlickTime);
-    connect(flickTimer, SIGNAL(timeout()), this, SLOT(flickCheck()));
+    // By default multi-touch is disabled
+    if (enableMultiTouch) {
+        setAcceptTouchEvents(true);
+    }
 
     longPressTimer->setSingleShot(true);
     longPressTimer->setInterval(LongPressTime);
@@ -83,15 +89,23 @@
     popup->hidePopup();
 
     feedbackPlayer = MComponentData::feedbackPlayer();
+
+    connect(MTheme::instance(), SIGNAL(themeChangeCompleted()),
+            this, SLOT(onThemeChangeCompleted()),
+            Qt::UniqueConnection);
 }
 
 KeyButtonArea::~KeyButtonArea()
 {
-    delete flickTimer;
     delete longPressTimer;
     delete popup;
 }
 
+void KeyButtonArea::setInputMethodMode(M::InputMethodMode inputMethodMode)
+{
+    InputMethodMode = inputMethodMode;
+}
+
 void KeyButtonArea::buttonInformation(int row, int column, const VKBDataKey *&dataKey, QSize &size, bool &stretchesHorizontally)
 {
     // We share the same button instance with different key bindings.
@@ -123,7 +137,7 @@
 
 ISymIndicator *KeyButtonArea::symIndicator()
 {
-	return 0;
+    return 0;
 }
 
 void KeyButtonArea::updatePopup(const QPoint &pointerPosition, const IKeyButton *key)
@@ -167,22 +181,31 @@
 void
 KeyButtonArea::onHide()
 {
+    clearActiveKeys();
     unlockDeadkeys();
 }
 
 void
-KeyButtonArea::switchLevel(int level, bool capslock)
+KeyButtonArea::switchLevel(int level)
 {
-    currentLevel = level;
+    if (level != currentLevel) {
+        currentLevel = level;
+
+        // Update uppercase / lowercase
+        updateButtonModifiers();
 
-    if (shiftButton) {
-        shiftButton->setSelected(capslock);
+        update();
     }
+}
 
-    // Update uppercase / lowercase
-    updateButtonModifiers();
+int KeyButtonArea::level() const
+{
+    return currentLevel;
+}
 
-    update();
+void KeyButtonArea::setShiftStatus(bool /*shiftOn*/, bool /*capslock*/)
+{
+    // Empty default implementation
 }
 
 bool
@@ -193,255 +216,308 @@
     return movement >= MovementThreshold;
 }
 
-KeyEvent KeyButtonArea::keyToKeyEvent(const IKeyButton &key, QKeyEvent::Type eventType) const
+void KeyButtonArea::resizeEvent(QGraphicsSceneResizeEvent *event)
 {
-    Qt::KeyboardModifiers modifiers = (currentLevel == 1) ? Qt::ShiftModifier : Qt::NoModifier;
-    KeyEvent event;
+    const int newWidth = static_cast<int>(event->newSize().width());
 
-    if (activeDeadkey != NULL) {
-        event = key.key().toKeyEvent(eventType, activeDeadkey->label().at(0), modifiers);
-    } else {
-        event = key.key().toKeyEvent(eventType, modifiers);
+    if (newWidth != static_cast<int>(event->oldSize().width())) {
+        updateButtonGeometriesForWidth(newWidth);
     }
+}
 
-    return event;
+void
+KeyButtonArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+    if (!enableMultiTouch) {
+        // Qt always assigns zero to the first touch point, so pass id = 0.
+        touchPointPressed(event->pos().toPoint(), 0);
+    }
 }
 
-void KeyButtonArea::resizeEvent(QGraphicsSceneResizeEvent *event)
+
+void
+KeyButtonArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
 {
-    const int newWidth = static_cast<int>(event->newSize().width());
-    if (newWidth != static_cast<int>(event->oldSize().width())) {
-        // All main keyboards should take the whole available width so we restrict
-        // the button width here. This is applied only if we have equal button width.
-        int equalButtonWidth = -1; // the new width if it's same for all
-        if ((buttonSizeScheme == ButtonSizeEqualExpanding)
-             || (buttonSizeScheme == ButtonSizeEqualExpandingPhoneNumber)) {
-            const int HorizontalSpacing = style()->spacingHorizontal();
-            const int MaxButtonWidth = qRound(static_cast<qreal>(newWidth + HorizontalSpacing)
-                                              / static_cast<qreal>(section->maxColumns())
-                                              - HorizontalSpacing);
+    if (scene()->mouseGrabberItem() == this) {
+        // Ungrab mouse explicitly since we probably used grabMouse() to get it.
+        ungrabMouse();
+    }
 
-            equalButtonWidth = MaxButtonWidth;
-        }
-        updateButtonGeometries(newWidth, equalButtonWidth);
+    if (!enableMultiTouch) {
+        touchPointReleased(event->pos().toPoint(), 0);
     }
 }
 
-void
-KeyButtonArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
+
+void KeyButtonArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
 {
-    pointerPos = event->pos().toPoint();
+    if (!enableMultiTouch) {
+        touchPointMoved(event->pos().toPoint(), 0);
+    }
+}
 
-    IKeyButton *key = keyAt(pointerPos);
+void KeyButtonArea::setActiveKey(IKeyButton *key, TouchPointInfo &tpi)
+{
+    // Selected buttons are currently skipped.
+    QString accent;
 
-    if (!key) {
-        event->ignore();
-        return;
+    if (activeDeadkey) {
+        accent = activeDeadkey->label();
     }
 
-    mTimestamp("KeyButtonArea", key->label());
+    if (tpi.activeKey && (tpi.activeKey != key)) {
+        // Release key
+        tpi.activeKey->setDownState(false);
+        // odd level numbers are upper case,
+        // even level numbers are lower case
+        emit keyReleased(tpi.activeKey, accent, level() % 2);
+        tpi.activeKey = 0;
+    }
 
-    fingerInsideArea = true;
+    if (key && (tpi.activeKey != key)) {
+        // Press key
+        tpi.activeKey = key;
+        tpi.activeKey->setDownState(true);
+        emit keyPressed(tpi.activeKey, accent, level() % 2);
+    }
+}
 
-    longPressTimer->start();
+void KeyButtonArea::clearActiveKeys()
+{
+    for (int i = 0; i < touchPoints.count(); ++i) {
+        setActiveKey(0, touchPoints[i]);
+    }
+}
+
+void KeyButtonArea::click(IKeyButton *key)
+{
+    if (!key->isDeadKey()) {
+        QString accent;
+
+        if (activeDeadkey) {
+            accent = activeDeadkey->label();
+        }
 
-    // Stop accurate mode if pressed key makes accurate mode irrelevant
-    if (accurateMode)
+        // Check if we need to disable accurate mode
         accurateCheckContent(key->label());
 
-    // Check if accurate mode is still on.
-    if (accurateMode) {
-        // Show popup in accurate mode.
-        if (usePopup) {
-            updatePopup(pointerPos, key);
+        unlockDeadkeys();
+
+        emit keyClicked(key, accent, level() % 2);
+    } else if (key == activeDeadkey) {
+        unlockDeadkeys();
+    } else {
+        // Deselect previous dead key, if any
+        if (activeDeadkey) {
+            activeDeadkey->setSelected(false);
         }
-    }
 
-    if (flickTimer->isActive()) {
-        flickTimer->stop();
-    }
+        activeDeadkey = key;
+        activeDeadkey->setSelected(true);
 
-    flicked = false;
-    flickStartPos = pointerPos;
-    flickedKey = key;
-    flickTimer->start();
+        updateButtonModifiers();
+    }
+}
 
-    setActiveKey(key);
+QVariant KeyButtonArea::itemChange(GraphicsItemChange change, const QVariant &value)
+{
+    if (change == QGraphicsItem::ItemVisibleChange && !value.toBool()) {
+        onHide();
+    }
+    return QGraphicsItem::itemChange(change, value);
 }
 
+void KeyButtonArea::grabMouseEvent(QEvent */*event*/)
+{
+    // If keybuttonarea is hidden without mouseReleaseEvent
+    // the enabled <flicked> would stay true if mouse
+    // grab is obtained again without mousePressEvent.
+    // This would ignore mouseReleaseEvent and would not cause keyClicked.
+    wasGestureTriggered = false;
+}
 
-void
-KeyButtonArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+void KeyButtonArea::ungrabMouseEvent(QEvent */*event*/)
 {
-    bool flickTimerActive = flickTimer->isActive();
+    // longPressTimer is running if flicked without releasing
+    // (or releasing after this keybuttonarea is hidden)
     longPressTimer->stop();
-    flickTimer->stop();
-    fingerInsideArea = false;
-    popup->hidePopup();
 
-    pointerPos = event->pos().toPoint();
+    // Make sure popup is hidden even if mouse grab
+    // is lost without mouse release event.
+    popup->hidePopup();
+}
 
-    IKeyButton *key = keyAt(pointerPos);
+bool KeyButtonArea::sceneEvent(QEvent *event)
+{
+    if (event->type() == QEvent::TouchBegin
+        || event->type() == QEvent::TouchUpdate
+        || event->type() == QEvent::TouchEnd) {
+        QTouchEvent *touch = static_cast<QTouchEvent*>(event);
+
+        if (event->type() == QEvent::TouchBegin) {
+            touchPoints.clear();
+        }
+
+        foreach (const QTouchEvent::TouchPoint &tp, touch->touchPoints()) {
+
+            switch (tp.state()) {
+            case Qt::TouchPointPressed:
+                touchPointPressed(tp.pos().toPoint(), tp.id());
+                break;
+            case Qt::TouchPointMoved:
+                touchPointMoved(tp.pos().toPoint(), tp.id());
+                break;
+            case Qt::TouchPointReleased:
+                touchPointReleased(tp.pos().toPoint(), tp.id());
+                break;
+            default:
+                break;
+            }
+        }
 
-    if (key) {
-        mTimestamp("KeyButtonArea", key->label());
+        return true;
     }
 
-    // It's presumably possible that we're getting this release event on top
-    // of another after press event (of another key) without first getting a
-    // move event (or at least such move event that we handle).  Which means
-    // that we must send release event for the previous key and press event
-    // for this key before sending release and clicked events for this key.
-    if (key && (key != activeKey)) {
-        setActiveKey(key);
-    }
+    return MWidget::sceneEvent(event);
+}
 
-    if (scene()->mouseGrabberItem() == this) {
-        // Ungrab mouse explicitly since we probably used grabMouse() to get it.
-        // Ungrab event handler will clear active key.
-        ungrabMouse();
-    } else {
-        setActiveKey(0);
-    }
+void KeyButtonArea::touchPointPressed(const QPoint &pos, int id)
+{
+    newestTouchPointId = id;
+
+    // Create new TouchPointInfo structure and overwrite any previous one.
+    touchPoints[id] = TouchPointInfo();
+    TouchPointInfo &tpi = touchPoints[id];
+    tpi.pos = pos;
+    tpi.initialPos = pos;
+
+    // Reset gesture checks.
+    wasGestureTriggered = false;
+
+    // Reset long-press check.
+    longPressTimer->start();
 
-    // Check if keyboard was flicked or
-    // release happens fast and far enough from the start
-    if (flicked || (flickTimerActive && flickCheck() == true)) {
+    IKeyButton *key = keyAt(pos);
+    if (!key) {
         return;
     }
 
-    // Handle click
-    if (key) {
-        if (!key->isDeadKey()) {
-            KeyEvent clickEvent = keyToKeyEvent(*key, QEvent::KeyRelease);
+    mTimestamp("KeyButtonArea", key->label());
 
-            unlockDeadkeys();
+    tpi.initialKey = key;
+    tpi.fingerInsideArea = true;
 
-            // Check if we need to disable accurate mode
-            accurateCheckContent(key->label());
+    swipeGestureCount = 0;
 
-            emit keyClicked(clickEvent);
-        } else {
-            clickAtDeadkey(key);
-            update();
+    if (accurateMode) {
+        // Stop accurate mode if pressed key makes accurate mode irrelevant
+        accurateCheckContent(key->label());
+
+        // Check if accurate mode is still on.
+        // Show popup in accurate mode.
+        if (accurateMode && usePopup && (id == newestTouchPointId)) {
+            updatePopup(pos, key);
         }
     }
-}
 
+    setActiveKey(key, tpi);
+}
 
-void KeyButtonArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+void KeyButtonArea::touchPointMoved(const QPoint &pos, int id)
 {
-    if (!isObservableMove(pointerPos, event->pos()))
+    TouchPointInfo &tpi = touchPoints[id];
+
+    if (!isObservableMove(tpi.pos, pos))
         return;
 
-    pointerPos = event->pos().toPoint();
+    tpi.pos = pos;
+    ++tpi.moveEventCount;
 
-    // Check if finger is on a key.
-    IKeyButton *key = keyAt(pointerPos);
-    if (!key) {
-
-        // Finger has slid off the keys
-        if (fingerInsideArea) {
-            if (accurateMode && feedbackPlayer)
-                feedbackPlayer->play(MFeedbackPlayer::Cancel);
+    if (isSwipeGesture(tpi)) {
+        return;
+    }
 
-            popup->hidePopup();
+    // Check if finger is on a key.
+    IKeyButton *key = keyAt(pos);
+    if (key) {
+        tpi.fingerInsideArea = true;
 
-            // Don't show button as pressed, and send release event.
-            setActiveKey(0);
+        if ((tpi.activeKey != key) && accurateMode && feedbackPlayer) {
+            // Finger has slid from a key to an adjacent one.
+            feedbackPlayer->play(MFeedbackPlayer::Press);
         }
 
-        fingerInsideArea = false;
-        longPressTimer->stop();
-    } else {
-        fingerInsideArea = true;
-
         // If popup is visible, always update the position,
         // even if accurate mode is not enabled. This is for
         // Sym view, who doesn't care about accurate mode.
-        if (usePopup && (accurateMode || popup->isPopupVisible())) {
-            updatePopup(pointerPos, key);
+        if (usePopup
+            && (id == newestTouchPointId)
+            && (accurateMode || popup->isPopupVisible())) {
+            updatePopup(pos, key);
         }
 
-        if (activeKey != key) {
-            setActiveKey(key);
-
-            if (accurateMode && feedbackPlayer) {
-                // Finger has slid from a key to an adjacent one.
-                feedbackPlayer->play(MFeedbackPlayer::Press);
-            }
-
+        if (tpi.activeKey != key) {
             // Use has to keep finger still to generate long press.
             // isObservableMove() makes this task easier for the user.
             if (longPressTimer->isActive())
                 longPressTimer->start();
         }
-    } // inside area
-}
-
-void KeyButtonArea::setActiveKey(IKeyButton *key)
-{
-    // Selected buttons are currently skipped.
+    } else {
+        if (tpi.fingerInsideArea && accurateMode && feedbackPlayer) {
+            feedbackPlayer->play(MFeedbackPlayer::Cancel);
+        }
+        // Finger has slid off the keys
+        if (tpi.fingerInsideArea && (id == newestTouchPointId)) {
+            popup->hidePopup();
+        }
 
-    if (activeKey && (activeKey != key)) {
-        // Release key
-        activeKey->setDownState(false);
-        KeyEvent releaseEvent = keyToKeyEvent(*activeKey, QEvent::KeyRelease);
-        emit keyReleased(releaseEvent);
-        activeKey = 0;
+        longPressTimer->stop();
+        tpi.fingerInsideArea = false;
     }
 
-    if (key && (activeKey != key)) {
-        // Press key
-        activeKey = key;
-        activeKey->setDownState(true);
-        KeyEvent pressEvent = keyToKeyEvent(*activeKey, QEvent::KeyPress);
-        emit keyPressed(pressEvent);
-    }
+    setActiveKey(key, tpi);
 }
 
-QVariant KeyButtonArea::itemChange(GraphicsItemChange change, const QVariant &value)
+void KeyButtonArea::touchPointReleased(const QPoint &pos, int id)
 {
-    if (change == QGraphicsItem::ItemVisibleChange && !value.toBool()) {
-        onHide();
-    }
-    return QGraphicsItem::itemChange(change, value);
-}
+    TouchPointInfo &tpi = touchPoints[id];
 
-void KeyButtonArea::grabMouseEvent(QEvent */*event*/)
-{
-    // If keybuttonarea is hidden without mouseReleaseEvent
-    // the enabled <flicked> would stay true if mouse
-    // grab is obtained again without mousePressEvent.
-    // This would ignore mouseReleaseEvent and would not cause keyClicked.
-    flicked = false;
-}
+    tpi.fingerInsideArea = false;
 
-void KeyButtonArea::ungrabMouseEvent(QEvent */*event*/)
-{
-    // longPressTimer is running if flicked without releasing
-    // (or releasing after this keybuttonarea is hidden)
+    // No more long-press triggerings, although would still be possible to make
+    // with another touch point.
     longPressTimer->stop();
 
-    // Make sure popup is hidden even if mouse grab
-    // is lost without mouse release event.
-    popup->hidePopup();
+    // Same thing here, hide popup although otherwise could be shown on
+    // another touch point.
+    if (id == newestTouchPointId) {
+        popup->hidePopup();
+    }
 
-    // Release any key we have currently active
-    setActiveKey(0);
-}
+    IKeyButton *key = keyAt(pos);
 
-void
-KeyButtonArea::clickAtDeadkey(const IKeyButton *deadKey)
-{
-    Q_ASSERT(deadKey);
+    if (key) {
+        mTimestamp("KeyButtonArea", key->label());
 
-    if (deadKey == activeDeadkey) {
-        unlockDeadkeys();
+        // It's presumably possible that we're getting this release event on top
+        // of another after press event (of another key) without first getting a
+        // move event (or at least such move event that we handle).  Which means
+        // that we must send release event for the previous key and press event
+        // for this key before sending release and clicked events for this key.
+        setActiveKey(key, tpi); // in most cases, does nothing
+        setActiveKey(0, tpi); // release key
+
+        // Check if keyboard was swiped or
+        // release happens fast and far enough from the start.
+        // If so, then skip click.
+        // Altough we associate flick gesture with the newest touch point
+        // it can still mistrigger because sometimes, when clicked nearly
+        // simultaneously, we receive a single move between two pressed points.
+        if (id != newestTouchPointId || !wasGestureTriggered) {
+            click(key);
+        }
     } else {
-        activeDeadkey = deadKey;
-
-        updateButtonModifiers();
+        setActiveKey(0, tpi);
     }
 }
 
@@ -449,6 +525,7 @@
 KeyButtonArea::unlockDeadkeys()
 {
     if (activeDeadkey) {
+        activeDeadkey->setSelected(false);
         activeDeadkey = 0;
         updateButtonModifiers();
     }
@@ -456,8 +533,8 @@
 
 void KeyButtonArea::popupStart()
 {
-    if (usePopup) {
-        updatePopup(pointerPos);
+    if (usePopup && touchPoints.contains(newestTouchPointId)) {
+        updatePopup(touchPoints[newestTouchPointId].pos);
     }
 }
 
@@ -511,45 +588,89 @@
 }
 
 bool
-KeyButtonArea::flickCheck()
+KeyButtonArea::isSwipeGesture(const TouchPointInfo &tpi)
 {
-    if (flicked)
+    if ((InputMethodMode == M::InputMethodModeDirect) || wasGestureTriggered
+        || tpi.gestureTimer.elapsed() > GestureTimeOut) {
         return false;
+    }
+
+    const QPointF deltaPos = tpi.initialPos - tpi.pos;
+    const qreal ScalingFactor = .5;
+    int HorizontalThreshold = static_cast<int>(boundingRect().width() * ScalingFactor);
+    int VerticalThreshold = static_cast<int>(boundingRect().height() * ScalingFactor);
+
+    bool result = isHorizontalSwipeGesture(deltaPos, HorizontalThreshold, VerticalThreshold,
+                                           tpi.moveEventCount);
+    if (!result) {
+        result = isVerticalSwipeGesture(deltaPos, HorizontalThreshold, VerticalThreshold,
+                                        tpi.moveEventCount, tpi.initialKey);
+    }
 
-    bool res = false;
-    QPointF diff = flickStartPos - pointerPos;
+    if (result) {
+        popup->hidePopup();
+        wasGestureTriggered = true;
+        swipeGestureCount = 0;
+    }
+
+    return result;
+}
 
-    if (diff.y() > -FlickLeftRightVerticalThreshold &&
-            diff.y() < FlickLeftRightVerticalThreshold) {
-        if (diff.x() > FlickLeftRightHorizontalThreshold) {
-            res = true;
-            emit flickLeft();
-        } else if (diff.x() < -FlickLeftRightHorizontalThreshold) {
-            res = true;
-            emit flickRight();
-        }
-    } else if (diff.x() > - FlickDownThreshold && diff.x() < FlickDownThreshold) {
-        if (diff.y() < - FlickDownThreshold) {
-            res = true;
-            emit flickDown();
-        } else if (diff.y() > FlickUpThreshold) {
-            const KeyBinding *binding = 0;
-            res = true;
-            if (flickedKey) {
-                binding = &flickedKey->binding();
-                flickedKey = 0;
+bool KeyButtonArea::isHorizontalSwipeGesture(const QPointF &delta, int absHorizontalThreshold,
+                                             int absVerticalThreshold, int moveEventCount)
+{
+    const int requiredEventCount = qMax(2, static_cast<int>(absHorizontalThreshold *
+                                                            PixelsToMoveEventsFactor));
+    bool result = false;
+
+    if ((qAbs(delta.y()) < absVerticalThreshold) &&
+        (moveEventCount >= requiredEventCount)) {
+        if (delta.x() > absHorizontalThreshold) {
+            if (++swipeGestureCount >= swipeGestureTouchPoints) {
+                result = true;
+                emit flickLeft();
+            }
+        } else if (delta.x() < -absHorizontalThreshold) {
+            if (++swipeGestureCount >= swipeGestureTouchPoints) {
+                result = true;
+                emit flickRight();
             }
-            emit flickUp(binding);
         }
     }
 
-    if (res) {
-        popup->hidePopup();
-        flicked = true;
+    return result;
+}
+
+bool KeyButtonArea::isVerticalSwipeGesture(const QPointF &delta, int absHorizontalThreshold,
+                                           int absVerticalThreshold, int moveEventCount,
+                                           const IKeyButton* button)
+{
+    const int requiredEventCount = qMax(2, static_cast<int>(absVerticalThreshold *
+                                                            PixelsToMoveEventsFactor));
+    bool result = false;
+
+    if ((qAbs(delta.x()) < absHorizontalThreshold) &&
+        (moveEventCount >= requiredEventCount)) {
+        if (delta.y() < -absVerticalThreshold) {
+            if (++swipeGestureCount >= swipeGestureTouchPoints) {
+                result = true;
+                emit flickDown();
+            }
+        } else if (delta.y() > absVerticalThreshold) {
+            if (++swipeGestureCount >= swipeGestureTouchPoints) {
+                // TODO: Replace flickUp gesture will be replaced by longpress anyway.
+                if (button) {
+                    result = true;
+                    emit flickUp(button->binding());
+                }
+            }
+        }
     }
-    return res;
+
+    return result;
 }
 
+
 const MVirtualKeyboardStyleContainer &KeyButtonArea::style() const
 {
     return *styleContainer;
@@ -607,3 +728,37 @@
 {
     // Empty default implementation
 }
+
+void KeyButtonArea::onThemeChangeCompleted()
+{
+    updateButtonGeometriesForWidth(size().width());
+}
+
+void KeyButtonArea::updateButtonGeometriesForWidth(int widthOfArea)
+{
+    // All main keyboards should take the whole available width so we restrict
+    // the button width here. This is applied only if we have equal button width.
+    int equalButtonWidth = -1; // the new width if it's same for all
+    if ((buttonSizeScheme == ButtonSizeEqualExpanding)
+         || (buttonSizeScheme == ButtonSizeEqualExpandingPhoneNumber)) {
+        const int HorizontalSpacing = style()->spacingHorizontal();
+        const int MaxButtonWidth = qRound(static_cast<qreal>(widthOfArea + HorizontalSpacing)
+                                          / static_cast<qreal>(section->maxColumns())
+                                          - HorizontalSpacing);
+
+        equalButtonWidth = MaxButtonWidth;
+    }
+    updateButtonGeometries(widthOfArea, equalButtonWidth);
+}
+
+KeyButtonArea::TouchPointInfo::TouchPointInfo()
+    : fingerInsideArea(false),
+      activeKey(0),
+      initialKey(0),
+      initialPos(),
+      pos(),
+      gestureTimer(),
+      moveEventCount(0)
+{
+    gestureTimer.start();
+}
--- m-keyboard/widgets/keybuttonarea.h
+++ m-keyboard/widgets/keybuttonarea.h
@@ -29,6 +29,8 @@
 #include <QHash>
 #include <QList>
 #include <QStringList>
+#include <QTouchEvent>
+#include <QTime>
 
 class MFeedbackPlayer;
 class MReactionMap;
@@ -73,7 +75,7 @@
     * \param usePopup Sets whether popup should be used when long press occurs.
     * \param parent The widget's parent.
     */
-    KeyButtonArea(MVirtualKeyboardStyleContainer *,
+    KeyButtonArea(const MVirtualKeyboardStyleContainer *,
                   QSharedPointer<const LayoutSection> section,
                   ButtonSizeScheme buttonSizeScheme = ButtonSizeEqualExpanding,
                   bool usePopup = false,
@@ -104,11 +106,19 @@
     //! Allows sym indicator to be controlled from outside.
     virtual ISymIndicator *symIndicator();
 
+    //! Returns current level of this layout.
+    int level() const;
+
+    //! Set input method mode for all KeyButtonArea instances
+    static void setInputMethodMode(M::InputMethodMode inputMethodMode);
+
 public slots:
     /*!
      * This slot is used to switch levels
      */
-    void switchLevel(int level, bool capslock);
+    void switchLevel(int level);
+
+    virtual void setShiftStatus(bool shiftOn, bool capslock);
 
     /*!
      * \brief Shows popup
@@ -120,11 +130,6 @@
     */
     void accurateStart();
 
-    /*!
-    * \brief Return true if the keyboard is flicked to left/right/down
-    */
-    bool flickCheck();
-
     virtual void drawReactiveAreas(MReactionMap *reactionMap, QGraphicsView *view);
 
     /*!
@@ -144,24 +149,30 @@
      * \brief Emitted when key is pressed
      * Note that this happens also when user keeps finger down/mouse
      * button pressed and moves over another key (event is about the new key)
-     * \param event key event
+     * \param key describes pressed button
+     * \param accent label of pressed dead key if any
+     * \param upperCase contains true if key is in uppercase state
      */
-    void keyPressed(const KeyEvent &event);
+    void keyPressed(const IKeyButton *key, const QString &accent, bool upperCase);
 
     /*!
      * \brief Emitted when key is released
      * Note that this happens also when user keeps finger down/mouse
      * button pressed and moves over another key (event is about the old key)
-     * \param event key event
+     * \param key describes released button
+     * \param accent label of pressed dead key if any
+     * \param upperCase contains true if key is in uppercase state
      */
-    void keyReleased(const KeyEvent &event);
+    void keyReleased(const IKeyButton *key, const QString &accent, bool upperCase);
 
     /*!
      * \brief Emitted when user releases mouse button/lifts finger
      * Except when done on a dead key
-     * \param event key event
+     * \param key describes clicked button
+     * \param accent label of pressed dead key if any
+     * \param upperCase contains true if key is in uppercase state
      */
-    void keyClicked(const KeyEvent &event);
+    void keyClicked(const IKeyButton *key, const QString &accent, bool upperCase);
 
     //! Emitted when flicked right
     void flickRight();
@@ -176,9 +187,36 @@
      * \brief Emitted when flicked up
      * \param binding Information about the key where mouse button was pressed
      */
-    void flickUp(const KeyBinding *binding);
+    void flickUp(const KeyBinding &binding);
 
 protected:
+    //! Stores touch point specific information.
+    struct TouchPointInfo {
+        TouchPointInfo();
+
+        //! True if finger is held down and is inside the layout's area.
+        bool fingerInsideArea;
+
+        //! Currently held down key
+        IKeyButton *activeKey;
+
+        //! Key that this touch point was first pressed on, if any.
+        const IKeyButton *initialKey;
+
+        //! Initial position of the touch point when it was first pressed.
+        QPoint initialPos;
+
+        //! Last known position of the touch point
+        QPoint pos;
+
+        //! Used to check whether gesture recognition happens within the
+        //! specified time frame.
+        QTime gestureTimer;
+
+        //! Counts move events between press & release
+        int moveEventCount;
+    };
+
     //! \brief Returns data and size information of a button in given \a row and \a column.
     void buttonInformation(int row, int column,
                            const VKBDataKey *&dataKey,
@@ -193,6 +231,7 @@
     virtual QVariant itemChange(GraphicsItemChange, const QVariant &);
     virtual void grabMouseEvent(QEvent *e);
     virtual void ungrabMouseEvent(QEvent *e);
+    virtual bool sceneEvent(QEvent *event);
     /*! \reimp_end */
 
     //! Called when widget is about to lose visibility.
@@ -203,12 +242,6 @@
     void updatePopup(const QPoint &pos, const IKeyButton *key = 0);
 
     /*!
-     * \brief click at deadKey
-     * \param key pointer to deadkey
-     */
-    void clickAtDeadkey(const IKeyButton *key);
-
-    /*!
     * \brief Verifies should we process cursor movement or not
     * \param pos QPointF new cursor position
     * \return bool
@@ -216,6 +249,14 @@
     bool isObservableMove(const QPointF &prevPos, const QPointF &pos);
 
     /*!
+    * \brief Return true if the keyboard is swiped to the left/right/down/up
+    *
+    * Once a gesture is recognized it will return false unless the next
+    * touchpoint is pressed. This is supposed to prevent conflicting gestures.
+    */
+    bool isSwipeGesture(const TouchPointInfo &tpi);
+
+    /*!
     * \brief Get level count of the virtual keyboard.
     * \return int. The level count.
     */
@@ -253,18 +294,45 @@
     const PopupBase &popupWidget() const;
 
     //! Sets button state and sends release & press events.
-    void setActiveKey(IKeyButton *key);
+    void setActiveKey(IKeyButton *key, TouchPointInfo &tpi);
 
-    //! Derived classes must set this if they have shift button and want it be locked.
-    IKeyButton *shiftButton;
+    void clearActiveKeys();
 
-private:
-    //! Turn key button into a KeyEvent, considering current dead key and modifier state
-    KeyEvent keyToKeyEvent(const IKeyButton &key, QKeyEvent::Type eventType) const;
+protected slots:
+    //! Update background images, text layouts, etc. when the theme changed.
+    virtual void onThemeChangeCompleted();
 
+private:
     //! Check whether given character will stop accurate mode.
     void accurateCheckContent(const QString &content);
 
+    //! \brief Touch point press handler.
+    //! \param id Touch point identifier defined by the system.
+    void touchPointPressed(const QPoint &pos, int id);
+
+    //! \brief Touch point move handler.
+    //! \param id Touch point identifier defined by the system.
+    void touchPointMoved(const QPoint &pos, int id);
+
+    //! \brief Touch point release handler.
+    //! \param id Touch point identifier defined by the system.
+    void touchPointReleased(const QPoint &pos, int id);
+
+    void click(IKeyButton *key);
+
+    //! \brief Horizontal swipe gesture recognizer
+    //! \return Whether a horizontal swipe gesture was recognized
+    bool isHorizontalSwipeGesture(const QPointF &delta, int absHorizontalThreshold, int absVerticalThreshold,
+                                  int moveEventCount);
+
+    //! \brief Vertical swipe gesture recognizer
+    //! \return Whether a vertical swipe gesture was recognized
+    bool isVerticalSwipeGesture(const QPointF &delta, int absHorizontalThreshold, int absVerticalThreshold,
+                                int moveEventCount, const IKeyButton* button);
+
+    //! \brief Computes the new button width and updates their geometries
+    void updateButtonGeometriesForWidth(int widthOfArea);
+
     //! Current level
     int currentLevel;
 
@@ -272,19 +340,10 @@
     PopupBase *popup;
 
     //! style
-    MVirtualKeyboardStyleContainer *styleContainer;
+    const MVirtualKeyboardStyleContainer *styleContainer;
 
-    //! Flicktimer
-    LimitedTimer *flickTimer;
-
-    //! Floating point flickStart position
-    QPointF flickStartPos;
-
-    //! Current pointer position
-    QPoint pointerPos;
-
-    //! True if finger is held down and is inside the layout's area.
-    bool fingerInsideArea;
+    //! Touch point id of the most recent press event.
+    int newestTouchPointId;
 
     //! Timer to detect long mouse press.
     LimitedTimer *longPressTimer;
@@ -298,17 +357,16 @@
     //! List of accent labels
     QList<QStringList> accentLabels;
 
-    //! Contains true if keyboard was flicked after last mouse press
-    bool flicked;
+    //! Whether a gesture was already triggered for any active touch point.
+    bool wasGestureTriggered;
 
-    //! Activated dead key
-    const IKeyButton *activeDeadkey;
+    //! Keys are QTouchEvent::TouchPoint id
+    QMap<int, TouchPointInfo> touchPoints;
 
-    //! Currently held down key
-    IKeyButton *activeKey;
+    bool enableMultiTouch;
 
-    //! Key that was pressed when flick gesture began.
-    const IKeyButton *flickedKey;
+    //! Activated dead key
+    IKeyButton *activeDeadkey;
 
     /*!
      * Feedback player instance
@@ -322,6 +380,14 @@
 
     const bool usePopup;
 
+    //! How many separate swipe gestures (one for each touchpoint) have been recognized.
+    int swipeGestureCount;
+
+    //! Controls the amount of touchpoints required by a gesture.
+    static int swipeGestureTouchPoints;
+
+    static M::InputMethodMode InputMethodMode;
+
 #ifdef UNIT_TEST
     friend class MReactionMapTester;
     friend class Ut_KeyButtonArea;
@@ -336,9 +402,9 @@
 class ISymIndicator
 {
 public:
-	virtual void activateSymIndicator() = 0;
-	virtual void activateAceIndicator() = 0;
-	virtual void deactivateIndicator() = 0;
+    virtual void activateSymIndicator() = 0;
+    virtual void activateAceIndicator() = 0;
+    virtual void deactivateIndicator()  = 0;
 };
 
 #endif
--- m-keyboard/widgets/layoutmenu.cpp
+++ m-keyboard/widgets/layoutmenu.cpp
-/* * This file is part of meego-keyboard *
- *
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
- * All rights reserved.
- * Contact: Nokia Corporation (directui at nokia.com)
- *
- * If you have questions regarding the use of this file, please contact
- * Nokia at directui at nokia.com.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * and appearing in the file LICENSE.LGPL included in the packaging
- * of this file.
- */
-
-
-
-#include "layoutmenu.h"
-#include "mvirtualkeyboardstyle.h"
-
-#include <MButtonGroup>
-
-#ifndef NOCONTROLPANEL
-#include <MControlPanelIf>
-#endif
-
-#include <MButton>
-#include <MDialog>
-#include <MGridLayoutPolicy>
-#include <MLabel>
-#include <MLayout>
-#include <MLinearLayoutPolicy>
-#include <MLocale>
-#include <MPopupList>
-#include <MSceneManager>
-#include <MTheme>
-#include <MNamespace>
-#include <MWidget>
-#include <mreactionmap.h>
-#include <mplainwindow.h>
-
-#include <QDebug>
-#include <QGraphicsItemAnimation>
-#include <QGraphicsLinearLayout>
-#include <QGraphicsSceneMouseEvent>
-#include <QPainter>
-#include <QStringListModel>
-
-namespace
-{
-    //! spacing for language menue items
-    const int Spacing = 10;
-
-    //! Control panel language page name
-    const QString CpLanguagePage("Language");
-};
-
-// FIXME: when menu is shown and a click is made outside it (that is, on the keyboard)
-// the menu disappears and bottom button isn't shown
-
-// FIXME: parent
-
-LayoutMenu::LayoutMenu(MVirtualKeyboardStyleContainer *style,
-                       QGraphicsWidget */* parent */)
-    : styleContainer(style),
-      active(false),
-      savedActive(false),
-      centralWidget(0),
-      titleLabel(0),
-      errorCorrectionLabel(0),
-      errorCorrectionButton(0),
-      layoutListLabel(0),
-      layoutListHeader(0),
-      layoutList(0),
-      languageSettingLabel(0),
-      languageSettingButton(0),
-      keyboardOptionDialog(0),
-      menuWidget(0),
-      mainLayout(0),
-      correctionAndLanguageLandscapeLayout(0)
-{
-    setObjectName("LayoutMenu");
-    getStyleValues();
-
-    loadLanguageMenu();
-}
-
-
-void LayoutMenu::loadLanguageMenu()
-{
-    //create dialog and widgets
-    centralWidget = new MWidget;
-    centralWidget->setGeometry(0, 0, baseSize.width(), baseSize.height() + buttonSize.height());
-
-    //% "Keyboard options"
-    keyboardOptionDialog = new MDialog(qtTrId("qtn_vkb_keyboard_options"), M::NoButton);
-    keyboardOptionDialog->setCentralWidget(centralWidget);
-    // Note: current (pre 0.20) libmeegotouch doesn't have dialog hidden on construction.
-    // do that explicitly here so the signals are emitted correctly
-    keyboardOptionDialog->hide();
-
-    connect(keyboardOptionDialog, SIGNAL(visibleChanged()), SLOT(visibleChangeHandler()));
-
-    /* Create widgets and put then into the layout policy */
-
-    //% "Error correction"
-    errorCorrectionLabel = new MLabel(qtTrId("qtn_vkb_error_correction"),
-                                        centralWidget);
-    errorCorrectionLabel->setAlignment(Qt::AlignCenter);
-    errorCorrectionLabel->setWordWrap(true);
-
-    //% "On"
-    errorCorrectionButton = new MButton(qtTrId("qtn_comm_on"), centralWidget);
-    errorCorrectionButton->setObjectName("MenuToggleButton");
-    errorCorrectionButton->setCheckable(true);
-    errorCorrectionButton->setChecked(true);
-    errorCorrectionButton->setMaximumWidth(baseSize.width() / 2);
-    connect(errorCorrectionButton, SIGNAL(clicked()), this, SLOT(synchronizeErrorCorrection()));
-
-    //% "Input language"
-    layoutListLabel = new MLabel(qtTrId("qtn_vkb_input_language"), centralWidget);
-    layoutListLabel->setAlignment(Qt::AlignCenter);
-
-    layoutListHeader = new MButton(centralWidget);
-    layoutListHeader->setMaximumWidth(baseSize.width() / 2);
-
-    layoutList = new MPopupList();
-    layoutList->setItemModel(new QStringListModel());
-
-    connect(layoutListHeader, SIGNAL(clicked()), this, SLOT(showLanguageList()));
-
-    //% "To modify the input languages, go to"
-    languageSettingLabel = new MLabel(qtTrId("qtn_vkb_language_setting_label"), centralWidget);
-    languageSettingLabel->setAlignment(Qt::AlignHCenter);
-
-    //TODO: connect languageSettingButton with language setting
-    //% "Language settings"
-    languageSettingButton = new MButton(qtTrId("qtn_vkb_language_setting"), centralWidget);
-    languageSettingButton->setMaximumWidth(baseSize.width() / 2);
-    connect(languageSettingButton, SIGNAL(clicked()), this, SLOT(openLanguageApplet()));
-
-    //create layout
-    QGraphicsLinearLayout *correctionLayout = new QGraphicsLinearLayout(Qt::Vertical);
-    correctionLayout->setSpacing(Spacing);
-    correctionLayout->addItem(errorCorrectionLabel);
-    correctionLayout->addItem(errorCorrectionButton);
-    correctionLayout->setAlignment(errorCorrectionLabel, Qt::AlignCenter);
-    correctionLayout->setAlignment(errorCorrectionButton, Qt::AlignCenter);
-
-    QGraphicsLinearLayout *languageLayout = new QGraphicsLinearLayout(Qt::Vertical);
-    languageLayout->setSpacing(Spacing);
-    languageLayout->addItem(layoutListLabel);
-    languageLayout->addItem(layoutListHeader);
-    languageLayout->setAlignment(layoutListLabel, Qt::AlignCenter);
-    languageLayout->setAlignment(layoutListHeader, Qt::AlignCenter);
-
-    correctionAndLanguageLandscapeLayout = new  QGraphicsLinearLayout(Qt::Horizontal);
-    correctionAndLanguageLandscapeLayout->setSpacing(Spacing);
-    correctionAndLanguageLandscapeLayout->addItem(correctionLayout);
-    correctionAndLanguageLandscapeLayout->addItem(languageLayout);
-
-    QGraphicsLinearLayout *languageSettingLayout = new  QGraphicsLinearLayout(Qt::Vertical);
-    languageSettingLayout->setSpacing(Spacing);
-    languageSettingLayout->addItem(languageSettingLabel);
-    languageSettingLayout->addItem(languageSettingButton);
-    languageSettingLayout->setAlignment(languageSettingLabel, Qt::AlignCenter);
-    languageSettingLayout->setAlignment(languageSettingButton, Qt::AlignCenter);
-
-    mainLayout = new MLayout;
-
-    //for landscape
-    MLinearLayoutPolicy *landscapePolicy = new MLinearLayoutPolicy(mainLayout, Qt::Vertical);
-    landscapePolicy->setSpacing(2 * Spacing);
-    landscapePolicy->addItem(correctionAndLanguageLandscapeLayout);
-    landscapePolicy->addItem(languageSettingLayout);
-
-    //for portrait
-    MLinearLayoutPolicy *portraitPolicy = new MLinearLayoutPolicy(mainLayout, Qt::Vertical);
-    portraitPolicy->setSpacing(2 * Spacing);
-    portraitPolicy->addItem(correctionLayout);
-    portraitPolicy->addItem(languageLayout);
-    portraitPolicy->addItem(languageSettingLayout);
-
-    centralWidget->setLayout(mainLayout);
-    mainLayout->setLandscapePolicy(landscapePolicy);
-    mainLayout->setPortraitPolicy(portraitPolicy);
-
-    // layoutList seems to be initially visible before calling appear()
-    layoutList->hide();
-}
-
-
-LayoutMenu::~LayoutMenu()
-{
-    //clear correctionAndLanguageLandscapeLayout manually
-    for (int i = 0; i < correctionAndLanguageLandscapeLayout->count(); i++)
-        correctionAndLanguageLandscapeLayout->removeAt(i);
-    //mainlayout will delete correctionAndLanguageLandscapeLayout within removeItem
-    mainLayout->removeItem(correctionAndLanguageLandscapeLayout);
-
-    // MPopupList does not take ownership of its model
-    if (layoutList->itemModel()) {
-        QAbstractItemModel *model = layoutList->itemModel();
-        layoutList->setItemModel(0);
-        delete model;
-    }
-
-    delete languageSettingLabel;
-    delete languageSettingButton;
-    delete titleLabel;
-    delete errorCorrectionLabel;
-    delete errorCorrectionButton;
-    delete menuWidget;
-    delete layoutListLabel;
-    delete layoutListHeader;
-    delete layoutList;
-
-    // MDialog's view will destroy centralWidget
-    delete keyboardOptionDialog;
-}
-
-
-void LayoutMenu::setLanguageList(const QStringList &titles, int selected)
-{
-    QStringListModel *model = qobject_cast<QStringListModel *>(layoutList->itemModel());
-
-    model->setStringList(titles);
-    QModelIndex index = model->index(selected);
-    layoutList->setCurrentIndex(index);
-    layoutListHeader->setText(index.data().toString());
-}
-
-
-void
-LayoutMenu::show()
-{
-    if (!active) {
-        active = true;
-        QSize visibleSceneSize = MPlainWindow::instance()->visibleSceneSize();
-        centralWidget->setPos(0, visibleSceneSize.height() - baseSize.height());
-
-        MPlainWindow::instance()->sceneManager()->execDialog(keyboardOptionDialog);
-    }
-}
-
-void LayoutMenu::visibleChangeHandler()
-{
-    QGraphicsObject *dialog = qobject_cast<QGraphicsObject *>(sender());
-    Q_ASSERT(dialog);
-    bool visibility = dialog->isVisible();
-
-    if (!visibility) {
-        active = false;
-        emit hidden();
-        emit regionUpdated(QRegion());
-    } else {
-        const QSize visibleSceneSize = MPlainWindow::instance()->visibleSceneSize();
-        emit regionUpdated(QRegion(0, 0, visibleSceneSize.width(), visibleSceneSize.height()));
-    }
-}
-
-bool
-LayoutMenu::isActive() const
-{
-    return active;
-}
-
-
-void LayoutMenu::save()
-{
-    savedActive = active;
-}
-
-
-void LayoutMenu::restore()
-{
-    if (savedActive) {
-        savedActive = false;
-        show();
-    }
-}
-
-
-void
-LayoutMenu::getStyleValues()
-{
-    baseSize = style()->menuSize();
-    buttonSize = style()->tabButtonSize();
-}
-
-
-void LayoutMenu::organizeContent(M::Orientation /* orientation */)
-{
-    getStyleValues();
-    keyboardOptionDialog->reject();
-}
-
-
-void LayoutMenu::enableErrorCorrection()
-{
-    if (!errorCorrectionButton->isChecked()) {
-        errorCorrectionButton->click();
-    }
-}
-
-
-void LayoutMenu::disableErrorCorrection()
-{
-    if (errorCorrectionButton->isChecked()) {
-        errorCorrectionButton->click();
-    }
-}
-
-
-void LayoutMenu::redrawReactionMaps()
-{
-    if (!keyboardOptionDialog || !keyboardOptionDialog->scene())
-        return;
-
-    foreach (QGraphicsView *view, keyboardOptionDialog->scene()->views()) {
-        MReactionMap *reactionMap = MReactionMap::instance(view);
-        if (!reactionMap)
-            continue;
-
-        // Clear all with inactive color.
-        reactionMap->setInactiveDrawingValue();
-        reactionMap->setTransform(QTransform());
-        reactionMap->fillRectangle(0, 0, reactionMap->width(), reactionMap->height());
-
-        // We have no active areas, buttons take care of feedback playing.
-    }
-}
-
-
-MVirtualKeyboardStyleContainer &LayoutMenu::style()
-{
-    return *styleContainer;
-}
-
-
-void LayoutMenu::showLanguageList()
-{
-    if (layoutList && layoutListHeader) {
-        MPlainWindow::instance()->sceneManager()->execDialog(layoutList);
-        QModelIndex index = layoutList->currentIndex();
-        layoutListHeader->setText(index.data(Qt::DisplayRole).toString());
-        emit languageSelected(index.row()); // QStringListModel has only rows.
-    }
-}
-
-
-void LayoutMenu::synchronizeErrorCorrection()
-{
-    if (errorCorrectionButton->isChecked()) {
-        emit errorCorrectionToggled(true);
-        //% "On"
-        errorCorrectionButton->setText(qtTrId("qtn_comm_on"));
-    } else {
-        emit errorCorrectionToggled(false);
-        //% "Off"
-        errorCorrectionButton->setText(qtTrId("qtn_comm_off"));
-    }
-}
-
-void LayoutMenu::openLanguageApplet()
-{
-#ifndef NOCONTROLPANEL
-    MControlPanelIf *dcpIf = new MControlPanelIf();
-    if (dcpIf->isValid()) {
-        dcpIf->appletPage(CpLanguagePage);
-    }
-    delete dcpIf;
-    dcpIf = NULL;
-#endif
-}
--- m-keyboard/widgets/layoutmenu.h
+++ m-keyboard/widgets/layoutmenu.h
-/* * This file is part of meego-keyboard *
- *
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
- * All rights reserved.
- * Contact: Nokia Corporation (directui at nokia.com)
- *
- * If you have questions regarding the use of this file, please contact
- * Nokia at directui at nokia.com.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * and appearing in the file LICENSE.LGPL included in the packaging
- * of this file.
- */
-
-
-
-#ifndef LAYOUTMENU_H
-#define LAYOUTMENU_H
-
-#include <QObject>
-#include <MNamespace>
-
-class QGraphicsLinearLayout;
-class QGraphicsWidget;
-class MLayout;
-class MLabel;
-class MButton;
-class MButtonGroup;
-class MPopupList;
-class MVirtualKeyboardStyleContainer;
-class MDialog;
-class MWidget;
-
-
-/*!
- * \brief Virtual keyboard configuration dialog
- */
-class LayoutMenu : public QObject
-{
-    Q_OBJECT
-    friend class Ut_MKeyboardHost;
-
-public:
-    /*!
-     * \brief Constructor
-     * \param style style container
-     * \param parent parent widget -- currently unused
-     */
-    LayoutMenu(MVirtualKeyboardStyleContainer *style, QGraphicsWidget *parent = 0);
-
-    /*!
-     * Destructor
-     */
-    ~LayoutMenu();
-
-    //! Sets the list of available languages. These should
-    //! be descriptive titles, not language codes.
-    void setLanguageList(const QStringList &titles, int selected);
-
-    //!  organize content when orientation is changed
-    void organizeContent(M::Orientation orientation);
-
-    //! Save state before rotation
-    void save();
-
-    //! Restore state after rotation
-    void restore();
-
-    /*!
-     * enable/disable error correction
-     */
-    void enableErrorCorrection();
-    void disableErrorCorrection();
-
-    //! Whether layout menu is displayed
-    bool isActive() const;
-
-public slots:
-    /*!
-     * \brief Open the dialog if not open already.
-     *
-     * Returns only when user dismisses the dialog.
-     */
-    void show();
-
-    /*!
-     * Draw the reactive areas of this dialog
-     */
-    void redrawReactionMaps();
-
-
-signals:
-    //! Emitted when turn on/off error correction
-    void errorCorrectionToggled(bool on);
-
-    //! Emitted when layoutmenu is hidden
-    void hidden();
-
-    //! Emitted when interactive region of the menu has changed
-    void regionUpdated(const QRegion &);
-
-    //! Signals that user has selected a language. Index refers to
-    //! a language in language list the menu was given.
-    void languageSelected(int index);
-
-private slots:
-    void synchronizeErrorCorrection();
-
-    void showLanguageList();
-
-    //! Opens language settings page in mcontrolpanel.
-    void openLanguageApplet();
-
-    void visibleChangeHandler();
-
-private:
-    /*!
-     * Method to Show animation
-     */
-
-    void setupShowAndHide();
-    void getStyleValues();
-
-    /*!
-     * load language menu
-     */
-    void loadLanguageMenu();
-
-    //! Getter for style container
-    MVirtualKeyboardStyleContainer &style();
-
-    //! Style attributes
-    MVirtualKeyboardStyleContainer *styleContainer;
-
-    QSize buttonSize;
-
-    //! To check if menu is active
-    bool active;
-
-    //! to check if menu is active after rotation
-    bool savedActive;
-
-    //! baseSize
-    QSize baseSize;
-
-    //! Menu item
-    MWidget *centralWidget;
-    MLabel *titleLabel;
-    MLabel *errorCorrectionLabel;
-    MButton *errorCorrectionButton;
-    MButtonGroup *errorCorectionButtonGroup;
-    MLabel *layoutListLabel;
-    MButton *layoutListHeader;
-    MPopupList *layoutList;
-    MLabel *languageSettingLabel;
-    MButton *languageSettingButton;
-
-    MDialog *keyboardOptionDialog;
-    MWidget *menuWidget;
-    MLayout *mainLayout;
-    QGraphicsLinearLayout *correctionAndLanguageLandscapeLayout;
-};
-
-#endif
--- m-keyboard/widgets/mbuttonarea.cpp
+++ m-keyboard/widgets/mbuttonarea.cpp
@@ -56,7 +56,7 @@
 MButtonArea::~MButtonArea()
 {
     // Release any key that might be pressed before destroying them.
-    setActiveKey(0);
+    clearActiveKeys();
 
     setLayout(0);
     qDeleteAll(buttons);
@@ -130,10 +130,6 @@
 
             FlickUpButton *button = new FlickUpButton(*dataKey);
 
-            if (dataKey->binding()->action() == KeyBinding::ActionShift) {
-                shiftButton = button;
-            }
-
             if (stretchesHorizontally) {
                 button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
             } else {
--- m-keyboard/widgets/mimcorrectioncandidatewidget.cpp
+++ m-keyboard/widgets/mimcorrectioncandidatewidget.cpp
@@ -21,7 +21,6 @@
 #include <QGraphicsSceneMouseEvent>
 #include <QDebug>
 #include <QString>
-#include <QFontMetrics>
 
 #include <MSceneManager>
 #include <mreactionmap.h>
@@ -50,20 +49,13 @@
     /*! \reimp */
     virtual MWidget *createCell(const QModelIndex &index, MWidgetRecycler &recycler) const;
     virtual void updateCell(const QModelIndex &index, MWidget *cell) const;
-    virtual QSizeF cellSize() const;
     /*! \reimp_end */
 private:
     void updateContentItemMode(const QModelIndex &index, MContentItem *contentItem) const;
-
-    QSizeF size;
 };
 
 MImCorrectionContentItemCreator::MImCorrectionContentItemCreator()
 {
-    // Initializes size
-    MContentItem cell(MContentItem::SingleTextLabel);
-    cell.setObjectName(CandidatesItemObjectName);
-    size = cell.effectiveSizeHint(Qt::PreferredSize);
 }
 
 MWidget *MImCorrectionContentItemCreator::createCell(const QModelIndex &index, MWidgetRecycler &recycler) const
@@ -91,11 +83,6 @@
     updateContentItemMode(index, contentItem);
 }
 
-QSizeF MImCorrectionContentItemCreator::cellSize() const
-{
-    return size;
-}
-
 void MImCorrectionContentItemCreator::updateContentItemMode(const QModelIndex &index,
         MContentItem *contentItem) const
 {
@@ -114,7 +101,6 @@
     : MWidget(parent),
       rotationInProgress(false),
       candidatePosition(0, 0),
-      fontMetrics(0),
       sceneManager(MPlainWindow::instance()->sceneManager()),
       containerWidget(new MWidget(this)),
       candidatesWidget(new MList(containerWidget)),
@@ -137,19 +123,11 @@
     candidatesWidget->setCellCreator(cellCreator);
     candidatesWidget->setItemModel(candidatesModel);
     connect(candidatesWidget, SIGNAL(itemClicked(const QModelIndex &)), this, SLOT(select(const QModelIndex &)));
-
-    //TODO: This is a hack way to get font information from MList.
-    //Could be refined later if MList provides other better way.
-    MLabel label;
-    label.setObjectName(CandidatesItemLabelObjectName);
-    fontMetrics  = new QFontMetrics(label.font());
 }
 
 
 MImCorrectionCandidateWidget::~MImCorrectionCandidateWidget()
 {
-    delete fontMetrics;
-    fontMetrics = 0;
     delete candidatesModel;
 }
 
@@ -173,10 +151,16 @@
     // Calculate the width for MContentItem dynamically.
     // To ensure the whole words in candidate list could be shown.
     candidateWidth = 0;
+    MLabel label;
+    label.setObjectName(CandidatesItemLabelObjectName);
     foreach (const QString &candidate, filteredCandidateList) {
-        candidateWidth = qMax(candidateWidth, fontMetrics->width(candidate));
+        label.setText(candidate);
+        candidateWidth = qMax(candidateWidth, label.preferredSize().width());
     }
-    candidateWidth += candidatesWidget->preferredWidth();
+
+    qreal left, top, right, bottom;
+    label.getContentsMargins(&left, &top, &right, &bottom);
+    candidateWidth += left + right;
 }
 
 void MImCorrectionCandidateWidget::setPreeditString(const QString &string)
--- m-keyboard/widgets/mimcorrectioncandidatewidget.h
+++ m-keyboard/widgets/mimcorrectioncandidatewidget.h
@@ -26,7 +26,6 @@
 class MList;
 class MImCorrectionContentItemCreator;
 class QStringListModel;
-class QFontMetrics;
 
 /*!
   \class MImCorrectionCandidateWidget
@@ -135,13 +134,12 @@
     bool rotationInProgress;
     QString m_preeditString;
     QPoint candidatePosition;
-    QFontMetrics *fontMetrics;
     MSceneManager *sceneManager;
     MWidget *containerWidget;
     MList *candidatesWidget;
     MImCorrectionContentItemCreator *cellCreator;
     QStringListModel *candidatesModel;
-    int candidateWidth;
+    qreal candidateWidth;
 
     Q_DISABLE_COPY(MImCorrectionCandidateWidget)
 };
--- m-keyboard/widgets/mimtoolbar.cpp
+++ m-keyboard/widgets/mimtoolbar.cpp
@@ -17,12 +17,14 @@
 
 
 #include "mimtoolbar.h"
-#include "toolbardata.h"
-#include "toolbarmanager.h"
-#include "toolbarwidget.h"
 #include "layoutsmanager.h"
 #include "mhardwarekeyboard.h"
 #include "mvirtualkeyboardstyle.h"
+#include "mtoolbarbutton.h"
+#include "mtoolbarlabel.h"
+
+#include <mtoolbardata.h>
+#include <mtoolbaritem.h>
 
 #include <MNamespace>
 #include <MButton>
@@ -37,19 +39,17 @@
 namespace
 {
     //!object name for toolbar buttons
-    const QString ObjectNameToolbarButtons("VirtualKeyboardToolbarButton");
-    const QString ObjectNameCloseButton("VirtualKeyboardCloseButton");
     const QString ObjectNameToolbar("MImToolbar");
     const QString ObjectNameToolbarLeft("VirtualKeyboardToolbarLeft");
     const QString ObjectNameToolbarRight("VirtualKeyboardToolbarRight");
-    const QString IconNameCloseButton("icon-m-input-methods-close");
+    const QString NameToolbarCopyPasteButton("VirtualKeyboardCopyPasteButton");
 };
 
-MImToolbar::MImToolbar(MVirtualKeyboardStyleContainer &style, QGraphicsWidget *parent)
+MImToolbar::MImToolbar(const MVirtualKeyboardStyleContainer &style, QGraphicsWidget *parent)
     : MWidget(parent),
-      toolbarMgr(ToolbarManager::instance()),
       textSelected(false),
-      copyPaste(new MButton),
+      copyPasteItem(new MToolbarItem(NameToolbarCopyPasteButton, MInputMethod::ItemButton)),
+      copyPaste(new MToolbarButton(copyPasteItem, this)),
       copyPasteStatus(InputMethodNoCopyPaste),
       leftBar(true, this),
       rightBar(true, this),
@@ -57,41 +57,30 @@
       shiftState(ModifierClearState),
       fnState(ModifierClearState)
 {
-    // Empty button bars are hidden.
-    leftBar.hide();
-    rightBar.hide();
-
-    setObjectName(ObjectNameToolbar);
     leftBar.setObjectName(ObjectNameToolbarLeft);
     rightBar.setObjectName(ObjectNameToolbarRight);
+    setObjectName(ObjectNameToolbar);
 
     setupLayout();
 
     loadDefaultButtons();
 
     connect(this, SIGNAL(visibleChanged()), this, SLOT(updateVisibility()));
-
-    connect(&toolbarMgr, SIGNAL(buttonClicked(ToolbarWidget)), this, SLOT(handleButtonClick(ToolbarWidget)));
 }
 
 MImToolbar::~MImToolbar()
 {
-    delete copyPaste;
-    copyPaste = 0;
 }
 
 void MImToolbar::setupLayout()
 {
-    QGraphicsLinearLayout *mainLayout = new QGraphicsLinearLayout(Qt::Horizontal, this);
+    QGraphicsLinearLayout *mainLayout = new QGraphicsLinearLayout(Qt::Vertical, this);
     mainLayout->setContentsMargins(0, 0, 0, 0);
 
-    // Add the left and right side WidgetBar widgets with a stretch item in between.
-    mainLayout->addItem(&leftBar);
-    mainLayout->addStretch();
-    mainLayout->addItem(&rightBar);
+    QGraphicsLinearLayout *rowLayout = new QGraphicsLinearLayout(Qt::Horizontal, mainLayout);
 
-    mainLayout->setAlignment(&leftBar, Qt::AlignBottom);
-    mainLayout->setAlignment(&rightBar, Qt::AlignBottom);
+    setupRowLayout(rowLayout, &leftBar, &rightBar);
+    mainLayout->insertItem(0, rowLayout);
 
     resize(geometry().width(), layout()->preferredHeight());
 }
@@ -99,7 +88,6 @@
 void MImToolbar::loadDefaultButtons()
 {
     // Setup copy/paste button.
-    copyPaste->setObjectName(ObjectNameToolbarButtons);
     copyPaste->setVisible(false);
     //% "Copy"
     copyPaste->setText(qtTrId("qtn_comm_copy"));
@@ -116,35 +104,35 @@
     return region;
 }
 
-void MImToolbar::handleButtonClick(const ToolbarWidget &button)
+void MImToolbar::handleButtonClick(MToolbarItem *item)
 {
-    if (button.type() != ToolbarWidget::Button)
+    if (!item || item->type() != MInputMethod::ItemButton)
         return;
 
-    foreach(const ToolbarWidget::Action *action, button.actions) {
-        switch (action->type) {
-        case ToolbarWidget::SendKeySequence:
-            sendKeySequence(action->keys);
+    foreach(QSharedPointer<const MToolbarItemAction> action, item->actions()) {
+        switch (action->type()) {
+        case MInputMethod::ActionSendKeySequence:
+            sendKeySequence(action->keys());
             break;
-        case ToolbarWidget::SendString:
-            sendStringRequest(action->text);
+        case MInputMethod::ActionSendString:
+            sendStringRequest(action->text());
             break;
-        case ToolbarWidget::SendCommand:
+        case MInputMethod::ActionSendCommand:
             //TODO:not support yet
             break;
-        case ToolbarWidget::Copy:
+        case MInputMethod::ActionCopy:
             emit copyPasteRequest(InputMethodCopy);
             break;
-        case ToolbarWidget::Paste:
+        case MInputMethod::ActionPaste:
             emit copyPasteRequest(InputMethodPaste);
             break;
-        case ToolbarWidget::ShowGroup:
-            showGroup(action->group);
+        case MInputMethod::ActionShowGroup:
+            showGroup(action->group());
             break;
-        case ToolbarWidget::HideGroup:
-            hideGroup(action->group);
+        case MInputMethod::ActionHideGroup:
+            hideGroup(action->group());
             break;
-        case ToolbarWidget::Unknown:
+        case MInputMethod::ActionUndefined:
             break;
         }
     }
@@ -161,96 +149,193 @@
 
 void MImToolbar::updateVisibility()
 {
-    qDebug() << __PRETTY_FUNCTION__;
-    //set widget's visibility according showOn and hideOn premiss and current selection status
-    foreach(ToolbarWidget *w, toolbarMgr.widgetList()) {
-        if ((textSelected && w->hideOn != ToolbarWidget::WhenSelectingText)
-                || (w->showOn == ToolbarWidget::Always)) {
-            w->setVisible(true);
-        } else {
-            w->setVisible(false);
+    if (currentToolbar) {
+        foreach (const QSharedPointer<MToolbarItem> item, currentToolbar->allItems())
+        {
+            if ((item->showOn() == MInputMethod::VisibleAlways)
+                    || (textSelected && item->showOn() == MInputMethod::VisibleWhenSelectingText)
+                    || (!textSelected && item->hideOn() == MInputMethod::VisibleWhenSelectingText)) {
+                item->setVisible(true);
+            }
+
+            if ((!textSelected && item->showOn() == MInputMethod::VisibleWhenSelectingText)
+                    || (textSelected && item->hideOn() == MInputMethod::VisibleWhenSelectingText)) {
+                item->setVisible(false);
+            }
         }
     }
-
-    // Update widgets according to toolbar models.
-    updateWidgets();
+    arrangeWidgets();
 }
 
-void MImToolbar::loadCustomWidgets(Qt::Alignment align)
+void MImToolbar::loadCustomWidgets()
 {
-    qDebug() << __PRETTY_FUNCTION__ << align;
-    //the widgets gotten from toolbarMgr are already ordered acording their priority with alignment.
-    QList<ToolbarWidget *> widgets = toolbarMgr.widgetList(align);
-    //show widgets according their status and priority
-    int widgetCount = 0;
-    foreach(ToolbarWidget *toolbarWidget, widgets) {
-        MWidget *widget = toolbarMgr.widget(toolbarWidget->name());
-        if (!widget)
-            continue;
-        if (toolbarWidget->isVisible()) {
-            widget->setVisible(true);
-            //if widget is Visible, then insert it to the right position
-            insertItem(widgetCount, widget, align);
-            ++widgetCount;
-        } else {
-            widget->setVisible(false);
-            removeItem(widget);
+    if (!currentToolbar) {
+        return;
+    }
+
+    const M::Orientation orientation = MPlainWindow::instance()->sceneManager()->orientation();
+    QSharedPointer<const MToolbarLayout> layout = currentToolbar->layout(orientation);
+    QGraphicsLinearLayout *mainLayout = static_cast<QGraphicsLinearLayout*>(this->layout());
+
+    QList<QSharedPointer<const MToolbarRow> > rows = layout->rows();
+
+    //create additional rows if necessary
+    for (int n = 0; n < rows.count() - 1; ++n) {
+        QSharedPointer<const MToolbarRow> row = rows[n];
+        QGraphicsLinearLayout *rowLayout = new QGraphicsLinearLayout(Qt::Horizontal, mainLayout);
+        WidgetBar *leftWidget  = new WidgetBar(true, this);
+        WidgetBar *rightWidget = new WidgetBar(true, this);
+
+        leftWidget->setObjectName(ObjectNameToolbarLeft);
+        rightWidget->setObjectName(ObjectNameToolbarRight);
+        setupRowLayout(rowLayout, leftWidget, rightWidget);
+        mainLayout->insertItem(n, rowLayout);
+
+        foreach (QSharedPointer<MToolbarItem> item , row->items()) {
+            createAndAppendWidget(item, leftWidget, rightWidget);
         }
     }
+
+    //add custom items to bottom row
+    QSharedPointer<const MToolbarRow> row = rows.last();
+    foreach (QSharedPointer<MToolbarItem> item, row->items()) {
+        createAndAppendWidget(item, &leftBar, &rightBar);
+    }
+
+    int buttonIndex = rightBar.indexOf(copyPaste);
+    if (buttonIndex >= 0 && buttonIndex != rightBar.count() - 1) {
+        // copy button position is inccorect now,
+        // so we move it to correcrt place
+        removeItem(copyPaste);
+        insertItem(rightBar.count(), copyPaste, Qt::AlignRight);
+    }
+    mainLayout->invalidate();
 }
 
-void MImToolbar::unloadCustomWidgets(Qt::Alignment align)
+void MImToolbar::createAndAppendWidget(QSharedPointer<MToolbarItem> item,
+                                       WidgetBar *leftWidget,
+                                       WidgetBar *rightWidget)
 {
-    QList<ToolbarWidget *> widgets = toolbarMgr.widgetList(align);
-    foreach(ToolbarWidget *toolbarWidget, widgets) {
-        MWidget *widget = toolbarMgr.widget(toolbarWidget->name());
-        if (!widget)
-            continue;
-        widget->setVisible(false);
-        removeItem(widget);
+    MWidget *widget = 0;
+    WidgetBar *sidebar = 0;
+
+    if (item->alignment() == Qt::AlignLeft) {
+        sidebar = leftWidget;
+    } else {
+        sidebar = rightWidget;
+    }
+    if (item->type() == MInputMethod::ItemButton) {
+        widget = new MToolbarButton(item, sidebar);
+
+        connect(widget, SIGNAL(clicked(MToolbarItem*)),
+                this, SLOT(handleButtonClick(MToolbarItem*)));
+    } else {
+        widget = new MToolbarLabel(item, sidebar);
+    }
+    customWidgets.append(widget);
+    sidebar->append(widget);
+    if (sidebar->count() == 1) {
+        sidebar->show();
     }
 }
 
-void MImToolbar::updateWidgets(bool customWidgetsChanged)
+void MImToolbar::setupRowLayout(QGraphicsLinearLayout *rowLayout,
+                                WidgetBar *leftWidget,
+                                WidgetBar *rightWidget)
+{
+    rowLayout->setContentsMargins(0, 0, 0, 0);
+    rowLayout->setMaximumWidth(MPlainWindow::instance()->visibleSceneSize().width());
+    rowLayout->setPreferredWidth(MPlainWindow::instance()->visibleSceneSize().width());
+
+    // Empty button bars are hidden.
+    leftWidget->hide();
+    rightWidget->hide();
+    // Add the left and right side WidgetBar widgets with a stretch item in between.
+    rowLayout->addItem(leftWidget);
+    rowLayout->addStretch();
+    rowLayout->addItem(rightWidget);
+
+    rowLayout->setAlignment(leftWidget, Qt::AlignBottom);
+    rowLayout->setAlignment(rightWidget, Qt::AlignBottom);
+}
+
+void MImToolbar::unloadCustomWidgets()
 {
-    if (customWidgetsChanged) {
-        loadCustomWidgets(Qt::AlignLeft);
-        loadCustomWidgets(Qt::AlignRight);
+    QGraphicsLinearLayout *mainLayout = static_cast<QGraphicsLinearLayout*>(layout());
+    QList<QGraphicsLinearLayout*> rows;
+
+    //delete all dynamically created rows
+    for (int n = 0; n < mainLayout->count() - 1; ++n) {
+        QGraphicsLinearLayout *rowLayout = dynamic_cast<QGraphicsLinearLayout*>(mainLayout->itemAt(n));
+
+        if (rowLayout) {
+            WidgetBar *leftBar  = dynamic_cast<WidgetBar*>(rowLayout->itemAt(0));
+            WidgetBar *rightBar = dynamic_cast<WidgetBar*>(rowLayout->itemAt(1));
+
+            delete leftBar;
+            delete rightBar;
+            rows << rowLayout;
+        }
     }
 
+    qDeleteAll(rows);
+    qDeleteAll(customWidgets);
+    customWidgets.clear();
+    leftBar.cleanup();
+    rightBar.cleanup();
+}
+
+void MImToolbar::arrangeWidgets()
+{
     if (isVisible()) {
         layout()->invalidate();
+        layout()->activate();
+        resize(geometry().width(), layout()->preferredHeight());
     }
 
     emit regionUpdated();
+    emit availabilityChanged((rightBar.count() != 0) || (leftBar.count() != 0));
 }
 
 void MImToolbar::showGroup(const QString &group)
 {
     bool changed = false;
-    foreach(ToolbarWidget *w, toolbarMgr.widgetList()) {
-        if (w->group == group && !(w->isVisible())) {
-            w->setVisible(true);
+
+    if (!currentToolbar) {
+        return;
+    }
+
+    foreach (const QSharedPointer<MToolbarItem> item, currentToolbar->allItems())
+    {
+        if (item->group() == group && !(item->isVisible())) {
+            item->setVisible(true);
             changed = true;
         }
     }
 
     if (changed) {
-        updateWidgets();
+        arrangeWidgets();
     }
 }
 
 void MImToolbar::hideGroup(const QString &group)
 {
     bool changed = false;
-    foreach(ToolbarWidget *w, toolbarMgr.widgetList()) {
-        if (w->group == group && w->isVisible()) {
-            w->setVisible(false);
+
+    if (!currentToolbar) {
+        return;
+    }
+
+    foreach (const QSharedPointer<MToolbarItem> item, currentToolbar->allItems())
+    {
+        if (item->group() == group && item->isVisible()) {
+            item->setVisible(false);
             changed = true;
         }
     }
+
     if (changed) {
-        updateWidgets(true);
+        arrangeWidgets();
     }
 }
 
@@ -289,26 +374,26 @@
     return modify;
 }
 
-void MImToolbar::showToolbarWidget(qlonglong id)
+void MImToolbar::showToolbarWidget(QSharedPointer<const MToolbarData> toolbar)
 {
-    qDebug() << __PRETTY_FUNCTION__ << id;
-    if (id != toolbarMgr.currentToolbar()) {
-        unloadCustomWidgets(Qt::AlignLeft);
-        unloadCustomWidgets(Qt::AlignRight);
+    if (toolbar == currentToolbar) {
+        return;
     }
-    ToolbarManager::instance().loadToolbar(id);
+
+    unloadCustomWidgets();
+
+    currentToolbar = toolbar;
+    loadCustomWidgets();
+
     if (isVisible())
         updateVisibility();
 }
 
 void MImToolbar::hideToolbarWidget()
 {
-    qDebug() << __PRETTY_FUNCTION__;
-    unloadCustomWidgets(Qt::AlignLeft);
-    unloadCustomWidgets(Qt::AlignRight);
-    ToolbarManager::instance().reset();
-    if (isVisible())
-        updateVisibility();
+    currentToolbar.clear();
+    unloadCustomWidgets();
+    arrangeWidgets();
 }
 
 void MImToolbar::copyPasteButtonHandler()
@@ -366,8 +451,7 @@
         break;
     }
     if (changed) {
-        // Update only positions.
-        updateWidgets(false);
+        arrangeWidgets();
     }
     qDebug() << __PRETTY_FUNCTION__ << copyPaste->isVisible();
 }
@@ -417,15 +501,23 @@
     // Draw all widgets geometries.
     reactionMap->setReactiveDrawingValue();
 
-    for (int j = 0; j < 2; ++j) {
-        WidgetBar *sidebar = ((j == 0) ? &leftBar : &rightBar);
-        if (!sidebar->isVisible()) {
-            continue;
-        }
-        reactionMap->setTransform(sidebar, view);
+    for (int n = 0; n < layout()->count(); ++n) {
+        QGraphicsLinearLayout *row = dynamic_cast<QGraphicsLinearLayout*>(layout()->itemAt(n));
 
-        for (int i = 0; i < sidebar->count(); ++i) {
-            reactionMap->fillRectangle(sidebar->widgetAt(i)->geometry());
+        if (row) {
+            for (int j = 0; j < row->count(); ++j) {
+                WidgetBar *sidebar = dynamic_cast<WidgetBar*>(row->itemAt(j));
+                if (!sidebar || !sidebar->isVisible()) {
+                    continue;
+                }
+                reactionMap->setTransform(sidebar, view);
+
+                for (int i = 0; i < sidebar->count(); ++i) {
+                    if (sidebar->widgetAt(i) && sidebar->widgetAt(i)->isVisible()) {
+                        reactionMap->fillRectangle(sidebar->widgetAt(i)->geometry());
+                    }
+                }
+            }
         }
     }
 }
@@ -439,6 +531,13 @@
     }
 }
 
+void MImToolbar::reload()
+{
+    //use brute force: destroy everything and construct it again
+    unloadCustomWidgets();
+    loadCustomWidgets();
+}
+
 void MImToolbar::clearReactiveAreas()
 {
     if (!scene())
@@ -453,6 +552,18 @@
 
     reactionMap->setTransform(this, view);
     reactionMap->setInactiveDrawingValue();
-    reactionMap->fillRectangle(leftBar.geometry());
-    reactionMap->fillRectangle(rightBar.geometry());
+
+    for (int n = 0; n < layout()->count(); ++n) {
+        QGraphicsLinearLayout *row = dynamic_cast<QGraphicsLinearLayout*>(layout()->itemAt(n));
+
+        if (row) {
+            for (int j = 0; j < row->count(); ++j) {
+                WidgetBar *sidebar = dynamic_cast<WidgetBar*>(row->itemAt(j));
+                if (sidebar) {
+                    reactionMap->fillRectangle(sidebar->geometry());
+                }
+            }
+        }
+    }
 }
+
--- m-keyboard/widgets/mimtoolbar.h
+++ m-keyboard/widgets/mimtoolbar.h
@@ -22,12 +22,19 @@
 #include <MWidget>
 #include "widgetbar.h"
 #include "mkeyboardcommon.h"
+#include <minputmethodnamespace.h>
+
+#include <QPointer>
+#include <QSharedPointer>
 
 class MReactionMap;
 class ToolbarManager;
 class MVirtualKeyboardStyleContainer;
-class MButton;
+class MToolbarButton;
+class MToolbarItem;
 class ToolbarWidget;
+class MToolbarData;
+class MToolbarItem;
 
 /*!
   \brief MImToolbar implement the toolbar for virtualkeyboard.
@@ -55,7 +62,7 @@
      * \param style Styling information.
      * \param parent Parent object.
      */
-    explicit MImToolbar(MVirtualKeyboardStyleContainer &style,
+    explicit MImToolbar(const MVirtualKeyboardStyleContainer &style,
                         QGraphicsWidget *parent = 0);
 
     //! Destructor
@@ -72,7 +79,7 @@
      * the toolbar will be visible when show().
      * \param id      Unique identifier of the custom toolbar.
      */
-    void showToolbarWidget(qlonglong id);
+    void showToolbarWidget(QSharedPointer<const MToolbarData> toolbar);
 
     /*!
      * \brief Hides all custom toolbars, this also means they are removed from visible virtual keyboard.
@@ -85,6 +92,9 @@
     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *);
     //! \reimp_end
 
+    //! Reload toolbar if it should be updated
+    void reload();
+
 public slots:
     /*!
      * \brief Sets the status if there are some selection text.
@@ -100,17 +110,22 @@
 
 
 private slots:
-    void handleButtonClick(const ToolbarWidget &);
+    //! Invoked when custom button on toolbar is clicked
+    void handleButtonClick(MToolbarItem *item);
 
-    void showGroup(const QString &);
+    //! Show all widgets belong to given \a group
+    void showGroup(const QString &group);
 
-    void hideGroup(const QString &);
+    //! Hide all widgets belong to given \a group
+    void hideGroup(const QString &group);
 
-    void sendKeySequence(const QString &);
+    //! Send key events corresponding to given \a keys.
+    void sendKeySequence(const QString &keys);
 
     //! Invoked when copy/paste button is clicked
     void copyPasteButtonHandler();
 
+    //! Show or hide buttons according to toolbar definition and text tselection status
     void updateVisibility();
 
 signals:
@@ -132,6 +147,10 @@
      */
     void copyPasteClicked(CopyPasteState action);
 
+    //! \brief Emitted when toolbar availability changes
+    //! \param available true when there are widgets in the toolbar; false otherwise
+    void availabilityChanged(bool available);
+
 private:
     void setupLayout();
 
@@ -139,14 +158,20 @@
 
     void updateRegion();
 
-    void loadCustomWidgets(Qt::Alignment align);
+    void loadCustomWidgets();
 
-    void unloadCustomWidgets(Qt::Alignment align);
+    void unloadCustomWidgets();
 
-    void updateWidgets(bool customWidgetsChanged = true);
+    void arrangeWidgets();
 
     Qt::KeyboardModifiers keyModifiers(int key) const;
 
+    void setupRowLayout(QGraphicsLinearLayout *rowLayout, WidgetBar *leftBar,
+                        WidgetBar *rightBar);
+
+    void createAndAppendWidget(QSharedPointer<MToolbarItem> item, WidgetBar *leftWidget,
+                               WidgetBar *rightWidget);
+
     /*!
      * \brief Inserts item to \a align part of the toolbar at index,
      * or before any item that is currently at index in \a align part of the toolbar.
@@ -167,17 +192,25 @@
 
     void clearReactiveAreas();
 
-    const ToolbarManager &toolbarMgr;
     bool textSelected;
+
+    //! ToolbarItem for Copy/Paste button.
+    // Don't call any method belongs to MToolbarItem which attributes are managed internally.
+    QSharedPointer<MToolbarItem> copyPasteItem;
+
     //! Copy/Paste button
-    MButton *copyPaste;
+    MToolbarButton *copyPaste;
     //! Copy/paste button status
     CopyPasteState copyPasteStatus;
 
     WidgetBar leftBar;  //! Widget to hold left-aligned toolbar widgets
     WidgetBar rightBar; //! Widget to hold right-aligned toolbar widgets
 
-    MVirtualKeyboardStyleContainer &style; //! Styling information
+    QSharedPointer<const MToolbarData> currentToolbar; //! Pointer to definition of current toolbar
+
+    QList<QPointer<MWidget> > customWidgets; //! All custom widgets in this toolbar
+
+    const MVirtualKeyboardStyleContainer &style; //! Styling information
 
     friend class Ut_MImToolbar;
 
--- m-keyboard/widgets/mkeyboardsettingswidget.cpp
+++ m-keyboard/widgets/mkeyboardsettingswidget.cpp
+/* * This file is part of m-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#include "mkeyboardsettingswidget.h"
+
+#include <MButton>
+#include <MLabel>
+#include <MLayout>
+#include <MLocale>
+#include <MGridLayoutPolicy>
+#include <MLinearLayoutPolicy>
+#include <MContentItem>
+#include <MAbstractCellCreator>
+#include <MList>
+#include <MDialog>
+#include <MInfoBanner>
+
+#include <QObject>
+#include <QGraphicsLinearLayout>
+#include <QStandardItemModel>
+#include <QItemSelectionModel>
+#include <QTimer>
+#include <QDebug>
+
+class MKeyboardCellCreator: public MAbstractCellCreator<MContentItem>
+{
+public:
+    /*! \reimp */
+    virtual MWidget *createCell (const QModelIndex &index,
+                                 MWidgetRecycler &recycler) const;
+    virtual void updateCell(const QModelIndex &index, MWidget *cell) const;
+    /*! \reimp_end */
+private:
+    void updateContentItemMode(const QModelIndex &index, MContentItem *contentItem) const;
+};
+
+MWidget *MKeyboardCellCreator::createCell (const QModelIndex &index,
+                                           MWidgetRecycler &recycler) const
+{
+    MContentItem *cell = qobject_cast<MContentItem *>(recycler.take("MContentItem"));
+    if (!cell) {
+        cell = new MContentItem(MContentItem::SingleTextLabel);
+    }
+    updateCell(index, cell);
+    return cell;
+}
+
+void MKeyboardCellCreator::updateCell(const QModelIndex &index, MWidget *cell) const
+{
+    MContentItem *contentItem = qobject_cast<MContentItem *>(cell);
+
+    QString langId = index.data(Qt::UserRole + 1).toString();
+    contentItem->setTitle(langId);
+}
+
+void MKeyboardCellCreator::updateContentItemMode(const QModelIndex &index,
+                                                 MContentItem *contentItem) const
+{
+    const int row = index.row();
+    bool thereIsNextRow = index.sibling(row + 1, 0).isValid();
+    if (row == 0) {
+        contentItem->setItemMode(MContentItem::SingleColumnTop);
+    } else if (thereIsNextRow) {
+        contentItem->setItemMode(MContentItem::SingleColumnCenter);
+    } else {
+        contentItem->setItemMode(MContentItem::SingleColumnBottom);
+    }
+}
+
+MKeyboardSettingsWidget::MKeyboardSettingsWidget(MKeyboardSettings *settings, QGraphicsItem *parent)
+    : MWidget(parent),
+      settingsObject(settings),
+      keyboardDialog(0),
+      keyboardList(0)
+{
+    MLayout *layout = new MLayout(this);
+
+    landscapePolicy = new MGridLayoutPolicy(layout);
+    landscapePolicy->setContentsMargins(0, 0, 0, 0);
+    landscapePolicy->setSpacing(0);
+    //To make sure that both columns have the same width, give them the same preferred width.
+    landscapePolicy->setColumnPreferredWidth(0, 800);
+    landscapePolicy->setColumnPreferredWidth(1, 800);
+    portraitPolicy = new MLinearLayoutPolicy(layout, Qt::Vertical);
+    portraitPolicy->setContentsMargins(0, 0, 0, 0);
+    portraitPolicy->setSpacing(0);
+
+    layout->setLandscapePolicy(landscapePolicy);
+    layout->setPortraitPolicy(portraitPolicy);
+
+    buildUi();
+    syncErrorCorrectionState();
+    retranslateUi();
+    connectSlots();
+}
+
+MKeyboardSettingsWidget::~MKeyboardSettingsWidget()
+{
+    delete keyboardDialog;
+    keyboardDialog = 0;
+}
+
+void MKeyboardSettingsWidget::buildUi()
+{
+    selectedKeyboardsItem = new MContentItem(MContentItem::TwoTextLabels, this);
+    connect(selectedKeyboardsItem, SIGNAL(clicked()), this, SLOT(showKeyboardList()));
+    addItem(selectedKeyboardsItem);
+
+    errorCorrectionSwitch = new MButton(this);
+    errorCorrectionSwitch->setViewType(MButton::switchType);
+    errorCorrectionSwitch->setCheckable(true);
+    errorCorrectionLabel = new MLabel(this);
+    //% "Error correction"
+    errorCorrectionLabel->setText(qtTrId("qtn_txts_error_correction"));
+    errorCorrectionLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+    QGraphicsLinearLayout *l = new QGraphicsLinearLayout(Qt::Horizontal);
+    l->addItem(errorCorrectionLabel);
+    l->addItem(errorCorrectionSwitch);
+    l->setAlignment(errorCorrectionSwitch, Qt::AlignCenter);
+    (qobject_cast<MKeyboardSettingsWidget *>(this))->addItem(l);
+}
+
+void MKeyboardSettingsWidget::addItem(QGraphicsLayoutItem *item)
+{
+    int count = landscapePolicy->count();
+    int row = count / 2;
+    int column = count % 2;
+
+    landscapePolicy->addItem(item, row, column);
+    portraitPolicy->addItem(item);
+}
+
+void MKeyboardSettingsWidget::retranslateUi()
+{
+    updateTitle();
+    MWidget::retranslateUi();
+}
+
+void MKeyboardSettingsWidget::updateTitle()
+{
+    if (!settingsObject || !selectedKeyboardsItem)
+        return;
+    QStringList keyboards = settingsObject->selectedKeyboards().values();
+    //% "Installed keyboards (%1)"
+    QString title = qtTrId("qtn_txts_installed_keyboards")
+                            .arg(keyboards.count());
+    selectedKeyboardsItem->setTitle(title);
+    QString brief;
+    if (keyboards.count() > 0) {
+        foreach(const QString &keyboard, keyboards) {
+            if (!brief.isEmpty())
+                brief += QString(", ");
+            brief += keyboard;
+        }
+    } else {
+        //% "No keyboards installed"
+        brief = qtTrId("qtn_txts_no_keyboards");
+    }
+    selectedKeyboardsItem->setSubtitle(brief);
+
+    if (keyboardDialog) {
+        keyboardDialog->setTitle(title);
+    }
+}
+
+void MKeyboardSettingsWidget::connectSlots()
+{
+    connect(this, SIGNAL(visibleChanged()),
+            this, SLOT(handleVisibilityChanged()));
+
+    if (!settingsObject || !errorCorrectionSwitch)
+        return;
+
+    connect(errorCorrectionSwitch, SIGNAL(toggled(bool)),
+            this, SLOT(setErrorCorrectionState(bool)));
+    connect(settingsObject, SIGNAL(errorCorrectionChanged()),
+            this, SLOT(syncErrorCorrectionState()));
+    connect(settingsObject, SIGNAL(selectedKeyboardsChanged()),
+            this, SLOT(updateTitle()));
+    connect(settingsObject, SIGNAL(selectedKeyboardsChanged()),
+            this, SLOT(updateKeyboardSelectionModel()));
+}
+
+void MKeyboardSettingsWidget::showKeyboardList()
+{
+    if (!settingsObject || !keyboardDialog) {
+        QStringList keyboards = settingsObject->selectedKeyboards().values();
+        //% "Installed keyboards (%1)"
+        QString keyboardTitle = qtTrId("qtn_txts_installed_keyboards")
+                                       .arg(keyboards.count());
+        keyboardDialog = new MDialog(keyboardTitle, M::NoStandardButton);
+
+        keyboardList = new MList(keyboardDialog);
+        MKeyboardCellCreator *cellCreator = new MKeyboardCellCreator();
+        keyboardList->setCellCreator(cellCreator);
+        QStandardItemModel *model = new QStandardItemModel();
+        model->sort(0);
+        keyboardList->setItemModel(model);
+        keyboardList->setSelectionMode(MList::MultiSelection);
+        keyboardList->setSelectionModel(new QItemSelectionModel(model, this));
+        keyboardDialog->setCentralWidget(keyboardList);
+
+        connect(keyboardList, SIGNAL(itemClicked(const QModelIndex &)),
+                this, SLOT(updateSelectedKeyboards(const QModelIndex &)));
+    }
+    updateKeyboardModel();
+    keyboardDialog->exec();
+}
+
+void MKeyboardSettingsWidget::updateKeyboardModel()
+{
+    if (!settingsObject || !keyboardList)
+        return;
+    //always reload available layouts in case user install/remove some layouts
+    settingsObject->readAvailableKeyboards();
+    QStandardItemModel *model = static_cast<QStandardItemModel*> (keyboardList->itemModel());
+    model->clear();
+    foreach (QString keyboard, settingsObject->availableKeyboards()) {
+        QStandardItem *item = new QStandardItem(keyboard);
+        item->setData(keyboard);
+        model->appendRow(item);
+    }
+    updateKeyboardSelectionModel();
+}
+
+void MKeyboardSettingsWidget::updateKeyboardSelectionModel()
+{
+    if (!settingsObject || !keyboardList)
+        return;
+    QStandardItemModel *model = static_cast<QStandardItemModel*> (keyboardList->itemModel());
+    foreach (const QString &keyboard, settingsObject->selectedKeyboards().values()) {
+        QList<QStandardItem *> items = model->findItems(keyboard);
+        foreach (const QStandardItem *item, items) {
+            keyboardList->selectionModel()->select(item->index(), QItemSelectionModel::Select);
+        }
+    }
+}
+
+void MKeyboardSettingsWidget::updateSelectedKeyboards(const QModelIndex &index)
+{
+    if (!settingsObject || !index.isValid() || !keyboardList
+        || !keyboardList->selectionModel())
+        return;
+
+    QStringList updatedKeyboardTitles;
+    foreach (const QModelIndex &i, keyboardList->selectionModel()->selectedIndexes()) {
+        updatedKeyboardTitles << i.data(Qt::DisplayRole).toString();
+    }
+    if (updatedKeyboardTitles.isEmpty()) {
+        notifyNoKeyboards();
+    }
+    settingsObject->setSelectedKeyboards(updatedKeyboardTitles);
+    //update titles
+    retranslateUi();
+}
+
+void MKeyboardSettingsWidget::setErrorCorrectionState(bool toggled)
+{
+    if (!settingsObject)
+        return;
+    if (toggled != settingsObject->errorCorrection())
+        settingsObject->setErrorCorrection(toggled) ;
+}
+
+void MKeyboardSettingsWidget::syncErrorCorrectionState()
+{
+    if (!settingsObject)
+        return;
+    const bool errorCorrectionState = settingsObject->errorCorrection();
+    if (errorCorrectionSwitch
+        && errorCorrectionSwitch->isChecked() != errorCorrectionState) {
+        errorCorrectionSwitch->setChecked(errorCorrectionState);
+    }
+}
+
+void MKeyboardSettingsWidget::notifyNoKeyboards()
+{
+    MInfoBanner *noKeyboardsNotification = new MInfoBanner(MInfoBanner::Information);
+    //% "No keyboards installed"
+    noKeyboardsNotification->setBodyText(qtTrId("qtn_txts_no_keyboards"));
+    noKeyboardsNotification->appear(MSceneWindow::DestroyWhenDone);
+    QTimer::singleShot(1000, noKeyboardsNotification, SLOT(disappear()));
+}
+
+void MKeyboardSettingsWidget::handleVisibilityChanged()
+{
+    // This is a workaround to hide settings dialog when keyboard is hidden.
+    // And it could be removed when NB#177922 is fixed.
+    if (!isVisible() && keyboardDialog && keyboardDialog->isVisible()) {
+        // reject settings dialog if the visibility of settings widget
+        // is changed from shown to hidden.
+        keyboardDialog->reject();
+    }
+}
--- m-keyboard/widgets/mkeyboardsettingswidget.h
+++ m-keyboard/widgets/mkeyboardsettingswidget.h
+/* * This file is part of m-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#ifndef MKEYBOARDSETTINGSWIDGET_H
+#define MKEYBOARDSETTINGSWIDGET_H
+
+#include <QObject>
+#include <MWidget>
+#include "mkeyboardsettings.h"
+
+class QGraphicsItem;
+class QGraphicsLayoutItem;
+class MContentItem;
+class MButton;
+class MLabel;
+class MDialog;
+class MList;
+class QModelIndex;
+class MGridLayoutPolicy;
+class MLinearLayoutPolicy;
+
+class MKeyboardSettingsWidget : public MWidget
+{
+    Q_OBJECT
+public:
+    MKeyboardSettingsWidget(MKeyboardSettings *, QGraphicsItem *parent = 0);
+    virtual ~MKeyboardSettingsWidget();
+
+protected:
+    //! reimp
+    virtual void retranslateUi();
+    //! reimp_end
+
+private slots:
+    void showKeyboardList();
+    void updateTitle();
+    void updateKeyboardSelectionModel();
+    void updateSelectedKeyboards(const QModelIndex &);
+    void setErrorCorrectionState(bool toggled);
+    void syncErrorCorrectionState();
+    void handleVisibilityChanged();
+
+private:
+    void buildUi();
+    void addItem(QGraphicsLayoutItem *item);
+    void updateKeyboardModel();
+    void notifyNoKeyboards();
+    void connectSlots();
+
+    MKeyboardSettings *settingsObject;
+    MGridLayoutPolicy *landscapePolicy;
+    MLinearLayoutPolicy *portraitPolicy;
+    MButton *errorCorrectionSwitch;
+    MLabel *errorCorrectionLabel;
+    MDialog *keyboardDialog;
+    MList *keyboardList;
+    MContentItem *selectedKeyboardsItem;
+};
+
+#endif
--- m-keyboard/widgets/mtoolbarbutton.cpp
+++ m-keyboard/widgets/mtoolbarbutton.cpp
@@ -15,16 +15,47 @@
  */
 
 #include "mtoolbarbutton.h"
+#include "mtoolbarbuttonview.h"
+#include <mtoolbaritem.h>
 #include <MButton>
 #include <QFileInfo>
 #include <QPixmap>
 #include <QDebug>
 
-MToolbarButton::MToolbarButton(QGraphicsItem *parent)
+MToolbarButton::MToolbarButton(QSharedPointer<MToolbarItem> item,
+                               QGraphicsItem *parent)
     : MButton(parent),
       icon(0),
-      sizePercent(100)
+      sizePercent(100),
+      itemPtr(item)
 {
+    setView(new MToolbarButtonView(this));
+
+    if (!item->iconId().isEmpty()){
+        setIconID(item->iconId());
+    } else {
+        sizePercent = itemPtr->size();
+        setIconFile(itemPtr->icon());
+    }
+
+    if (!item->textId().isEmpty()) {
+        setText(qtTrId(itemPtr->textId().toUtf8().data()));
+    } else {
+        setText(itemPtr->text());
+    }
+    setCheckable(item->toggle());
+    if (itemPtr->toggle()) {
+        setChecked(itemPtr->pressed());
+
+        connect(this, SIGNAL(clicked(bool)),
+                itemPtr.data(), SLOT(setPressed(bool)));
+    }
+    setVisible(item->isVisible());
+
+    connect(this, SIGNAL(clicked(bool)),
+            this, SLOT(onClick()));
+    connect(itemPtr.data(), SIGNAL(propertyChanged(const QString&)),
+            this, SLOT(updateData(const QString&)));
 }
 
 MToolbarButton::~MToolbarButton()
@@ -65,7 +96,8 @@
     // kludge controller shouldn't really do painting.
     // but this is neccesary now to support drawing the custom icon on the button.
     MButton::paint(painter, option, widget);
-    if (icon) {
+    if (iconID().isEmpty() && icon) {
+        // TODO: to use style specified in css.
         // scale the icon to limit it insize button according sizePercent and button boundingRect
         // but keep the icon's origin ratio.
         QSizeF size = boundingRect().size();
@@ -78,3 +110,35 @@
         painter->drawPixmap(iconRect, *icon, QRectF(icon->rect()));
     }
 }
+
+QSharedPointer<MToolbarItem> MToolbarButton::item()
+{
+    return itemPtr;
+}
+
+void MToolbarButton::updateData(const QString &attribute)
+{
+    if (attribute == "icon") {
+        setIconFile(itemPtr->icon());
+    } else if (attribute == "iconId") {
+        setIconID(itemPtr->iconId());
+    } else if (attribute == "text") {
+        setText(itemPtr->text());
+    } else if (attribute == "textId") {
+        setText(qtTrId(itemPtr->textId().toUtf8().data()));
+    } else if (attribute == "pressed" && itemPtr->toggle()) {
+        setChecked(itemPtr->pressed());
+    } else if (attribute == "visible") {
+        setVisible(itemPtr->isVisible());
+        emit availabilityChanged();
+    } else if (attribute == "size") {
+        sizePercent = itemPtr->size();
+        update();
+    }
+}
+
+void MToolbarButton::onClick()
+{
+    emit clicked(itemPtr.data());
+}
+
--- m-keyboard/widgets/mtoolbarbutton.h
+++ m-keyboard/widgets/mtoolbarbutton.h
@@ -18,24 +18,29 @@
 #define MTOOLBARBUTTON_H
 
 #include <MButton>
+#include <QSharedPointer>
+
 /*!
  * \class MToolbarWidget
  * \brief MToolbarWidget is provide for the buttons in the input method toolbar.
  *
- * MToolbarWidget is inherit from MButton. It can use the icon which is not in current theme,
- * by setIcon() with the absolute file name of the icon. And the icon will be scaled according
- * setIconPercent() and button size.
+ * MToolbarWidget inherits from MButton. It can not only use the iconID, but also use the icon
+ * which is not in current theme, by setIcon() with the absolute file name of the icon, and the
+ * icon will be scaled according setIconPercent() and button size.
  */
 class QPixmap;
+class MToolbarItem;
 
 class MToolbarButton : public MButton
 {
     Q_OBJECT
+    Q_DISABLE_COPY(MToolbarButton)
+
 public:
     /*!
      * \Brief Constructor
      */
-    explicit MToolbarButton(QGraphicsItem *parent = 0);
+    explicit MToolbarButton(QSharedPointer<MToolbarItem> item, QGraphicsItem *parent = 0);
 
     //! Destructor
     virtual ~MToolbarButton();
@@ -61,10 +66,36 @@
                        QWidget *widget = 0);
     //! \reimp_end
 
+    //! Return pointer to corresponding toolbar item.
+    QSharedPointer<MToolbarItem> item();
+
+signals:
+    /*!
+     * \brief Emitted when button is clicked.
+     * \param item Pointer to corresponding toolbar item.
+     *
+     * Warning: do not store pointer which is used as parameter for this signal,
+     * call MToolbarItem::item() if you need to get pointer to toolbar item.
+     */
+    void clicked(MToolbarItem *item);
+
+    //! \brief Emitted when visibility (in a sense of the button being available
+    //! or not) changes.
+    void availabilityChanged();
+
+private slots:
+    //! Update button's properties when properties of toolbar item are updated.
+    void updateData(const QString &attribute);
+
+    //! Emits clicked(MToolbarItem *) when base class emits clicked(bool)
+    void onClick();
+
 private:
     QPixmap *icon;
     QString iconFile;
     int sizePercent;
+    QSharedPointer<MToolbarItem> itemPtr;
+
     friend class Ut_MImToolbar;
 };
 
--- m-keyboard/widgets/mtoolbarbuttonstyle.h
+++ m-keyboard/widgets/mtoolbarbuttonstyle.h
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#ifndef TOOLBAR_BUTTON_H
+#define TOOLBAR_BUTTON_H
+
+#include <mbuttoniconstyle.h>
+
+// Inheriting from MWidgetStyle crashes when it tries to set the button's label font!
+class M_EXPORT MToolbarButtonStyle : public MButtonIconStyle
+{
+    Q_OBJECT
+    M_STYLE(MToolbarButtonStyle)
+};
+
+class M_EXPORT MToolbarButtonStyleContainer : public MButtonIconStyleContainer
+{
+    M_STYLE_CONTAINER(MToolbarButtonStyle)
+};
+
+#endif
+
--- m-keyboard/widgets/mtoolbarbuttonview.cpp
+++ m-keyboard/widgets/mtoolbarbuttonview.cpp
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#include "mtoolbarbuttonview.h"
+#include "mtoolbarbutton.h"
+
+MToolbarButtonView::MToolbarButtonView(MToolbarButton *controller)
+    : MButtonView(controller)
+{
+}
+
--- m-keyboard/widgets/mtoolbarbuttonview.h
+++ m-keyboard/widgets/mtoolbarbuttonview.h
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#ifndef MTOOLBARBUTTONVIEW_H
+#define MTOOLBARBUTTONVIEW_H
+
+#include <MButtonView>
+#include "mtoolbarbuttonstyle.h"
+
+class MToolbarButton;
+
+class MToolbarButtonView : public MButtonView
+{
+    Q_OBJECT
+    M_VIEW(MButtonModel, MToolbarButtonStyle)
+
+public:
+    explicit MToolbarButtonView(MToolbarButton *controller);
+};
+
+#endif
+
--- m-keyboard/widgets/mtoolbarlabel.cpp
+++ m-keyboard/widgets/mtoolbarlabel.cpp
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#include "mtoolbarlabel.h"
+#include <mtoolbaritem.h>
+
+MToolbarLabel::MToolbarLabel(QSharedPointer<MToolbarItem> item,
+                             QGraphicsItem *parent)
+    : MLabel(parent),
+      itemPtr(item)
+{
+    if (!item->textId().isEmpty()) {
+        setText(qtTrId(item->textId().toUtf8().data()));
+    } else {
+        setText(item->text());
+    }
+    setVisible(item->isVisible());
+
+    connect(item.data(), SIGNAL(propertyChanged(const QString&)),
+            this, SLOT(updateData(const QString&)));
+}
+
+MToolbarLabel::~MToolbarLabel()
+{
+}
+
+QSharedPointer<MToolbarItem> MToolbarLabel::item()
+{
+    return itemPtr;
+}
+
+void MToolbarLabel::updateData(const QString &attribute)
+{
+    if (attribute == "text") {
+        setText(itemPtr->text());
+    } else if (attribute == "textId") {
+        setText(qtTrId(itemPtr->textId().toUtf8().data()));
+    } else if (attribute == "visible") {
+        setVisible(itemPtr->isVisible());
+        emit availabilityChanged();
+    }
+}
+
--- m-keyboard/widgets/mtoolbarlabel.h
+++ m-keyboard/widgets/mtoolbarlabel.h
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#ifndef MTOOLBARLABEL_H
+#define MTOOLBARLABEL_H
+
+#include <MLabel>
+#include <QSharedPointer>
+
+/*!
+ * \class MToolbarLabel
+ * \brief MToolbarLabel is provided for the labelss in the input method toolbar.
+ *
+ * MToolbarLabel is inherit from MLabel. It is used to show text only.
+ */
+class MToolbarItem;
+
+class MToolbarLabel : public MLabel
+{
+    Q_OBJECT
+    Q_DISABLE_COPY(MToolbarLabel)
+
+public:
+    /*!
+     * \Brief Constructor
+     */
+    explicit MToolbarLabel(QSharedPointer<MToolbarItem> item, QGraphicsItem *parent = 0);
+
+    //! Destructor
+    virtual ~MToolbarLabel();
+
+    //! Return pointer to corresponding toolbar item.
+    QSharedPointer<MToolbarItem> item();
+
+signals:
+    //! \brief Emitted when visibility (in a sense of the label being available
+    //! or not) changes.
+    void availabilityChanged();
+
+private slots:
+    //! Update label's properties when properties of toolbar item are updated.
+    void updateData(const QString &attribute);
+
+private:
+    //! MToolbarItem is used as model for this label.
+    QSharedPointer<MToolbarItem> itemPtr;
+};
+
+#endif
+
--- m-keyboard/widgets/mvirtualkeyboard.cpp
+++ m-keyboard/widgets/mvirtualkeyboard.cpp
@@ -25,6 +25,13 @@
 #include "notification.h"
 #include "vkbdatakey.h"
 #include "mimtoolbar.h"
+#include "ikeybutton.h"
+#include "keyevent.h"
+#include "keyeventhandler.h"
+#include "grip.h"
+#include "sharedhandlearea.h"
+
+#include <mtoolbardata.h>
 
 #include <QDebug>
 #include <QPainter>
@@ -41,19 +48,26 @@
 #include <MApplication>
 
 
+namespace
+{
+    // This GConf item defines whether multitouch is enabled or disabled
+    const char * const MultitouchSettings = "/meegotouch/inputmethods/multitouch/enabled";
+}
+
 const QString MVirtualKeyboard::WordSeparators("-.,!? \n");
 
 
 MVirtualKeyboard::MVirtualKeyboard(const LayoutsManager &layoutsManager,
-                                       QGraphicsWidget *parent)
+                                   const MVirtualKeyboardStyleContainer *styleContainer,
+                                   QGraphicsWidget *parent)
     : MWidget(parent),
       mainLayout(new QGraphicsLinearLayout(Qt::Vertical, this)),
       currentLevel(0),
       numLevels(2),
       activity(Inactive),
-      styleContainer(0),
+      styleContainer(styleContainer),
       sceneManager(MPlainWindow::instance()->sceneManager()),
-      shiftLevel(ShiftOff),
+      shiftLevel(ModifierClearState),
       currentLayoutType(LayoutData::General),
       currentOrientation(sceneManager->orientation()),
       hideShowByFadingOnly(false),
@@ -72,14 +86,21 @@
     setObjectName("MVirtualKeyboard");
     hide();
 
-    styleContainer = new MVirtualKeyboardStyleContainer;
-    styleContainer->initialize(objectName(), "MVirtualKeyboardView", 0);
-
     notification = new Notification(styleContainer, this);
 
-    createSwitcher();
+    eventHandler = new KeyEventHandler(this);
+    connect(eventHandler, SIGNAL(keyPressed(const KeyEvent &)),
+            this, SIGNAL(keyPressed(const KeyEvent &)));
+    connect(eventHandler, SIGNAL(keyReleased(const KeyEvent &)),
+            this, SIGNAL(keyReleased(const KeyEvent &)));
+    connect(eventHandler, SIGNAL(keyClicked(const KeyEvent &)),
+            this, SIGNAL(keyClicked(const KeyEvent &)));
+    connect(eventHandler, SIGNAL(shiftPressed(bool)),
+            this, SLOT(setFunctionRowState(bool)));
 
-    createToolbar();
+    enableMultiTouch = MGConfItem(MultitouchSettings).value().toBool();
+
+    createSwitcher();
 
     setupTimeLine();
 
@@ -88,10 +109,23 @@
     setMinimumWidth(0);
 
     // add stuff to the layout
+
     mainLayout->setContentsMargins(0, 0, 0, 0);
     mainLayout->setSpacing(0);
-    mainLayout->addItem(imToolbar);
-    mainLayout->setAlignment(imToolbar, Qt::AlignCenter);
+
+    createToolbar();
+
+    sharedHandleArea = new SharedHandleArea(*imToolbar);
+    sharedHandleArea->setZValue(-1); // popup should be on top of sharedHandleArea
+    connect(sharedHandleArea, SIGNAL(regionUpdated()), this, SLOT(organizeContentAndSendRegion()));
+    mainLayout->addItem(sharedHandleArea);
+    connectHandle(*sharedHandleArea);
+
+    Grip &keyboardGrip = *new Grip(this);
+    keyboardGrip.setZValue(-1); // popup should be on top of keyboardGrip
+    keyboardGrip.setObjectName("KeyboardHandle");
+    mainLayout->addItem(&keyboardGrip);
+    connectHandle(keyboardGrip);
 
     mainLayout->addItem(mainKeyboardSwitcher); // start in qwerty
 
@@ -122,9 +156,24 @@
 
     delete notification;
     notification = 0;
+}
+
+
+template <class T>
+void MVirtualKeyboard::connectHandle(const T &handle)
+{
+    connect(&handle, SIGNAL(flickLeft(const FlickGesture &)), this, SLOT(flickLeftHandler()));
+    connect(&handle, SIGNAL(flickRight(const FlickGesture &)), this, SLOT(flickRightHandler()));
+    connect(&handle, SIGNAL(flickDown(const FlickGesture &)), this, SLOT(handleHandleFlickDown(const FlickGesture &)));
+}
+
 
-    delete styleContainer;
-    styleContainer = 0;
+void MVirtualKeyboard::handleHandleFlickDown(const FlickGesture &/* gesture */)
+{
+    if (activeState == OnScreen) {
+        hideKeyboard();
+        emit userInitiatedHide();
+    }
 }
 
 
@@ -157,15 +206,13 @@
 
 void MVirtualKeyboard::createToolbar()
 {
-    imToolbar = new MImToolbar(style(), this);
+    imToolbar = new MImToolbar(style());
 
     // Set z value below default level (0.0) so popup will be on top of toolbar.
     // More correct way to fix this, though more difficult, would be to have only one
     // popup instance in dvkb and set its z value higher.
     imToolbar->setZValue(-1.0);
 
-    connect(imToolbar, SIGNAL(regionUpdated()),
-            this, SLOT(sendVKBRegion()));
     connect(imToolbar, SIGNAL(copyPasteRequest(CopyPasteState)),
             this, SIGNAL(copyPasteRequest(CopyPasteState)));
     connect(imToolbar, SIGNAL(sendKeyEventRequest(const QKeyEvent &)),
@@ -176,9 +223,9 @@
             this, SIGNAL(copyPasteClicked(CopyPasteState)));
 }
 
-void MVirtualKeyboard::showToolbarWidget(qlonglong id)
+void MVirtualKeyboard::showToolbarWidget(QSharedPointer<const MToolbarData> toolbar)
 {
-    imToolbar->showToolbarWidget(id);
+    imToolbar->showToolbarWidget(toolbar);
 }
 
 void MVirtualKeyboard::hideToolbarWidget()
@@ -192,7 +239,7 @@
     mTimestamp("MVirtualKeyboard", "start");
 
     // The second item in layout holds the currently used keyboard. Draw under it.
-    const QRectF backgroundGeometry = layout()->itemAt(1)->geometry();
+    const QRectF backgroundGeometry = layout()->itemAt(KeyboardIndex)->geometry();
 
     if (MApplication::softwareRendering()) {
         if (backgroundPixmap.isNull()
@@ -233,35 +280,39 @@
 MVirtualKeyboard::switchLevel()
 {
     switch (shiftLevel) {
-    case ShiftOff:
+    case ModifierClearState:
         currentLevel = 0;
         break;
-    case ShiftOn:
+    case ModifierLatchedState:
         currentLevel = 1;
         break;
-    case ShiftLock:
+    case ModifierLockedState:
         currentLevel = 1;
         break;
     }
 
-    const bool capsLock = (shiftLevel == ShiftLock);
+    const bool capsLock = (shiftLevel == ModifierLockedState);
 
     for (int i = 0; i < mainKeyboardSwitcher->count(); ++i) {
         // the subwidgets have main section as first item in their layout, function row as second.
         // handling main section:
         static_cast<KeyButtonArea *>(mainKeyboardSwitcher->widget(i)->layout()->itemAt(0))->
-                switchLevel(currentLevel, capsLock);
+                switchLevel(currentLevel);
 
-        // TODO: When introducing multitouch we should make function row to change level
-        // according to pressed state of the shift button rather than general level.
+        // Function row shift update, level does not change for the layout.
         static_cast<KeyButtonArea *>(mainKeyboardSwitcher->widget(i)->layout()->itemAt(1))->
-                switchLevel(currentLevel, capsLock);
+            setShiftStatus(currentLevel == 1, capsLock);
+
+        if (!enableMultiTouch) {
+            static_cast<KeyButtonArea *>(mainKeyboardSwitcher->widget(i)->layout()->itemAt(1))->
+                switchLevel(currentLevel);
+        }
     }
 }
 
 
 void
-MVirtualKeyboard::setShiftState(ShiftLevel level)
+MVirtualKeyboard::setShiftState(ModifierState level)
 {
     if (shiftLevel != level) {
         shiftLevel = level;
@@ -286,7 +337,7 @@
 void
 MVirtualKeyboard::flickLeftHandler()
 {
-    if (!mainKeyboardSwitcher->isRunning()) {
+    if ((activeState == OnScreen) && !mainKeyboardSwitcher->isRunning()) {
         if (mainKeyboardSwitcher->isAtBoundary(HorizontalSwitcher::Right)) {
             emit pluginSwitchRequired(M::SwitchForward);
             return;
@@ -299,9 +350,9 @@
 
 
 void
-MVirtualKeyboard::flickUpHandler(const KeyBinding *binding)
+MVirtualKeyboard::flickUpHandler(const KeyBinding &binding)
 {
-    if (binding && binding->action() == KeyBinding::ActionSym) {
+    if (binding.action() == KeyBinding::ActionSym) {
         emit showSymbolViewRequested();
     }
 }
@@ -310,7 +361,7 @@
 void
 MVirtualKeyboard::flickRightHandler()
 {
-    if (!mainKeyboardSwitcher->isRunning()) {
+    if ((activeState == OnScreen) && !mainKeyboardSwitcher->isRunning()) {
         if (mainKeyboardSwitcher->isAtBoundary(HorizontalSwitcher::Left)) {
             emit pluginSwitchRequired(M::SwitchBackward);
             return;
@@ -324,6 +375,7 @@
 
 void MVirtualKeyboard::showKeyboard(bool fadeOnly)
 {
+    qDebug() << __PRETTY_FUNCTION__ << fadeOnly;
     organizeContent(sceneManager->orientation());
 
     if (activity == Active) {
@@ -360,8 +412,9 @@
         // something else changes during the animation.  But normally the region should be
         // the same as the one we send now.  We do this initial region sending after
         // show() so that we can use region().  We cannot use sendVKBRegion() since region
-        // updates are suppressed.
-        emit regionUpdated(region().translated(0, regionOffset));
+        // updates are suppressed and because we want to apply the offset.
+        emit regionUpdated(region(true, true).translated(0, regionOffset));
+        emit inputMethodAreaUpdated(region().translated(0, regionOffset));
     } else if (hideShowByFadingOnly) {
         // fade() doesn't alter the position when we're just fading
         setPos(0, sceneManager->visibleSceneSize().height() - actualHeight());
@@ -397,7 +450,7 @@
 void MVirtualKeyboard::resetState()
 {
     // Default state for shift is ShiftOff.
-    setShiftState(ShiftOff);
+    setShiftState(ModifierClearState);
 
     // Dead keys are unlocked in KeyButtonArea::onHide().
     // As long as this method is private, and only called from
@@ -420,7 +473,7 @@
     int result = size().height();
 
     if ((activeState != OnScreen)) {
-        result = imToolbar->size().height();
+        result = dynamic_cast<QGraphicsWidget *>(mainLayout->itemAt(SharedHandleAreaIndex))->size().height();
     }
 
     return result;
@@ -436,12 +489,15 @@
         recreateKeyboards();
         mainKeyboardSwitcher->setCurrent(index);
 
+        // load proper layout
+        imToolbar->reload();
+
         // invalidate layouts so we get updated size infos
-        mainLayout->invalidate();
         numberKeyboard->layout()->invalidate();
         phoneNumberKeyboard->layout()->invalidate();
     }
 
+    mainLayout->invalidate();
     resize(MPlainWindow::instance()->visibleSceneSize().width(), mainLayout->preferredHeight());
     if ((activity == Active) && (showHideTimeline.state() != QTimeLine::Running)) {
         setPos(0, sceneManager->visibleSceneSize().height() - actualHeight());
@@ -487,6 +543,15 @@
 }
 
 
+void MVirtualKeyboard::organizeContentAndSendRegion()
+{
+    if (isVisible()) {
+        organizeContent(currentOrientation);
+        sendVKBRegion();
+    }
+}
+
+
 void MVirtualKeyboard::sendVKBRegion()
 {
     regionUpdateRequested = true;
@@ -494,24 +559,30 @@
     if (!sendRegionUpdates)
         return;
 
-    emit regionUpdated(region());
+    emit regionUpdated(region(true, true));
+    emit inputMethodAreaUpdated(region());
 }
 
-QRegion MVirtualKeyboard::region(const bool includeToolbar) const
+QRegion MVirtualKeyboard::region(const bool notJustMainKeyboardArea,
+                                 const bool includeExtraInteractiveAreas) const
 {
     QRegion region;
 
     if (isVisible()) {
         imToolbar->layout()->activate();
         mainLayout->activate();
-        if (includeToolbar) {
-            region |= imToolbar->region();
+        if (notJustMainKeyboardArea) {
+            region |= sharedHandleArea->region(includeExtraInteractiveAreas);
         }
 
         // Main keyboard area (qwerty/number/etc.)
         if (activeState == OnScreen) {
             mainLayout->activate();
-            region |= mapRectToScene(mainLayout->itemAt(1)->geometry()).toRect();
+            qDebug() << __PRETTY_FUNCTION__ << mainLayout->itemAt(KeyboardIndex)->geometry();
+            region |= mapRectToScene(mainLayout->itemAt(KeyboardIndex)->geometry()).toRect();
+            if (notJustMainKeyboardArea) {
+                region |= mapRectToScene(mainLayout->itemAt(KeyboardHandleIndex)->geometry()).toRect();
+            }
         }
     }
 
@@ -525,15 +596,10 @@
     }
 
     activeState = newState;
-    qDebug() << __PRETTY_FUNCTION__ << newState << imToolbar->geometry() << imToolbar->region();
     resetState();
-    qDebug() << __PRETTY_FUNCTION__ << imToolbar->geometry() << imToolbar->region();
 
-    static_cast<QGraphicsWidget *>(mainLayout->itemAt(1))->setVisible(newState == OnScreen);
-    organizeContent(currentOrientation);
-    if (isVisible()) {
-        sendVKBRegion();
-    }
+    static_cast<QGraphicsWidget *>(mainLayout->itemAt(KeyboardIndex))->setVisible(newState == OnScreen);
+    organizeContentAndSendRegion();
 }
 
 MIMHandlerState MVirtualKeyboard::keyboardState() const
@@ -550,8 +616,8 @@
     // such as qwerty + function row.
     QGraphicsLayout *keyboardLayout = 0;
 
-    QGraphicsLayoutItem *item = mainLayout->itemAt(1);
-    if (item == mainKeyboardSwitcher) {
+    QGraphicsLayoutItem *item = mainLayout->itemAt(KeyboardIndex);
+    if (item == mainKeyboardSwitcher && mainKeyboardSwitcher->currentWidget()) {
         keyboardLayout = mainKeyboardSwitcher->currentWidget()->layout();
     } else {
         keyboardLayout = static_cast<QGraphicsWidget *>(item)->layout();
@@ -598,7 +664,8 @@
         // Draw keyboard area with inactive color to prevent transparent holes.
         reactionMap->setInactiveDrawingValue();
         reactionMap->setTransform(this, view);
-        reactionMap->fillRectangle(layout()->itemAt(1)->geometry());
+        reactionMap->fillRectangle(layout()->itemAt(KeyboardIndex)->geometry());
+        reactionMap->fillRectangle(layout()->itemAt(KeyboardHandleIndex)->geometry());
 
         if (activeState == OnScreen) {
             drawButtonsReactionMaps(reactionMap, view);
@@ -611,7 +678,7 @@
 }
 
 
-MVirtualKeyboardStyleContainer &MVirtualKeyboard::style()
+const MVirtualKeyboardStyleContainer &MVirtualKeyboard::style() const
 {
     return *styleContainer;
 }
@@ -640,7 +707,7 @@
     currentLayoutType = newLayoutType;
 
     // remove what currently is in the keyboard position in the main layout
-    QGraphicsLayoutItem *previousItem = mainLayout->itemAt(1);
+    QGraphicsLayoutItem *previousItem = mainLayout->itemAt(KeyboardIndex);
     mainLayout->removeItem(previousItem);
     static_cast<QGraphicsWidget *>(previousItem)->hide();
 
@@ -658,7 +725,7 @@
         break;
     }
 
-    mainLayout->insertItem(1, newWidget);
+    mainLayout->insertItem(KeyboardIndex, newWidget);
     if (activeState == OnScreen) {
         newWidget->show();
     } else {
@@ -666,11 +733,7 @@
     }
 
     // resize and update keyboards if needed
-    organizeContent(currentOrientation);
-
-    if (isVisible()) {
-        sendVKBRegion();
-    }
+    organizeContentAndSendRegion();
 }
 
 void MVirtualKeyboard::suppressRegionUpdate(bool suppress)
@@ -701,9 +764,9 @@
 }
 
 
-MVirtualKeyboard::ShiftLevel MVirtualKeyboard::shiftStatus() const
+ModifierState MVirtualKeyboard::shiftStatus() const
 {
-    return ShiftLevel(shiftLevel);
+    return ModifierState(shiftLevel);
 }
 
 
@@ -747,7 +810,7 @@
         // NOTE: Switcher already has correct index if language change was
         // initiated by a flick gesture.
         if (mainKeyboardSwitcher->count() >= languageIndex) {
-            mainKeyboardSwitcher->switchTo(languageIndex);
+            mainKeyboardSwitcher->setCurrent(languageIndex);
         }
     }
 }
@@ -775,6 +838,12 @@
                 languageIndex = 0;
             }
         }
+
+        // TODO: we should simplify the whole languageReset(). Now
+        // MVirtualKeyboard manages currentLanguage and HorizontalSwitcher also
+        // manages its current widget index.  We always have to synchronize
+        // both of them if one is changed (in the right order, too).
+        currentLanguage = "";
     }
 
     recreateKeyboards();
@@ -824,7 +893,7 @@
 
     // All sections may not be of the same height so we send a region just in
     // case.  That also causes reaction maps to be redrawn.
-    sendVKBRegion();
+    organizeContentAndSendRegion();
 }
 
 
@@ -857,14 +926,12 @@
 
         KeyButtonArea *mainSection = createMainSectionView(language, LayoutData::General,
                                                            currentOrientation);
-        mainSection->setObjectName("VirtualKeyboardMainRow");
 
         KeyButtonArea *functionRow = createSectionView(language, LayoutData::General,
                                                        currentOrientation,
                                                        LayoutData::functionkeySection,
                                                        KeyButtonArea::ButtonSizeFunctionRow,
                                                        false, languagePage);
-        functionRow->setObjectName("VirtualKeyboardFunctionRow");
 
         if (mainSection == 0 || functionRow == 0) {
             qCritical("Problem loading language to switcher");
@@ -874,6 +941,9 @@
             continue;
         }
 
+        mainSection->setObjectName("VirtualKeyboardMainRow");
+        functionRow->setObjectName("VirtualKeyboardFunctionRow");
+
         languageLayout->addItem(mainSection);
         languageLayout->addItem(functionRow);
 
@@ -919,33 +989,29 @@
 
     KeyButtonArea *view = new SingleWidgetButtonArea(styleContainer, layoutSection,
                                                      sizeScheme, usePopup, parent);
-    Q_ASSERT(view);
 
-    connect(view, SIGNAL(keyPressed(const KeyEvent &)),
-            this, SIGNAL(keyPressed(const KeyEvent &)));
-
-    connect(view, SIGNAL(keyReleased(const KeyEvent &)),
-            this, SIGNAL(keyReleased(const KeyEvent &)));
-
-    connect(view, SIGNAL(keyClicked(const KeyEvent &)),
-            this, SIGNAL(keyClicked(const KeyEvent &)));
+    eventHandler->addEventSource(view);
 
     connect(view, SIGNAL(flickDown()), this, SLOT(hideKeyboard()));
     connect(view, SIGNAL(flickDown()), this, SIGNAL(userInitiatedHide()));
-    connect(view, SIGNAL(flickUp(const KeyBinding *)),
-            this, SLOT(flickUpHandler(const KeyBinding *)));
+    connect(view, SIGNAL(flickUp(KeyBinding)),
+            this, SLOT(flickUpHandler(KeyBinding)));
 
     return view;
 }
 
+void MVirtualKeyboard::setFunctionRowState(bool shiftPressed)
+{
+    if (enableMultiTouch) {
+        //TODO: time treshold to avoid flickering?
+        static_cast<KeyButtonArea *>(mainKeyboardSwitcher->currentWidget()->layout()->itemAt(1))->
+            switchLevel(shiftPressed ? 1 : 0);
+    }
+}
 
 void MVirtualKeyboard::setCopyPasteButton(bool copyAvailable, bool pasteAvailable)
 {
     imToolbar->setCopyPasteButton(copyAvailable, pasteAvailable);
-    organizeContent(currentOrientation);
-    if (isVisible()) {
-        sendVKBRegion();
-    }
 }
 
 void MVirtualKeyboard::setSelectionStatus(bool hasSelection)
@@ -978,13 +1044,11 @@
                                                   currentOrientation, LayoutData::mainSection,
                                                   KeyButtonArea::ButtonSizeEqualExpanding,
                                                   false, numberKeyboard);
-    numberArea->setObjectName("VirtualKeyboardNumberMainRow");
 
     KeyButtonArea *numberFunctionRow
         = createSectionView(defaultLanguage, LayoutData::Number, currentOrientation,
                             LayoutData::functionkeySection, KeyButtonArea::ButtonSizeFunctionRowNumber,
                             false, numberKeyboard);
-    numberFunctionRow->setObjectName("VirtualKeyboardNumberFunctionRow");
 
     numberLayout->addItem(numberArea);
     numberLayout->addItem(numberFunctionRow);
@@ -994,13 +1058,11 @@
                                                  currentOrientation, LayoutData::mainSection,
                                                  KeyButtonArea::ButtonSizeEqualExpandingPhoneNumber,
                                                  false, phoneNumberKeyboard);
-    phoneArea->setObjectName("VirtualKeyboardPhoneMainRow");
 
     KeyButtonArea *phoneFunctionArea
         = createSectionView(defaultLanguage, LayoutData::PhoneNumber, currentOrientation,
                             LayoutData::functionkeySection, KeyButtonArea::ButtonSizeFunctionRowNumber,
                             false, phoneNumberKeyboard);
-    phoneFunctionArea->setObjectName("VirtualKeyboardPhoneFunctionRow");
 
     phoneNumberLayout->addItem(phoneArea);
     phoneNumberLayout->addItem(phoneFunctionArea);
@@ -1009,6 +1071,11 @@
     if (numberArea == 0 || numberFunctionRow == 0 || phoneArea == 0 || phoneFunctionArea == 0) {
         qFatal("Error loading number keyboard");
     }
+
+    numberArea->setObjectName("VirtualKeyboardNumberMainRow");
+    numberFunctionRow->setObjectName("VirtualKeyboardNumberFunctionRow");
+    phoneArea->setObjectName("VirtualKeyboardPhoneMainRow");
+    phoneFunctionArea->setObjectName("VirtualKeyboardPhoneFunctionRow");
 }
 
 void MVirtualKeyboard::showToolbar()
@@ -1067,7 +1134,7 @@
 
 void MVirtualKeyboard::hideMainArea()
 {
-    QGraphicsItem *item = dynamic_cast<QGraphicsItem*>(mainLayout->itemAt(1));
+    QGraphicsItem *item = dynamic_cast<QGraphicsItem*>(mainLayout->itemAt(KeyboardIndex));
     if (item) {
         item->hide();
     }
@@ -1076,9 +1143,14 @@
 
 void MVirtualKeyboard::showMainArea()
 {
-    QGraphicsItem *item = dynamic_cast<QGraphicsItem*>(mainLayout->itemAt(1));
+    QGraphicsItem *item = dynamic_cast<QGraphicsItem*>(mainLayout->itemAt(KeyboardIndex));
     if (item) {
         item->show();
     }
 }
 
+void MVirtualKeyboard::setInputMethodMode(M::InputMethodMode mode)
+{
+    KeyButtonArea::setInputMethodMode(mode);
+    sharedHandleArea->setInputMethodMode(mode);
+}
--- m-keyboard/widgets/mvirtualkeyboard.h
+++ m-keyboard/widgets/mvirtualkeyboard.h
@@ -25,7 +25,9 @@
 #include "layoutdata.h"
 #include <mimhandlerstate.h>
 #include <mimdirection.h>
+#include <minputmethodnamespace.h>
 #include <MWidget>
+#include <MNamespace>
 #include <QPixmap>
 #include <QSharedPointer>
 #include <QTimeLine>
@@ -45,6 +47,12 @@
 class VkbToolbar;
 class MImToolbar;
 class MReactionMap;
+class KeyEventHandler;
+class MToolbarData;
+class Handle;
+class Grip;
+class FlickGesture;
+class SharedHandleArea;
 
 /*!
   \class MVirtualKeyboard
@@ -62,19 +70,13 @@
     friend class Ut_MKeyboardHost;
 
 public:
-    //! Shift key states
-    typedef enum {
-        ShiftOff,
-        ShiftOn,
-        ShiftLock
-    } ShiftLevel;
-
-
     /*!
      * \brief Constructor for creating an virtual keyboard object.
      * \param parent Parent object.
      */
-    MVirtualKeyboard(const LayoutsManager &layoutsManager, QGraphicsWidget *parent = 0);
+    MVirtualKeyboard(const LayoutsManager &layoutsManager,
+                     const MVirtualKeyboardStyleContainer *styleContainer,
+                     QGraphicsWidget *parent = 0);
 
     //! Destructor
     ~MVirtualKeyboard();
@@ -103,15 +105,12 @@
      */
     QString selectedLanguage() const;
 
-    //! Getter for style container
-    MVirtualKeyboardStyleContainer &style();
-
     //! Sets keyboard type according text entry type, type matches M::TextContentType
     void setKeyboardType(const int type);
 
     // for unit tests
     //! Returns shift key status
-    ShiftLevel shiftStatus() const;
+    ModifierState shiftStatus() const;
 
     //! Characters defines word boundaries
     static const QString WordSeparators;
@@ -142,19 +141,17 @@
     void finalizeOrientationChange();
 
     /*!
-     * \brief Shows a custom toolbar with unique \a id.
-     * Loads a custom toolbar according \a id, if successfuly loads,
-     * the toolbar will be visible when virtual keyboard is shown.
-     * \param id      Unique identifier of the custom toolbar.
+     * \brief Creates widgets to visualize given \a toolbar.
+     * \param toolbar      Pointer to toolbar definition.
      */
-    void showToolbarWidget(qlonglong id);
+    void showToolbarWidget(QSharedPointer<const MToolbarData> toolbar);
 
     /*!
      * \brief Hides all custom toolbars, this means they are removed from visible virtual keyboard.
      */
     void hideToolbarWidget();
 
-    QRegion region(bool includeToolbar = true) const;
+    QRegion region(bool notJustMainKeyboardArea = true, bool includeExtraInteractiveAreas = false) const;
 
     /*!
      * \brief Shows or hides some keyboard's widgets depending on keyboard state.
@@ -181,6 +178,9 @@
      */
     void switchLanguage(M::InputMethodSwitchDirection direction, bool enableAnimation);
 
+    //! Set input method mode
+    void setInputMethodMode(M::InputMethodMode mode);
+
 public slots:
     /*!
      * Method to switch level. Changes into next possible level.
@@ -191,7 +191,7 @@
     /*!
      * Method to set shift state
      */
-    void setShiftState(ShiftLevel level);
+    void setShiftState(ModifierState level);
 
     /*!
      * Method to Show the keyboard
@@ -230,6 +230,12 @@
 
 private slots:
     /*!
+     * \brief Switch function row to upper/lower case
+     * according to given parameter
+     */
+    void setFunctionRowState(bool shiftPressed);
+
+    /*!
      * Handler for Right flick operation
      */
     void flickRightHandler();
@@ -243,7 +249,7 @@
      * \brief Handler for upward flick operation
      * \param binding Key binding
      */
-    void flickUpHandler(const KeyBinding *binding);
+    void flickUpHandler(const KeyBinding &binding);
 
     /*!
      * Method to fade the vkb during transition
@@ -264,12 +270,18 @@
     void onSectionSwitched(QGraphicsWidget *previous, QGraphicsWidget *current);
 
     /*!
-     * Send \a regionUpdated signal with the current region of this widget and
-     * its children combined, unless \a suppressRegionUpdate has been used to
-     * suppress updates.
+     * Send \a regionUpdated and \a inputMethodAreaUpdated signals with the
+     * current region of this widget and its children combined, unless \a
+     * suppressRegionUpdate has been used to suppress updates.
      */
     void sendVKBRegion();
 
+    //! \brief Call organizeContent() and sendVKBRegion() if the vkb is visible
+    void organizeContentAndSendRegion();
+
+    //! Handle flick down gesture signals from handle areas
+    void handleHandleFlickDown(const FlickGesture &gesture);
+
 signals:
     /*!
      * \brief Emitted when key is pressed
@@ -297,6 +309,9 @@
     //! \see MInputMethodBase::regionUpdated()
     void regionUpdated(const QRegion &);
 
+    //! \see MInputMethodBase::inputMethodAreaUpdated()
+    void inputMethodAreaUpdated(const QRegion &);
+
     //! This signal is emitted when input language is changed
     //! \param language this is always the language from XML file in unmodified form
     void languageChanged(const QString &language);
@@ -344,6 +359,9 @@
 
 
 private:
+    //! Getter for style container
+    const MVirtualKeyboardStyleContainer &style() const;
+
     const LayoutData *currentLayoutModel() const;
 
     /*!
@@ -411,7 +429,18 @@
     // keyboard
     int actualHeight() const;
 
+    //! Connect signals from a \a handle widget or whatever provides identical flick signals
+    template <class T>
+    void connectHandle(const T &handleLike);
+
 private:
+    //! Main layout indices
+    enum LayoutIndex {
+        SharedHandleAreaIndex,
+        KeyboardHandleIndex,
+        KeyboardIndex
+    };
+
     //! Keyboard state wrt. \a showKeyboard / \a hideKeyboard calls.
     enum Activity {
         Active,                 // After showKeyboard call
@@ -445,7 +474,7 @@
     Activity activity;
 
     //! Current Style being used
-    MVirtualKeyboardStyleContainer *styleContainer;
+    const MVirtualKeyboardStyleContainer *styleContainer;
 
     //! Scene manager to get the device width and height
     MSceneManager *sceneManager;
@@ -487,7 +516,15 @@
     QSharedPointer<QPixmap> backgroundPixmap;
 
     MIMHandlerState activeState;
+
+    KeyEventHandler *eventHandler;
+
+    //! Contains true if multi-touch is enabled
+    bool enableMultiTouch;
+
+    //! Handle area (to be) shared between symbol view and virtual keyboard
+    //! TODO: move this to host
+    SharedHandleArea *sharedHandleArea;
 };
 
 #endif
-
--- m-keyboard/widgets/mvirtualkeyboardstyle.h
+++ m-keyboard/widgets/mvirtualkeyboardstyle.h
@@ -69,9 +69,15 @@
     M_STYLE_ATTRIBUTE(QString, keyBackgroundId, KeyBackgroundId)
     M_STYLE_ATTRIBUTE(QString, keyBackgroundPressedId, KeyBackgroundPressedId)
     M_STYLE_ATTRIBUTE(QString, keyBackgroundSelectedId, KeyBackgroundSelectedId)
+    M_STYLE_ATTRIBUTE(int, keyBackgroundBorderLeft, KeyBackgroundBorderLeft)
+    M_STYLE_ATTRIBUTE(int, keyBackgroundBorderRight, KeyBackgroundBorderRight)
+    M_STYLE_ATTRIBUTE(int, keyBackgroundBorderTop, KeyBackgroundBorderTop)
+    M_STYLE_ATTRIBUTE(int, keyBackgroundBorderBottom, KeyBackgroundBorderBottom)
 
     M_STYLE_PTR_ATTRIBUTE(MScalableImage *, keyBackgroundSymIndicatorSym, KeyBackgroundSymIndicatorSym)
     M_STYLE_PTR_ATTRIBUTE(MScalableImage *, keyBackgroundSymIndicatorAce, KeyBackgroundSymIndicatorAce)
+    M_STYLE_PTR_ATTRIBUTE(MScalableImage *, keyBackgroundSymIndicatorSymPressed, KeyBackgroundSymIndicatorSymPressed)
+    M_STYLE_PTR_ATTRIBUTE(MScalableImage *, keyBackgroundSymIndicatorAcePressed, KeyBackgroundSymIndicatorAcePressed)
 
     M_STYLE_ATTRIBUTE(QSize, keyBackspaceIconSize, KeyBackspaceIconSize)
     M_STYLE_ATTRIBUTE(QString, keyBackspaceIconId, KeyBackspaceIconId)
--- m-keyboard/widgets/notification.cpp
+++ m-keyboard/widgets/notification.cpp
@@ -35,7 +35,7 @@
 };
 
 
-Notification::Notification(MVirtualKeyboardStyleContainer *style, QGraphicsWidget *parent)
+Notification::Notification(const MVirtualKeyboardStyleContainer *style, QGraphicsWidget *parent)
     : MWidget(parent),
       styleContainer(style)
 {
--- m-keyboard/widgets/notification.h
+++ m-keyboard/widgets/notification.h
@@ -42,7 +42,7 @@
      * \brief Constructor for creating notification object.
      * \param parent QGraphicsWidget.
      */
-    Notification(MVirtualKeyboardStyleContainer *style, QGraphicsWidget *parent);
+    Notification(const MVirtualKeyboardStyleContainer *style, QGraphicsWidget *parent);
 
     //! Destructor
     ~Notification();
@@ -91,7 +91,7 @@
     QFont font;
 
     //! CSS style container
-    MVirtualKeyboardStyleContainer *styleContainer;
+    const MVirtualKeyboardStyleContainer *styleContainer;
 
     //! CSS attributes
     QColor border;
--- m-keyboard/widgets/sharedhandlearea.cpp
+++ m-keyboard/widgets/sharedhandlearea.cpp
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#include "grip.h"
+#include "handle.h"
+#include "mimtoolbar.h"
+#include "sharedhandlearea.h"
+
+#include <QDebug>
+#include <QGraphicsLinearLayout>
+
+
+SharedHandleArea::SharedHandleArea(MImToolbar &toolbar, QGraphicsWidget *parent)
+    : MWidget(parent),
+      mainLayout(*new QGraphicsLinearLayout(Qt::Vertical, this)),
+      invisibleHandle(*new Handle(this)),
+      toolbarGrip(*new Grip(this)),
+      zeroSizeToolbarGrip(*new QGraphicsWidget(this)),
+      zeroSizeInvisibleHandle(*new QGraphicsWidget(this))
+{
+    mainLayout.setContentsMargins(0, 0, 0, 0);
+    mainLayout.setSpacing(0);
+
+    invisibleHandle.setObjectName("InvisibleHandle");
+    invisibleHandle.hide();
+    zeroSizeInvisibleHandle.setMaximumSize(0, 0);
+    zeroSizeInvisibleHandle.show();
+    mainLayout.addItem(&zeroSizeInvisibleHandle);
+    connectHandle(invisibleHandle);
+
+    toolbarGrip.setObjectName("KeyboardToolbarHandle");
+    toolbarGrip.hide();
+    zeroSizeToolbarGrip.setMaximumSize(0, 0);
+    zeroSizeToolbarGrip.show();
+    mainLayout.addItem(&zeroSizeToolbarGrip);
+    connectHandle(toolbarGrip);
+
+    connect(&toolbar, SIGNAL(availabilityChanged(bool)), this, SLOT(handleToolbarAvailability(bool)));
+
+    Handle &toolbarHandle = *new Handle(this);
+    toolbarHandle.setObjectName("KeyboardToolbarBackgroundHandle");
+    toolbarHandle.setChild(&toolbar);
+    connectHandle(toolbarHandle);
+
+    mainLayout.addItem(&toolbarHandle);
+    mainLayout.setAlignment(&toolbarHandle, Qt::AlignCenter);
+
+    connect(&toolbar, SIGNAL(regionUpdated()), this, SIGNAL(regionUpdated()));
+}
+
+
+SharedHandleArea::~SharedHandleArea()
+{
+}
+
+
+void SharedHandleArea::handleToolbarAvailability(const bool available)
+{
+    QGraphicsWidget &previousItem(*dynamic_cast<QGraphicsWidget *>(
+                                      mainLayout.itemAt(ToolbarHandleIndex)));
+    mainLayout.removeItem(&previousItem);
+    previousItem.hide();
+    QGraphicsWidget &newItem(available ? toolbarGrip : zeroSizeToolbarGrip);
+    mainLayout.insertItem(ToolbarHandleIndex, &newItem);
+    newItem.setVisible(available);
+    emit regionUpdated();
+}
+
+
+void SharedHandleArea::connectHandle(const Handle &handle)
+{
+    connect(&handle, SIGNAL(flickLeft(const FlickGesture &)), this, SIGNAL(flickLeft(const FlickGesture &)));
+    connect(&handle, SIGNAL(flickRight(const FlickGesture &)), this, SIGNAL(flickRight(const FlickGesture &)));
+    connect(&handle, SIGNAL(flickUp(const FlickGesture &)), this, SIGNAL(flickUp(const FlickGesture &)));
+    connect(&handle, SIGNAL(flickDown(const FlickGesture &)), this, SIGNAL(flickDown(const FlickGesture &)));
+}
+
+
+void SharedHandleArea::setInputMethodMode(const M::InputMethodMode mode)
+{
+    // Toggle invisible gesture handle area on/off
+    QGraphicsWidget &previousItem(*dynamic_cast<QGraphicsWidget *>(
+                                      mainLayout.itemAt(InvisibleHandleIndex)));
+    mainLayout.removeItem(&previousItem);
+    previousItem.hide();
+    QGraphicsWidget &newItem(mode == M::InputMethodModeDirect ? invisibleHandle : zeroSizeInvisibleHandle);
+    mainLayout.insertItem(InvisibleHandleIndex, &newItem);
+    newItem.setVisible(mode == M::InputMethodModeDirect);
+    emit regionUpdated();
+}
+
+
+QRegion SharedHandleArea::region(const bool includeExtraInteractiveAreas) const
+{
+    QRegion region(mapRectToScene(mainLayout.itemAt(ToolbarHandleIndex)->geometry()).toRect());
+
+    region |= mapRectToScene(mainLayout.itemAt(ToolbarIndex)->geometry()).toRect();
+
+    if (includeExtraInteractiveAreas) {
+        region |= mapRectToScene(mainLayout.itemAt(InvisibleHandleIndex)->geometry()).toRect();
+    }
+
+    return region;
+}
--- m-keyboard/widgets/sharedhandlearea.h
+++ m-keyboard/widgets/sharedhandlearea.h
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#ifndef SHAREDHANDLEAREA_H
+#define SHAREDHANDLEAREA_H
+
+#include <MWidget>
+#include <MNamespace>
+
+class QGraphicsLinearLayout;
+class FlickGesture;
+class MImToolbar;
+class Handle;
+class Grip;
+
+/*!
+  \brief SharedHandleArea represents the handle area shared between the vkb and the symbol
+  view
+
+  The shared handle area contains an invisible handle, toolbar grip and the toolbar (as a
+  child of a handle), in that order.
+*/
+class SharedHandleArea : public MWidget
+{
+    Q_OBJECT
+
+public:
+    /*!
+     * \brief Constructor
+     * \param toolbar toolbar widget
+     * \param parent Parent object.
+     */
+    explicit SharedHandleArea(MImToolbar &toolbar, QGraphicsWidget *parent = 0);
+
+    //! Destructor
+    virtual ~SharedHandleArea();
+
+    //! Set input method mode
+    void setInputMethodMode(M::InputMethodMode mode);
+
+    //! \return region of the widget, including the invisible handle if
+    //! \a includeExtraInteractiveAreas is true
+    QRegion region(bool includeExtraInteractiveAreas = false) const;
+
+signals:
+    void flickUp(const FlickGesture &gesture);
+    void flickDown(const FlickGesture &gesture);
+    void flickLeft(const FlickGesture &gesture);
+    void flickRight(const FlickGesture &gesture);
+
+    void regionUpdated();
+
+private slots:
+    //! Handle changes in toolbar availability
+    void handleToolbarAvailability(bool available);
+
+private:
+    //! Connect signals from a \a handle widget
+    void connectHandle(const Handle &handle);
+
+private:
+    enum LayoutIndex {
+        InvisibleHandleIndex,
+        ToolbarHandleIndex,
+        ToolbarIndex,
+    };
+
+    QGraphicsLinearLayout &mainLayout;
+
+    //! Invisible gesture handle used only in direct mode
+    Handle &invisibleHandle;
+
+    //! Toolbar grip
+    Grip &toolbarGrip;
+
+    //! Dummy widget we use in place of toolbarGrip in the layout when it's not visible
+    QGraphicsWidget &zeroSizeToolbarGrip;
+
+    //! Dummy widget we use in place of the invisible gesture handle when it's
+    //! not ... err, visible (in its usual invisible way)
+    QGraphicsWidget &zeroSizeInvisibleHandle;
+};
+
+#endif
--- m-keyboard/widgets/singlewidgetbutton.cpp
+++ m-keyboard/widgets/singlewidgetbutton.cpp
@@ -27,7 +27,8 @@
 SingleWidgetButton::SingleWidgetButton(const VKBDataKey &key,
                                        const MVirtualKeyboardStyleContainer &style,
                                        QGraphicsItem &parent)
-    : dataKey(key),
+    : width(0),
+      dataKey(key),
       shift(false),
       currentLabel(dataKey.binding(false)->label()),
       currentState(Normal),
--- m-keyboard/widgets/singlewidgetbuttonarea.cpp
+++ m-keyboard/widgets/singlewidgetbuttonarea.cpp
@@ -37,7 +37,7 @@
 #include <mreactionmap.h>
 #include <MTheme>
 
-SingleWidgetButtonArea::SingleWidgetButtonArea(MVirtualKeyboardStyleContainer *style,
+SingleWidgetButtonArea::SingleWidgetButtonArea(const MVirtualKeyboardStyleContainer *style,
                                                QSharedPointer<const LayoutSection> sectionModel,
                                                ButtonSizeScheme buttonSizeScheme,
                                                bool usePopup,
@@ -47,7 +47,7 @@
       rowList(sectionModel->rowCount()),
       symState(SymIndicatorInactive),
       symIndicatorButton(0),
-      shiftCapsLock(false),
+      shiftButton(0),
       pixmap1(0),
       pixmap2(0),
       pixmap3(0),
@@ -98,21 +98,22 @@
     pixmap2 = MTheme::pixmap(style()->keyBackgroundPressedId(), defaultSize);
     pixmap3 = MTheme::pixmap(style()->keyBackgroundSelectedId(), defaultSize);
 
-    keyBackgrounds[0].setPixmap(pixmap1); // normal
-    keyBackgrounds[1].setPixmap(pixmap2); // pressed
-    keyBackgrounds[2].setPixmap(pixmap3); // selected
-
-    // Border size 10 is suitable for all sane size buttons we're using.
-    const int border = 10;
-    keyBackgrounds[0].setBorders(border, border, border, border);
-    keyBackgrounds[1].setBorders(border, border, border, border);
-    keyBackgrounds[2].setBorders(border, border, border, border);
+    keyBackgrounds[NormalBackground].setPixmap(pixmap1);
+    keyBackgrounds[KeyPressedBackground].setPixmap(pixmap2);
+    keyBackgrounds[KeySelectedBackground].setPixmap(pixmap3);
+
+    for (int idx = 0; idx < KeyBackgroundTypeCount; ++idx) {
+        keyBackgrounds[idx].setBorders(style()->keyBackgroundBorderLeft(),
+                                       style()->keyBackgroundBorderRight(),
+                                       style()->keyBackgroundBorderTop(),
+                                       style()->keyBackgroundBorderBottom());
+    }
 }
 
 SingleWidgetButtonArea::~SingleWidgetButtonArea()
 {
     // Release any key that might be pressed before destroying them.
-    setActiveKey(0);
+    clearActiveKeys();
 
     for (RowIterator rowIter(rowList.begin()); rowIter != rowList.end(); ++rowIter) {
         qDeleteAll(rowIter->buttons);
@@ -385,6 +386,7 @@
         buildTextLayout();
     }
     // Draw text next.
+    painter->setPen(style()->fontColor());
     textLayout.draw(painter, QPoint());
 }
 
@@ -431,11 +433,22 @@
     return 0;
 }
 
+void SingleWidgetButtonArea::setShiftStatus(bool shiftOn, bool capslock)
+{
+    if (shiftButton) {
+        shiftButton->setModifiers(shiftOn);
+        shiftButton->setSelected(capslock);
+    }
+}
+
 void SingleWidgetButtonArea::modifiersChanged(const bool shift, const QChar accent)
 {
     for (RowIterator row(rowList.begin()); row != rowList.end(); ++row) {
         foreach (SingleWidgetButton *button, row->buttons) {
-            button->setModifiers(shift, accent);
+            // Shift button is separated from the normal level changing.
+            if (button != this->shiftButton) {
+                button->setModifiers(shift, accent);
+            }
         }
     }
 
@@ -534,42 +547,33 @@
 
 ISymIndicator *SingleWidgetButtonArea::symIndicator()
 {
-	return this;
+    return this;
 }
 
 // ISymIndicator implementation
 void SingleWidgetButtonArea::activateSymIndicator()
 {
-    // Use same image for all button states for now. Some different graphics may
-    // be introduced later for the intermediate step between sym and ace modes.
-    // while holding button down.
-	const MScalableImage *image = style()->keyBackgroundSymIndicatorSym();
-    symIndicatorBackgrounds[0] = image;
-    symIndicatorBackgrounds[1] = image;
-    symIndicatorBackgrounds[2] = image;
-    update();
+    updateIndicatorBackgrounds(style()->keyBackgroundSymIndicatorSym(),
+                               style()->keyBackgroundSymIndicatorSymPressed());
 
     if (symState == SymIndicatorInactive) {
         // We have changed the text. Sym has two-line text in active mode.
         textDirty = true;
     }
-    symState = AceActive;
+    symState = SymActive;
 }
 
 // ISymIndicator implementation
 void SingleWidgetButtonArea::activateAceIndicator()
 {
-    const MScalableImage *image = style()->keyBackgroundSymIndicatorAce();
-    symIndicatorBackgrounds[0] = image;
-    symIndicatorBackgrounds[1] = image;
-    symIndicatorBackgrounds[2] = image;
-    update();
+    updateIndicatorBackgrounds(style()->keyBackgroundSymIndicatorAce(),
+                               style()->keyBackgroundSymIndicatorAcePressed());
 
     if (symState == SymIndicatorInactive) {
         // We have changed the text. Sym has two-line text in active mode.
         textDirty = true;
     }
-    symState = SymActive;
+    symState = AceActive;
 }
 
 // ISymIndicator implementation
@@ -583,3 +587,28 @@
     }
 }
 
+void SingleWidgetButtonArea::updateIndicatorBackgrounds(const MScalableImage *normal, const MScalableImage *pressed)
+{
+    // Use same image for all button states for now. Some different graphics may
+    // be introduced later for the intermediate step between sym and ace modes.
+    // while holding button down.
+    symIndicatorBackgrounds[NormalBackground] = normal;
+    symIndicatorBackgrounds[KeyPressedBackground] = pressed;
+    symIndicatorBackgrounds[KeySelectedBackground] = normal;
+    update();
+}
+
+void SingleWidgetButtonArea::onThemeChangeCompleted()
+{
+    KeyButtonArea::onThemeChangeCompleted();
+
+    if (symState == SymActive) {
+        updateIndicatorBackgrounds(style()->keyBackgroundSymIndicatorSym(),
+                                   style()->keyBackgroundSymIndicatorSymPressed());
+    } else if (symState == AceActive) {
+        updateIndicatorBackgrounds(style()->keyBackgroundSymIndicatorAce(),
+                                   style()->keyBackgroundSymIndicatorAcePressed());
+    }
+
+    buildTextLayout();
+}
--- m-keyboard/widgets/singlewidgetbuttonarea.h
+++ m-keyboard/widgets/singlewidgetbuttonarea.h
@@ -33,7 +33,16 @@
 class SingleWidgetButtonArea : public KeyButtonArea, public ISymIndicator
 {
 public:
-    SingleWidgetButtonArea(MVirtualKeyboardStyleContainer *,
+    //! Used to differentiate background images of a button.
+    enum KeyBackgroundType {
+        NormalBackground = 0,
+        KeyPressedBackground = 1,
+        KeySelectedBackground = 2,
+
+        KeyBackgroundTypeCount
+    };
+
+    SingleWidgetButtonArea(const MVirtualKeyboardStyleContainer *,
                            QSharedPointer<const LayoutSection>,
                            ButtonSizeScheme buttonSizeScheme = ButtonSizeEqualExpanding,
                            bool usePopup = false,
@@ -45,6 +54,7 @@
     virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *view);
     virtual QRectF boundingRect() const;
     virtual ISymIndicator *symIndicator();
+    virtual void setShiftStatus(bool shiftOn, bool capslock);
 
     // From ISymIndicator
     virtual void activateSymIndicator();
@@ -59,6 +69,7 @@
     virtual void updateButtonGeometries(int availableWidth, int equalButtonWidth);
     virtual IKeyButton *keyAt(const QPoint &pos) const;
     virtual void modifiersChanged(bool shift, QChar accent = QChar());
+    virtual void onThemeChangeCompleted();
     /*! \reimp_end */
 
 private:
@@ -78,6 +89,9 @@
     //! \brief Fetches optimum size image from MTheme to be used in MScalableImage.
     void fetchOptimumSizeButtonBackgrounds(QSize size);
 
+    //! \brief Update indicator backgrounds from current theme.
+    void updateIndicatorBackgrounds(const MScalableImage *normal, const MScalableImage *pressed);
+
     struct ButtonRow {
         QList<SingleWidgetButton*> buttons;
 
@@ -89,7 +103,7 @@
         int offset;
         int cachedWidth; // includes left & right margin
     };
-    
+
     typedef QVector<ButtonRow> ButtonRowList;
     typedef ButtonRowList::iterator RowIterator;
     typedef ButtonRowList::const_iterator ConstRowIterator;
@@ -98,10 +112,10 @@
     ButtonRowList rowList;
 
     //! Normal button backgrounds
-    MScalableImage keyBackgrounds[3];
+    MScalableImage keyBackgrounds[KeyBackgroundTypeCount];
 
     //! Special set of button backgrounds for sym state indicator.
-    const MScalableImage *symIndicatorBackgrounds[3];
+    const MScalableImage *symIndicatorBackgrounds[KeyBackgroundTypeCount];
 
     //! Current state of the sym indicator
     SymIndicatorState symState;
@@ -110,7 +124,8 @@
     //! if such exists in the current layout.
     const SingleWidgetButton *symIndicatorButton;
 
-    bool shiftCapsLock;
+    //! Shift button is stored here if current layout has a shift button.
+    SingleWidgetButton *shiftButton;
 
     const QPixmap *pixmap1;
     const QPixmap *pixmap2;
@@ -123,6 +138,7 @@
 
 #ifdef UNIT_TEST
     friend class Ut_KeyButtonArea;
+    friend class Ut_KeyEventHandler;
     friend class Bm_KeyButtonArea; //benchmarks
 #endif
 
--- m-keyboard/widgets/symbolview.cpp
+++ m-keyboard/widgets/symbolview.cpp
@@ -20,6 +20,8 @@
 #include "horizontalswitcher.h"
 #include "layoutsmanager.h"
 #include "symbolview.h"
+#include "keyeventhandler.h"
+#include "grip.h"
 
 #include <MSceneManager>
 #include <MScalableImage>
@@ -49,11 +51,14 @@
     const QString ObjectNameCloseButton("VirtualKeyboardCloseButton");
 
     const QString SymCloseIcon("icon-m-input-methods-close");
+
+    // This GConf item defines whether multitouch is enabled or disabled
+    const char * const MultitouchSettings = "/meegotouch/inputmethods/multitouch/enabled";
 };
 
 
 
-SymbolView::SymbolView(const LayoutsManager &layoutsManager, MVirtualKeyboardStyleContainer *style,
+SymbolView::SymbolView(const LayoutsManager &layoutsManager, const MVirtualKeyboardStyleContainer *style,
                        const QString &language, QGraphicsWidget *parent)
     : MWidget(parent),
       styleContainer(style),
@@ -62,6 +67,8 @@
       activity(Inactive),
       activePage(0),
       shift(0),
+      shiftHeldDown(false),
+      ignoreShiftClick(false),
       layoutsMgr(layoutsManager),
       pageSwitcher(0),
       functionRow(0),
@@ -71,6 +78,18 @@
       verticalLayout(*new QGraphicsLinearLayout(Qt::Vertical, this)),
       keyAreaLayout(*new QGraphicsLinearLayout(Qt::Vertical))
 {
+    eventHandler = new KeyEventHandler(this);
+    connect(eventHandler, SIGNAL(keyPressed(const KeyEvent &)),
+            this, SIGNAL(keyPressed(const KeyEvent &)));
+    connect(eventHandler, SIGNAL(keyReleased(const KeyEvent &)),
+            this, SIGNAL(keyReleased(const KeyEvent &)));
+    connect(eventHandler, SIGNAL(keyClicked(const KeyEvent &)),
+            this, SIGNAL(keyClicked(const KeyEvent &)));
+    connect(eventHandler, SIGNAL(shiftPressed(bool)),
+            this, SLOT(setFunctionRowState(bool)));
+
+    enableMultiTouch = MGConfItem(MultitouchSettings).value().toBool();
+
     hide();
     setupShowAndHide();
     setupLayout();
@@ -99,6 +118,11 @@
     verticalLayout.setSpacing(0);
     verticalLayout.setContentsMargins(0, 0, 0, 0);
 
+    Grip &symbolViewGrip = *new Grip(this);
+    symbolViewGrip.setObjectName("KeyboardHandle");
+    verticalLayout.addItem(&symbolViewGrip);
+    connectHandle(symbolViewGrip);
+
     keyAreaLayout.setSpacing(style()->spacingVertical());
     keyAreaLayout.setContentsMargins(style()->paddingLeft(), style()->paddingTop(),
                                      style()->paddingRight(), style()->paddingBottom());
@@ -106,6 +130,14 @@
     verticalLayout.addItem(&keyAreaLayout);
 }
 
+
+void SymbolView::connectHandle(const Handle &handle)
+{
+    connect(&handle, SIGNAL(flickLeft(const FlickGesture &)), this, SLOT(switchToNextPage()));
+    connect(&handle, SIGNAL(flickRight(const FlickGesture &)), this, SLOT(switchToPrevPage()));
+    connect(&handle, SIGNAL(flickDown(const FlickGesture &)), this, SLOT(hideSymbolView()));
+}
+
 void SymbolView::reloadContent()
 {
     // Get layout model which for current language and orientation.
@@ -280,11 +312,6 @@
 
     showTimeLine->start();
 
-    if (mode == FollowMouseShowMode) {
-        pageSwitcher->currentWidget()->grabMouse();
-        mouseDownKeyArea = true;
-    }
-
     emit showingUp();
 }
 
@@ -317,8 +344,9 @@
         pageSwitcher->setCurrent(0);
         showSymbolView();
     } else {
+        pageSwitcher->switchTo(id < activePage ? HorizontalSwitcher::Left
+                                               : HorizontalSwitcher::Right);
         activePage = id;
-        pageSwitcher->switchTo(activePage);
     }
 
     selectedLayout = qobject_cast<KeyButtonArea *>(pageSwitcher->currentWidget());
@@ -381,9 +409,9 @@
 
     functionRow = createKeyButtonArea(layout.section(LayoutData::functionkeySection),
                                       KeyButtonArea::ButtonSizeFunctionRow, false);
-    functionRow->setObjectName("SymbolFunctionRow");
 
     if (functionRow) {
+        functionRow->setObjectName("SymbolFunctionRow");
         functionRow->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
         keyAreaLayout.addItem(functionRow);
     }
@@ -392,9 +420,12 @@
 void SymbolView::addPage(QSharedPointer<const LayoutSection> symbolSection)
 {
     KeyButtonArea *page = createKeyButtonArea(symbolSection);
-    page->setObjectName("SymbolMainRow");
 
     if (page) {
+        page->setObjectName("SymbolMainRow");
+
+        connect(this, SIGNAL(levelSwitched(int)), page, SLOT(switchLevel(int)));
+
         connect(page, SIGNAL(flickLeft()), SLOT(switchToNextPage()));
         connect(page, SIGNAL(flickRight()), SLOT(switchToPrevPage()));
         connect(page, SIGNAL(flickDown()), SLOT(hideSymbolView()));
@@ -420,14 +451,7 @@
         keysWidget = new SingleWidgetButtonArea(styleContainer, section, sizeScheme, enablePopup);
         keysWidget->setFont(style()->font());
 
-        connect(this, SIGNAL(levelSwitched(int, bool)), keysWidget, SLOT(switchLevel(int, bool)));
-
-        connect(keysWidget, SIGNAL(keyClicked(const KeyEvent &)),
-                SIGNAL(keyClicked(const KeyEvent &)));
-        connect(keysWidget, SIGNAL(keyPressed(const KeyEvent &)),
-                SIGNAL(keyPressed(const KeyEvent &)));
-        connect(keysWidget, SIGNAL(keyReleased(const KeyEvent &)),
-                SIGNAL(keyReleased(const KeyEvent &)));
+        eventHandler->addEventSource(keysWidget);
     }
     return keysWidget;
 }
@@ -449,14 +473,23 @@
     reposition(size().toSize().height());
 }
 
-
-void SymbolView::switchLevel(int level, bool capslock)
+void SymbolView::switchLevel(int level)
 {
     shift = level;
-    emit levelSwitched(shift, capslock);
+    if (!enableMultiTouch && functionRow) {
+        functionRow->switchLevel(level);
+    }
+    emit levelSwitched(shift);
     updateSymIndicator();
 }
 
+void SymbolView::setShiftStatus(bool shiftOn, bool capslock)
+{
+    if (functionRow) {
+        functionRow->setShiftStatus(shiftOn, capslock);
+    }
+}
+
 int SymbolView::currentLevel() const
 {
     return shift;
@@ -464,7 +497,7 @@
 
 void SymbolView::setLanguage(const QString &lang)
 {
-    if (lang != currentLanguage) {
+    if (lang != currentLanguage && layoutsMgr.languageList().contains(lang)) {
         currentLanguage = lang;
         reloadContent();
     }
@@ -529,6 +562,13 @@
     }
 }
 
+void SymbolView::setFunctionRowState(bool shiftPressed)
+{
+    if (enableMultiTouch && functionRow) {
+        functionRow->switchLevel(shiftPressed ? 1 : 0);
+    }
+}
+
 void SymbolView::redrawReactionMaps()
 {
     if (!scene()) {
@@ -567,7 +607,7 @@
 }
 
 
-MVirtualKeyboardStyleContainer &SymbolView::style()
+const MVirtualKeyboardStyleContainer &SymbolView::style() const
 {
     return *styleContainer;
 }
@@ -605,7 +645,7 @@
     ISymIndicator *symIndicator = functionRow->symIndicator();
 
      if (symIndicator) {
-         if (currentLevel() == 0) {
+         if (functionRow->level() == 0) {
              QString title = pageTitle(activePage);
 
              if (title == SymLabel) {
@@ -627,8 +667,7 @@
 
     // SymbolView always occupies the same area if opened.
     if (isActive()) {
-        // add sym characters and function row
-        region |= mapRectToScene(keyAreaLayout.geometry()).toRect();
+        region |= mapRectToScene(verticalLayout.geometry()).toRect();
     }
 
     return region;
--- m-keyboard/widgets/symbolview.h
+++ m-keyboard/widgets/symbolview.h
@@ -39,7 +39,8 @@
 class KeyEvent;
 class LayoutSection;
 class SymIndicatorButton;
-
+class KeyEventHandler;
+class Handle;
 
 /*!
  * \brief SymbolView is used to show different layouts symbols/upper case/lower case
@@ -64,7 +65,7 @@
      * \param baseSize QSize
      * \param parent Parent object.
      */
-    SymbolView(const LayoutsManager &layoutsManager, MVirtualKeyboardStyleContainer *,
+    SymbolView(const LayoutsManager &layoutsManager, const MVirtualKeyboardStyleContainer *,
                const QString &language, QGraphicsWidget *parent = 0);
 
     /*!
@@ -77,11 +78,12 @@
     void finalizeOrientationChange();
 
     /*!
-    * Method to switch layout when shift button is pressed
+    * Method to switch layout level when shift button is pressed
     * \param level int 1 for upper case, otherwise 0
-    * \param capslock Shift locked state
     */
-    void switchLevel(int level, bool capslock);
+    void switchLevel(int level);
+
+    void setShiftStatus(bool shiftOn, bool capslock);
 
     //! Returns current level.
     int currentLevel() const;
@@ -156,7 +158,7 @@
 
 signals:
     //! Used to broadcast shift state to all pages/KeyButtonAreas.
-    void levelSwitched(int, bool);
+    void levelSwitched(int);
 
     /*!
      * Emitted on clicked on layout
@@ -203,6 +205,12 @@
     void onSwitchStarting(QGraphicsWidget *current, QGraphicsWidget *next);
     void switchDone();
 
+    /*!
+     * \brief Switch function row to upper/lower case
+     * according to given parameter
+     */
+    void setFunctionRowState(bool shiftPressed);
+
 private:
     //! symbol view state wrt. \a showSymbolView / \a hideSymbolView calls.
     enum Activity {
@@ -245,7 +253,7 @@
                                        bool enablePopup = true);
 
     //! Getter for style container
-    MVirtualKeyboardStyleContainer &style();
+    const MVirtualKeyboardStyleContainer &style() const;
 
     //! Retrieves title of a symbol section from given page.
     QString pageTitle(int pageIndex) const;
@@ -253,9 +261,12 @@
     //! \brief Updates the Sym button to visually indicate the current active page.
     void updateSymIndicator();
 
+    //! Connect signals from a \a handle widget
+    void connectHandle(const Handle &handle);
+
 private:
     //! Current style being used.
-    MVirtualKeyboardStyleContainer *styleContainer;
+    const MVirtualKeyboardStyleContainer *styleContainer;
 
     //! Manage animation
     QGraphicsItemAnimation *showAnimation;
@@ -279,6 +290,12 @@
     //! Case selector: 0 for lower case, 1 for upper case
     int shift;
 
+    //! Keeps track of shift up/down status.
+    bool shiftHeldDown;
+
+    //! When this is set true the next shift click is ignored.
+    bool ignoreShiftClick;
+
     const LayoutsManager &layoutsMgr;
 
     HorizontalSwitcher *pageSwitcher;
@@ -300,6 +317,12 @@
     //! This layout holds symbol characters and function row.
     QGraphicsLinearLayout &keyAreaLayout;
 
+    //! Pointer to handler for button events
+    KeyEventHandler *eventHandler;
+
+    //! Contains true if multi-touch is enabled
+    bool enableMultiTouch;
+
 #ifdef UNIT_TEST
     friend class Ut_SymbolView;
 #endif
--- m-keyboard/widgets/widgetbar.cpp
+++ m-keyboard/widgets/widgetbar.cpp
@@ -63,6 +63,11 @@
 
     mainLayout.insertItem(index, widget);
     mainLayout.setAlignment(widget, Qt::AlignVCenter); // In case we have widgets that differs in height.
+
+    if (-1 != widget->metaObject()->indexOfSignal("availabilityChanged()")) {
+        connect(widget, SIGNAL(availabilityChanged()),
+                this, SLOT(updateLayout()));
+    }
 }
 
 void WidgetBar::append(MWidget *widget)
@@ -74,10 +79,17 @@
 {
     mainLayout.removeItem(widget);
     widgets.removeOne(widget);
+    disconnect(widget, 0, this, 0);
 }
 
 void WidgetBar::clear()
 {
+    foreach (QPointer<MWidget> widget, widgets) {
+        if (widget) {
+            disconnect(widget, 0, this, 0);
+        }
+    }
+
     widgets.clear();
     while (mainLayout.count() > 0) {
         mainLayout.removeAt(0);
@@ -103,6 +115,11 @@
     return widgets.indexOf(const_cast<MWidget *>(widget));
 }
 
+void WidgetBar::cleanup()
+{
+    widgets.removeAll(QPointer<MWidget>());
+}
+
 void WidgetBar::mousePressEvent(QGraphicsSceneMouseEvent *)
 {
     // Stop propagating
@@ -114,3 +131,61 @@
                        style()->paddingRight(), 0);
 }
 
+QSizeF WidgetBar::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
+{
+    // if there is no visible items in the widgetbar, just return empty size.
+    if (count() <= 0)
+        return QSizeF(0, 0);
+    else
+        return MStylableWidget::sizeHint(which, constraint);
+}
+
+void WidgetBar::updateLayout()
+{
+    MWidget *widget = qobject_cast<MWidget *>(sender());
+
+    if (!widget) {
+        return;
+    }
+
+    int index = widgets.indexOf(widget);
+
+    if (index < 0) {
+        return;
+    }
+
+    if (!widget->isVisible()) {
+        //widget is hidden, so just remove it from layout
+        mainLayout.removeItem(widget);
+    } else {
+        //widget is shown, so put it into layout before closest
+        //visible neighbor on right side
+
+        //find next visible widget
+        ++index;
+        while (index < widgets.count() && !widgets.at(index)->isVisible()) {
+            ++index;
+        }
+        int layoutIndex = 0;
+        if (index < widgets.count()) {
+            //get index of found widget from the layout
+            layoutIndex = layoutIndexOf(widgets.at(index));
+        } else {
+            layoutIndex = mainLayout.count();
+        }
+        mainLayout.insertItem(layoutIndex, widget);
+    }
+}
+
+int WidgetBar::layoutIndexOf(const MWidget *widget) const
+{
+    int layoutIndex = 0;
+
+    while (layoutIndex < mainLayout.count()
+            && mainLayout.itemAt(layoutIndex) != widget) {
+        ++layoutIndex;
+    }
+
+    return layoutIndex;
+}
+
--- m-keyboard/widgets/widgetbar.h
+++ m-keyboard/widgets/widgetbar.h
@@ -24,6 +24,7 @@
 #include <MStylableWidget>
 
 #include <QList>
+#include <QPointer>
 
 class MWidget;
 class QGraphicsLinearLayout;
@@ -47,6 +48,8 @@
     int count() const;
 
     //! \brief Inserts a \a widget to specified \a index.
+    //!
+    //! \a widget must provide availabilityChanged() signal.
     void insert(int index, MWidget *widget);
 
     //! \brief Appends \a widget to the right end of the row.
@@ -68,6 +71,19 @@
     // if widget was not found
     int indexOf(const MWidget *widget) const;
 
+    //! Remove all pointers to destroyed widgets from
+    // internal lists
+    void cleanup();
+
+public:
+    //! \reimp
+    virtual QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
+    //! \reimp_end
+
+private slots:
+    //! Update layout when some child widget is shown or hidden.
+    void updateLayout();
+
 protected:
     //! \reimp
     virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
@@ -75,7 +91,11 @@
     //! \reimp_end
 
 private:
-    typedef QList<MWidget *> WidgetList;
+    //! Return index of given \a widget inside layout
+    int layoutIndexOf(const MWidget *widget) const;
+
+private:
+    typedef QList<QPointer<MWidget> > WidgetList;
 
     QGraphicsLinearLayout &mainLayout;
 
@@ -84,6 +104,8 @@
     WidgetList widgets;
 
     M_STYLABLE_WIDGET(WidgetBarStyle)
+
+    friend class Ut_WidgetBar;
 };
 
 #endif
--- m-keyboard/widgets/widgets.pri
+++ m-keyboard/widgets/widgets.pri
@@ -10,6 +10,8 @@
     $$WIDGETS_DIR/widgetbarstyle.h \
     $$WIDGETS_DIR/flickupbuttonstyle.h \
     $$WIDGETS_DIR/mvirtualkeyboardstyle.h \
+    $$WIDGETS_DIR/handlestyle.h \
+    $$WIDGETS_DIR/mtoolbarbuttonstyle.h \
 
 HEADERS += \
     $$STYLE_HEADERS \
@@ -21,7 +23,6 @@
     $$WIDGETS_DIR/flickupbutton.h \
     $$WIDGETS_DIR/flickupbuttonview.h \
     $$WIDGETS_DIR/horizontalswitcher.h \
-    $$WIDGETS_DIR/layoutmenu.h \
     $$WIDGETS_DIR/notification.h \
     $$WIDGETS_DIR/symbolview.h \
     $$WIDGETS_DIR/keybuttonarea.h \
@@ -33,6 +34,13 @@
     $$WIDGETS_DIR/popupfactory.h \
     $$WIDGETS_DIR/popupplugin.h \
     $$WIDGETS_DIR/mtoolbarbutton.h \
+    $$WIDGETS_DIR/mtoolbarbuttonview.h \
+    $$WIDGETS_DIR/mtoolbarlabel.h \
+    $$WIDGETS_DIR/handle.h \
+    $$WIDGETS_DIR/grip.h \
+    $$WIDGETS_DIR/flickgesture.h \
+    $$WIDGETS_DIR/sharedhandlearea.h \
+    $$WIDGETS_DIR/mkeyboardsettingswidget.h \
 
 
 SOURCES += \
@@ -44,7 +52,6 @@
     $$WIDGETS_DIR/flickupbutton.cpp \
     $$WIDGETS_DIR/flickupbuttonview.cpp \
     $$WIDGETS_DIR/horizontalswitcher.cpp \
-    $$WIDGETS_DIR/layoutmenu.cpp \
     $$WIDGETS_DIR/notification.cpp \
     $$WIDGETS_DIR/symbolview.cpp \
     $$WIDGETS_DIR/keybuttonarea.cpp \
@@ -54,6 +61,13 @@
     $$WIDGETS_DIR/popupbase.cpp \
     $$WIDGETS_DIR/popupfactory.cpp \
     $$WIDGETS_DIR/mtoolbarbutton.cpp \
+    $$WIDGETS_DIR/mtoolbarbuttonview.cpp \
+    $$WIDGETS_DIR/mtoolbarlabel.cpp \
+    $$WIDGETS_DIR/handle.cpp \
+    $$WIDGETS_DIR/grip.cpp \
+    $$WIDGETS_DIR/flickgesture.cpp \
+    $$WIDGETS_DIR/sharedhandlearea.cpp \
+    $$WIDGETS_DIR/mkeyboardsettingswidget.cpp \
 
 INCLUDEPATH += $$WIDGETS_DIR
 DEPENDPATH += $$WIDGETS_DIR
--- meego-keyboard.schemas
+++ meego-keyboard.schemas
@@ -7,7 +7,7 @@
       <owner>meegotouch</owner>
       <type>list</type>
       <list_type>string</list_type>
-      <default>[en,ar,cs,da,de,en,es,fi,fr,it,nl,no,pl,pt,ru,sv]</default>
+      <default>[en_gb,da,de,es,fi,fr,it,ru,sv]</default>
       <locale name="C">
         <short>Language list</short>
         <long>Language list</long>
@@ -19,7 +19,7 @@
       <applyto>/meegotouch/inputmethods/languages/default</applyto>
       <owner>meegotouch</owner>
       <type>string</type>
-      <default>en</default>
+      <default>en_gb</default>
       <locale name="C">
         <short>Default language</short>
         <long>Default language</long>
@@ -31,7 +31,7 @@
       <applyto>/meegotouch/inputmethods/correctionenabled</applyto>
       <owner>meegotouch</owner>
       <type>bool</type>
-      <default>true</default>
+      <default>false</default>
       <locale name="C">
         <short>Whether error correction is enabled</short>
         <long>Whether error correction is enabled</long>
--- translations
+++ translations
+(directory)
--- translations/translations.pro
+++ translations/translations.pro
+LANGUAGES =
+CATALOGNAME = virtual-keyboard
+SOURCEDIR = $$PWD/../m-keyboard/ $$PWD/../m-keyboard/widgets/ $$PWD/../m-keyboard/common/
+TRANSLATIONDIR = $$PWD
+TRANSLATION_INSTALLDIR = /usr/share/l10n/meegotouch
+
+CONFIG += meegotouch_defines meegotouch_translations
--- unit_test/bm_keybuttonarea/bm_keybuttonarea.cpp
+++ unit_test/bm_keybuttonarea/bm_keybuttonarea.cpp
@@ -36,7 +36,6 @@
     MApplication::setLoadMInputContext(false);
     app = new MApplication(argc, app_name);
 
-    MTheme::instance()->loadCSS("/usr/share/meegotouch/virtual-keyboard/css/864x480.css");
     style = new MVirtualKeyboardStyleContainer;
     style->initialize("MVirtualKeyboard", "MVirtualKeyboardView", 0);
 }
--- unit_test/bm_symbols/bm_symbols.cpp
+++ unit_test/bm_symbols/bm_symbols.cpp
@@ -36,7 +36,6 @@
     MApplication::setLoadMInputContext(false);
     app = new MApplication(argc, app_name);
 
-    MTheme::instance()->loadCSS("/usr/share/meegotouch/virtual-keyboard/css/864x480.css");
     style = new MVirtualKeyboardStyleContainer;
     style->initialize("MVirtualKeyboard", "MVirtualKeyboardView", 0);
 }
--- unit_test/common_check.pri
+++ unit_test/common_check.pri
@@ -8,7 +8,7 @@
 check-xml.commands = ../rt.sh $$TARGET
 check-xml.depends += $$TARGET
 
-QMAKE_CLEAN += *.log *.xml *~
+QMAKE_CLEAN += *.log *~
 
 target.path = /usr/lib/meego-keyboard-tests/$$TARGET
 INSTALLS += target
--- unit_test/stubs/mreactionmap_stub.h
+++ unit_test/stubs/mreactionmap_stub.h
@@ -154,6 +154,7 @@
  */
 
 MReactionMap::MReactionMap(QWidget *topLevelWidget, const QString &appIdentifier, QObject *parent)
+    : d(0)
 {
     gMReactionMapStub->mreactionMapConstructor(topLevelWidget, appIdentifier, parent);
 }
--- unit_test/unit_test.pro
+++ unit_test/unit_test.pro
@@ -15,7 +15,6 @@
           ut_horizontalswitcher \
           ut_layoutsmanager \
           ut_mimtoolbar \
-          ut_toolbarmanager \
           ut_mhardwarekeyboard \
           ut_hwkbcharloopsmanager \
           bm_keybuttonarea \
--- unit_test/ut_horizontalswitcher/ut_horizontalswitcher.cpp
+++ unit_test/ut_horizontalswitcher/ut_horizontalswitcher.cpp
@@ -20,7 +20,7 @@
 #include <QApplication>
 #include <QPointer>
 
-Q_DECLARE_METATYPE(HorizontalSwitcher::Direction);
+Q_DECLARE_METATYPE(HorizontalSwitcher::SwitchDirection);
 Q_DECLARE_METATYPE(QGraphicsWidget *);
 
 void Ut_HorizontalSwitcher::initTestCase()
@@ -52,35 +52,30 @@
     }
 }
 
-void Ut_HorizontalSwitcher::testAddRemoveWidgets()
+void Ut_HorizontalSwitcher::testAddWidgets()
 {
-    const int numberOfWidgets = 5;
-
-    QList<QGraphicsWidget *> widgets;
-    QGraphicsWidget *w;
-
     QVERIFY(subject->count() == 0);
+    QVERIFY(subject->current() == -1);
+    QVERIFY(subject->currentWidget() == 0);
 
-    for (int i = 0; i < numberOfWidgets; ++i) {
-        w = new QGraphicsWidget();
-        widgets.append(w);
-        subject->addWidget(w);
-        QCOMPARE(subject->count(), i + 1);
-    }
+    const int numberOfWidgets = 5;
 
-    for (int i = numberOfWidgets - 1; i >= 0; --i) {
-        w = widgets.at(i);
-        subject->removeWidget(w);
-        QCOMPARE(subject->count(), i);
+    for (int i = 0; i < numberOfWidgets; ++i) {
+        QGraphicsWidget *w = 0;
+        subject->addWidget(w = new QGraphicsWidget);
+        QVERIFY(!w->isVisible() || w == subject->currentWidget());
+        QVERIFY(w->parentItem() == subject);
+        QVERIFY(w->scene() == subject->scene());
     }
 
-    // Add again and remove with removeAll()
-    for (int i = 0; i < numberOfWidgets; ++i)
-        subject->addWidget(widgets.at(i));
-    subject->removeAll();
-    QCOMPARE(subject->count(), 0);
+    QVERIFY(subject->count() == numberOfWidgets);
+    QVERIFY((subject->current() >= 0) && (subject->current() < subject->count()));
+    QVERIFY(subject->currentWidget() != 0);
+    QVERIFY(subject->currentWidget()->isVisible());
 
-    qDeleteAll(widgets);
+    subject->deleteAll();
+    QVERIFY(subject->count() == 0);
+    QVERIFY(subject->current() == -1);
 }
 
 void Ut_HorizontalSwitcher::testShowWidgets()
@@ -112,30 +107,31 @@
     QTest::addColumn<int>("current");
     QTest::addColumn<int>("expected");
 
-    QTest::newRow("Empty1")    << 0 <<  0 << -1;
-    QTest::newRow("Invalid0")  << 0 << -1 << -1;
-    QTest::newRow("Invalid1")  << 1 << -1 << -1;
-    QTest::newRow("Invalid2")  << 2 << -1 << -1;
+    QTest::newRow("Empty1")     << 0 <<  0 << -1;
+    QTest::newRow("Invalid0")   << 0 << -1 << -1;
+    QTest::newRow("AddOne")     << 1 << -1 <<  0;
+    QTest::newRow("AddTwo")     << 2 << -1 <<  0;
     QTest::newRow("3 widgets1") << 3 <<  0 <<  0;
     QTest::newRow("3 widgets2") << 3 <<  1 <<  1;
 }
 
+// FIXME: This test tests more about addWidget than it tests about setCurrent ...
 void Ut_HorizontalSwitcher::testSetCurrent()
 {
+    QVERIFY(subject->count() == 0);
+
     QFETCH(int, numWidgets);
     QFETCH(int, current);
     QFETCH(int, expected);
-    QGraphicsWidget *expectedWidget = NULL;
-    QList<QGraphicsWidget *> widgets;
+
+    QGraphicsWidget *expectedWidget = 0;
 
     for (int i = 0; i < numWidgets; ++i) {
-        QGraphicsWidget *widget = new QGraphicsWidget();
-        widgets.append(widget);
-        subject->addWidget(widget);
+        subject->addWidget(new QGraphicsWidget);
     }
 
     if (expected >= 0) {
-        expectedWidget = widgets.at(expected);
+        expectedWidget = subject->widget(expected);
     }
 
     subject->setCurrent(current);
@@ -146,7 +142,7 @@
 void Ut_HorizontalSwitcher::testSwitchLeftRight_data()
 {
     QTest::addColumn<int>("widgetCount");
-    QTest::addColumn<HorizontalSwitcher::Direction>("direction");
+    QTest::addColumn<HorizontalSwitcher::SwitchDirection>("direction");
     QTest::addColumn<bool>("loop");
     QTest::addColumn<int>("currentIndex");
     QTest::addColumn<int>("expectedIndex");
@@ -163,7 +159,7 @@
 void Ut_HorizontalSwitcher::testSwitchLeftRight()
 {
     QFETCH(int, widgetCount);
-    QFETCH(HorizontalSwitcher::Direction, direction);
+    QFETCH(HorizontalSwitcher::SwitchDirection, direction);
     QFETCH(bool, loop);
     QFETCH(int, currentIndex);
     QFETCH(int, expectedIndex);
@@ -240,7 +236,7 @@
 {
     QCOMPARE(subject->current(), -1);
     subject->addWidget(new QGraphicsWidget());
-    subject->switchTo(0);
+    subject->setCurrent(0);
     QCOMPARE(subject->current(), 0);
     QVERIFY(subject->currentWidget()->isVisible());
 }
@@ -250,7 +246,7 @@
     QCOMPARE(subject->current(), -1);
     subject->addWidget(new QGraphicsWidget());
 
-    subject->switchTo(0);
+    subject->setCurrent(0);
     QVERIFY(subject->isAtBoundary(HorizontalSwitcher::Left) == true);
     QVERIFY(subject->isAtBoundary(HorizontalSwitcher::Right) == true);
 
@@ -259,11 +255,11 @@
     QVERIFY(subject->isAtBoundary(HorizontalSwitcher::Left) == true);
     QVERIFY(subject->isAtBoundary(HorizontalSwitcher::Right) == false);
 
-    subject->switchTo(1);
+    subject->setCurrent(1);
     QVERIFY(subject->isAtBoundary(HorizontalSwitcher::Left) == false);
     QVERIFY(subject->isAtBoundary(HorizontalSwitcher::Right) == false);
 
-    subject->switchTo(2);
+    subject->setCurrent(2);
     QVERIFY(subject->isAtBoundary(HorizontalSwitcher::Left) == false);
     QVERIFY(subject->isAtBoundary(HorizontalSwitcher::Right) == true);
 }
--- unit_test/ut_horizontalswitcher/ut_horizontalswitcher.h
+++ unit_test/ut_horizontalswitcher/ut_horizontalswitcher.h
@@ -36,7 +36,7 @@
     void initTestCase();
     void cleanupTestCase();
 
-    void testAddRemoveWidgets();
+    void testAddWidgets();
     void testSetCurrent_data();
     void testSetCurrent();
     void testShowWidgets();
--- unit_test/ut_keybutton/ut_keybutton.cpp
+++ unit_test/ut_keybutton/ut_keybutton.cpp
@@ -37,7 +37,6 @@
     // Avoid waiting if im server is not responding
     MApplication::setLoadMInputContext(false);
     app = new MApplication(argc, app_name);
-    MTheme::instance()->loadCSS("/usr/share/meegotouch/virtual-keyboard/css/864x480.css");
 
     style = new MVirtualKeyboardStyleContainer;
     style->initialize("MVirtualKeyboard", "MVirtualKeyboardView", 0);
--- unit_test/ut_keybuttonarea/ut_keybuttonarea.cpp
+++ unit_test/ut_keybuttonarea/ut_keybuttonarea.cpp
@@ -33,13 +33,18 @@
 #include <QDir>
 #include <QGraphicsLayout>
 #include <QGraphicsSceneMouseEvent>
+#include <QTouchEvent>
+
+#include <algorithm>
 
 namespace
 {
-    const int LongPressTime = 1000; // same as in keybuttonarea.cpp
+    const int LongPressTime = 0; // same as in keybuttonarea.cpp
 }
 
 Q_DECLARE_METATYPE(KeyEvent);
+Q_DECLARE_METATYPE(IKeyButton*);
+Q_DECLARE_METATYPE(const IKeyButton*);
 
 typedef KeyButtonArea *(*KBACreator)(MVirtualKeyboardStyleContainer *styleContainer,
                                      QSharedPointer<const LayoutSection> section,
@@ -48,6 +53,7 @@
                                      QGraphicsWidget *parent);
 
 Q_DECLARE_METATYPE(KBACreator);
+Q_DECLARE_METATYPE(IKeyButton::ButtonState);
 
 KeyButtonArea *createSingleWidgetKeyButtonArea(MVirtualKeyboardStyleContainer *styleContainer,
                                                QSharedPointer<const LayoutSection> section,
@@ -77,11 +83,13 @@
     MApplication::setLoadMInputContext(false);
     app = new MApplication(argc, app_name);
 
-    MTheme::instance()->loadCSS("/usr/share/meegotouch/virtual-keyboard/css/864x480.css");
     style = new MVirtualKeyboardStyleContainer;
     style->initialize("MVirtualKeyboard", "MVirtualKeyboardView", 0);
 
     qRegisterMetaType<KeyEvent>();
+    qRegisterMetaType<const IKeyButton*>();
+    qRegisterMetaType<IKeyButton*>();
+    qRegisterMetaType<IKeyButton::ButtonState>();
 
     new MPlainWindow; // Create singleton
 }
@@ -143,7 +151,7 @@
         subject->resize(defaultLayoutSize());
 
         for (int level = 0; level < 2; level++) {
-            subject->switchLevel(level, false);
+            subject->switchLevel(level);
 
             box = keyAt(0, 0)->buttonRect().size();
             qDebug() << "Current level" << level << "; Box size=" << box;
@@ -188,7 +196,7 @@
 
         subject->resize(defaultLayoutSize());
         for (int level = 0; level < 2; level++) {
-            subject->switchLevel(level, false);
+            subject->switchLevel(level);
 
             box = keyAt(0, 0)->buttonRect().size();
             qDebug() << "Current level" << level << "; Box size=" << box << subject->size();
@@ -219,7 +227,7 @@
     const IKeyButton *button = 0;
 
     keyboard = new KeyboardData;
-    QVERIFY(keyboard->loadNokiaKeyboard("en.xml"));
+    QVERIFY(keyboard->loadNokiaKeyboard("en_us.xml"));
     subject = createKba(style, keyboard->layout(LayoutData::General, M::Landscape)->section(LayoutData::mainSection),
                         KeyButtonArea::ButtonSizeEqualExpanding,
                         false, 0);
@@ -259,72 +267,54 @@
 void Ut_KeyButtonArea::testFlickCheck_data()
 {
     QTest::addColumn<KBACreator>("createKba");
-    QTest::newRow("SingleWidgetArea") << &createSingleWidgetKeyButtonArea;
-    QTest::newRow("MButtonArea") << &createMButtonArea;
+    QTest::addColumn<bool>("directMode");
+    QTest::newRow("SingleWidgetArea") << &createSingleWidgetKeyButtonArea << false;
+    QTest::newRow("SingleWidgetArea") << &createSingleWidgetKeyButtonArea << true;
+    QTest::newRow("MButtonArea") << &createMButtonArea << false;
+    QTest::newRow("MButtonArea") << &createMButtonArea << true;
 }
 
 void Ut_KeyButtonArea::testFlickCheck()
 {
     QFETCH(KBACreator, createKba);
+    QFETCH(bool, directMode);
 
     keyboard = new KeyboardData;
-    QVERIFY(keyboard->loadNokiaKeyboard("en.xml"));
+    QVERIFY(keyboard->loadNokiaKeyboard("en_us.xml"));
     subject = createKba(style, keyboard->layout(LayoutData::General, M::Landscape)->section(LayoutData::mainSection),
                         KeyButtonArea::ButtonSizeEqualExpanding,
                         false, 0);
+    KeyButtonArea::setInputMethodMode(directMode ? M::InputMethodModeDirect : M::InputMethodModeNormal);
+    MPlainWindow::instance()->scene()->addItem(subject);
     subject->resize(defaultLayoutSize());
 
-    QList<QPointF> positions;
-    QList<int> left;
-    QList<int> right;
-    QList<int> down;
-    QList<int> up;
-    QList<bool> outcome;
-    QSignalSpy spyLeft(subject, SIGNAL(flickLeft()));
-    QSignalSpy spyRight(subject, SIGNAL(flickRight()));
-    QSignalSpy spyDown(subject, SIGNAL(flickDown()));
-    QSignalSpy spyUp(subject, SIGNAL(flickUp(const KeyBinding *)));
-    bool result;
-
-    QVERIFY(spyLeft.isValid());
-    QVERIFY(spyRight.isValid());
-    QVERIFY(spyDown.isValid());
-    QVERIFY(spyUp.isValid());
-
-    positions << QPointF(0, 0)
-              << QPointF(25, 25)
-              << QPointF(75, 75)
-              << QPointF(25, -75)
-              << QPointF(-75, 5)
-              << QPointF(75, 5)
-              << QPointF(0, 75);
-    left  << 0 << 0 << 0 << 0 << 0 << 1 << 0;
-    right << 0 << 0 << 0 << 0 << 1 << 0 << 0;
-    down  << 0 << 0 << 0 << 1 << 0 << 0 << 0;
-    up    << 0 << 0 << 0 << 0 << 0 << 0 << 1;
-    outcome << false << false << false
-            << true << true << true
-            << true;
-
-    QVERIFY(positions.count() == outcome.count());
-    QVERIFY(positions.count() == left.count());
-    subject->pointerPos = QPoint(0, 0);
-
-    for (int n = 0; n < positions.count(); ++n) {
-        spyLeft.clear();
-        spyRight.clear();
-        spyDown.clear();
-        spyUp.clear();
-        qDebug() << "test position" << positions.at(n);
-        subject->flickStartPos = positions.at(n);
-        subject->flicked = false;
-        result = subject->flickCheck();
-        QCOMPARE(result, outcome.at(n));
-        QCOMPARE(left.at(n), spyLeft.count());
-        QCOMPARE(right.at(n), spyRight.count());
-        QCOMPARE(down.at(n), spyDown.count());
-        QCOMPARE(up.at(n), spyUp.count());
-    }
+    // A series of touch points that will not create a gesture yet:
+    PointList base;
+    for (int idx = 0; idx < 8; ++idx) {
+        // But each new point has to overcome the movement threshold:
+        base << QPoint(idx * 6, idx * 6); 
+    }
+    recognizeGesture(base, NoGesture);
+
+    PointList rightSwipe0 = PointList(base);
+    rightSwipe0 << QPoint(600, 0);
+    recognizeGesture(rightSwipe0, directMode ? NoGesture : SwipeRightGesture);
+    recognizeGesture(reversed(rightSwipe0), directMode ? NoGesture : SwipeLeftGesture);
+
+    // A swipe does not have to be a strictly increasing sequence:
+    PointList rightSwipe1 = PointList(base);
+    rightSwipe1 << QPoint(0, 0) << QPoint(600, 0);
+    recognizeGesture(rightSwipe1, directMode ? NoGesture : SwipeRightGesture);
+    recognizeGesture(reversed(rightSwipe1), directMode ? NoGesture : SwipeLeftGesture);
+
+    PointList downSwipe = PointList(base);
+    downSwipe << QPoint(0, 800);
+    recognizeGesture(downSwipe, directMode ? NoGesture : SwipeDownGesture);
+    recognizeGesture(reversed(downSwipe), NoGesture); // No key set - can't swipe up ...
+
+    PointList conflictingSwipe = PointList(base);
+    conflictingSwipe << QPoint(800, 800);
+    recognizeGesture(conflictingSwipe, NoGesture);
 }
 
 void Ut_KeyButtonArea::testSceneEvent_data()
@@ -340,18 +330,26 @@
 
     //initialization
     keyboard = new KeyboardData;
-    QVERIFY(keyboard->loadNokiaKeyboard("en.xml"));
+    QVERIFY(keyboard->loadNokiaKeyboard("en_us.xml"));
     subject = createKba(style, keyboard->layout(LayoutData::General, M::Landscape)->section(LayoutData::mainSection),
                         KeyButtonArea::ButtonSizeEqualExpanding,
                         false, 0);
     MPlainWindow::instance()->scene()->addItem(subject);
     subject->resize(defaultLayoutSize());
 
+    // Skip test for multitouch, since there are no mouse events:
+    if (subject->acceptTouchEvents()) {
+        return;
+    }
+
     QGraphicsSceneMouseEvent *press = new QGraphicsSceneMouseEvent(QEvent::GraphicsSceneMousePress);
     QGraphicsSceneMouseEvent *release = new QGraphicsSceneMouseEvent(QEvent::GraphicsSceneMouseRelease);
     QGraphicsSceneMouseEvent *move = new QGraphicsSceneMouseEvent(QEvent::GraphicsSceneMouseMove);
-    QSignalSpy spy(subject, SIGNAL(keyClicked(const KeyEvent &)));
-    QSignalSpy spyPressed(subject, SIGNAL(keyPressed(const KeyEvent &)));
+    QSignalSpy spy(subject, SIGNAL(keyClicked(const IKeyButton*, const QString&, bool)));
+    QSignalSpy spyPressed(subject, SIGNAL(keyPressed(const IKeyButton*, const QString&, bool)));
+
+    QVERIFY(spy.isValid());
+    QVERIFY(spyPressed.isValid());
 
     press->setPos(QPoint(1, 1));
     release->setPos(QPoint(10, 10));
@@ -386,18 +384,18 @@
     //at least we should not chrash here
     QImage *image = new QImage(QSize(864, 480), QImage::Format_ARGB32_Premultiplied);
     QPainter painter;
-    QVERIFY(painter.begin(image) == true);
+    QVERIFY(painter.begin(image));
 
     //initialization
     keyboard = new KeyboardData;
-    QVERIFY(keyboard->loadNokiaKeyboard("en.xml"));
+    QVERIFY(keyboard->loadNokiaKeyboard("en_us.xml"));
     subject = createKba(style, keyboard->layout(LayoutData::General, M::Landscape)->section(LayoutData::mainSection),
                         KeyButtonArea::ButtonSizeEqualExpanding,
                         false, 0);
     subject->resize(defaultLayoutSize());
-    subject->pointerPos = QPoint(20, 20); // top left button
-    subject->fingerInsideArea = true;
-    subject->accurateStart();
+    MPlainWindow::instance()->scene()->addItem(subject);
+
+    subject->touchPointPressed(QPoint(20, 20), 0); // top left button
     //actual testing
     subject->paint(&painter, 0, 0);
 }
@@ -420,12 +418,14 @@
                         false, 0);
     MPlainWindow::instance()->scene()->addItem(subject);
     subject->resize(defaultLayoutSize());
-    QSignalSpy spy(subject, SIGNAL(keyClicked(const KeyEvent &)));
-    const IKeyButton *key = 0;
+    QSignalSpy spy(subject, SIGNAL(keyClicked(const IKeyButton*, const QString&, bool)));
+    IKeyButton *key = 0;
     QList<int> positions;
     int i;
     positions << 0 << 1 << 2 << 5 << 6;
 
+    QVERIFY(spy.isValid());
+
     //!!! z is the character that won't be changed when deadkey is locked
     QStringList lowerUnicodes;
     lowerUnicodes << QChar('a') << QChar('z') << QChar('e') << QChar('y') << QChar('u');
@@ -450,7 +450,7 @@
     QVERIFY(key->isDeadKey());
     QString c = QChar(0x00B4);
     QCOMPARE(key->label(), c);
-    subject->clickAtDeadkey(key);
+    subject->click(key);
     //click at deadkey for the first time, just lock the deadkey, won't emit cliked() signal
     QCOMPARE(spy.count(), 0);
 
@@ -460,7 +460,7 @@
     }
 
     //test for shift status
-    subject->switchLevel(1, false);
+    subject->switchLevel(1);
     for (i = 0; i < positions.count(); i++) {
         QCOMPARE(keyAt(0, positions[i])->label(), upperDKUnicodes.at(i));
     }
@@ -472,27 +472,72 @@
     }
 
     //test for shift off status
-    subject->switchLevel(0, false);
+    subject->switchLevel(0);
     for (i = 0; i < positions.count(); i++) {
         QCOMPARE(keyAt(0, positions[i])->label(), lowerUnicodes.at(i));
     }
 
     // Lock deadkey again.
-    subject->clickAtDeadkey(key);
+    subject->click(key);
     for (i = 0; i < positions.count(); i++) {
         QCOMPARE(keyAt(0, positions[i])->label(), lowerDKUnicodes.at(i));
     }
 
-    QGraphicsSceneMouseEvent *release = new QGraphicsSceneMouseEvent(QEvent::GraphicsSceneMouseRelease);
-    release->setPos(QPointF(keyAt(0, 0)->buttonBoundingRect().x() + 1.0, 1.0)); // on some valid key
-    subject->mouseReleaseEvent(release);
+    subject->click(keyAt(0, 0));
     //key release on not deadkey, will emit clicked() signal
     QCOMPARE(spy.count(), 1);
     //any keypress, the deadkey should be unlocked
     for (i = 0; i < positions.count(); i++) {
         QCOMPARE(keyAt(0, positions[i])->label(), lowerUnicodes.at(i));
     }
-    delete release;
+}
+
+void Ut_KeyButtonArea::testSelectedDeadkeys()
+{
+    keyboard = new KeyboardData;
+    QVERIFY(keyboard->loadNokiaKeyboard("fr.xml"));
+    subject = createSingleWidgetKeyButtonArea(style, keyboard->layout(LayoutData::General, M::Landscape)->section(LayoutData::mainSection),
+                                              KeyButtonArea::ButtonSizeEqualExpanding,
+                                              false, 0);
+    MPlainWindow::instance()->scene()->addItem(subject);
+
+    // Pick two deadkeys to play around with.
+    IKeyButton *deadkey1 = keyAt(2, 7); // row 3, column 7
+    IKeyButton *deadkey2 = keyAt(2, 8); // row 3, column 8
+    IKeyButton *regularKey = keyAt(0, 0); // first key, top left
+
+    QVERIFY(deadkey1 && deadkey1->isDeadKey());
+    QVERIFY(deadkey2 && deadkey2->isDeadKey());
+    QVERIFY(regularKey && !regularKey->isDeadKey());
+
+    QCOMPARE(deadkey1->state(), IKeyButton::Normal);
+    QCOMPARE(deadkey2->state(), IKeyButton::Normal);
+    QCOMPARE(regularKey->state(), IKeyButton::Normal);
+
+    // Press dead key down
+    subject->click(deadkey1);
+    QCOMPARE(deadkey1->state(), IKeyButton::Selected);
+
+    // Release it by clicking regular key
+    subject->click(regularKey);
+    QCOMPARE(deadkey1->state(), IKeyButton::Normal);
+
+    // Down again
+    subject->click(deadkey1);
+    QCOMPARE(deadkey1->state(), IKeyButton::Selected);
+
+    // Release it by clicking itself again.
+    subject->click(deadkey1);
+    QCOMPARE(deadkey1->state(), IKeyButton::Normal);
+
+    // Down again
+    subject->click(deadkey1);
+    QCOMPARE(deadkey1->state(), IKeyButton::Selected);
+
+    // Release it by clicking the other dead key.
+    subject->click(deadkey2);
+    QCOMPARE(deadkey1->state(), IKeyButton::Normal);
+    QCOMPARE(deadkey2->state(), IKeyButton::Selected);
 }
 
 void Ut_KeyButtonArea::testImportedLayouts_data()
@@ -555,7 +600,7 @@
     QFETCH(KBACreator, createKba);
 
     keyboard = new KeyboardData;
-    QVERIFY(keyboard->loadNokiaKeyboard("en.xml"));
+    QVERIFY(keyboard->loadNokiaKeyboard("en_us.xml"));
     subject = createKba(style, keyboard->layout(LayoutData::General, M::Landscape)->section(LayoutData::mainSection),
                         KeyButtonArea::ButtonSizeEqualExpanding, true, 0);
     MPlainWindow::instance()->scene()->addItem(subject);
@@ -572,21 +617,25 @@
     subject->accurateStop();
 
     // make long press
-    QGraphicsSceneMouseEvent mouseEvent;
-    mouseEvent.setPos(QPointF(20.0f, 20.0f)); // approximately the top left key on layout
 
-    subject->mousePressEvent(&mouseEvent);
+    const QPoint mousePos(20, 20); // approximately the top left key on layout
+    const int touchId = 0;
+
+    //popup should be shown immediately, so we comment out this part of test
+#if 0
+    subject->touchPointPressed(mousePos, touchId);
     QTest::qWait(LongPressTime - 100); // not enough time
-    subject->mouseReleaseEvent(&mouseEvent);
+    subject->touchPointReleased(mousePos, touchId);
     QVERIFY(!subject->isAccurateMode());
+#endif
 
-    subject->mousePressEvent(&mouseEvent);
+    subject->touchPointPressed(mousePos, touchId);
     QTest::qWait(LongPressTime + 100); // long enough
 
     // When accurate mode is on and mouse down we should have popup enabled
     QVERIFY(subject->isPopupActive());
 
-    subject->mouseReleaseEvent(&mouseEvent);
+    subject->touchPointReleased(mousePos, touchId);
     QVERIFY(subject->isAccurateMode());
 }
 
@@ -602,33 +651,42 @@
     QFETCH(KBACreator, createKba);
 
     keyboard = new KeyboardData;
-    QVERIFY(keyboard->loadNokiaKeyboard("en.xml"));
+    QVERIFY(keyboard->loadNokiaKeyboard("en_us.xml"));
     subject = createKba(style, keyboard->layout(LayoutData::General, M::Landscape)->section(LayoutData::mainSection),
                         KeyButtonArea::ButtonSizeEqualExpanding, true, 0);
     MPlainWindow::instance()->scene()->addItem(subject);
     subject->resize(defaultLayoutSize());
 
+    const QPoint mousePos(20, 20); // approximately the top left key on layout
+    const int touchId = 0;
+
     // Test popup activation
 
     // direct call
+
+    // Popup won't show up unless it is given a position. We give it via a mouse press.
+
+    //popup should be shown immediately, so we comment out this part of test
+#if 0
+    subject->touchPointPressed(mousePos, touchId);
     subject->popupStart();
     QVERIFY(subject->isPopupActive());
     subject->popup->hidePopup();
     QVERIFY(!subject->isPopupActive());
+    subject->touchPointReleased(mousePos, touchId);
 
     // make long press
-    QGraphicsSceneMouseEvent mouseEvent;
-    mouseEvent.setPos(QPointF(20.0f, 20.0f)); // approximately the top left key on layout
 
-    subject->mousePressEvent(&mouseEvent);
+    subject->touchPointPressed(mousePos, touchId);
     QTest::qWait(LongPressTime - 100); // not enough time
-    subject->mouseReleaseEvent(&mouseEvent);
     QVERIFY(!subject->isPopupActive());
+    subject->touchPointReleased(mousePos, touchId);
+#endif
 
-    subject->mousePressEvent(&mouseEvent);
+    subject->touchPointPressed(mousePos, touchId);
     QTest::qWait(LongPressTime + 100); // long enough
     QVERIFY(subject->isPopupActive());
-    subject->mouseReleaseEvent(&mouseEvent);
+    subject->touchPointReleased(mousePos, touchId);
 }
 
 void Ut_KeyButtonArea::testInitialization_data()
@@ -642,7 +700,7 @@
 {
     QFETCH(KBACreator, createKba);
     keyboard = new KeyboardData;
-    QVERIFY(keyboard->loadNokiaKeyboard("en.xml"));
+    QVERIFY(keyboard->loadNokiaKeyboard("en_us.xml"));
     subject = createKba(style, keyboard->layout(LayoutData::General, M::Landscape)->section(LayoutData::mainSection),
                         KeyButtonArea::ButtonSizeEqualExpanding,
                         false, 0);
@@ -694,37 +752,120 @@
     QVERIFY(buttonFoundFromRight); // button should be found from right side
 }
 
-void Ut_KeyButtonArea::testShiftCapsLock_data()
-{
-    QTest::addColumn<KBACreator>("createKba");
-    QTest::newRow("SingleWidgetArea") << &createSingleWidgetKeyButtonArea;
-    QTest::newRow("MButtonArea") << &createMButtonArea;
-}
-
 void Ut_KeyButtonArea::testShiftCapsLock()
 {
-    QFETCH(KBACreator, createKba);
-
     // Load any layout that has function row with shift
     keyboard = new KeyboardData;
-    QVERIFY(keyboard->loadNokiaKeyboard("en.xml"));
+    QVERIFY(keyboard->loadNokiaKeyboard("en_us.xml"));
     const LayoutData *layout = keyboard->layout(LayoutData::General, M::Landscape);
     QVERIFY(layout);
     QSharedPointer<const LayoutSection> functionRowSection = layout->section(LayoutData::functionkeySection);
 
-    subject = createKba(style, functionRowSection, KeyButtonArea::ButtonSizeFunctionRow, false, 0);
+    subject = createSingleWidgetKeyButtonArea(style, functionRowSection,
+                                              KeyButtonArea::ButtonSizeFunctionRow,
+                                              false, 0);
 
-    IKeyButton *shiftButton = subject->shiftButton;
+    SingleWidgetButton *shiftButton = static_cast<SingleWidgetButtonArea *>(subject)->shiftButton;
     QVERIFY(shiftButton);
     QVERIFY(shiftButton->state() == IKeyButton::Normal);
 
-    subject->switchLevel(0, true);
+    subject->setShiftStatus(true, true);
     QVERIFY(shiftButton->state() == IKeyButton::Selected);
 
-    subject->switchLevel(0, false);
+    subject->setShiftStatus(true, false);
     QVERIFY(shiftButton->state() == IKeyButton::Normal);
 }
 
+void Ut_KeyButtonArea::testMultiTouch()
+{
+    keyboard = new KeyboardData;
+    QVERIFY(keyboard->loadNokiaKeyboard("en_us.xml"));
+    const LayoutData *layout = keyboard->layout(LayoutData::General, M::Landscape);
+    QVERIFY(layout);
+    QSharedPointer<const LayoutSection> functionRowSection = layout->section(LayoutData::mainSection);
+
+    subject = createSingleWidgetKeyButtonArea(style, functionRowSection,
+                                              KeyButtonArea::ButtonSizeFunctionRow,
+                                              false, 0);
+    MPlainWindow::instance()->scene()->addItem(subject);
+    subject->resize(defaultLayoutSize());
+
+    const IKeyButton *key0 = keyAt(0, 0);
+    const IKeyButton *key1 = keyAt(1, 0);
+    const IKeyButton *key2 = keyAt(0, 1);
+
+    QVERIFY(key0);
+    QVERIFY(key1);
+    QVERIFY(key2);
+
+    QSignalSpy pressed(subject, SIGNAL(keyPressed(const IKeyButton*, const QString&, bool)));
+    QSignalSpy released(subject, SIGNAL(keyReleased(const IKeyButton*, const QString&, bool)));
+    QSignalSpy clicked(subject, SIGNAL(keyClicked(const IKeyButton*, const QString&, bool )));
+
+    QVERIFY(pressed.isValid());
+    QVERIFY(released.isValid());
+    QVERIFY(clicked.isValid());
+
+    const QPoint pos0 = key0->buttonRect().center();
+    const QPoint pos1 = key1->buttonRect().center();
+    const QPoint pos2 = key2->buttonRect().center();
+
+    /*
+     * Verify following conditions:
+     * 1) signals are emitted in correct order
+     * 2) every signal corresponds to correct key
+     */
+    subject->touchPointPressed(pos0, 0);
+    QCOMPARE(pressed.count(), 1);
+    QVERIFY(pressed.at(0).first().value<const IKeyButton*>() == key0);
+    QCOMPARE(released.count(), 0);
+    QCOMPARE(clicked.count(), 0);
+
+    subject->touchPointPressed(pos1, 1);
+    QCOMPARE(pressed.count(), 2);
+    QVERIFY(pressed.at(1).first().value<const IKeyButton*>() == key1);
+    QCOMPARE(released.count(), 0);
+    QCOMPARE(clicked.count(), 0);
+
+    subject->touchPointReleased(pos0, 0);
+    subject->touchPointReleased(pos1, 1);
+    QCOMPARE(pressed.count(), 2);
+    QCOMPARE(released.count(), 2);
+    QVERIFY(released.at(0).first().value<const IKeyButton*>() == key0);
+    QVERIFY(released.at(1).first().value<const IKeyButton*>() == key1);
+    QCOMPARE(clicked.count(), 2);
+    QVERIFY(clicked.at(0).first().value<const IKeyButton*>() == key0);
+    QVERIFY(clicked.at(1).first().value<const IKeyButton*>() == key1);
+
+    pressed.clear();
+    released.clear();
+    clicked.clear();
+
+    // Verify if could click on some keys while other key is pressed
+    subject->touchPointPressed(pos0, 0);
+    subject->touchPointPressed(pos1, 1);
+    subject->touchPointReleased(pos0, 0);
+    subject->touchPointPressed(pos2, 0);
+    subject->touchPointReleased(pos2, 0);
+    subject->touchPointReleased(pos1, 1);
+
+    QCOMPARE(pressed.count(), 3);
+    QCOMPARE(released.count(), 3);
+    QCOMPARE(clicked.count(), 3);
+
+    QVERIFY(pressed.at(0).first().value<const IKeyButton*>() == key0);
+    QVERIFY(pressed.at(1).first().value<const IKeyButton*>() == key1);
+    QVERIFY(pressed.at(2).first().value<const IKeyButton*>() == key2);
+
+    QVERIFY(released.at(0).first().value<const IKeyButton*>() == key0);
+    QVERIFY(released.at(1).first().value<const IKeyButton*>() == key2);
+    QVERIFY(released.at(2).first().value<const IKeyButton*>() == key1);
+
+    QVERIFY(clicked.at(0).first().value<const IKeyButton*>() == key0);
+    QVERIFY(clicked.at(1).first().value<const IKeyButton*>() == key2);
+    QVERIFY(clicked.at(2).first().value<const IKeyButton*>() == key1);
+}
+
 void Ut_KeyButtonArea::changeOrientation(M::OrientationAngle angle)
 {
     if (MPlainWindow::instance()->orientationAngle() != angle) {
@@ -743,14 +884,14 @@
 }
 
 // Helper method to get key in certain row and column from current subject.
-const IKeyButton *Ut_KeyButtonArea::keyAt(unsigned int row, unsigned int column) const
+IKeyButton *Ut_KeyButtonArea::keyAt(unsigned int row, unsigned int column) const
 {
     // If this fails there is something wrong with the test.
     Q_ASSERT(subject
              && (row < static_cast<unsigned int>(subject->rowCount()))
              && (column < static_cast<unsigned int>(subject->sectionModel()->columnsAt(row))));
 
-    const IKeyButton *key = 0;
+    IKeyButton *key = 0;
 
     if (dynamic_cast<MButtonArea *>(subject)) {
         MButtonArea *buttonArea = static_cast<MButtonArea *>(subject);
@@ -767,5 +908,38 @@
     return key;
 }
 
+void Ut_KeyButtonArea::recognizeGesture(const PointList &pl, GestureType gt, int touchPointId)
+{
+    QSignalSpy leftSwipeSpy(subject, SIGNAL(flickLeft()));
+    QSignalSpy rightSwipeSpy(subject, SIGNAL(flickRight()));
+    QSignalSpy upSwipeSpy(subject, SIGNAL(flickUp(KeyBinding)));
+    QSignalSpy downSwipeSpy(subject, SIGNAL(flickDown()));
+
+    subject->touchPointPressed(pl[0], touchPointId);
+
+    for (int n = 1; n < pl.count(); ++n) {
+        subject->touchPointMoved(pl[n], touchPointId);
+    }
+
+    // Not needed for the gesture, but we don't want to leave a pressed touch
+    // point without a release:
+    subject->touchPointReleased(pl[pl.count() - 1], touchPointId);
+
+    qDebug() << "gesture type = " << gt;
+    QCOMPARE(leftSwipeSpy.count(),
+             gt == SwipeLeftGesture ? 1 : 0);
+    QCOMPARE(rightSwipeSpy.count(),
+             gt == SwipeRightGesture ? 1 : 0);
+    QCOMPARE(upSwipeSpy.count(),
+             gt == SwipeUpGesture ? 1 : 0);
+    QCOMPARE(downSwipeSpy.count(),
+             gt == SwipeDownGesture ? 1 : 0);
+}
+
 
+Ut_KeyButtonArea::PointList Ut_KeyButtonArea::reversed(const PointList &in) const {
+    PointList result;
+    std::reverse_copy(in.begin(), in.end(), std::back_inserter(result));
+    return result;
+}
 QTEST_APPLESS_MAIN(Ut_KeyButtonArea);
--- unit_test/ut_keybuttonarea/ut_keybuttonarea.h
+++ unit_test/ut_keybuttonarea/ut_keybuttonarea.h
@@ -56,6 +56,7 @@
     void testPaint();
     void testDeadkeys_data();
     void testDeadkeys();
+    void testSelectedDeadkeys();
     void testImportedLayouts_data();
     void testImportedLayouts();
     void testAccurateMode_data();
@@ -66,13 +67,26 @@
     void testInitialization();
     void testFunctionRowAlignmentBug_data();
     void testFunctionRowAlignmentBug();
-    void testShiftCapsLock_data();
     void testShiftCapsLock();
+    void testMultiTouch();
 
 private:
+    enum GestureType {
+        NoGesture = 0,
+        SwipeLeftGesture = 1,
+        SwipeRightGesture = 2,
+        SwipeUpGesture = 3,
+        SwipeDownGesture = 4
+    };
+
+    typedef QList<QPoint> PointList;
+
     void changeOrientation(M::OrientationAngle angle);
     QSize defaultLayoutSize();
-    const IKeyButton *keyAt(unsigned int row, unsigned int column) const;
+    void recognizeGesture(const PointList &pl, GestureType gt, int touchPointId = 0);
+    PointList reversed(const PointList &in) const;
+
+    IKeyButton *keyAt(unsigned int row, unsigned int column) const;
 };
 
 #endif // UT_KEYBUTTONAREA_H
--- unit_test/ut_keyeventhandler
+++ unit_test/ut_keyeventhandler
+(directory)
--- unit_test/ut_keyeventhandler/ut_keyeventhandler.cpp
+++ unit_test/ut_keyeventhandler/ut_keyeventhandler.cpp
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#include "ut_keyeventhandler.h"
+#include "keyeventhandler.h"
+#include "mvirtualkeyboardstyle.h"
+#include "singlewidgetbuttonarea.h"
+#include "singlewidgetbutton.h"
+#include "flickupbutton.h"
+#include "mbuttonarea.h"
+#include "keyboarddata.h"
+#include "vkbdatakey.h"
+#include "mplainwindow.h"
+#include "popupbase.h"
+
+#include <MApplication>
+#include <MScene>
+#include <MSceneManager>
+#include <MTheme>
+
+#include <QDir>
+#include <QGraphicsLayout>
+#include <QGraphicsSceneMouseEvent>
+#include <QTouchEvent>
+
+namespace
+{
+//    const int LongPressTime = 1000; // same as in keybuttonarea.cpp
+}
+
+Q_DECLARE_METATYPE(KeyEvent);
+Q_DECLARE_METATYPE(IKeyButton*);
+
+
+void Ut_KeyEventHandler::initTestCase()
+{
+    static int argc = 1;
+    static char *app_name[1] = { (char *) "ut_keybuttonarea" };
+
+    // Avoid waiting if im server is not responding
+    MApplication::setLoadMInputContext(false);
+    app = new MApplication(argc, app_name);
+
+    style = new MVirtualKeyboardStyleContainer;
+    style->initialize("MVirtualKeyboard", "MVirtualKeyboardView", 0);
+
+    qRegisterMetaType<KeyEvent>();
+    qRegisterMetaType<IKeyButton*>();
+
+    new MPlainWindow; // Create singleton
+}
+
+void Ut_KeyEventHandler::cleanupTestCase()
+{
+    delete MPlainWindow::instance();
+    delete style;
+    style = 0;
+    delete app;
+    app = 0;
+}
+
+void Ut_KeyEventHandler::init()
+{
+    keyboard = new KeyboardData;
+    QVERIFY(keyboard->loadNokiaKeyboard("en.xml"));
+    keyArea = new SingleWidgetButtonArea(style, keyboard->layout(LayoutData::General, M::Landscape)->section(LayoutData::functionkeySection),
+                        KeyButtonArea::ButtonSizeEqualExpanding,
+                        false, 0);
+    MPlainWindow::instance()->scene()->addItem(keyArea);
+
+    keyArea->resize(defaultLayoutSize());
+
+    subject = new KeyEventHandler();
+
+    space = findKey(KeyBinding::ActionSpace);
+    QVERIFY(space);
+
+    shift = findKey(KeyBinding::ActionShift);
+    QVERIFY(shift);
+}
+
+void Ut_KeyEventHandler::cleanup()
+{
+    delete subject;
+    delete keyArea;
+    delete keyboard;
+    subject = 0;
+    keyArea = 0;
+    keyboard = 0;
+    space = 0;
+    shift = 0;
+}
+
+void Ut_KeyEventHandler::testKeyPress()
+{
+    QSignalSpy spyKeyPressed(subject, SIGNAL(keyPressed(const KeyEvent&)));
+    QSignalSpy spyShiftPressed(subject, SIGNAL(shiftPressed(bool)));
+
+    QVERIFY(spyKeyPressed.isValid());
+    QVERIFY(spyShiftPressed.isValid());
+
+    subject->handleKeyPress(space, "", false);
+
+    QCOMPARE(spyKeyPressed.count(), 1);
+    QCOMPARE(spyShiftPressed.count(), 0);
+
+    subject->handleKeyPress(shift, "", false);
+
+    QCOMPARE(spyKeyPressed.count(), 2);
+    QCOMPARE(spyShiftPressed.count(), 1);
+    QVERIFY(spyShiftPressed.first().first().toBool() == true);
+}
+
+void Ut_KeyEventHandler::testKeyRelease()
+{
+    QSignalSpy spyKeyReleased(subject, SIGNAL(keyReleased(const KeyEvent&)));
+    QSignalSpy spyShiftReleased(subject, SIGNAL(shiftPressed(bool)));
+
+    QVERIFY(spyKeyReleased.isValid());
+    QVERIFY(spyShiftReleased.isValid());
+
+    subject->handleKeyPress(space, "", false);
+    subject->handleKeyRelease(space, "", false);
+
+    QCOMPARE(spyKeyReleased.count(), 1);
+    QCOMPARE(spyShiftReleased.count(), 0);
+
+    subject->handleKeyRelease(shift, "", false);
+
+    QCOMPARE(spyKeyReleased.count(), 2);
+    QCOMPARE(spyShiftReleased.count(), 0);
+
+    subject->handleKeyPress(shift, "", false);
+    spyShiftReleased.clear();
+    subject->handleKeyRelease(shift, "", false);
+
+    QCOMPARE(spyKeyReleased.count(), 3);
+    QCOMPARE(spyShiftReleased.count(), 1);
+    QVERIFY(spyShiftReleased.first().first().toBool() == false);
+}
+
+void Ut_KeyEventHandler::testKeyClick()
+{
+    QSignalSpy spyKeyClicked(subject, SIGNAL(keyClicked(const KeyEvent&)));
+
+    QVERIFY(spyKeyClicked.isValid());
+
+    subject->handleKeyPress(shift, "", false);
+    subject->handleKeyRelease(shift, "", false);
+    subject->handleKeyClick(shift, "", false);
+
+    QCOMPARE(spyKeyClicked.count(), 1);
+    QVERIFY(spyKeyClicked.first().first().value<KeyEvent>().qtKey() == Qt::Key_Shift);
+    spyKeyClicked.clear();
+
+    subject->handleKeyPress(shift, "", false);
+    subject->handleKeyPress(space, "", false);
+    subject->handleKeyRelease(space, "", false);
+    subject->handleKeyClick(space, "", false);
+    subject->handleKeyRelease(shift, "", false);
+    subject->handleKeyClick(shift, "", false);
+
+    QCOMPARE(spyKeyClicked.count(), 1);
+    QVERIFY(spyKeyClicked.first().first().value<KeyEvent>().qtKey() != Qt::Key_Shift);
+}
+
+QSize Ut_KeyEventHandler::defaultLayoutSize()
+{
+    // Take visible scene size as layout size, but reduce keyboard's paddings first from its width.
+    // The height value is ignored since KeyButtonAreas determine their own height.
+    return MPlainWindow::instance()->visibleSceneSize()
+            - QSize((*style)->paddingLeft() + (*style)->paddingRight(), 0);
+}
+
+// Helper method to get key
+const IKeyButton *Ut_KeyEventHandler::findKey(KeyBinding::KeyAction action)
+{
+    SingleWidgetButtonArea *buttonArea = dynamic_cast<SingleWidgetButtonArea *>(keyArea);
+    Q_ASSERT(buttonArea);
+
+    foreach (const SingleWidgetButtonArea::ButtonRow &row, buttonArea->rowList) {
+        foreach (SingleWidgetButton *button, row.buttons) {
+            if (button->binding().action() == action) {
+                return button;
+            }
+        }
+    }
+    return 0;
+}
+
+
+QTEST_APPLESS_MAIN(Ut_KeyEventHandler);
--- unit_test/ut_keyeventhandler/ut_keyeventhandler.h
+++ unit_test/ut_keyeventhandler/ut_keyeventhandler.h
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * and appearing in the file LICENSE.LGPL included in the packaging
+ * of this file.
+ */
+
+#ifndef UT_KEYEVENTHANDLER_H
+#define UT_KEYEVENTHANDLER_H
+
+#include <QtTest/QtTest>
+#include <QObject>
+#include "mnamespace.h"
+#include "vkbdatakey.h"
+
+class MApplication;
+class MVirtualKeyboardStyleContainer;
+class KeyButtonArea;
+class KeyboardData;
+class IKeyButton;
+class KeyEventHandler;
+
+class Ut_KeyEventHandler : public QObject
+{
+    Q_OBJECT
+
+private:
+    MApplication *app;
+    MVirtualKeyboardStyleContainer *style;
+    KeyButtonArea *keyArea;
+    KeyboardData *keyboard;
+    KeyEventHandler *subject;
+    const IKeyButton *space;
+    const IKeyButton *shift;
+
+private slots:
+    void init();
+    void cleanup();
+    void initTestCase();
+    void cleanupTestCase();
+
+    void testKeyPress();
+    void testKeyRelease();
+    void testKeyClick();
+
+private:
+    QSize defaultLayoutSize();
+    const IKeyButton *findKey(KeyBinding::KeyAction);
+};
+
+#endif // UT_KEYEVENTHANDLER_H
+
--- unit_test/ut_keyeventhandler/ut_keyeventhandler.pro
+++ unit_test/ut_keyeventhandler/ut_keyeventhandler.pro
+TEMPLATE = app
+CONFIG += QtTest meegotouch MImServer meegoimframework
+DEPENDPATH += .
+INCLUDEPATH += 	. \
+
+LIBS += -L/usr/lib -Wl,-rpath=/usr/lib/meego-im-plugins/ -lmeego-keyboard
+#LIBS += -L/usr/lib -Wl,-rpath=/usr/lib/meego-im-plugins/ -lmeego-keyboard
+
+
+# Input
+HEADERS += ut_keyeventhandler.h
+SOURCES += ut_keyeventhandler.cpp
+
+include(../common_check.pri)
--- unit_test/ut_layoutsmanager/ut_layoutsmanager.cpp
+++ unit_test/ut_layoutsmanager/ut_layoutsmanager.cpp
@@ -79,11 +79,6 @@
 
 void Ut_LayoutsManager::initTestCase()
 {
-    MGConfItem languageListSetting(LanguageListSettingName);
-
-    QStringList langlist;
-    langlist << "fi" << "ru" << "ar_SA";
-    languageListSetting.set(QVariant(langlist));
 }
 
 void Ut_LayoutsManager::cleanupTestCase()
@@ -93,6 +88,11 @@
 void Ut_LayoutsManager::init()
 {
     LoadableKeyboards.clear();
+    LoadableKeyboards << "fi.xml" << "ru.xml" << "ar.xml";
+    MGConfItem languageListSetting(LanguageListSettingName);
+    QStringList langlist;
+    langlist << "fi" << "ru" << "ar";
+    languageListSetting.set(QVariant(langlist));
 }
 
 void Ut_LayoutsManager::cleanup()
@@ -102,6 +102,21 @@
 
 // Tests.....................................................................
 
+void Ut_LayoutsManager::testLayouts()
+{
+    LoadableKeyboards.clear();
+    LoadableKeyboards << "fi.xml" << "ru.xml" << "ar.xml" << "en_GB.xml";
+    MGConfItem languageListSetting(LanguageListSettingName);
+    QStringList langlist;
+    langlist << "Fi" << "rU" << "AR" << "en_GB";
+    languageListSetting.set(QVariant(langlist));
+    std::auto_ptr<LayoutsManager> subject(new LayoutsManager);
+    foreach (const QString &lang, langlist) {
+        // stored language code should be lowercase
+        QVERIFY(subject->languageList().contains(lang.toLower()));
+    }
+}
+
 void Ut_LayoutsManager::testNumberLayouts()
 {
     std::auto_ptr<LayoutsManager> subject(new LayoutsManager);
@@ -155,7 +170,7 @@
     // Asking with Arabic language shouldn't make a difference as this
     // stuff works solely based on the number format setting.
     layout = dynamic_cast<const TestLayoutModel *>(
-                 subject->layout("ar_SA", LayoutData::Number, M::Landscape));
+                 subject->layout("ar", LayoutData::Number, M::Landscape));
     QVERIFY(!layout);
 
     // If, however, number format is set to Arabic and we can load it,
@@ -167,7 +182,7 @@
     QVERIFY(layout);
     QCOMPARE(layout->modelId, NumberKeyboardFileArabic);
     layout = dynamic_cast<const TestLayoutModel *>(
-                 subject->layout("ar_SA", LayoutData::Number, M::Landscape));
+                 subject->layout("ar", LayoutData::Number, M::Landscape));
     QVERIFY(layout);
     QCOMPARE(layout->modelId, NumberKeyboardFileArabic);
 
@@ -243,7 +258,7 @@
     QCOMPARE(layout->modelId, PhoneNumberKeyboardFileLatin);
     displayLanguageSetting.set("ar");
     layout = dynamic_cast<const TestLayoutModel *>(
-                 subject->layout("ar_SA", LayoutData::PhoneNumber, M::Landscape));
+                 subject->layout("ar", LayoutData::PhoneNumber, M::Landscape));
     QVERIFY(layout);
     QCOMPARE(layout->modelId, PhoneNumberKeyboardFileLatin);
 
@@ -264,7 +279,7 @@
     // ...and of course for Arabic.
     displayLanguageSetting.set("ar");
     layout = dynamic_cast<const TestLayoutModel *>(
-                 subject->layout("ar_SA", LayoutData::PhoneNumber, M::Landscape));
+                 subject->layout("ar", LayoutData::PhoneNumber, M::Landscape));
     QVERIFY(layout);
     QCOMPARE(layout->modelId, PhoneNumberKeyboardFileArabic);
 }
--- unit_test/ut_layoutsmanager/ut_layoutsmanager.h
+++ unit_test/ut_layoutsmanager/ut_layoutsmanager.h
@@ -32,6 +32,7 @@
     void init();
     void cleanup();
 
+    void testLayouts();
     void testNumberLayouts();
     void testPhoneNumberLayouts();
 };
--- unit_test/ut_mhardwarekeyboard/hwkbcharloopsmanager_stub.h
+++ unit_test/ut_mhardwarekeyboard/hwkbcharloopsmanager_stub.h
@@ -41,7 +41,8 @@
 };
 
 HwKbCharLoopsManager::HwKbCharLoopsManager()
-    : configLanguage(SystemDisplayLanguage)
+    : current(0),
+      configLanguage(SystemDisplayLanguage)
 {
 }
 
--- unit_test/ut_mhardwarekeyboard/testinputcontextconnection.h
+++ unit_test/ut_mhardwarekeyboard/testinputcontextconnection.h
@@ -74,6 +74,10 @@
     {
     }
 
+    virtual void setDetectableAutoRepeat(bool /* enabled */)
+    {
+    }
+
     virtual void setGlobalCorrectionEnabled(bool)
     {
     }
--- unit_test/ut_mhardwarekeyboard/ut_mhardwarekeyboard.cpp
+++ unit_test/ut_mhardwarekeyboard/ut_mhardwarekeyboard.cpp
@@ -112,7 +112,7 @@
     inputContextConnection = new TestInputContextConnection;
     m_hkb = new MHardwareKeyboard(*inputContextConnection, 0);
     m_hkb->reset();
-    m_hkb->focusChanged(true);
+    m_hkb->enable();
     m_hkb->setKeyboardType(M::FreeTextContentType);
 }
 
@@ -380,7 +380,7 @@
     QCOMPARE(shiftSpy.count(), 0);
     modifierSpy.clear();
 
-    m_hkb->focusChanged(true);
+    m_hkb->enable();
     m_hkb->setKeyboardType(M::NumberContentType);
     countBeforeAutoCaps = modifierSpy.count();
     m_hkb->setAutoCapitalization(true);
@@ -389,7 +389,7 @@
     QVERIFY(checkLockedState(ShiftMask | LockMask | FnModifierMask, FnModifierMask));
     QCOMPARE(modifierSpy.count(), countBeforeAutoCaps);
     QCOMPARE(shiftSpy.count(), 0);
-    m_hkb->focusChanged(true);
+    m_hkb->enable();
     m_hkb->setKeyboardType(M::FreeTextContentType);
     modifierSpy.clear();
 
@@ -443,7 +443,7 @@
     QVERIFY(modifierSpy.isValid());
 
     // State is cleared on focus in...
-    m_hkb->focusChanged(true);
+    m_hkb->enable();
     QVERIFY(checkLatchedState(ShiftMask | FnModifierMask, 0));
     QVERIFY(checkLockedState(ShiftMask | LockMask | FnModifierMask, 0));
     QVERIFY(!m_hkb->autoCaps);
@@ -457,7 +457,7 @@
     // Modifiers are also unlatched/unlocked on focus out.  We don't care about
     // notifications.
     setState(state);
-    m_hkb->focusChanged(false);
+    m_hkb->disable();
     QVERIFY(checkLatchedState(ShiftMask | FnModifierMask, 0));
     QVERIFY(checkLockedState(ShiftMask | LockMask | FnModifierMask, 0));
     QVERIFY(!m_hkb->autoCaps);
@@ -500,6 +500,7 @@
     QVERIFY(checkLockedState(ShiftMask | LockMask | FnModifierMask, FnModifierMask));
 }
 
+
 void Ut_MHardwareKeyboard::testShiftShiftCapsLock_data()
 {
     QTest::addColumn<int>("state");
@@ -577,7 +578,7 @@
 
     // Press+release gives us signal
     QVERIFY(!filterKeyPress(SymKey, Qt::NoModifier, "", KeycodeNonCharacter, 0));
-    QVERIFY(filterKeyRelease(SymKey, Qt::NoModifier, "", KeycodeNonCharacter, SymModifierMask));
+    QVERIFY(!filterKeyRelease(SymKey, Qt::NoModifier, "", KeycodeNonCharacter, SymModifierMask));
     QCOMPARE(symSpy.count(), 1);
     symSpy.clear();
 
@@ -632,6 +633,7 @@
     QCOMPARE(symSpy.count(), 0);
 }
 
+
 void Ut_MHardwareKeyboard::testSymPlusCharSwitchs()
 {
     QSignalSpy symSpy(m_hkb, SIGNAL(symbolKeyClicked()));
@@ -658,11 +660,72 @@
     QCOMPARE(inputContextConnection->keyEventsSent(), static_cast<unsigned int >(0));
     QVERIFY(filterKeyRelease(Qt::Key_O, Qt::NoModifier, "b", KeycodeCharacter, SymModifierMask));
     QCOMPARE(inputContextConnection->lastCommitString(), QString(QChar(0x00F6)));
-    QCOMPARE(inputContextConnection->keyEventsSent(), static_cast<unsigned int >(1));
+    QCOMPARE(inputContextConnection->keyEventsSent(), static_cast<unsigned int >(2));
 
     QVERIFY(!filterKeyRelease(SymKey, Qt::NoModifier, "", KeycodeNonCharacter, SymModifierMask));
 
     QCOMPARE(symSpy.count(), 0);
 }
 
+
+void Ut_MHardwareKeyboard::testReleaseEvents()
+{
+    // Ordinary character
+    QVERIFY(filterKeyPress(Qt::Key_A, Qt::NoModifier, "a", KeycodeCharacter, 0));
+    QCOMPARE(inputContextConnection->keyEventsSent(), static_cast<unsigned int>(0));
+    QVERIFY(filterKeyRelease(Qt::Key_A, Qt::NoModifier, "a", KeycodeCharacter, 0));
+    QCOMPARE(inputContextConnection->keyEventsSent(), static_cast<unsigned int>(2));
+    QCOMPARE(inputContextConnection->lastKeyEvent().type(), QEvent::KeyRelease);
+
+    // Backspace with autocapitalization change (which we don't do, we just simulate the
+    // event that would be generated because of that) between press and release events
+    QVERIFY(!filterKeyPress(Qt::Key_Backspace, Qt::NoModifier, "\b", KeycodeCharacter, 0));
+    QCOMPARE(inputContextConnection->keyEventsSent(), static_cast<unsigned int>(2));
+    QVERIFY(filterKeyRelease(Qt::Key_Delete, Qt::ShiftModifier, "\177", KeycodeCharacter, 0));
+    QCOMPARE(inputContextConnection->keyEventsSent(), static_cast<unsigned int>(3));
+    QCOMPARE(inputContextConnection->lastKeyEvent().type(), QEvent::KeyRelease);
+    QCOMPARE(inputContextConnection->lastKeyEvent().key(), static_cast<int>(Qt::Key_Backspace));
+    QCOMPARE(inputContextConnection->lastKeyEvent().modifiers(), Qt::ShiftModifier);
+    QCOMPARE(inputContextConnection->lastKeyEvent().text(), QString("\b"));
+}
+
+
+void Ut_MHardwareKeyboard::testDelete_data()
+{
+    QTest::addColumn<int>("state");
+    QTest::newRow("Clear") << 0;
+    QTest::newRow("Shift latched") << 1;
+    QTest::newRow("Shift locked") << 2;
+    QTest::newRow("Fn latched") << 4;
+    QTest::newRow("Fn locked") << 5;
+}
+
+void Ut_MHardwareKeyboard::testDelete()
+{
+    QFETCH(int, state);
+
+    setState(state);
+
+    // Native and Qt modifiers (except for Qt::ShiftModifier) in all of the
+    // following filterKey* calls don't match the reality.
+
+    filterKeyPress(Qt::Key_Shift, Qt::NoModifier, "", KeycodeNonCharacter, 0);
+
+    QVERIFY(filterKeyPress(Qt::Key_Delete, Qt::ShiftModifier, "\177", KeycodeCharacter, 0));
+    QCOMPARE(inputContextConnection->keyEventsSent(), static_cast<unsigned int>(1));
+    QCOMPARE(inputContextConnection->lastKeyEvent().type(), QEvent::KeyPress);
+    QCOMPARE(inputContextConnection->lastKeyEvent().key(), static_cast<int>(Qt::Key_Delete));
+    QCOMPARE(inputContextConnection->lastKeyEvent().modifiers(), Qt::NoModifier);
+    QCOMPARE(inputContextConnection->lastKeyEvent().text(), QString("\177"));
+
+    QVERIFY(filterKeyRelease(Qt::Key_Delete, Qt::ShiftModifier, "\177", KeycodeCharacter, 0));
+    QCOMPARE(inputContextConnection->keyEventsSent(), static_cast<unsigned int>(2));
+    QCOMPARE(inputContextConnection->lastKeyEvent().type(), QEvent::KeyRelease);
+    QCOMPARE(inputContextConnection->lastKeyEvent().key(), static_cast<int>(Qt::Key_Delete));
+    QCOMPARE(inputContextConnection->lastKeyEvent().modifiers(), Qt::NoModifier);
+    QCOMPARE(inputContextConnection->lastKeyEvent().text(), QString("\177"));
+
+    filterKeyRelease(Qt::Key_Shift, Qt::NoModifier, "", KeycodeNonCharacter, 0);
+}
+
 QTEST_APPLESS_MAIN(Ut_MHardwareKeyboard);
--- unit_test/ut_mhardwarekeyboard/ut_mhardwarekeyboard.h
+++ unit_test/ut_mhardwarekeyboard/ut_mhardwarekeyboard.h
@@ -56,6 +56,10 @@
     void testSymPlusCharacterBasic();
     void testSymPlusCharSwitchs();
 
+    void testReleaseEvents();
+    void testDelete_data();
+    void testDelete();
+
 private:
     bool checkLatchedState(unsigned int mask, unsigned int value) const;
     bool checkLockedState(unsigned int mask, unsigned int value) const;
--- unit_test/ut_mimcorrectioncandidatewidget/ut_mimcorrectioncandidatewidget.cpp
+++ unit_test/ut_mimcorrectioncandidatewidget/ut_mimcorrectioncandidatewidget.cpp
@@ -37,8 +37,6 @@
     MApplication::setLoadMInputContext(false);
     app = new MApplication(dummyArgc, dummyArgv);
 
-    MTheme::instance()->loadCSS("/usr/share/meegotouch/virtual-keyboard/css/864x480.css");
-
     // MImCorrectionCandidateWidget uses this internally
     new MPlainWindow;
     if (MPlainWindow::instance()->orientationAngle() != M::Angle0) {
@@ -96,13 +94,16 @@
 
     // Goes over sceneHeight limit
     QTest::newRow("positive3") <<QPoint(700, sceneHeight - 50) << -1
-        << QPoint(700, (sceneHeight - testCandidateWidgetSize.height()));
+                               << QPoint(700, ((sceneHeight - testCandidateWidgetSize.height()) > 0)?
+                                               (sceneHeight - testCandidateWidgetSize.height()):0);
 
     // No room above so aligns to y=0.
     QTest::newRow("bottom limit 1") << QPoint(10, 10) << 4 << QPoint(10, 0);
 
     // There is room above so bottom limit holds (y+height=bottomlimit).
-    QTest::newRow("bottom limit 2") << QPoint(10, 250) << 220 << QPoint(10, 220 - testCandidateWidgetSize.height());
+    QTest::newRow("bottom limit 2") << QPoint(10, 250) << 220
+                                    << QPoint(10, ((220 - testCandidateWidgetSize.height()) > 0)?
+                                              (220 - testCandidateWidgetSize.height()):0);
 }
 
 void Ut_MImCorrectionCandidateWidget::checkPositionByPoint()
--- unit_test/ut_mimtoolbar/testtoolbar.xml
+++ unit_test/ut_mimtoolbar/testtoolbar.xml
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE DUI_IM_TOOLBAR_WIDGET SYSTEM 'ImToolbarDTD.dtd'>
+
+<toolbar version="1">
+    <layout>
+        <row>
+            <button name="testbutton1" group="group1" priority="0" showon="always" alignment="left" text="testbutton1" toggle="true">
+                <actions>
+                    <sendkeysequence keysequence="Ctrl+I"/>
+                    <copy/>
+                    <showgroup group="group3"/>
+                </actions>
+            </button>
+            <label name="testlabel1" group="group4" priority="1" showon="always" hideon="selectedtext" alignment="left" text="testlabel1"/>
+            <button name="testbutton2" group="group2" priority="0" showon="always" alignment="right" text="testbutton2">
+                <actions>
+                    <sendstring string="test string"/>
+                    <paste/>
+                    <hidegroup group="group1"/>
+                </actions>
+            </button>
+        <!-- /row>
+        <row -->
+            <button name="testbutton3" group="group3" priority="1" showon="selectedtext" alignment="right" text="testbutton3">
+            </button>
+        </row>
+    </layout>
+</toolbar>
--- unit_test/ut_mimtoolbar/ut_mimtoolbar.cpp
+++ unit_test/ut_mimtoolbar/ut_mimtoolbar.cpp
@@ -18,25 +18,27 @@
 
 #include "ut_mimtoolbar.h"
 #include "mimtoolbar.h"
-#include "toolbarmanager.h"
-#include "toolbardata.h"
 #include "mtoolbarbutton.h"
+#include "mtoolbarlabel.h"
 #include "mapplication.h"
 #include "mvirtualkeyboard.h"
 #include "layoutsmanager.h"
 #include "mvirtualkeyboardstyle.h"
 #include <mplainwindow.h>
+#include <mtoolbardata.h>
 #include <MTheme>
 #include <MSceneWindow>
 #include <MButton>
 #include <MLabel>
 #include <MInfoBanner>
+#include <MScene>
 #include "mgconfitem_stub.h"
 
 #include <QtTest/QTest>
 #include <QObject>
 #include <QDebug>
 #include <QFile>
+#include <QDir>
 #include <QStringList>
 #include <QSignalSpy>
 #include <QKeyEvent>
@@ -46,10 +48,7 @@
 Q_DECLARE_METATYPE(CopyPasteState);
 namespace
 {
-    // This file doesn't really exist in filesystem, its memory representation
-    // is constructed in init().
-    QString ToolbarFileName("/usr/share/meegotouch/imtoolbars/testtoolbar.xml");
-    qlonglong ToolbarId(qrand());
+    QString ToolbarFileName = "/testtoolbar.xml";
 
     int indexOf(const QGraphicsLayout *layout, const QGraphicsLayoutItem *item)
     {
@@ -83,95 +82,24 @@
     qRegisterMetaType<CopyPasteState>("CopyPasteState");
     LayoutsManager::createInstance();
 
-    QString cssFile("../../m-keyboard/theme/864x480.css");
-    if (!QFile::exists(cssFile)) {
-        cssFile = "/usr/share/meegotouch/virtual-keyboard/css/864x480.css";
-        QVERIFY(QFile::exists(cssFile));
-    }
-    MTheme::instance()->loadCSS(cssFile);
-
     style = new MVirtualKeyboardStyleContainer;
     style->initialize("MVirtualKeyboard", "MVirtualKeyboardView", 0);
 
-    ToolbarManager::createInstance();
-    //fill up toolbar with some data
-    ToolbarData *toolbar = new ToolbarData;
-    toolbar->toolbarFileName = ToolbarFileName;
-    ToolbarWidget *b1 = new ToolbarWidget(ToolbarWidget::Button);
-    b1->widgetName = "testbutton1";
-    b1->group = "group1";
-    b1->priority = 0;
-    b1->orientation = M::Landscape;
-    b1->showOn = ToolbarWidget::Always;
-    b1->hideOn = ToolbarWidget::Undefined;
-    b1->alignment = Qt::AlignLeft;
-    b1->text = "testbutton1";
-    b1->textId = "";
-    b1->toggle = true;
-    b1->pressed = false;
-    ToolbarWidget::Action *action11 = new ToolbarWidget::Action(ToolbarWidget::SendKeySequence);
-    action11->keys = "Ctrl+I";
-    b1->actions.append(action11);
-    ToolbarWidget::Action *action12 = new ToolbarWidget::Action(ToolbarWidget::Copy);
-    b1->actions.append(action12);
-    ToolbarWidget::Action *action13 = new ToolbarWidget::Action(ToolbarWidget::ShowGroup);
-    action13->group = "group3";
-    b1->actions.append(action13);
-    toolbar->widgets.append(b1);
-
-    ToolbarWidget *l1 = new ToolbarWidget(ToolbarWidget::Label);
-    l1->widgetName = "testlabel1";
-    l1->group = "group4";
-    l1->priority = 1;
-    l1->orientation = M::Landscape;
-    l1->showOn = ToolbarWidget::Always;
-    l1->hideOn = ToolbarWidget::WhenSelectingText;
-    l1->alignment = Qt::AlignLeft;
-    l1->text = "testlabel1";
-    l1->textId = "";
-    toolbar->widgets.append(l1);
-
-    ToolbarWidget *b2 = new ToolbarWidget(ToolbarWidget::Button);
-    b2->widgetName = "testbutton2";
-    b2->group = "group2";
-    b2->priority = 0;
-    b2->orientation = M::Landscape;
-    b2->showOn = ToolbarWidget::Always;
-    b2->hideOn = ToolbarWidget::Undefined;
-    b2->alignment = Qt::AlignRight;
-    b2->text = "testbutton2";
-    b2->textId = "";
-    ToolbarWidget::Action *action21 = new ToolbarWidget::Action(ToolbarWidget::SendString);
-    action21->text = "test string";
-    b2->actions.append(action21);
-    ToolbarWidget::Action *action22 = new ToolbarWidget::Action(ToolbarWidget::Paste);
-    b2->actions.append(action22);
-    ToolbarWidget::Action *action23 = new ToolbarWidget::Action(ToolbarWidget::HideGroup);
-    action23->group = "group1";
-    b2->actions.append(action23);
-    toolbar->widgets.append(b2);
-
-    ToolbarWidget *b3 = new ToolbarWidget(ToolbarWidget::Button);
-    b3->widgetName = "testbutton3";
-    b3->group = "group3";
-    b3->priority = 1;
-    b3->orientation = M::Landscape;
-    b3->showOn = ToolbarWidget::WhenSelectingText;
-    b3->hideOn = ToolbarWidget::Undefined;
-    b3->alignment = Qt::AlignRight;
-    b3->text = "testbutton3";
-    b3->textId = "";
-    toolbar->widgets.append(b3);
-
-    ToolbarManager::instance().toolbars.insert(ToolbarId, ToolbarFileName);
-    ToolbarManager::instance().cachedToolbars.insert(ToolbarId, toolbar);
-    ToolbarManager::instance().cachedToolbarIds.prepend(ToolbarId);
-}
+    new MPlainWindow; // Create singleton
 
+    ToolbarFileName = QCoreApplication::applicationDirPath() + ToolbarFileName;
+    QVERIFY(QFile::exists(ToolbarFileName));
+}
 
 void Ut_MImToolbar::init()
 {
     m_subject = new MImToolbar(*style);
+    MPlainWindow::instance()->scene()->addItem(m_subject);
+
+    //fill up toolbar with some data
+    toolbarData = QSharedPointer<MToolbarData>(new MToolbarData);
+    bool ok = toolbarData->loadNokiaToolbarXml(ToolbarFileName);
+    QVERIFY(ok);
 }
 
 
@@ -182,8 +110,9 @@
 
 void Ut_MImToolbar::cleanupTestCase()
 {
-    ToolbarManager::destroyInstance();
+    toolbarData.clear();
     LayoutsManager::destroyInstance();
+    delete MPlainWindow::instance();
     delete style;
     style = 0;
     delete app;
@@ -250,44 +179,44 @@
 {
     QSignalSpy spy(m_subject, SIGNAL(regionUpdated()));
     QVERIFY(spy.isValid());
-    m_subject->showToolbarWidget(ToolbarId);
+    m_subject->showToolbarWidget(toolbarData);
     //toolbar buttons depend on the its data
     //including spacing widget and close button
-    QCOMPARE(m_subject->leftBar.count(), 2);
-    QCOMPARE(m_subject->rightBar.count(), 1);
+    QCOMPARE(m_subject->leftBar.layout()->count(), 2);
+    QCOMPARE(m_subject->rightBar.layout()->count(), 1);
     QCOMPARE(spy.count(), 1);
     spy.clear();
 }
 
 void Ut_MImToolbar::testShowGroup()
 {
-    m_subject->showToolbarWidget(ToolbarId);
+    m_subject->showToolbarWidget(toolbarData);
     //find button testbutton2, which click will show group test
-    MButton *button = qobject_cast<MButton *>(m_subject->toolbarMgr.widget("testbutton1"));
+    MButton *button = qobject_cast<MButton *>(find("testbutton1"));
     QVERIFY(button != 0);
     button->click();
-    QCOMPARE(m_subject->leftBar.count(), 2);
-    QCOMPARE(m_subject->rightBar.count(), 2);
+    QCOMPARE(m_subject->leftBar.layout()->count(), 2);
+    QCOMPARE(m_subject->rightBar.layout()->count(), 2);
 }
 
 void Ut_MImToolbar::testHideGroup()
 {
-    m_subject->showToolbarWidget(ToolbarId);
+    m_subject->showToolbarWidget(toolbarData);
     //find button testbutton2, which click will hide group test
-    MButton *button = qobject_cast<MButton *>(m_subject->toolbarMgr.widget("testbutton2"));
+    MButton *button = qobject_cast<MButton *>(find("testbutton2"));
     QVERIFY(button != 0);
     button->click();
-    QCOMPARE(m_subject->leftBar.count(), 1);
-    QCOMPARE(m_subject->rightBar.count(), 1);
+    QCOMPARE(m_subject->leftBar.layout()->count(), 1);
+    QCOMPARE(m_subject->rightBar.layout()->count(), 1);
 }
 
 void Ut_MImToolbar::testSendString()
 {
-    m_subject->showToolbarWidget(ToolbarId);
+    m_subject->showToolbarWidget(toolbarData);
     QSignalSpy spy(m_subject, SIGNAL(sendStringRequest(const QString &)));
     QVERIFY(spy.isValid());
     //find button testbutton2, which click will send string
-    MButton *button = qobject_cast<MButton *>(m_subject->toolbarMgr.widget("testbutton2"));
+    MButton *button = qobject_cast<MButton *>(find("testbutton2"));
     QVERIFY(button != 0);
     button->click();
     QVERIFY(spy.count() == 1);
@@ -296,13 +225,13 @@
 
 void Ut_MImToolbar::testKeySequenceString()
 {
-    m_subject->showToolbarWidget(ToolbarId);
+    m_subject->showToolbarWidget(toolbarData);
     //find button testbutton1, which click will send key sequence (QKeyEvent)
     //because QKeyEvent is not supported by MetaType, use its own slot to test it.
     keyEvents = 0;
     connect(m_subject, SIGNAL(sendKeyEventRequest(const QKeyEvent &)),
             this, SLOT(receiveKeyEvent(const QKeyEvent &)));
-    MButton *button = qobject_cast<MButton *>(m_subject->toolbarMgr.widget("testbutton1"));
+    MButton *button = qobject_cast<MButton *>(find("testbutton1"));
     QVERIFY(button != 0);
     button->click();
     QVERIFY(keyEvents > 0);
@@ -311,7 +240,7 @@
 
 void Ut_MImToolbar::testHideToolbarWidget()
 {
-    m_subject->showToolbarWidget(ToolbarId);
+    m_subject->showToolbarWidget(toolbarData);
     m_subject->hideToolbarWidget();
 }
 
@@ -325,9 +254,9 @@
     QSignalSpy spy(m_subject, SIGNAL(copyPasteRequest(CopyPasteState)));
     QVERIFY(spy.isValid());
 
-    m_subject->showToolbarWidget(ToolbarId);
+    m_subject->showToolbarWidget(toolbarData);
     //find button testbutton2, which click will copy
-    MButton *button = qobject_cast<MButton *>(m_subject->toolbarMgr.widget("testbutton1"));
+    MButton *button = qobject_cast<MButton *>(find("testbutton1"));
     QVERIFY(button != 0);
     button->click();
     QVERIFY(spy.count() == 1);
@@ -342,9 +271,9 @@
     QSignalSpy spy(m_subject, SIGNAL(copyPasteRequest(CopyPasteState)));
     QVERIFY(spy.isValid());
 
-    m_subject->showToolbarWidget(ToolbarId);
+    m_subject->showToolbarWidget(toolbarData);
     //find button testbutton2, which click will paste
-    MButton *button = qobject_cast<MButton *>(m_subject->toolbarMgr.widget("testbutton2"));
+    MButton *button = qobject_cast<MButton *>(find("testbutton2"));
     QVERIFY(button != 0);
     button->click();
     QVERIFY(spy.count() == 1);
@@ -359,9 +288,10 @@
 {
     QSignalSpy regionSignals(m_subject, SIGNAL(regionUpdated()));
 
-    m_subject->showToolbarWidget(ToolbarId);
-    QCOMPARE(m_subject->rightBar.count(), 1);
+    m_subject->showToolbarWidget(toolbarData);
     QCOMPARE(regionSignals.count(), 1);
+    m_subject->updateVisibility();
+    QCOMPARE(regionSignals.count(), 2);
 
     // Get region when there are two buttons on the right.
     QRegion regionTwoButtons = m_subject->region();
@@ -372,13 +302,16 @@
 
     // We need to add a new button, let's use groups.
     // Clicking testbutton1 will add one button to the right.
-    MButton *button = qobject_cast<MButton *>(m_subject->toolbarMgr.widget("testbutton1"));
+    MButton *button = qobject_cast<MButton *>(find("testbutton1"));
     QVERIFY(button != 0);
     button->click();
-    QCOMPARE(m_subject->rightBar.count(), 2);
+
+    while (QCoreApplication::hasPendingEvents()) {
+        QCoreApplication::processEvents();
+    }
 
     // Button added, check that regionUpdate() was emitted.
-    QCOMPARE(regionSignals.count(), 2);
+    QCOMPARE(regionSignals.count(), 3);
 
     // Get region when there are three buttons on the right.
     QRegion regionThreeButtons = m_subject->region();
@@ -391,44 +324,29 @@
 
     m_subject->hideToolbarWidget();
 
-    QCOMPARE(regionSignals.count(), 3);
+    QCOMPARE(regionSignals.count(), 4);
 
     m_subject->hide();
 
-    QCOMPARE(regionSignals.count(), 4);
+    QCOMPARE(regionSignals.count(), 5);
     QVERIFY(m_subject->region().isEmpty());
 }
 
-void Ut_MImToolbar::testSetToolbarItemAttribute()
+MWidget* Ut_MImToolbar::find(const QString &name)
 {
-    m_subject->showToolbarWidget(ToolbarId);
-    QString text("dummy_label");
-
-    MToolbarButton *button = qobject_cast<MToolbarButton *>(m_subject->toolbarMgr.widget("testbutton1"));
-    QVERIFY(button != 0);
-    QCOMPARE(button->isCheckable(), true);
-    QCOMPARE(button->isChecked(), false);
-
-    MLabel *label = qobject_cast<MLabel *>(m_subject->toolbarMgr.widget("testlabel1"));
-    QVERIFY(label != 0);
-
-    ToolbarManager::instance().setToolbarItemAttribute(ToolbarId, "testlabel1", "text", text);
-    QCOMPARE(label->text(), text);
-
-    ToolbarManager::instance().setToolbarItemAttribute(ToolbarId, "testbutton1", "text", text);
-    QCOMPARE(button->text(), text);
-
-    ToolbarManager::instance().setToolbarItemAttribute(ToolbarId, "testbutton1", "pressed", QVariant(true));
-    QCOMPARE(button->isChecked(), true);
+    foreach (QPointer<MWidget> widget, m_subject->customWidgets) {
+        MToolbarButton *button = qobject_cast<MToolbarButton*>(widget);
+        if (button && button->item() && button->item()->name() == name) {
+            return button;
+        }
 
-    ToolbarManager::instance().setToolbarItemAttribute(ToolbarId, "testbutton1", "pressed", QVariant(false));
-    QCOMPARE(button->isChecked(), false);
+        MToolbarLabel *label = qobject_cast<MToolbarLabel*>(widget);
+        if (label && label->item() && label->item()->name() == name) {
+            return label;
+        }
+    }
 
-    QString icon("dummy_icon");
-    ToolbarManager::instance().setToolbarItemAttribute(ToolbarId, "testbutton1", "icon", icon);
-    QCOMPARE(button->iconFile, icon);
-    ToolbarManager::instance().setToolbarItemAttribute(ToolbarId, "testbutton1", "icon", QString(""));
-    QCOMPARE(button->iconFile, QString(""));
+    return 0;
 }
 
 QTEST_APPLESS_MAIN(Ut_MImToolbar);
--- unit_test/ut_mimtoolbar/ut_mimtoolbar.h
+++ unit_test/ut_mimtoolbar/ut_mimtoolbar.h
@@ -21,10 +21,14 @@
 
 #include <QtTest/QTest>
 #include <QObject>
+#include <QSharedPointer>
+#include <mtoolbardata.h>
+
 class MApplication;
 class MImToolbar;
 class QKeyEvent;
 class MVirtualKeyboardStyleContainer;
+class MWidget;
 
 class Ut_MImToolbar : public QObject
 {
@@ -35,6 +39,7 @@
     MImToolbar *m_subject;
     int keyEvents;
     MVirtualKeyboardStyleContainer *style;
+    QSharedPointer<MToolbarData> toolbarData;
 
 private slots:
     //! initialize application and class
@@ -53,9 +58,13 @@
     void testCopy();
     void testPaste();
     void testRegion();
-    void testSetToolbarItemAttribute();
 
     void receiveKeyEvent(const QKeyEvent &);
+
+private:
+    // Find custom widget by given \a name
+    MWidget *find(const QString &name);
+
 };
 
 #endif
--- unit_test/ut_mimtoolbar/ut_mimtoolbar.pro
+++ unit_test/ut_mimtoolbar/ut_mimtoolbar.pro
@@ -20,4 +20,8 @@
 SOURCES += ut_mimtoolbar.cpp \
            ../stubs/fakegconf.cpp
 
+target.files += \
+           $$TARGET \
+           testtoolbar.xml \
+
 include(../common_check.pri)
--- unit_test/ut_mkeyboardhost/minputcontextstubconnection.cpp
+++ unit_test/ut_mkeyboardhost/minputcontextstubconnection.cpp
@@ -154,3 +154,7 @@
 {
     keyRedirectionEnabled = enabled;
 }
+
+void MInputContextStubConnection::setDetectableAutoRepeat(bool /*enabled*/)
+{
+}
--- unit_test/ut_mkeyboardhost/minputcontextstubconnection.h
+++ unit_test/ut_mkeyboardhost/minputcontextstubconnection.h
@@ -50,6 +50,7 @@
 
     virtual bool surroundingText(QString &text, int &cursorPosition);
     virtual void setRedirectKeys(bool enabled);
+    virtual void setDetectableAutoRepeat(bool enabled);
 
     QString preedit;
     QString commit;
--- unit_test/ut_mkeyboardhost/ut_mkeyboardhost.cpp
+++ unit_test/ut_mkeyboardhost/ut_mkeyboardhost.cpp
@@ -21,10 +21,9 @@
 #include <mhardwarekeyboard.h>
 #include <mkeyboardhost.h>
 #include <mvirtualkeyboardstyle.h>
-#include <layoutmenu.h>
 #include <symbolview.h>
 
-#include "duiimenginewords.h"
+#include <mimenginewords.h>
 
 #include "mgconfitem_stub.h"
 #include "minputcontextstubconnection.h"
@@ -38,6 +37,7 @@
 #include <MWidgetController>
 #include <MDialog>
 
+#include <QGraphicsLayout>
 #include <QDir>
 
 #include <X11/X.h>
@@ -51,8 +51,10 @@
     bool gAccurateMode = false;
     int gSetKeyboardStateCallCount = 0;
     MIMHandlerState gSetKeyboardStateParam = OnScreen;
-    const int LayoutMenuShowTime = 300; // in ms
     const int SceneRotationTime = 1400; // in ms
+
+    // This GConf item defines whether multitouch is enabled or disabled
+    const char * const MultitouchSettings = "/meegotouch/inputmethods/multitouch/enabled";
 }
 
 namespace QTest
@@ -71,7 +73,7 @@
 
 Q_DECLARE_METATYPE(QSet<MIMHandlerState>)
 Q_DECLARE_METATYPE(MIMHandlerState)
-
+Q_DECLARE_METATYPE(ModifierState)
 
 static void waitForSignal(const QObject* object, const char* signal, int timeout = 500)
 {
@@ -111,9 +113,10 @@
     // Avoid waiting if im server is not responding
     MApplication::setLoadMInputContext(false);
     app = new MApplication(argc, app_name);
-    MTheme::instance()->loadCSS("/usr/share/meegotouch/virtual-keyboard/css/864x480.css");
     inputContext = new MInputContextStubConnection;
     window = new MPlainWindow;
+
+    MGConfItem(MultitouchSettings).set(true);
 }
 
 void Ut_MKeyboardHost::cleanupTestCase()
@@ -131,6 +134,8 @@
     // Uses dummy driver
     MGConfItem engineConfig(InputMethodCorrectionEngine);
     engineConfig.set(QVariant(QString("dummyimdriver")));
+    MGConfItem config(InputMethodCorrectionSetting);
+    config.set(QVariant(false));
 
     subject = new MKeyboardHost(inputContext, 0);
     inputContext->clear();
@@ -353,6 +358,7 @@
 {
     subject->show();
     MGConfItem config(InputMethodCorrectionSetting);
+    config.set(QVariant(true));
 
     QVERIFY(subject->imCorrectionEngine != 0);
     //default error correction option is true;
@@ -382,19 +388,19 @@
 
     inputContext->cursorPos = 0;
     subject->update();
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOn);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierLatchedState);
 
     inputContext->cursorPos = 1;
     subject->update();
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOff);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierClearState);
 
     inputContext->cursorPos = 12;
     subject->update();
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOff);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierClearState);
 
     inputContext->cursorPos = 13;
     subject->update();
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOn);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierLatchedState);
 
 
     subject->hide();
@@ -402,23 +408,23 @@
 
     inputContext->cursorPos = 13;
     subject->update();
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOn);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierLatchedState);
 
     inputContext->cursorPos = 16;
     subject->update();
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOff);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierClearState);
 
     inputContext->cursorPos = 31;
     subject->update();
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOn);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierLatchedState);
 
     inputContext->cursorPos = 33;
     subject->update();
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOn);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierLatchedState);
 
     inputContext->cursorPos = 0;
     subject->update();
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOn);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierLatchedState);
     // When autoCaps is on and shift is latched, any key input except shift and backspace (in an sepcial case)
     // will turn off shift.
     KeyEvent press("a", QEvent::KeyPress);
@@ -426,18 +432,18 @@
     subject->handleKeyPress(press);
     subject->handleKeyRelease(release);
     subject->handleKeyClick(release);
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOff);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierClearState);
 
     // If there are some preedit, capitalization should be off.
     subject->preedit = "Test";
     inputContext->cursorPos = 0;
     subject->update();
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOff);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierClearState);
 
     subject->preedit = "";
     inputContext->cursorPos = 0;
     subject->update();
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOn);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierLatchedState);
     // The special case for backspace when autoCaps is on, that is cursor is at 0 position,
     // should not change the shift state.
     press = KeyEvent("", QEvent::KeyPress, Qt::Key_Backspace);
@@ -445,17 +451,17 @@
     subject->handleKeyPress(press);
     subject->handleKeyRelease(release);
     subject->handleKeyClick(release);
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOn);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierLatchedState);
 
     // If cursor is not at 0 position, backspace should also change the shift state.
     inputContext->cursorPos = 2;
     subject->update();
-    subject->vkbWidget->setShiftState(MVirtualKeyboard::ShiftOn);
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOn);
+    subject->vkbWidget->setShiftState(ModifierLatchedState);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierLatchedState);
     subject->handleKeyPress(press);
     subject->handleKeyRelease(release);
     subject->handleKeyClick(release);
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOff);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierClearState);
 
     // Test holding backspace with preedit.
     press = KeyEvent("", QEvent::KeyPress, Qt::Key_Backspace);
@@ -464,9 +470,9 @@
     subject->preedit = "You can use";
     // initial state: preedit("You can use"), shift state:latched, start holding backspace
     subject->update();
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOff);
-    subject->vkbWidget->setShiftState(MVirtualKeyboard::ShiftOn);
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOn);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierClearState);
+    subject->vkbWidget->setShiftState(ModifierLatchedState);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierLatchedState);
 
     // press and release backspace before timeout will only delete one character,
     subject->handleKeyPress(press);
@@ -474,7 +480,7 @@
     subject->handleKeyRelease(release);
     subject->handleKeyClick(release);
     subject->update();
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOff);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierClearState);
     QCOMPARE(subject->preedit, QString("You can us"));
 
     // but hold backspace longer than timeout, will delete the whole preedit.
@@ -483,17 +489,17 @@
     QTest::qWait(interval / 2);
     QVERIFY(subject->backSpaceTimer.isActive());
     subject->update();
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOff);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierClearState);
     QTest::qWait((interval / 2) + 50);
     // final state: preedit(""), shift state:on, after holding backspace enough time.
     QVERIFY(subject->preedit.isEmpty());
     QVERIFY(!subject->backSpaceTimer.isActive());
     inputContext->cursorPos = 13;
     subject->update();
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOn);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierLatchedState);
     subject->handleKeyRelease(release);
     subject->handleKeyClick(release);
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOn);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierLatchedState);
 
     subject->hide();
     QTest::qWait(MVirtualKeyboard::ShowHideTime + 50);
@@ -504,28 +510,28 @@
     subject->show();
     subject->update();
     QTest::qWait(MVirtualKeyboard::ShowHideTime + 50);
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOff);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierClearState);
 
     // When shift is latched, any key input except shift will turn off shift.
-    subject->vkbWidget->setShiftState(MVirtualKeyboard::ShiftOn);
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOn);
+    subject->vkbWidget->setShiftState(ModifierLatchedState);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierLatchedState);
     press = KeyEvent("a", QEvent::KeyPress);
     release = KeyEvent(press, QEvent::KeyRelease);
     subject->handleKeyPress(press);
     subject->handleKeyRelease(release);
     subject->handleKeyClick(release);
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOff);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierClearState);
 
     // Backspace will also change the shift state when cursor is at 0 position.
     inputContext->cursorPos = 0;
-    subject->vkbWidget->setShiftState(MVirtualKeyboard::ShiftOn);
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOn);
+    subject->vkbWidget->setShiftState(ModifierLatchedState);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierLatchedState);
     press = KeyEvent("", QEvent::KeyPress, Qt::Key_Backspace);
     release = KeyEvent(press, QEvent::KeyRelease);
     subject->handleKeyPress(press);
     subject->handleKeyRelease(release);
     subject->handleKeyClick(release);
-    QVERIFY(subject->vkbWidget->shiftStatus() == MVirtualKeyboard::ShiftOff);
+    QVERIFY(subject->vkbWidget->shiftStatus() == ModifierClearState);
 }
 
 void Ut_MKeyboardHost::testApplicationOrientationChanged()
@@ -600,6 +606,7 @@
     // is made visible right before the animation starts.
     QCOMPARE(spy.count(), c1);
     QCOMPARE(spy2.count(), c2);
+
     QCOMPARE(region(spy, c1 - 1), region(spy2, 0));
     QVERIFY(!region(spy, c1 - 1).isEmpty());
 
@@ -611,19 +618,39 @@
     QCOMPARE(spy2.count(), c2);
     qDebug() << "Passthrough region: " << region(spy, 1);
     qDebug() << "libmeegotouch region: " << region(spy2, 1);
-    QCOMPARE(region(spy, c1 - 1), region(spy2, 1));
+    QVERIFY((region(spy, c1 - 1) - region(spy2, 1)).isEmpty());
 
-    // When layout menu is shown, input method area doesn't change...
-    QTimer::singleShot(LayoutMenuShowTime, subject->layoutMenu->keyboardOptionDialog, SLOT(reject()));
-    qDebug() << "Opening and closing layout menu...";
-    subject->showLayoutMenu();
-    waitForSignal(subject->layoutMenu, SIGNAL(regionUpdated(const QRegion&)));
-    qDebug() << "...layout menu closed.";
-    c1 += 2;
+    // In normal input method mode there is no invisible handle with non-zero area
+    const QRect zeroSizeInvisibleHandleRect(
+        dynamic_cast<QGraphicsWidget*>(subject->vkbWidget->layout()->itemAt(MVirtualKeyboard::SharedHandleAreaIndex))->layout()->itemAt(0)
+        ->geometry().toRect());
+    QVERIFY(zeroSizeInvisibleHandleRect.isEmpty());
+
+    // In direct mode an invisible handle is added on top of the keyboard
+    subject->vkbWidget->setInputMethodMode(M::InputMethodModeDirect);
+    ++c1;
+    ++c2;
+    QCOMPARE(spy.count(), c1);
+    QCOMPARE(spy2.count(), c2);
+
+    const QRect invisibleHandleRect(
+        dynamic_cast<QGraphicsWidget*>(subject->vkbWidget->layout()->itemAt(MVirtualKeyboard::SharedHandleAreaIndex))->layout()->itemAt(0)
+        ->geometry().toRect());
+    QVERIFY(!invisibleHandleRect.isEmpty());
+    const QRegion invisibleHandleRegion(
+        invisibleHandleRect.translated(0, (region(spy2, 0).boundingRect().top()
+                                           - invisibleHandleRect.height())));
+
+    QCOMPARE(region(spy, c1 - 1), region(spy2, c2 - 1) + invisibleHandleRegion);
+
+    subject->vkbWidget->setInputMethodMode(M::InputMethodModeNormal);
+    ++c1;
+    ++c2;
     QCOMPARE(spy.count(), c1);
     QCOMPARE(spy2.count(), c2);
-    // ...and after closing the region is again the same as the input method area
+
     QCOMPARE(region(spy, c1 - 1), region(spy2, c2 - 1));
+    QCOMPARE(region(spy, c1 - 1), region(spy2, c1 - 3));
 
     // In opaque mode, candidate widget has its own window, so no regions are sent to kbhost.
 #ifndef DUI_IM_DISABLE_TRANSLUCENCY
@@ -636,7 +663,7 @@
     subject->correctionCandidateWidget->hide();
     ++c1;
     QCOMPARE(spy.count(), c1);
-    QCOMPARE(spy2.count(), 2);
+    QCOMPARE(spy2.count(), c2);
     QCOMPARE(region(spy, c1 - 1), region(spy2, c2 - 1));
 #endif
 
@@ -654,7 +681,8 @@
     ++c2;
     QCOMPARE(spy.count(), c1);
     QCOMPARE(spy2.count(), c2);
-    QCOMPARE(region(spy, c1BeforeSymOpen - 1), region(spy, c1 - 1)); // the same as before opening it
+    // the same as before opening it
+    QCOMPARE(region(spy, c1BeforeSymOpen - 1), region(spy, c1 - 1));
 
     // Hide the keyboard -> empty region and input method area
     subject->hide();
@@ -674,7 +702,11 @@
     rotateToAngle(M::Angle270);
     subject->show();
     QTest::qWait(MVirtualKeyboard::ShowHideTime + 50);
+
+    QCOMPARE(spy.count(), 2);
+    QCOMPARE(spy2.count(), 2);
     QCOMPARE(region(spy, 1), region(spy2, 1));
+
     QRegion region270(region(spy, 1));
     subject->hide();
     QTest::qWait(MVirtualKeyboard::ShowHideTime + 50);
@@ -800,18 +832,21 @@
 void Ut_MKeyboardHost::testSymbolKeyClick()
 {
     QVERIFY(subject->symbolView);
+
+    // Symbol view is toggled by clicking the Sym button.
+
+    // Initially symbol view is closed.
     QVERIFY(!subject->symbolView->isActive());
-    //symbol key click will active symbol view and switch the pages
-    int currentPageIndex;
-    for (int i = 0; i < subject->symbolView->pageCount(); i++) {
+    bool symOpenExpected = false;
+
+    for (int clicks = 1; clicks <= 3; ++clicks) {
         subject->handleSymbolKeyClick();
-        QVERIFY(subject->symbolView->isActive());
-        currentPageIndex = subject->symbolView->currentPage();
-        QCOMPARE(currentPageIndex, i);
+
+        const bool symOpen = subject->symbolView->isActive();
+        symOpenExpected = !symOpenExpected;
+
+        QCOMPARE(symOpen, symOpenExpected);
     }
-    //if reach the last page, then symbol view will be closed
-    subject->handleSymbolKeyClick();
-    QVERIFY(!subject->symbolView->isActive());
 }
 
 void Ut_MKeyboardHost::testUpdateSymbolViewLevel()
@@ -861,32 +896,33 @@
 
     //onscreen state
     QVERIFY(subject->vkbWidget);
-    QSignalSpy spy1(subject->vkbWidget, SIGNAL(shiftLevelChanged()));
-
     subject->autoCapsEnabled = false; // disable auto caps
-    subject->vkbWidget->setShiftState(MVirtualKeyboard::ShiftOff);
+    subject->vkbWidget->setShiftState(ModifierClearState);
     state.clear();
     state << OnScreen;
     subject->setState(state);
+    QSignalSpy spy1(subject->vkbWidget, SIGNAL(shiftLevelChanged()));
+
     QVERIFY(!subject->symbolView->isActive());
     subject->symbolView->showSymbolView();
     QVERIFY(subject->symbolView->isActive());
     QCOMPARE(subject->symbolView->currentLevel(), 0);
-    QCOMPARE(subject->vkbWidget->shiftStatus(), MVirtualKeyboard::ShiftOff);
+    QCOMPARE(subject->vkbWidget->shiftStatus(), ModifierClearState);
 
-    subject->vkbWidget->setShiftState(MVirtualKeyboard::ShiftOn);
-    QCOMPARE(subject->vkbWidget->shiftStatus(), MVirtualKeyboard::ShiftOn);
+    spy1.clear();
+    subject->vkbWidget->setShiftState(ModifierLatchedState);
+    QCOMPARE(subject->vkbWidget->shiftStatus(), ModifierLatchedState);
     QCOMPARE(spy1.count(), 1);
     QCOMPARE(subject->symbolView->currentLevel(), 1);
 
-    subject->vkbWidget->setShiftState(MVirtualKeyboard::ShiftLock);
+    subject->vkbWidget->setShiftState(ModifierLockedState);
     QCOMPARE(spy1.count(), 2);
-    QCOMPARE(subject->vkbWidget->shiftStatus(), MVirtualKeyboard::ShiftLock);
+    QCOMPARE(subject->vkbWidget->shiftStatus(), ModifierLockedState);
     QCOMPARE(subject->symbolView->currentLevel(), 1);
 
-    subject->vkbWidget->setShiftState(MVirtualKeyboard::ShiftOff);
+    subject->vkbWidget->setShiftState(ModifierClearState);
     QCOMPARE(spy1.count(), 3);
-    QCOMPARE(subject->vkbWidget->shiftStatus(), MVirtualKeyboard::ShiftOff);
+    QCOMPARE(subject->vkbWidget->shiftStatus(), ModifierClearState);
     QCOMPARE(subject->symbolView->currentLevel(), 0);
 
     subject->hide();
@@ -951,4 +987,106 @@
     QCOMPARE(inputContext->commit, QString(event2.text()[0]) + " ");
 }
 
+void Ut_MKeyboardHost::testPressShift_data()
+{
+    QTest::addColumn<MIMHandlerState>("state");
+    QTest::addColumn<ModifierState>("initialShiftState");
+    QTest::addColumn<ModifierState>("expectedShiftState");
+    QTest::addColumn<bool>("enableMultiTouch");
+
+    QTest::newRow("screen lowercase") << OnScreen << ModifierClearState   << ModifierLatchedState << true;
+    QTest::newRow("screen latched")   << OnScreen << ModifierLatchedState << ModifierClearState << true;
+    QTest::newRow("screen locked")    << OnScreen << ModifierLockedState  << ModifierClearState << true;
+
+    QTest::newRow("hw lowercase") << Hardware << ModifierClearState   << ModifierClearState << true;
+    QTest::newRow("hw latched")   << Hardware << ModifierLatchedState << ModifierLatchedState << true;
+    QTest::newRow("hw locked")    << Hardware << ModifierLockedState  << ModifierLockedState << true;
+
+    QTest::newRow("single-touch lowercase") << OnScreen << ModifierClearState   << ModifierClearState << false;
+    QTest::newRow("single-touch latched")   << OnScreen << ModifierLatchedState << ModifierLatchedState << false;
+    QTest::newRow("single-touch locked")    << OnScreen << ModifierLockedState  << ModifierLockedState << false;
+}
+
+void Ut_MKeyboardHost::testPressShift()
+{
+    QFETCH(MIMHandlerState, state);
+    QFETCH(ModifierState, initialShiftState);
+    QFETCH(ModifierState, expectedShiftState);
+    QFETCH(bool, enableMultiTouch);
+
+    QSet<MIMHandlerState> set;
+    set << state;
+
+    KeyEvent pressShift(QString(), QEvent::KeyPress, Qt::Key_Shift, KeyEvent::NotSpecial, Qt::ShiftModifier);
+
+    subject->setState(set);
+    subject->vkbWidget->setShiftState(initialShiftState);
+    subject->enableMultiTouch = enableMultiTouch;
+
+    subject->handleKeyPress(pressShift);
+    QVERIFY(subject->vkbWidget->shiftStatus() == expectedShiftState);
+
+    subject->handleKeyPress(pressShift);
+    QVERIFY(subject->vkbWidget->shiftStatus() == expectedShiftState);
+}
+
+void Ut_MKeyboardHost::testReleaseShift_data()
+{
+    QTest::addColumn<MIMHandlerState>("state");
+    QTest::addColumn<ModifierState>("initialShiftState");
+    QTest::addColumn<ModifierState>("expectedShiftState");
+    QTest::addColumn<bool>("upperCase");
+    QTest::addColumn<bool>("upperCase2");
+
+    QTest::newRow("screen lowercase") << OnScreen << ModifierClearState   << ModifierClearState   << false << false;
+    QTest::newRow("screen latched")   << OnScreen << ModifierLatchedState << ModifierLatchedState << false << false;
+    QTest::newRow("screen locked")    << OnScreen << ModifierLockedState  << ModifierLockedState  << false << false;
+
+    QTest::newRow("screen lowercase 2") << OnScreen << ModifierClearState   << ModifierLatchedState << false << true;
+    QTest::newRow("screen latched   2") << OnScreen << ModifierLatchedState << ModifierClearState   << true  << false;
+    QTest::newRow("screen locked    2") << OnScreen << ModifierLockedState  << ModifierLatchedState << false << true;
+
+    QTest::newRow("hw lowercase") << Hardware << ModifierClearState   << ModifierClearState   << false << false;
+    QTest::newRow("hw latched")   << Hardware << ModifierLatchedState << ModifierLatchedState << false << false;
+    QTest::newRow("hw locked")    << Hardware << ModifierLockedState  << ModifierLockedState  << false << false;
+}
+
+void Ut_MKeyboardHost::testReleaseShift()
+{
+    QFETCH(MIMHandlerState, state);
+    QFETCH(ModifierState, initialShiftState);
+    QFETCH(ModifierState, expectedShiftState);
+    QFETCH(bool, upperCase);
+    QFETCH(bool, upperCase2);
+
+    QSet<MIMHandlerState> set;
+    set << state;
+
+    KeyEvent pressShift  (QString(), QEvent::KeyPress,   Qt::Key_Shift, KeyEvent::NotSpecial, Qt::ShiftModifier);
+    KeyEvent releaseShift(QString(), QEvent::KeyRelease, Qt::Key_Shift, KeyEvent::NotSpecial, Qt::ShiftModifier);
+
+    subject->setState(set);
+    subject->vkbWidget->setShiftState(initialShiftState);
+    subject->upperCase = upperCase;
+
+    subject->handleKeyPress(pressShift);
+    subject->upperCase = upperCase2;
+    subject->handleKeyRelease(releaseShift);
+    QVERIFY(subject->vkbWidget->shiftStatus() == expectedShiftState);
+
+    subject->handleKeyRelease(releaseShift);
+    QVERIFY(subject->vkbWidget->shiftStatus() == expectedShiftState);
+}
+
+void Ut_MKeyboardHost::testCommitPreeditOnStateChange()
+{
+    const QString text("fish");
+    subject->setPreedit(text);
+    QSet<MIMHandlerState> state;
+    state << Hardware;
+    subject->setState(state);
+    QCOMPARE(inputContext->commit, text);
+}
+
 QTEST_APPLESS_MAIN(Ut_MKeyboardHost);
+
--- unit_test/ut_mkeyboardhost/ut_mkeyboardhost.h
+++ unit_test/ut_mkeyboardhost/ut_mkeyboardhost.h
@@ -70,6 +70,14 @@
     void testKeyCycle_data();
     void testKeyCycle();
 
+    void testPressShift_data();
+    void testPressShift();
+
+    void testReleaseShift_data();
+    void testReleaseShift();
+
+    void testCommitPreeditOnStateChange();
+
 private:
     void rotateToAngle(M::OrientationAngle);
 };
--- unit_test/ut_mkeyboardhost/ut_mkeyboardhost.pro
+++ unit_test/ut_mkeyboardhost/ut_mkeyboardhost.pro
@@ -6,16 +6,17 @@
 
 LIBS += -L/usr/lib -Wl,-rpath=/usr/lib/meego-im-plugins/ -lmeego-keyboard
 
-CONFIG += duiimengine duiimenginewords link_pkgconfig
+CONFIG += meegoimengine meegoimenginewords link_pkgconfig
 PKGCONFIG += gconf-2.0
 
 # Input
 HEADERS += ut_mkeyboardhost.h \
            minputcontextstubconnection.h \
            ../stubs/mgconfitem_stub.h \
-           ../stubs/fakegconf.h
+           ../stubs/fakegconf.h \
+
 SOURCES += ut_mkeyboardhost.cpp \
            minputcontextstubconnection.cpp \
-           ../stubs/fakegconf.cpp
+           ../stubs/fakegconf.cpp \
 
 include(../common_check.pri)
--- unit_test/ut_mkeyboardplugin/ut_mkeyboardplugin.cpp
+++ unit_test/ut_mkeyboardplugin/ut_mkeyboardplugin.cpp
@@ -51,12 +51,6 @@
     // some simple checks that the functions seems to work
     // check name of plugin
     QVERIFY(m_subject->name() == "MeegoKeyboard");
-
-    // check possible languages
-    QVERIFY(m_subject->languages().count() == 1);
-
-    // only language at the moment is 'en' for this plugin
-    QVERIFY(m_subject->languages().indexOf("en") != -1);
 }
 
 
--- unit_test/ut_mvirtualkeyboard/ut_mvirtualkeyboard.cpp
+++ unit_test/ut_mvirtualkeyboard/ut_mvirtualkeyboard.cpp
@@ -19,10 +19,10 @@
 #include "mapplication.h"
 #include "mgconfitem_stub.h"
 #include "mreactionmaptester.h"
+#include "mvirtualkeyboardstyle.h"
 #include "mvirtualkeyboard.h"
 #include "horizontalswitcher.h"
 #include "layoutsmanager.h"
-#include "toolbarmanager.h"
 #include "notification.h"
 #include "ut_mvirtualkeyboard.h"
 #include "vkbdatakey.h"
@@ -41,7 +41,6 @@
 #include <QGraphicsLayout>
 #include <mtexteditmodel.h>
 #include <mtheme.h>
-#include <layoutmenu.h>
 
 namespace
 {
@@ -57,11 +56,6 @@
 {
 }
 
-LayoutMenu::~LayoutMenu()
-{
-//this stub allows to avoid crash in libmeegotouch
-}
-
 void Notification::displayText(const QString &message)
 {
     Q_UNUSED(message);
@@ -84,28 +78,14 @@
     MGConfItem item1(InputMethodSetting);
 
     QStringList langlist;
-    langlist << "en_GB" << "fi" << "ar_SA";
+    langlist << "en_GB" << "fi" << "ar";
     item1.set(QVariant(langlist));
 
     QString DefaultLanguageSetting("/meegotouch/inputmethods/languages/default");
     MGConfItem item2(DefaultLanguageSetting);
-    QString defaultlanguage = "en_GB";
+    QString defaultlanguage = "en_gb";
     item2.set(QVariant(defaultlanguage));
 
-    QString pixmapDirectory("../../m-keyboard/theme");
-    if (!QFile::exists(pixmapDirectory)) {
-        pixmapDirectory = "/usr/share/meegotouch/virtual-keyboard/images";
-        QVERIFY(QFile::exists(pixmapDirectory));
-    }
-    MTheme::instance()->addPixmapDirectory(pixmapDirectory);
-
-    QString cssFile("../../m-keyboard/theme/864x480.css");
-    if (!QFile::exists(cssFile)) {
-        cssFile = "/usr/share/meegotouch/virtual-keyboard/css/864x480.css";
-        QVERIFY(QFile::exists(cssFile));
-    }
-    MTheme::instance()->loadCSS(cssFile);
-
     // MVirtualkeyboard uses MPlainWindow internally so we need to instantiate it.
     new MPlainWindow; // creates a static instance
 
@@ -115,14 +95,17 @@
     MPlainWindow::instance()->sceneManager()->appearSceneWindowNow(vkbParent);
 
     LayoutsManager::createInstance();
-    ToolbarManager::createInstance();
+
+    vkbStyleContainer = new MVirtualKeyboardStyleContainer;
+    vkbStyleContainer->initialize("MVirtualKeyboard", "MVirtualKeyboardView", 0);
 }
 
 void Ut_MVirtualKeyboard::cleanupTestCase()
 {
-    ToolbarManager::destroyInstance();
     LayoutsManager::destroyInstance();
     delete vkbParent;
+    delete vkbStyleContainer;
+    vkbStyleContainer = 0;
     delete MPlainWindow::instance();
     delete app;
     app = 0;
@@ -130,7 +113,7 @@
 
 void Ut_MVirtualKeyboard::init()
 {
-    m_vkb = new MVirtualKeyboard(LayoutsManager::instance(), vkbParent);
+    m_vkb = new MVirtualKeyboard(LayoutsManager::instance(), vkbStyleContainer, vkbParent);
 
     connect(m_vkb, SIGNAL(regionUpdated(const QRegion &)), m_vkb, SLOT(redrawReactionMaps()));
 
@@ -143,6 +126,7 @@
     // Stub might have been set to a local instance.
     gMReactionMapStub = &gDefaultMReactionMapStub;
     delete m_vkb;
+    m_vkb = 0;
 }
 
 void Ut_MVirtualKeyboard::clickBackspaceTest()
@@ -211,10 +195,10 @@
 
 void Ut_MVirtualKeyboard::setShiftStateTest()
 {
-    QList<MVirtualKeyboard::ShiftLevel> levels;
-    levels << MVirtualKeyboard::ShiftOn << MVirtualKeyboard::ShiftOff
-           << MVirtualKeyboard::ShiftLock;
-    foreach(MVirtualKeyboard::ShiftLevel level, levels) {
+    QList<ModifierState> levels;
+    levels << ModifierLatchedState << ModifierClearState
+           << ModifierLockedState;
+    foreach(ModifierState level, levels) {
         m_vkb->setShiftState(level);
         QCOMPARE(m_vkb->shiftStatus(), level);
     }
@@ -366,7 +350,7 @@
     QCOMPARE(m_vkb->activity, MVirtualKeyboard::Active);
 
     // Set states that should be changed next time opening vkb.
-    m_vkb->setShiftState(MVirtualKeyboard::ShiftOn); // Shift on
+    m_vkb->setShiftState(ModifierLatchedState); // Shift on
 
     // Test after reopening the keyboard, rather than after closing.
     m_vkb->hideKeyboard();
@@ -374,12 +358,12 @@
     m_vkb->showKeyboard();
     QTest::qWait(MVirtualKeyboard::ShowHideTime + 50);
 
-    QCOMPARE(m_vkb->shiftStatus(), MVirtualKeyboard::ShiftOff); // Shift should be off
+    QCOMPARE(m_vkb->shiftStatus(), ModifierClearState); // Shift should be off
 }
 
 void Ut_MVirtualKeyboard::switchLevelTest()
 {
-    m_vkb->shiftLevel = MVirtualKeyboard::ShiftLock;
+    m_vkb->shiftLevel = ModifierLockedState;
     m_vkb->switchLevel();
     QCOMPARE(m_vkb->currentLevel, 1);
 }
@@ -796,16 +780,17 @@
     m_vkb->setCopyPasteButton(true, false);
     QVERIFY(top >= m_vkb->geometry().top());
     top = m_vkb->geometry().top();
+    const int topInHardwareState(top);
 
     //show whole keyboard
     m_vkb->setKeyboardState(OnScreen);
-    top -= m_vkb->layout()->itemAt(1)->geometry().height();
+    top -= m_vkb->layout()->itemAt(MVirtualKeyboard::KeyboardIndex)->geometry().height()
+        + m_vkb->layout()->itemAt(MVirtualKeyboard::KeyboardHandleIndex)->geometry().height();
     QCOMPARE(top, int(m_vkb->geometry().top()));
 
     //show toolbar only
     m_vkb->setKeyboardState(Hardware);
-    top += m_vkb->layout()->itemAt(1)->geometry().height();
-    QCOMPARE(top, int(m_vkb->geometry().top()));
+    QCOMPARE(topInHardwareState, int(m_vkb->geometry().top()));
 }
 
 void Ut_MVirtualKeyboard::testReactionMaps()
@@ -871,10 +856,10 @@
     QSignalSpy spy(m_vkb, SIGNAL(showSymbolViewRequested()));
     QVERIFY(spy.isValid());
 
-    m_vkb->flickUpHandler(0);
+    m_vkb->flickUpHandler(KeyBinding());
     QCOMPARE(spy.count(), 0);
 
-    m_vkb->flickUpHandler(&binding);
+    m_vkb->flickUpHandler(binding);
     QCOMPARE(spy.count(), expected);
 }
 
--- unit_test/ut_mvirtualkeyboard/ut_mvirtualkeyboard.h
+++ unit_test/ut_mvirtualkeyboard/ut_mvirtualkeyboard.h
@@ -26,6 +26,7 @@
 
 class MApplication;
 class MVirtualKeyboard;
+class MVirtualKeyboardStyleContainer;
 class QGraphicsScene;
 class LayoutSection;
 class MSceneWindow;
@@ -37,6 +38,7 @@
     MApplication *app;
     MVirtualKeyboard *m_vkb;
     MSceneWindow *vkbParent;
+    MVirtualKeyboardStyleContainer *vkbStyleContainer;
     QSharedPointer<const LayoutSection> functionkeySection;
     int numFunctionKeys;
 
--- unit_test/ut_symbolview/ut_symbolview.cpp
+++ unit_test/ut_symbolview/ut_symbolview.cpp
@@ -44,7 +44,7 @@
 {
     const QString InputMethodSettingName("/meegotouch/inputmethods/languages");
     const QString DefaultLanguageSettingName("/meegotouch/inputmethods/languages/default");
-    const QString DefaultLanguage("en");
+    const QString DefaultLanguage("en_us");
 
     const int SceneRotationTime = 1400;
 } // namespace
@@ -59,14 +59,13 @@
     // Avoid waiting if im server is not responding
     MApplication::setLoadMInputContext(false);
     app = new MApplication(argc, app_name);
-    MTheme::instance()->loadCSS("/usr/share/meegotouch/virtual-keyboard/css/864x480.css");
     style = new MVirtualKeyboardStyleContainer;
     style->initialize("MVirtualKeyboard", "MVirtualKeyboardView", 0);
 
     MGConfItem inputMethodSetting(InputMethodSettingName);
 
     QStringList langlist;
-    langlist << "en";
+    langlist << "en_us";
     inputMethodSetting.set(QVariant(langlist));
 
     MGConfItem defaultLanguageSetting(DefaultLanguageSettingName);
@@ -304,4 +303,14 @@
     subject->finalizeOrientationChange();
 }
 
+void Ut_SymbolView::testSetLanguage()
+{
+    // set an invalid language, at least it won't crash
+    // and still has the laste valid language.
+    QString oldLanguage = subject->currentLanguage;
+    subject->setLanguage("ThisLanguageLayoutShouldNotExist");
+    QVERIFY(subject->currentLanguage != "ThisLanguageLayoutShouldNotExist");
+    QCOMPARE(subject->currentLanguage, oldLanguage);
+}
+
 QTEST_APPLESS_MAIN(Ut_SymbolView);
--- unit_test/ut_symbolview/ut_symbolview.h
+++ unit_test/ut_symbolview/ut_symbolview.h
@@ -56,6 +56,7 @@
     void testChangeTab();
     void testHideWithFlick_data();
     void testHideWithFlick();
+    void testSetLanguage();
 
 private:
     void rotateToAngle(M::OrientationAngle angle);
--- unit_test/ut_toolbarmanager/ut_toolbarmanager.cpp
+++ unit_test/ut_toolbarmanager/ut_toolbarmanager.cpp
-/* * This file is part of meego-keyboard *
- *
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
- * All rights reserved.
- * Contact: Nokia Corporation (directui at nokia.com)
- *
- * If you have questions regarding the use of this file, please contact
- * Nokia at directui at nokia.com.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * and appearing in the file LICENSE.LGPL included in the packaging
- * of this file.
- */
-
-
-
-#include "ut_toolbarmanager.h"
-#include <toolbarmanager.h>
-#include <toolbardata.h>
-#include <MApplication>
-#include <QDebug>
-
-
-namespace {
-    const int MaximumToolbarCount = 10;
-}
-
-// overwrite ToolbarData::loadNokiaToolbarXml to avoid loading actual xml file.
-bool ToolbarData::loadNokiaToolbarXml(const QString &fileName)
-{
-    Q_UNUSED(fileName);
-    toolbarFileName = fileName;
-    return true;
-}
-
-void Ut_ToolbarManager::initTestCase()
-{
-    // Avoid waiting if im server is not responding
-    MApplication::setLoadMInputContext(false);
-
-    static char *argv[1] = {(char *) "ut_toolbarmanager"};
-    static int argc = 1;
-    app = new MApplication(argc, argv);
-}
-
-void Ut_ToolbarManager::cleanupTestCase()
-{
-    delete app;
-    app = 0;
-}
-
-void Ut_ToolbarManager::init()
-{
-}
-
-void Ut_ToolbarManager::cleanup()
-{
-}
-
-void Ut_ToolbarManager::testLoadToolbar()
-{
-    std::auto_ptr<ToolbarManager> subject(new ToolbarManager);
-    QList<qlonglong> toolbarIds;
-    for (qlonglong i = 1; i <= 14; i ++)
-        toolbarIds <<  i;
-    QStringList toolbars;
-    toolbars << "testToolbar1"
-             << "testToolbar2"
-             << "testToolbar3"
-             << "testToolbar4"
-             << "testToolbar5"
-             << "testToolbar6"
-             << "testToolbar7"
-             << "testToolbar8"
-             << "testToolbar9"
-             << "testToolbar10"
-             << "testToolbar11"
-             << "testToolbar12"
-             << "testToolbar13"
-             << "testToolbar14";
-
-    int toolbarCount = 0;
-    // register all toolbars
-    for (int i = 0; i < toolbarIds.count(); i++) {
-        subject->registerToolbar(toolbarIds.at(i), toolbars.at(i));
-        toolbarCount ++;
-        QTest::qWait(50);
-        //toolbar loop can only cache no more than MaximumToolbarCount toolbars
-        if (toolbarCount < MaximumToolbarCount)
-            QCOMPARE(subject->toolbarList().count(), toolbarCount);
-        else
-            QCOMPARE(subject->toolbarList().count(), MaximumToolbarCount);
-    }
-
-    for (int i = 0; i < toolbarIds.count(); i++) {
-        QVERIFY(subject->loadToolbar(toolbarIds.at(i)));
-        QTest::qWait(50);
-        // the loaded toolbar is the current toolbar
-        QCOMPARE(subject->currentToolbar(), toolbarIds.at(i));
-        QVERIFY(subject->toolbarList().contains(toolbarIds.at(i)));
-        if (i > MaximumToolbarCount) {
-            // the rarely used toolbar will be removed from cached toolbars
-            QVERIFY(!subject->toolbarList().contains(toolbarIds.at(i - MaximumToolbarCount)));
-        }
-    }
-
-    toolbarCount = toolbarIds.count();
-    foreach (qlonglong id, toolbarIds) {
-        QVERIFY(subject->toolbars.contains(id));
-        subject->unregisterToolbar(id);
-        toolbarCount --;
-        QCOMPARE(subject->toolbars.count(), toolbarCount);
-        QVERIFY(!subject->toolbars.contains(id));
-    }
-}
-
-QTEST_APPLESS_MAIN(Ut_ToolbarManager);
-
--- unit_test/ut_toolbarmanager/ut_toolbarmanager.h
+++ unit_test/ut_toolbarmanager/ut_toolbarmanager.h
-/* * This file is part of meego-keyboard *
- *
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
- * All rights reserved.
- * Contact: Nokia Corporation (directui at nokia.com)
- *
- * If you have questions regarding the use of this file, please contact
- * Nokia at directui at nokia.com.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * and appearing in the file LICENSE.LGPL included in the packaging
- * of this file.
- */
-
-
-
-#ifndef UT_TOOLBARMANAGER_H
-#define UT_TOOLBARMANAGER_H
-
-#include <QObject>
-#include <QtTest/QTest>
-
-class MApplication;
-
-class Ut_ToolbarManager : public QObject
-{
-    Q_OBJECT
-
-private slots:
-    void initTestCase();
-    void cleanupTestCase();
-    void init();
-    void cleanup();
-    void testLoadToolbar();
-
-private:
-    MApplication *app;
-};
-
-#endif
-
--- unit_test/ut_toolbarmanager/ut_toolbarmanager.pro
+++ unit_test/ut_toolbarmanager/ut_toolbarmanager.pro
-TEMPLATE = app
-CONFIG += QtTest meegotouch
-DEPENDPATH += .
-INCLUDEPATH += 	. \
-		../../m-keyboard/ \
-		../stubs/
-
-LIBS += -Wl,-rpath=/usr/lib/meego-im-plugins/ -L../../m-keyboard -lmeego-keyboard
-
-# Input
-HEADERS += ut_toolbarmanager.h \
-
-SOURCES += ut_toolbarmanager.cpp \
-
-include(../common_check.pri)
--- unit_test/ut_vkbdatakey/ut_vkbdatakey.cpp
+++ unit_test/ut_vkbdatakey/ut_vkbdatakey.cpp
@@ -37,7 +37,6 @@
     // Avoid waiting if im server is not responding
     MApplication::setLoadMInputContext(false);
     app = new MApplication(argc, app_name);
-    MTheme::instance()->loadCSS("/usr/share/meegotouch/virtual-keyboard/css/864x480.css");
 }
 
 void Ut_VKBDataKey::cleanupTestCase()
--- unit_test/ut_widgetbar/ut_widgetbar.cpp
+++ unit_test/ut_widgetbar/ut_widgetbar.cpp
@@ -16,12 +16,15 @@
 
 #include "ut_widgetbar.h"
 #include "widgetbar.h"
+#include "mtoolbarbutton.h"
+#include "mtoolbarlabel.h"
 
 #include <MApplication>
 #include <MButton>
 #include <MLabel>
 
 #include <QGraphicsLayout>
+#include <mtoolbaritem.h>
 
 void Ut_WidgetBar::initTestCase()
 {
@@ -208,5 +211,44 @@
     QCOMPARE(index, -1);
 }
 
+void Ut_WidgetBar::testLayoutUpdates()
+{
+    QSharedPointer<MToolbarItem> buttonItem1(new MToolbarItem("buttonItem1", MInputMethod::ItemButton));
+    QSharedPointer<MToolbarItem> buttonItem2(new MToolbarItem("buttonItem2", MInputMethod::ItemButton));
+    QSharedPointer<MToolbarItem> buttonItem3(new MToolbarItem("buttonItem3", MInputMethod::ItemButton));
+    QSharedPointer<MToolbarItem> labelItem(new MToolbarItem("labelItem", MInputMethod::ItemLabel));
+
+    MToolbarButton *button1 = new MToolbarButton(buttonItem1);
+    MToolbarButton *button2 = new MToolbarButton(buttonItem2);
+    MToolbarButton *button3 = new MToolbarButton(buttonItem3);
+    MToolbarLabel *label1 = new MToolbarLabel(labelItem);
+
+    subject->insert(0, button1);
+    subject->insert(1, button2);
+    subject->insert(2, label1);
+    subject->insert(3, button3);
+
+    QCOMPARE(subject->layout()->count(), 4);
+
+    labelItem->setVisible(false);
+    buttonItem2->setVisible(false);
+    buttonItem1->setVisible(false);
+
+    QCOMPARE(subject->layout()->count(), 1);
+    QCOMPARE(subject->layoutIndexOf(button3), 0);
+
+    buttonItem2->setVisible(true);
+    QCOMPARE(subject->layoutIndexOf(button2), 0);
+
+    labelItem->setVisible(true);
+    QCOMPARE(subject->layoutIndexOf(button2), 0);
+    QCOMPARE(subject->layoutIndexOf(label1), 1);
+
+    buttonItem1->setVisible(true);
+    QCOMPARE(subject->layoutIndexOf(button1), 0);
+    QCOMPARE(subject->layoutIndexOf(button2), 1);
+    QCOMPARE(subject->layoutIndexOf(label1), 2);
+    QCOMPARE(subject->layoutIndexOf(button3), 3);
+}
 
 QTEST_APPLESS_MAIN(Ut_WidgetBar);
--- unit_test/ut_widgetbar/ut_widgetbar.h
+++ unit_test/ut_widgetbar/ut_widgetbar.h
@@ -47,6 +47,8 @@
     void testLayoutContent();
 
     void testIndexOf();
+
+    void testLayoutUpdates();
 };
 
 #endif // UT_WIDGETBAR_H
--- unit_test/ut_widgetbar/ut_widgetbar.pro
+++ unit_test/ut_widgetbar/ut_widgetbar.pro
@@ -1,14 +1,21 @@
 TEMPLATE = app
-CONFIG += QtTest meegotouch
+CONFIG += QtTest meegotouch meegoimframework
 
 include(../common_check.pri)
 
-STYLE_HEADERS += $$WIDGETS_DIR/widgetbarstyle.h
+STYLE_HEADERS += $$WIDGETS_DIR/widgetbarstyle.h \
+                 $$WIDGETS_DIR/mtoolbarbuttonstyle.h \
 
 SOURCES += ut_widgetbar.cpp \
-           $$WIDGETS_DIR/widgetbar.cpp
+           $$WIDGETS_DIR/widgetbar.cpp \
+           $$WIDGETS_DIR/mtoolbarbutton.cpp \
+           $$WIDGETS_DIR/mtoolbarlabel.cpp \
+           $$WIDGETS_DIR/mtoolbarbuttonview.cpp \
 
 HEADERS += ut_widgetbar.h \
            $$WIDGETS_DIR/widgetbar.h \
+           $$WIDGETS_DIR/mtoolbarbutton.h \
+           $$WIDGETS_DIR/mtoolbarlabel.h \
+           $$WIDGETS_DIR/mtoolbarbuttonview.h \
            $$STYLE_HEADERS \
 

++++++ meegotouch-inputmethodkeyboard.yaml
--- meegotouch-inputmethodkeyboard.yaml
+++ meegotouch-inputmethodkeyboard.yaml
@@ -1,6 +1,6 @@
 Name: meegotouch-inputmethodkeyboard
 Summary: MeeGo Virtual Keyboard
-Version: 0.4.2.1
+Version: 0.4.8
 Release: 1
 Group: System/GUI/Other 
 License: LGPL v2.1
@@ -9,14 +9,6 @@
     - "%{name}-%{version}.tar.bz2"
 Description: MeeGo Virtual Keyboard
 
-# Remove this once duiimengine, meegoimframework, meegotouchfeedback
-# and meegotouchfeedbackreactionmaps have been removed
-# Then uncomment lines in PkgConfigBR
-PkgBR:
-    - meegotouch-inputmethodframework-devel
-    - meegotouch-inputmethodengine-devel
-    - meegotouch-feedback-devel
-    - meegotouch-feedbackreactionmaps-devel
 PkgConfigBR:
     - QtCore >= 4.6.0
     - QtDBus
@@ -25,10 +17,9 @@
     - QtNetwork
     - QtGui
     - meegotouch 
-#    - MeegoImFramework
-#    - DuiImEngine
-#    - DuiImEngineWords
-#    - meegotouchfeedbackreactionmaps
+    - MeegoImFramework
+    - MeegoImEngine
+    - meegotouch-feedbackreactionmaps
 
 Provides:
     - duikeyboard >= 0.4.0


More information about the MeeGo-commits mailing list