src/hbinput/inputwidgets/hbinputbuttongroup.cpp
changeset 2 06ff229162e9
child 3 11d3954df52a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hbinput/inputwidgets/hbinputbuttongroup.cpp	Fri May 14 16:09:54 2010 +0300
@@ -0,0 +1,1764 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (developer.feedback@nokia.com)
+**
+** This file is part of the HbInput module of the UI Extensions for Mobile.
+**
+** GNU Lesser General Public License Usage
+** This file may be used 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.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at developer.feedback@nokia.com.
+**
+****************************************************************************/
+
+#include <QPainter>
+#include <QTextLayout>
+#include <QGraphicsSceneMouseEvent>
+#include <QTouchEvent>
+#include <QTimer>
+#include <QGraphicsDropShadowEffect>
+
+#include <hbmainwindow.h>
+#include <hbaction.h>
+#include <hbevent.h>
+#include <hbcolorscheme.h>
+#include <hbdialog.h>
+#include <hbframeitem.h>
+#include <hbwidgetfeedback.h>
+#include <hbdeviceprofile.h>
+#include "hbframedrawerpool_p.h"
+
+#include "hbinputbuttongroup.h"
+#include "hbinputbuttongroup_p.h"
+#include "hbinputbutton.h"
+
+/// @cond
+
+const QString HbNormalBackground("qtg_fr_input_btn_keypad_normal");
+const QString HbNormalPressedBackground("qtg_fr_input_btn_keypad_pressed");
+const QString HbNormalInActiveBackground("qtg_fr_input_btn_keypad_disabled");
+const QString HbNormalLatchedBackground("qtg_fr_input_btn_keypad_latched");
+
+const QString HbFunctionBackground("qtg_fr_input_btn_function_normal");
+const QString HbFunctionPressedBackground("qtg_fr_input_btn_function_pressed");
+const QString HbFunctionInActiveBackground("qtg_fr_input_btn_function_disabled");
+const QString HbFunctionLatchedBackground("qtg_fr_input_btn_function_latched");
+
+const QString HbPreviewBackground("qtg_fr_character_preview");
+
+const QString HbNormalColor("qtc_input_button_normal");
+const QString HbNormalColorPressed("qtc_input_button_pressed");
+const QString HbNormalColorInActive("qtc_input_button_disabled");
+const QString HbNormalColorLatched("qtc_input_button_latched");
+
+const QString HbFunctionColor("qtc_input_function_normal");
+const QString HbFunctionColorPressed("qtc_input_function_pressed");
+const QString HbFunctionColorInActive("qtc_input_function_disabled");
+const QString HbFunctionColorLatched("qtc_input_function_latched");
+
+const QString HbButtonPreviewColor("qtc_input_preview_normal");
+const QString HbCharacterSelectionPreviewColor("qtc_input_button_accented_normal");
+
+const int HbLongPressTimeout = 600;
+const int HbAutoRepeatTimeout = 100;
+
+const int HbTextTypeCount = HbInputButton::ButtonTypeCount * HbInputButton::ButtonStateCount;
+const int HbTextLayoutCount = HbTextTypeCount * 3;
+
+const qreal HbTextSizeInUnits = 5.75;
+const qreal HbPrimaryTextSizeInUnits = 5.37;
+const qreal HbSecondaryTextSizeInUnits = 3.36;
+const qreal HbLabelTextSizeInUnits = 9;
+const qreal HbPrimaryIconSizeInUnits = 5;
+const qreal HbSecondaryIconSizeInUnits = 3.36;
+const qreal HbHorizontalMarginInUnits = 0.75;
+const qreal HbVerticalMarginInUnits = 1.14;
+const qreal HbPreviewWidthInUnits = 10;
+const qreal HbPreviewHeightInUnits = 16;
+const qreal HbPreviewMarginInUnits = 3;
+
+const qreal HbTouchAreaSizeInUnits = 8;
+
+HbInputButtonGroupPrivate::HbInputButtonGroupPrivate()
+ : mUnitValue(0), mGridSize(1, 1), mButtonBorderSize(1.0), mEnabled(true),
+   mButtonPreviewEnabled(false), mCharacterSelectionPreviewEnabled(false),
+   mMultiTouchEnabled(true), mCharacterSelectionPreview(0), mBackground(0)
+{
+    for (int i = 0; i < HbTextLayoutCount; ++i) {
+        mTextLayouts.append(0);
+    }
+
+    updateColorArray();
+}
+
+HbInputButtonGroupPrivate::~HbInputButtonGroupPrivate()
+{
+    foreach(HbFrameDrawer *drawer, mButtonDrawers) {
+        HbFrameDrawerPool::release(drawer);
+    }
+
+    foreach (HbInputButton *button, mButtonData) {
+        delete button;
+    }
+    mButtonData.clear();
+
+    foreach (QTextLayout *layout, mTextLayouts) {
+        delete layout;
+    }
+
+    foreach (QTimer *timer, mLongPressTimers) {
+        delete timer;
+    }
+
+    delete mCharacterSelectionPreview;
+
+    HbFrameDrawerPool::release(mBackground);
+}
+
+void HbInputButtonGroupPrivate::updateGraphics(const QSizeF &size)
+{
+    if (!size.width() && !size.height()) {
+        return;
+    }
+
+    qreal cellWidth = size.width() / mGridSize.width();
+    qreal cellHeight = size.height() / mGridSize.height();
+
+    for (int i = 0; i < mButtonData.count(); ++i) {
+        HbInputButton *item = mButtonData.at(i);
+
+        qreal width = cellWidth * item->size().width() - 2 * mButtonBorderSize;
+        qreal height = cellHeight * item->size().height() - 2 * mButtonBorderSize;
+        QSizeF frameSize = QSizeF(width, height);
+        HbFrameDrawer *drawer = 0;
+        QColor color;
+        if (mEnabled) {
+            drawer = HbFrameDrawerPool::get(buttonGraphics(item->type(), item->state()), HbFrameDrawer::NinePieces, frameSize);
+            color = mColors.at(item->type() * HbInputButton::ButtonStateCount + item->state());
+        } else {
+            drawer = HbFrameDrawerPool::get(buttonGraphics(item->type(), HbInputButton::ButtonStateDisabled), HbFrameDrawer::NinePieces, frameSize);
+            color = mColors.at(item->type() * HbInputButton::ButtonStateCount + HbInputButton::ButtonStateDisabled);
+        }
+
+        if (i < mButtonDrawers.count()) {
+            if (drawer != mButtonDrawers.at(i)) {
+                HbFrameDrawerPool::release(mButtonDrawers.at(i));
+                mButtonDrawers.replace(i, drawer);
+            }
+        } else {
+            mButtonDrawers.append(drawer);
+        }
+
+        QList<HbIcon> icons = item->icons();
+        for (int i = 0; i < icons.count(); ++i) {
+            if (!icons.at(i).isNull()) {
+                icons[i].setColor(color);
+            }
+        }
+        item->setIcons(icons);
+    }
+
+    for (int i = mButtonDrawers.count() - 1; i >= mButtonData.count(); --i) {
+        HbFrameDrawerPool::release(mButtonDrawers.at(i));
+        mButtonDrawers.removeAt(i);
+    }
+}
+
+void HbInputButtonGroupPrivate::updateTextLayouts(const QSizeF &size)
+{
+    if (!size.width() && !size.height()) {
+        return;
+    }
+
+    QHash<int, QString> textContent;
+    for (int i = 0; i < HbTextLayoutCount; ++i) {
+        delete mTextLayouts[i];
+        mTextLayouts[i] = 0;
+    }
+
+    // Sort different button texts to correct text content based on the
+    // button type and state
+    for (int i = 0; i < mButtonData.count(); ++i) {
+        HbInputButton *item = mButtonData.at(i);
+
+        int index = item->type() * HbInputButton::ButtonStateCount + item->state();
+        if (!mEnabled) {
+            index = item->type() * HbInputButton::ButtonStateCount + HbInputButton::ButtonStateDisabled;
+        }
+
+        if (!item->text(HbInputButton::ButtonTextIndexPrimary).isEmpty() &&
+            item->icon(HbInputButton::ButtonIconIndexPrimary).isNull()) {
+            int primaryIndex = index;
+            if (item->text(HbInputButton::ButtonTextIndexSecondaryFirstRow).isEmpty() &&
+                item->icon(HbInputButton::ButtonIconIndexSecondaryFirstRow).isNull() &&
+                item->text(HbInputButton::ButtonTextIndexSecondarySecondRow).isEmpty() &&
+                item->icon(HbInputButton::ButtonIconIndexSecondarySecondRow).isNull()) {
+                primaryIndex += HbTextTypeCount;
+            }
+            textContent[primaryIndex] += item->text(HbInputButton::ButtonTextIndexPrimary);
+            textContent[primaryIndex] += QChar(QChar::LineSeparator);
+        }
+
+        index += HbTextTypeCount * 2;
+
+        if (!item->text(HbInputButton::ButtonTextIndexSecondaryFirstRow).isEmpty() &&
+            item->icon(HbInputButton::ButtonIconIndexSecondaryFirstRow).isNull()) {
+            textContent[index] += item->text(HbInputButton::ButtonTextIndexSecondaryFirstRow);
+            textContent[index] += QChar(QChar::LineSeparator);
+        }
+
+        if (!item->text(HbInputButton::ButtonTextIndexSecondarySecondRow).isEmpty() &&
+            item->icon(HbInputButton::ButtonIconIndexSecondarySecondRow).isNull()) {
+            textContent[index] += item->text(HbInputButton::ButtonTextIndexSecondarySecondRow);
+            textContent[index] += QChar(QChar::LineSeparator);
+        }
+    }
+
+    // Create text layouts for each text content
+    for (int index = 0; index < HbTextLayoutCount; ++index) {
+        if (textContent.contains(index)) {
+            int textIndex = index / HbTextTypeCount;
+            if (textIndex == 0) {
+                createPrimaryTextLayout(index, textContent, size);
+            } else if (textIndex == 1) {
+                createPrimarySingleTextLayout(index, textContent, size);
+            } else {
+                createSecondaryTextLayout(index, textContent, size);
+            }
+        }
+    }
+}
+
+void HbInputButtonGroupPrivate::updateCustomActions()
+{
+    for (int i = 0; i < mUsedCustomButtons.count(); ++i) {
+        if (i < mButtonData.count()) {
+            HbInputButton *item = mButtonData.at(mUsedCustomButtons.at(i));
+
+            item->setIcon(HbIcon(), HbInputButton::ButtonIconIndexPrimary);
+            item->setText(QString(), HbInputButton::ButtonTextIndexPrimary);
+            item->setText(QString(), HbInputButton::ButtonTextIndexSecondaryFirstRow);
+            item->setText(QString(), HbInputButton::ButtonTextIndexSecondarySecondRow);
+            item->setState(HbInputButton::ButtonStateReleased);
+        }
+    }
+    mUsedCustomButtons.clear();
+
+    for (int i = 0; i < mButtonData.count(); ++i) {
+        HbInputButton *item = mButtonData.at(i);
+
+        int actionIndex = item->keyCode() - HbInputButton::ButtonKeyCodeCustom;
+
+        if (actionIndex >= 0 && actionIndex < mCustomActions.count()) {
+            item->setIcon(mCustomActions.at(actionIndex)->icon(), HbInputButton::ButtonIconIndexPrimary);
+            if (!mCustomActions.at(actionIndex)->isEnabled()) {
+                item->setState(HbInputButton::ButtonStateDisabled);
+            }
+            mUsedCustomButtons.append(i);
+        }
+    }
+}
+
+void HbInputButtonGroupPrivate::updateButtonGrid(const QSizeF &size)
+{
+    mButtonGridPositions.clear();
+
+    if (!size.width() && !size.height()) {
+        return;
+    }
+
+    qreal cellWidth = size.width() / mGridSize.width();
+    qreal cellHeight = size.height() / mGridSize.height();
+
+    for (int i = 0; i < mButtonData.count(); ++i) {
+        HbInputButton *item = mButtonData.at(i);
+
+        for (int y = 0; y < item->size().height(); ++y) {
+            for (int x = 0; x < item->size().width(); ++x) {
+                QPair<int, int> position = QPair<int, int>(item->position().x() + x, item->position().y() + y);
+                mButtonGridPositions.insert(position, i);
+            }
+        }
+        QRectF rect = QRectF(item->position().x() * cellWidth, item->position().y() * cellHeight,
+                             item->size().width() * cellWidth, item->size().height() * cellHeight);
+        item->setBoundingRect(rect);
+    }
+}
+
+void HbInputButtonGroupPrivate::updateColorArray()
+{
+    mColors.clear();
+    for (int i = 0; i < HbTextTypeCount; ++i) {
+        HbInputButton::HbInputButtonType type = static_cast<HbInputButton::HbInputButtonType>(i / HbInputButton::ButtonStateCount);
+        HbInputButton::HbInputButtonState state = static_cast<HbInputButton::HbInputButtonState>(i % HbInputButton::ButtonStateCount);
+        mColors.append(HbColorScheme::color(buttonColor(type, state)));
+    }
+}
+
+void HbInputButtonGroupPrivate::showButtonPreview(HbInputButton * const item)
+{
+    Q_Q(HbInputButtonGroup);
+
+    int index = mButtonData.indexOf(item);
+    if (mButtonPreviewEnabled && item->type() != HbInputButton::ButtonTypeFunction &&
+        !mButtonPreview.contains(index)) {
+        HbInputButtonGroup *group = new HbInputButtonGroup(QSize(1, 1), q);
+        mButtonPreview.insert(index, group);
+
+        QList<HbInputButton*> buttons;
+        HbInputButton *previewItem = new HbInputButton(item->text(HbInputButton::ButtonTextIndexPrimary).at(0).unicode(), QPoint(0, 0));
+        previewItem->setType(HbInputButton::ButtonTypeLabel);
+        previewItem->setText(item->text(HbInputButton::ButtonTextIndexPrimary), HbInputButton::ButtonTextIndexPrimary);
+        buttons.append(previewItem);
+        group->setButtons(buttons);
+
+        qreal cellWidth = q->boundingRect().width() / mGridSize.width();
+        qreal cellHeight = q->boundingRect().height() / mGridSize.height();
+
+        QFont font = HbFontSpec(HbFontSpec::Primary).font();
+        font.setPixelSize(fontSize(ButtonTextTypeLabel));
+        QFontMetricsF fontMetrics(font);
+        qreal textWidth = fontMetrics.width(item->text(HbInputButton::ButtonTextIndexPrimary));
+
+        qreal width = textWidth + HbPreviewMarginInUnits * mUnitValue;
+        if (width < HbPreviewWidthInUnits * mUnitValue) {
+            width = HbPreviewWidthInUnits * mUnitValue;
+        }
+        qreal height = HbPreviewHeightInUnits * mUnitValue;
+        qreal x = (item->position().x() + 0.5 * item->size().width()) * cellWidth - 0.5 * width;
+        if (x < 0) {
+            x = 0;
+        } else if (x + width > q->boundingRect().width()) {
+            x = q->boundingRect().width() - width;
+        }
+        qreal y = item->position().y() * cellHeight - height;
+        group->setGeometry(QRectF(x, y, width, height));
+        if (q->parentItem()) {
+            group->setZValue(q->parentItem()->zValue() + 1);
+        }
+        
+        QGraphicsDropShadowEffect *effect = new QGraphicsDropShadowEffect;
+        effect->setBlurRadius(8);
+        group->setGraphicsEffect(effect);
+
+        group->setButtonBorderSize(0);
+        HbFrameDrawer *drawer = HbFrameDrawerPool::get(HbPreviewBackground, HbFrameDrawer::ThreePiecesHorizontal, QSizeF(width, height));
+        drawer->setFillWholeRect(true);
+        group->setBackground(drawer);
+        q->mainWindow()->scene()->addItem(group);
+    }
+}
+
+void HbInputButtonGroupPrivate::hideButtonPreview(HbInputButton * const item)
+{
+    int index = mButtonData.indexOf(item);
+    if (mButtonPreview.contains(index)) {
+        delete mButtonPreview.take(index);
+    }
+}
+
+void HbInputButtonGroupPrivate::showCharacterSelectionPreview(HbInputButton * const item)
+{
+    Q_Q(HbInputButtonGroup);
+
+    if (mCharacterSelectionPreviewEnabled && item->type() != HbInputButton::ButtonTypeFunction &&
+        item->mappedCharacters().count() > 1) {
+        
+        mProbabilities.clear();
+        q->cancelButtonPress();
+        
+        if (!mCharacterSelectionPreview) {
+            mCharacterSelectionPreview = new HbDialog();
+            mCharacterSelectionPreview->setModal(true);
+            mCharacterSelectionPreview->setBackgroundFaded(false);
+            mCharacterSelectionPreview->setTimeout(HbPopup::NoTimeout);
+            mCharacterSelectionPreview->setDismissPolicy(HbPopup::TapAnywhere);
+            mCharacterSelectionPreview->setFlag(QGraphicsItem::ItemIsPanel, true);
+            mCharacterSelectionPreview->setActive(false);
+            qreal margin = HbPreviewMarginInUnits * mUnitValue * 0.5;
+            mCharacterSelectionPreview->setContentsMargins(margin, 0, margin, 0);
+            QGraphicsDropShadowEffect *effect = new QGraphicsDropShadowEffect;
+            effect->setBlurRadius(8);
+            mCharacterSelectionPreview->setGraphicsEffect(effect);
+        }
+
+        HbInputButtonGroup *group = new HbInputButtonGroup(QSize(item->mappedCharacters().count(), 1));
+        QObject::connect(group, SIGNAL(buttonPressed(const QKeyEvent&)), q, SLOT(emitButtonPressed(const QKeyEvent&)));
+        QObject::connect(group, SIGNAL(buttonDoublePressed(const QKeyEvent&)), q, SLOT(emitButtonDoublePressed(const QKeyEvent&)));
+        QObject::connect(group, SIGNAL(buttonReleased(const QKeyEvent&)), q, SLOT(emitButtonReleased(const QKeyEvent&)));
+        QObject::connect(group, SIGNAL(buttonLongPressed(const QKeyEvent&)), q, SLOT(emitButtonLongPressed(const QKeyEvent&)));
+        QObject::connect(group, SIGNAL(pressedButtonChanged(const QKeyEvent&, const QKeyEvent&)), q, SLOT(emitPressedButtonChanged(const QKeyEvent&, const QKeyEvent&)));
+        
+        qreal cellWidth = q->boundingRect().width() / mGridSize.width();
+        qreal cellHeight = q->boundingRect().height() / mGridSize.height();
+
+        QFont font = HbFontSpec(HbFontSpec::Primary).font();
+        font.setPixelSize(fontSize(ButtonTextTypeLabel));
+        QFontMetricsF fontMetrics(font);
+        qreal textWidth = fontMetrics.width(item->mappedCharacters());
+
+        qreal width = textWidth + HbPreviewMarginInUnits * mUnitValue * item->mappedCharacters().count();
+        qreal height = HbPreviewHeightInUnits * mUnitValue;
+        qreal x = q->scenePos().x() + (item->position().x() + 0.5 * item->size().width()) * cellWidth;
+        qreal y = q->scenePos().y() + item->position().y() * cellHeight;
+
+        QList<HbInputButton*> buttons;
+        for (int i = 0; i < item->mappedCharacters().count(); ++i) {
+            HbInputButton *previewItem = new HbInputButton(item->keyCode(), QPoint(i, 0));
+            previewItem->setType(HbInputButton::ButtonTypeLabel);
+            previewItem->setText(item->mappedCharacters().at(i), HbInputButton::ButtonTextIndexPrimary);
+            buttons.append(previewItem);
+        }
+        group->setButtons(buttons);
+        group->setButtonBorderSize(0);
+
+        mCharacterSelectionPreview->setPreferredSize(QSizeF(width, height));
+        mCharacterSelectionPreview->setPreferredPos(QPointF(x, y), HbPopup::BottomEdgeCenter);
+        mCharacterSelectionPreview->setContentWidget(group);
+
+        HbFrameDrawer *drawer = HbFrameDrawerPool::get(HbPreviewBackground, HbFrameDrawer::ThreePiecesHorizontal, QSizeF(width, height));
+        drawer->setFillWholeRect(true);
+        mCharacterSelectionPreview->setBackgroundItem(new HbFrameItem(drawer));
+
+        mCharacterSelectionPreview->show();
+    }
+}
+
+void HbInputButtonGroupPrivate::pressEvent(const QPointF &position, bool emitSignal)
+{
+    Q_Q(HbInputButtonGroup);
+
+    if (!(position.x() >= 0 && position.x() < q->boundingRect().width() &&
+        position.y() >= 0 && position.y() < q->boundingRect().height())) {
+        return;
+    }
+
+    int column = static_cast<int>(position.x() / (q->boundingRect().width() / mGridSize.width()));
+    int row = static_cast<int>(position.y() / (q->boundingRect().height() / mGridSize.height()));
+
+    int index = mButtonGridPositions.value(QPair<int, int>(column, row));
+
+    if (index >= 0 && index < mButtonData.count()) {
+        HbInputButton *item = mButtonData.at(index);
+
+        if ((item->state() != HbInputButton::ButtonStateReleased && 
+            item->state() != HbInputButton::ButtonStateLatched) ||
+            (mCharacterSelectionPreview && mCharacterSelectionPreview->isVisible())) {
+            if (item->state() == HbInputButton::ButtonStateDisabled) {
+                startLongPress(index);
+            }
+            return;
+        }
+
+        HbWidgetFeedback::triggered(q, Hb::InstantPressed);
+
+        item->setState(HbInputButton::ButtonStatePressed);
+        updateGraphics(QSizeF(q->boundingRect().width(), q->boundingRect().height()));
+        updateTextLayouts(QSizeF(q->boundingRect().width(), q->boundingRect().height()));
+        q->update();
+
+        showButtonPreview(item);
+
+        startLongPress(index);
+
+        if (!mUsedCustomButtons.contains(index)) {
+            if (emitSignal) {
+                QString text;
+                if (item->type() == HbInputButton::ButtonTypeLabel) {
+                    text = item->text(HbInputButton::ButtonTextIndexPrimary);
+                }
+                QKeyEvent event(QEvent::KeyPress, item->keyCode(), Qt::NoModifier, text);
+                q->emitButtonPressed(event);
+            }
+        }
+    }
+}
+
+void HbInputButtonGroupPrivate::doublePressEvent(const QPointF &position, bool emitSignal)
+{
+    Q_Q(HbInputButtonGroup);
+
+    if (!(position.x() >= 0 && position.x() < q->boundingRect().width() &&
+        position.y() >= 0 && position.y() < q->boundingRect().height())) {
+        return;
+    }
+
+    int column = static_cast<int>(position.x() / (q->boundingRect().width() / mGridSize.width()));
+    int row = static_cast<int>(position.y() / (q->boundingRect().height() / mGridSize.height()));
+
+    int index = mButtonGridPositions.value(QPair<int, int>(column, row));
+
+    if (index >= 0 && index < mButtonData.count()) {
+        HbInputButton *item = mButtonData.at(index);
+
+        if ((item->state() != HbInputButton::ButtonStateReleased && 
+            item->state() != HbInputButton::ButtonStateLatched) ||
+            (mCharacterSelectionPreview && mCharacterSelectionPreview->isVisible())) {
+            if (item->state() == HbInputButton::ButtonStateDisabled) {
+                startLongPress(index);
+            }
+            return;
+        }
+
+        HbWidgetFeedback::triggered(q, Hb::InstantPressed);
+
+        item->setState(HbInputButton::ButtonStatePressed);
+        updateGraphics(QSizeF(q->boundingRect().width(), q->boundingRect().height()));
+        updateTextLayouts(QSizeF(q->boundingRect().width(), q->boundingRect().height()));
+        q->update();
+
+        showButtonPreview(item);
+
+        startLongPress(index);
+
+        if (!mUsedCustomButtons.contains(index)) {
+            if (emitSignal) {
+                QString text;
+                if (item->type() == HbInputButton::ButtonTypeLabel) {
+                    text = item->text(HbInputButton::ButtonTextIndexPrimary);
+                }
+                QKeyEvent event(QEvent::KeyPress, item->keyCode(), Qt::NoModifier, text);
+                q->emitButtonDoublePressed(event);
+            }
+        }
+    }
+}
+
+void HbInputButtonGroupPrivate::moveEvent(const QPointF &oldPosition, const QPointF &newPosition)
+{
+    Q_Q(HbInputButtonGroup);
+
+    int oldColumn = static_cast<int>(oldPosition.x() / (q->boundingRect().width() / mGridSize.width()));
+    int oldRow = static_cast<int>(oldPosition.y() / (q->boundingRect().height() / mGridSize.height()));
+    int newColumn = static_cast<int>(newPosition.x() / (q->boundingRect().width() / mGridSize.width()));
+    int newRow = static_cast<int>(newPosition.y() / (q->boundingRect().height() / mGridSize.height()));
+
+    int oldIndex = mButtonGridPositions.value(QPair<int, int>(oldColumn, oldRow));
+    int newIndex = mButtonGridPositions.value(QPair<int, int>(newColumn, newRow));
+
+    if (newPosition.x() >= 0 && newPosition.x() < q->boundingRect().width() &&
+        newPosition.y() >= 0 && newPosition.y() < q->boundingRect().height() &&
+        oldPosition.x() >= 0 && oldPosition.x() < q->boundingRect().width() &&
+        oldPosition.y() >= 0 && oldPosition.y() < q->boundingRect().height()) {
+        
+        if (oldIndex != newIndex) {
+            releaseEvent(oldPosition, false);
+            pressEvent(newPosition, false);
+
+            QString text;
+            HbInputButton *oldItem = mButtonData.at(oldIndex);
+            if (oldItem->type() == HbInputButton::ButtonTypeLabel) {
+                text = oldItem->text(HbInputButton::ButtonTextIndexPrimary);
+            }
+            QKeyEvent releaseEvent(QEvent::KeyRelease, oldItem->keyCode(), Qt::NoModifier, text);
+
+            HbInputButton *newItem = mButtonData.at(newIndex);
+            if (newItem->type() == HbInputButton::ButtonTypeLabel) {
+                text = newItem->text(HbInputButton::ButtonTextIndexPrimary);
+            }
+            QKeyEvent pressEvent(QEvent::KeyPress, newItem->keyCode(), Qt::NoModifier, text);
+
+            q->emitPressedButtonChanged(releaseEvent, pressEvent);
+        }
+    } else {
+        releaseEvent(oldPosition, false);
+        pressEvent(newPosition);
+    }
+}
+
+void HbInputButtonGroupPrivate::releaseEvent(const QPointF &position, bool emitSignal)
+{
+    Q_Q(HbInputButtonGroup);
+
+    if (!(position.x() >= 0 && position.x() < q->boundingRect().width() &&
+        position.y() >= 0 && position.y() < q->boundingRect().height())) {
+        return;
+    }
+
+    int column = static_cast<int>(position.x() / (q->boundingRect().width() / mGridSize.width()));
+    int row = static_cast<int>(position.y() / (q->boundingRect().height() / mGridSize.height()));
+
+    int index = mButtonGridPositions.value(QPair<int, int>(column, row));
+
+    if (index >= 0 && index < mButtonData.count()) {
+        HbInputButton *item = mButtonData.at(index);
+
+        cancelLongPress(index);
+
+        if (item->state() != HbInputButton::ButtonStatePressed) {
+            return;
+        }
+
+        HbWidgetFeedback::triggered(q, Hb::InstantReleased);
+
+        item->setState(HbInputButton::ButtonStateReleased);
+        updateGraphics(QSizeF(q->boundingRect().width(), q->boundingRect().height()));
+        updateTextLayouts(QSizeF(q->boundingRect().width(), q->boundingRect().height()));
+        q->update();
+
+        if (mCharacterSelectionPreview && mCharacterSelectionPreview->isVisible()) {
+            return;
+        }
+
+        hideButtonPreview(item);
+
+        if (emitSignal) {
+            HbWidgetFeedback::triggered(q, Hb::InstantClicked);
+            int actionIndex = item->keyCode() - HbInputButton::ButtonKeyCodeCustom;
+            if (actionIndex >= 0 && actionIndex < mCustomActions.count()) {
+                mCustomActions.at(actionIndex)->activate(QAction::Trigger);
+            } else {
+                calculateButtonProbabilities(position);
+
+                QString text;
+                if (item->type() == HbInputButton::ButtonTypeLabel) {
+                    text = item->text(HbInputButton::ButtonTextIndexPrimary);
+                }
+                QKeyEvent event(QEvent::KeyRelease, item->keyCode(), Qt::NoModifier, text);
+                q->emitButtonReleased(event);
+            }
+        }
+    }
+}
+
+void HbInputButtonGroupPrivate::longPressEvent()
+{
+    Q_Q(HbInputButtonGroup);
+
+    int index = mLongPressButtons.at(0);
+    mLongPressButtons.removeAt(0);
+    QTimer *timer = mLongPressTimers.at(0);
+    mLongPressTimers.removeAt(0);
+
+    if (index >= 0 && index < mButtonData.count()) {
+        HbInputButton *item = mButtonData.at(index);
+
+        if (item->autoRepeat() &&
+            (item->state() == HbInputButton::ButtonStatePressed ||
+            item->state() == HbInputButton::ButtonStateLatched)) {
+            mLongPressButtons.append(index);
+            mLongPressTimers.append(timer);
+            timer->start(HbAutoRepeatTimeout);
+
+            HbWidgetFeedback::triggered(q, Hb::InstantKeyRepeated);
+
+            QString text;
+            if (item->type() == HbInputButton::ButtonTypeLabel) {
+                text = item->text(HbInputButton::ButtonTextIndexPrimary);
+            }
+            QKeyEvent releaeEvent(QEvent::KeyRelease, item->keyCode(), Qt::NoModifier, text, true);
+            q->emitButtonReleased(releaeEvent);
+            QKeyEvent pressEvent(QEvent::KeyPress, item->keyCode(), Qt::NoModifier, text, true);
+            q->emitButtonPressed(pressEvent);
+        } else {
+            if (mCharacterSelectionPreviewEnabled) {
+                showCharacterSelectionPreview(item);
+            }
+
+            HbWidgetFeedback::triggered(q, Hb::InstantLongPressed);
+
+            delete timer;
+
+            QString text;
+            if (item->type() == HbInputButton::ButtonTypeLabel) {
+                text = item->text(HbInputButton::ButtonTextIndexPrimary);
+            }
+            QKeyEvent event(QEvent::KeyPress, item->keyCode(), Qt::NoModifier, text, true);
+            q->emitButtonLongPressed(event);
+        }
+    }
+}
+
+void HbInputButtonGroupPrivate::calculateButtonProbabilities(const QPointF &position)
+{
+    Q_Q(HbInputButtonGroup);
+
+    mProbabilities.clear();
+
+    qreal cellWidth = q->boundingRect().width() / mGridSize.width();
+    qreal cellHeight = q->boundingRect().height() / mGridSize.height();
+
+    QRectF touchArea = QRectF(position.x() - 0.5 * cellWidth, position.y() - 0.5 * cellHeight,
+                              HbTouchAreaSizeInUnits * mUnitValue, HbTouchAreaSizeInUnits * mUnitValue);
+
+    qreal probabilities = 0;
+    foreach (HbInputButton *button, mButtonData) {
+        QRectF intersection = button->boundingRect().intersected(touchArea);
+
+        if (intersection.isValid()) {
+            qreal probability = intersection.width() * intersection.height() / (touchArea.width() * touchArea.height());
+            probabilities += probability;
+
+            HbKeyPressProbability probableKey;
+            probableKey.keycode = button->keyCode();
+            probableKey.probability = probability;
+            mProbabilities.append(probableKey);
+        }
+    }
+
+    // Normalize
+    for (int i = 0; i < mProbabilities.count(); ++i) {
+        mProbabilities[i].probability /= probabilities;
+    }
+}
+
+void HbInputButtonGroupPrivate::createPrimarySingleTextLayout(int index, const QHash<int, QString> &textContent, const QSizeF &size)
+{
+    qreal cellWidth = size.width() / mGridSize.width();
+    qreal cellHeight = size.height() / mGridSize.height();
+
+    QFont font = HbFontSpec(HbFontSpec::Primary).font();
+
+    int typeIndex = index % HbTextTypeCount / HbInputButton::ButtonStateCount;
+    if (typeIndex == HbInputButton::ButtonTypeLabel) {
+        font.setPixelSize(fontSize(ButtonTextTypeLabel));
+    } else {
+        font.setPixelSize(fontSize(ButtonTextTypeSingle));
+    }
+
+    mTextLayouts[index] = new QTextLayout(textContent.value(index), font);
+    QFontMetricsF fontMetrics(font);
+
+    // Create text line for each button with primary text and correct type and state. Layout it
+    // to correct position
+    mTextLayouts.at(index)->beginLayout();
+    foreach (HbInputButton *item, mButtonData) {
+        int layoutIndex = item->type() * HbInputButton::ButtonStateCount + item->state() + HbTextTypeCount;
+        if (!mEnabled) {
+            layoutIndex = item->type() * HbInputButton::ButtonStateCount + HbInputButton::ButtonStateDisabled + HbTextTypeCount;
+        }
+        if (index == layoutIndex && !item->text(HbInputButton::ButtonTextIndexPrimary).isEmpty() &&
+            item->icon(HbInputButton::ButtonIconIndexPrimary).isNull() &&
+            item->text(HbInputButton::ButtonTextIndexSecondaryFirstRow).isEmpty() &&
+            item->icon(HbInputButton::ButtonIconIndexSecondaryFirstRow).isNull() &&
+            item->text(HbInputButton::ButtonTextIndexSecondarySecondRow).isEmpty() &&
+            item->icon(HbInputButton::ButtonIconIndexSecondarySecondRow).isNull()) {
+            qreal textWidth = fontMetrics.width(item->text(HbInputButton::ButtonTextIndexPrimary));
+            qreal textHeight = fontMetrics.height();
+            
+            QTextLine line = mTextLayouts.at(index)->createLine();
+            line.setNumColumns(1);
+
+            if (typeIndex == HbInputButton::ButtonTypeLabel) {
+                layoutTextLine(ButtonTextTypeLabel, item, QSizeF(cellWidth, cellHeight), line, QSizeF(textWidth, textHeight));
+            } else {
+                layoutTextLine(ButtonTextTypeSingle, item, QSizeF(cellWidth, cellHeight), line, QSizeF(textWidth, textHeight));
+            }
+        }
+    }
+    mTextLayouts.at(index)->endLayout();
+    mTextLayouts.at(index)->setCacheEnabled(true);
+}
+
+void HbInputButtonGroupPrivate::createPrimaryTextLayout(int index, const QHash<int, QString> &textContent, const QSizeF &size)
+{
+    qreal cellWidth = size.width() / mGridSize.width();
+    qreal cellHeight = size.height() / mGridSize.height();
+
+    QFont font = HbFontSpec(HbFontSpec::Primary).font();
+    font.setPixelSize(fontSize(ButtonTextTypePrimary));
+
+    mTextLayouts[index] = new QTextLayout(textContent.value(index), font);
+    QFontMetricsF fontMetrics(font);
+
+    // Create text line for each button with primary text and correct type and state. Layout it
+    // to correct position
+    mTextLayouts.at(index)->beginLayout();
+    foreach (HbInputButton *item, mButtonData) {
+        int layoutIndex = item->type() * HbInputButton::ButtonStateCount + item->state();
+        if (!mEnabled) {
+            layoutIndex = item->type() * HbInputButton::ButtonStateCount + HbInputButton::ButtonStateDisabled;
+        }
+        if (index == layoutIndex && !item->text(HbInputButton::ButtonTextIndexPrimary).isEmpty() &&
+            item->icon(HbInputButton::ButtonIconIndexPrimary).isNull() &&
+            !(item->text(HbInputButton::ButtonTextIndexSecondaryFirstRow).isEmpty() &&
+            item->icon(HbInputButton::ButtonIconIndexSecondaryFirstRow).isNull() &&
+            item->text(HbInputButton::ButtonTextIndexSecondarySecondRow).isEmpty() &&
+            item->icon(HbInputButton::ButtonIconIndexSecondarySecondRow).isNull())) {
+            qreal textWidth = fontMetrics.width(item->text(HbInputButton::ButtonTextIndexPrimary));
+            qreal textHeight = fontMetrics.height();
+
+            QTextLine line = mTextLayouts.at(index)->createLine();
+            line.setNumColumns(1);
+
+            layoutTextLine(ButtonTextTypePrimary, item, QSizeF(cellWidth, cellHeight), line, QSizeF(textWidth, textHeight));
+        }
+    }
+    mTextLayouts.at(index)->endLayout();
+    mTextLayouts.at(index)->setCacheEnabled(true);
+}
+
+void HbInputButtonGroupPrivate::createSecondaryTextLayout(int index, const QHash<int, QString> &textContent, const QSizeF &size)
+{
+    qreal cellWidth = size.width() / mGridSize.width();
+    qreal cellHeight = size.height() / mGridSize.height();
+
+    QFont font = HbFontSpec(HbFontSpec::Primary).font();
+    font.setPixelSize(fontSize(ButtonTextTypeSecondaryFirstRow));
+
+    mTextLayouts[index] = new QTextLayout(textContent.value(index), font);
+    QFontMetricsF fontMetrics(font);
+
+    // Create text line for each button with secondary first row or second row text and correct type and state.
+    // Layout it to correct position
+    mTextLayouts.at(index)->beginLayout();
+    foreach (HbInputButton *item, mButtonData) {
+        int layoutIndex = item->type() * HbInputButton::ButtonStateCount + item->state() + HbTextTypeCount * 2;
+        if (!mEnabled) {
+            layoutIndex = item->type() * HbInputButton::ButtonStateCount + HbInputButton::ButtonStateDisabled + HbTextTypeCount * 2;
+        }
+        if (index == layoutIndex) {
+            if (!item->text(HbInputButton::ButtonTextIndexSecondaryFirstRow).isEmpty() && 
+                item->icon(HbInputButton::ButtonIconIndexSecondaryFirstRow).isNull()) {
+                qreal textWidth = fontMetrics.width(item->text(HbInputButton::ButtonTextIndexSecondaryFirstRow));
+                qreal textHeight = fontMetrics.height();
+
+                QTextLine line = mTextLayouts.at(index)->createLine();
+                line.setNumColumns(1);
+
+                layoutTextLine(ButtonTextTypeSecondaryFirstRow, item, QSizeF(cellWidth, cellHeight), line, QSizeF(textWidth, textHeight));
+            }
+
+            if (!item->text(HbInputButton::ButtonTextIndexSecondarySecondRow).isEmpty() && 
+                item->icon(HbInputButton::ButtonIconIndexSecondarySecondRow).isNull()) {
+                qreal textWidth = fontMetrics.width(item->text(HbInputButton::ButtonTextIndexSecondarySecondRow));
+                qreal textHeight = fontMetrics.height();
+
+                QTextLine line = mTextLayouts.at(index)->createLine();
+                line.setNumColumns(1);
+
+                layoutTextLine(ButtonTextTypeSecondarySecondRow, item, QSizeF(cellWidth, cellHeight), line, QSizeF(textWidth, textHeight));
+            }
+        }
+    }
+    mTextLayouts.at(index)->endLayout();
+    mTextLayouts.at(index)->setCacheEnabled(true);
+}
+
+void HbInputButtonGroupPrivate::layoutTextLine(HbInputButtonTextType textType, const HbInputButton *button, const QSizeF &cellSize,
+                                               QTextLine &textLine, const QSizeF &textSize)
+{
+    qreal textPositionX = 0.0;
+    qreal textPositionY = 0.0;
+    if (textType == ButtonTextTypeSingle ||
+        textType == ButtonTextTypeLabel) {
+        textPositionX = (button->position().x() + 0.5 * button->size().width()) * cellSize.width() - 0.5 * textSize.width();
+        textPositionY = (button->position().y() + 0.5 * button->size().height()) * cellSize.height() - 0.5 * textSize.height();
+    } else if (textType == ButtonTextTypePrimary) {
+        textPositionX = button->position().x() * cellSize.width() + HbHorizontalMarginInUnits * mUnitValue + mButtonBorderSize;
+        textPositionY = (button->position().y() + 0.5 * button->size().height()) * cellSize.height() - 0.5 * textSize.height();
+    } else if (textType == ButtonTextTypeSecondaryFirstRow) {
+        textPositionX = (button->position().x() + button->size().width()) * cellSize.width() -
+            textSize.width() - HbHorizontalMarginInUnits * mUnitValue - mButtonBorderSize;
+        textPositionY = (button->position().y() + button->size().height()) * cellSize.height() -
+            textSize.height() - HbVerticalMarginInUnits * mUnitValue - mButtonBorderSize;
+    } else if (textType == ButtonTextTypeSecondarySecondRow) {
+        textPositionX = (button->position().x() + button->size().width()) * cellSize.width() -
+            textSize.width() - HbHorizontalMarginInUnits * mUnitValue - mButtonBorderSize;
+        textPositionY = button->position().y() * cellSize.height() + HbVerticalMarginInUnits * mUnitValue + mButtonBorderSize;
+    }
+    textLine.setPosition(QPointF(textPositionX, textPositionY));
+}
+
+QString HbInputButtonGroupPrivate::buttonGraphics(HbInputButton::HbInputButtonType type, HbInputButton::HbInputButtonState state)
+{
+    if (type == HbInputButton::ButtonTypeNormal) {
+        if (state == HbInputButton::ButtonStateReleased) {
+            return HbNormalBackground;
+        } else if (state == HbInputButton::ButtonStatePressed) {
+            return HbNormalPressedBackground;
+        } else if (state == HbInputButton::ButtonStateLatched) {
+            return HbNormalLatchedBackground;
+        } else if (state == HbInputButton::ButtonStateDisabled) {
+            return HbNormalInActiveBackground;
+        }
+    } else if (type == HbInputButton::ButtonTypeFunction) {
+        if (state == HbInputButton::ButtonStateReleased) {
+            return HbFunctionBackground;
+        } else if (state == HbInputButton::ButtonStatePressed) {
+            return HbFunctionPressedBackground;
+        } else if (state == HbInputButton::ButtonStateLatched) {
+            return HbFunctionLatchedBackground;
+        } else if (state == HbInputButton::ButtonStateDisabled) {
+            return HbFunctionInActiveBackground;
+        }
+    }
+    return QString("");
+}
+
+QString HbInputButtonGroupPrivate::buttonColor(HbInputButton::HbInputButtonType type, HbInputButton::HbInputButtonState state)
+{
+    if (type == HbInputButton::ButtonTypeNormal) {
+        if (state == HbInputButton::ButtonStateReleased) {
+            return HbNormalColor;
+        } else if (state == HbInputButton::ButtonStatePressed) {
+            return HbNormalColorPressed;
+        } else if (state == HbInputButton::ButtonStateLatched) {
+            return HbNormalColorLatched;
+        } else if (state == HbInputButton::ButtonStateDisabled) {
+            return HbNormalColorInActive;
+        }
+    } else if (type == HbInputButton::ButtonTypeFunction) {
+        if (state == HbInputButton::ButtonStateReleased) {
+            return HbFunctionColor;
+        } else if (state == HbInputButton::ButtonStatePressed) {
+            return HbFunctionColorPressed;
+        } else if (state == HbInputButton::ButtonStateLatched) {
+            return HbFunctionColorLatched;
+        } else if (state == HbInputButton::ButtonStateDisabled) {
+            return HbFunctionColorInActive;
+        }
+    } else if (type == HbInputButton::ButtonTypeLabel) {
+        if (mButtonData.count() == 1) {
+            return HbButtonPreviewColor;
+        } else {
+            return HbCharacterSelectionPreviewColor;
+        }
+    }
+    return QString("");
+}
+
+qreal HbInputButtonGroupPrivate::fontSize(HbInputButtonTextType textType)
+{
+    if (textType == ButtonTextTypeSingle) {
+        return HbTextSizeInUnits * mUnitValue;
+    } else if (textType == ButtonTextTypePrimary) {
+        return HbPrimaryTextSizeInUnits * mUnitValue;
+    } else if (textType == ButtonTextTypeSecondaryFirstRow ||
+        textType == ButtonTextTypeSecondarySecondRow) {
+        return HbSecondaryTextSizeInUnits * mUnitValue;
+    } else if (textType == ButtonTextTypeLabel) {
+        return HbLabelTextSizeInUnits * mUnitValue;
+    }
+    return 0;
+}
+
+void HbInputButtonGroupPrivate::startLongPress(int index)
+{
+    Q_Q(HbInputButtonGroup);
+    if (!mUsedCustomButtons.contains(index)) {
+        mLongPressButtons.append(index);
+        mLongPressTimers.append(new QTimer());
+        mLongPressTimers.back()->setSingleShot(true);
+        QObject::connect(mLongPressTimers.back(), SIGNAL(timeout()), q, SLOT(longPressEvent()));
+        mLongPressTimers.back()->start(HbLongPressTimeout);
+    }
+}
+
+void HbInputButtonGroupPrivate::cancelLongPress(int index)
+{
+    if (mLongPressButtons.contains(index)) {
+        int listIndex = mLongPressButtons.indexOf(index);
+        delete mLongPressTimers.at(listIndex);
+        mLongPressTimers.removeAt(listIndex);
+        mLongPressButtons.removeAt(listIndex);
+    }
+}
+
+/// @endcond
+
+/*!
+Constructor
+*/
+HbInputButtonGroup::HbInputButtonGroup(QGraphicsItem *parent)
+ : HbWidget(*new HbInputButtonGroupPrivate, parent)
+{
+    Q_D(HbInputButtonGroup);
+
+    d->mUnitValue = HbDeviceProfile::profile(mainWindow()).unitValue();
+
+    setAcceptedMouseButtons(Qt::LeftButton);
+}
+
+/*!
+Constructor
+*/
+HbInputButtonGroup::HbInputButtonGroup(HbInputButtonGroupPrivate &dd, QGraphicsItem *parent)
+ : HbWidget(dd, parent)
+{
+    Q_D(HbInputButtonGroup);
+
+    d->mUnitValue = HbDeviceProfile::profile(mainWindow()).unitValue();
+
+    setAcceptedMouseButtons(Qt::LeftButton);
+}
+
+/*!
+Constructor
+*/
+HbInputButtonGroup::HbInputButtonGroup(const QSize &size, QGraphicsItem *parent)
+ : HbWidget(*new HbInputButtonGroupPrivate, parent)
+{
+    Q_D(HbInputButtonGroup);
+
+    d->mUnitValue = HbDeviceProfile::profile(mainWindow()).unitValue();
+
+    setAcceptedMouseButtons(Qt::LeftButton);
+    
+    setGridSize(size);
+}
+
+/*!
+Constructor
+*/
+HbInputButtonGroup::HbInputButtonGroup(HbInputButtonGroupPrivate &dd, const QSize &size, QGraphicsItem *parent)
+ : HbWidget(dd, parent)
+{
+    Q_D(HbInputButtonGroup);
+
+    d->mUnitValue = HbDeviceProfile::profile(mainWindow()).unitValue();
+
+    setAcceptedMouseButtons(Qt::LeftButton);
+    
+    setGridSize(size);
+}
+
+/*!
+Destructor
+*/
+HbInputButtonGroup::~HbInputButtonGroup()
+{
+}
+
+/*!
+Sets new grid size and updates button group content based on the new grid size.
+
+\sa gridSize
+*/
+void HbInputButtonGroup::setGridSize(const QSize &size)
+{
+    Q_D(HbInputButtonGroup);
+
+    d->mGridSize = size;
+    if (d->mGridSize.width() < 1) {
+        d->mGridSize.setWidth(1);
+    }
+    if (d->mGridSize.height() < 1) {
+        d->mGridSize.setHeight(1);
+    }
+
+    setButtonBorderSize(d->mButtonBorderSize);
+    d->updateButtonGrid(QSizeF(boundingRect().width(), boundingRect().height()));
+    d->updateGraphics(QSizeF(boundingRect().width(), boundingRect().height()));
+    d->updateTextLayouts(QSizeF(boundingRect().width(), boundingRect().height()));
+    update();
+}
+
+/*!
+Returns current grid size.
+
+\sa setGridSize
+*/
+QSize HbInputButtonGroup::gridSize() const
+{
+    Q_D(const HbInputButtonGroup);
+
+    return d->mGridSize;
+}
+
+/*!
+Sets the button data and updates button group based on the new data.
+Takes ownership of the button items. Button items that are not in the new list 
+will be destroyed.
+
+\sa buttons
+\sa button
+*/
+void HbInputButtonGroup::setButtons(const QList<HbInputButton*> &data)
+{
+    Q_D(HbInputButtonGroup);
+
+    foreach (HbInputButton *button, d->mButtonData) {
+        if (!data.contains(button)) {
+            delete button;
+        }
+    }
+    d->mButtonData = data;
+
+    d->updateButtonGrid(QSizeF(boundingRect().width(), boundingRect().height()));
+    d->updateCustomActions();
+    d->updateColorArray();
+    d->updateGraphics(QSizeF(boundingRect().width(), boundingRect().height()));
+    d->updateTextLayouts(QSizeF(boundingRect().width(), boundingRect().height()));
+    update();
+}
+
+/*!
+Sets the button item and updates button group based on the new data.
+Takes ownership of the button item. Old button item in the given index will be destroyed.
+If null item is passed then the item from the given index will be removed.
+If index is out of bounds then the item is inserted to the end of button list.
+
+\sa buttons
+\sa button
+*/
+void HbInputButtonGroup::setButton(HbInputButton *data, int index)
+{
+    Q_D(HbInputButtonGroup);
+
+    if (index >= 0 && index < d->mButtonData.count()) {
+        if (data != d->mButtonData.at(index)) {
+            delete d->mButtonData.at(index);
+        }
+        if (data) {
+            d->mButtonData.replace(index, data);
+        } else {
+            d->mButtonData.removeAt(index);
+        }
+    } else {
+        d->mButtonData.append(data);
+    }
+    setButtons(d->mButtonData);
+}
+
+/*!
+Sets the button item and updates button group based on the new data.
+Takes ownership of the button item. Old button item in the given position will be destroyed.
+If null item is passed then the item from the given position will be removed.
+If the given position doesn't contain a button then the item is inserted to the end of button list.
+
+\sa buttons
+\sa button
+*/
+void HbInputButtonGroup::setButton(HbInputButton *data, int column, int row)
+{
+    Q_D(HbInputButtonGroup);
+
+    int index = d->mButtonGridPositions.value(QPair<int, int>(column, row));
+    setButton(data, index);
+}
+
+/*!
+Sets the button item and updates button group based on the new data.
+Takes ownership of the button item. Old button item with given key code will be destroyed.
+If null item is passed then the item with given key code will be removed.
+If group contains multiple buttons with same key code then the first one will be replaced.
+If there isn't any button with given key code then the button will be added to the end of button list.
+
+\sa buttons
+\sa button
+*/
+void HbInputButtonGroup::setButton(HbInputButton *data, HbInputButton::HbInputButtonKeyCode keyCode)
+{
+    Q_D(HbInputButtonGroup);
+
+    int index = 0;
+    for (; index < d->mButtonData.count(); ++index) {
+        HbInputButton *item = d->mButtonData.at(index);
+        if (item->keyCode() == keyCode) {
+            break;
+        }
+    }
+    
+    setButton(data, index);
+}
+
+/*!
+Returns button data.
+Ownership of the returned button items is not transferred.
+
+\sa setButtons
+\sa setButton
+*/
+QList<HbInputButton*> HbInputButtonGroup::buttons() const
+{
+    Q_D(const HbInputButtonGroup);
+
+    return d->mButtonData;
+}
+
+/*!
+Returns button item.
+Ownership of the returned button item is not transferred.
+
+\sa setButtons
+\sa setButton
+*/
+HbInputButton *HbInputButtonGroup::button(int index) const
+{
+    Q_D(const HbInputButtonGroup);
+
+    if (index >= 0 && index < d->mButtonData.count()) {
+        return d->mButtonData.at(index);
+    }
+    return 0;
+}
+
+/*!
+Returns button data.
+Ownership of the button items is not transferred.
+
+\sa setButtons
+\sa setButton
+*/
+HbInputButton *HbInputButtonGroup::button(int column, int row) const
+{
+    Q_D(const HbInputButtonGroup);
+    
+    int index = d->mButtonGridPositions.value(QPair<int, int>(column, row));
+    return button(index);
+}
+
+/*!
+Returns button data.
+Ownership of the button items is not transferred.
+
+\sa setButtons
+\sa setButton
+*/
+HbInputButton *HbInputButtonGroup::button(HbInputButton::HbInputButtonKeyCode keyCode) const
+{
+    Q_D(const HbInputButtonGroup);
+
+    foreach (HbInputButton *button, d->mButtonData) {
+        if (button->keyCode() == keyCode) {
+            return button;
+        }
+    }
+    return 0;
+}
+
+/*!
+Sets custom actions and updates button group based on the new data. Custom actions
+are mapped to buttons which keycode is equal or bigger than HbInputButtonKeyCustom.
+Ownership of the actions is not transferred.
+
+\sa customButtonActions
+*/
+void HbInputButtonGroup::setCustomButtonActions(const QList<HbAction*> &actions)
+{
+    Q_D(HbInputButtonGroup);
+
+    disconnect(this, SLOT(updateCustomButtons()));
+
+    d->mCustomActions = actions;
+
+    foreach (HbAction *action, d->mCustomActions) {
+        connect(action, SIGNAL(changed()), this, SLOT(updateCustomButtons()));
+    }
+
+    d->updateCustomActions();
+    d->updateGraphics(QSizeF(boundingRect().width(), boundingRect().height()));
+    d->updateTextLayouts(QSizeF(boundingRect().width(), boundingRect().height()));
+    update();
+}
+
+/*!
+Returns current custom actions.
+Ownership of the actions is not transferred.
+
+\sa setCustomButtonActions
+*/
+QList<HbAction*> HbInputButtonGroup::customButtonActions() const
+{
+    Q_D(const HbInputButtonGroup);
+
+    return d->mCustomActions;
+}
+
+/*!
+Sets the border size for the buttons and updates button group based on the new value.
+Size must be in a range between 0 to half of button size.
+
+\sa buttonBorderSize
+*/
+void HbInputButtonGroup::setButtonBorderSize(qreal borderSize)
+{
+    Q_D(HbInputButtonGroup);
+
+    if (borderSize < 0.0) {
+        borderSize = 0.0;
+    } else if (boundingRect().width() != 0.0 && boundingRect().height() != 0.0) {
+        qreal maxSize = boundingRect().width() / d->mGridSize.width() * 0.5;
+        if (boundingRect().width() > boundingRect().height()) {
+            maxSize = boundingRect().height() / d->mGridSize.height() * 0.5;
+        }
+        if (borderSize > maxSize) {
+            borderSize = maxSize;
+        }
+    }
+    d->mButtonBorderSize = borderSize;
+
+    d->updateGraphics(QSizeF(boundingRect().width(), boundingRect().height()));
+    update();
+}
+
+/*!
+Returns the border size.
+
+\sa setButtonBorderSize
+*/
+qreal HbInputButtonGroup::buttonBorderSize() const
+{
+    Q_D(const HbInputButtonGroup);
+
+    return d->mButtonBorderSize;
+}
+
+/*!
+Sets button preview state.
+
+\sa isButtonPreviewEnabled
+*/
+void HbInputButtonGroup::setButtonPreviewEnabled(bool enabled)
+{
+    Q_D(HbInputButtonGroup);
+
+    d->mButtonPreviewEnabled = enabled;
+}
+
+/*!
+Returns preview state.
+
+\sa setButtonPreviewEnabled
+*/
+bool HbInputButtonGroup::isButtonPreviewEnabled() const
+{
+    Q_D(const HbInputButtonGroup);
+
+    return d->mButtonPreviewEnabled;
+}
+
+/*!
+Sets button specific character selection preview state.
+
+\sa isCharacterSelectionPreviewEnabled
+*/
+void HbInputButtonGroup::setCharacterSelectionPreviewEnabled(bool enabled)
+{
+    Q_D(HbInputButtonGroup);
+
+    d->mCharacterSelectionPreviewEnabled = enabled;
+}
+
+/*!
+Returns button specific character selection preview state.
+
+\sa setCharacterSelectionPreviewEnabled
+*/
+bool HbInputButtonGroup::isCharacterSelectionPreviewEnabled() const
+{
+    Q_D(const HbInputButtonGroup);
+
+    return d->mCharacterSelectionPreviewEnabled;
+}
+
+
+/*!
+Sets multi touch enabled or disabled.
+
+\sa isMultiTouchEnabled
+*/
+void HbInputButtonGroup::setMultiTouchEnabled(bool enabled)
+{
+    Q_D(HbInputButtonGroup);
+
+    d->mMultiTouchEnabled = enabled;
+    setAcceptTouchEvents(enabled);
+}
+
+/*!
+Returns multi touch state.
+
+\sa setMultiTouchEnabled
+*/
+bool HbInputButtonGroup::isMultiTouchEnabled() const
+{
+    Q_D(const HbInputButtonGroup);
+    
+    return d->mMultiTouchEnabled;
+}
+
+/*!
+Sets button group background graphics.
+Takes ownership of the background object.
+*/
+void HbInputButtonGroup::setBackground(HbFrameDrawer *background)
+{
+    Q_D(HbInputButtonGroup);
+
+    HbFrameDrawerPool::release(d->mBackground);
+    d->mBackground = background;
+}
+
+/*!
+Returns all possible buttons the user could have intended to press
+for the last registered touch along with their corresponding probabilities.
+*/
+QList<HbKeyPressProbability> HbInputButtonGroup::buttonProbabilities() const
+{
+    Q_D(const HbInputButtonGroup);
+
+    return d->mProbabilities;
+}
+
+/*!
+Sets the button group enabled or disabled.
+
+\sa isEnabled
+*/
+void HbInputButtonGroup::setEnabled(bool enabled)
+{
+    Q_D(HbInputButtonGroup);
+
+    d->mEnabled = enabled;
+    d->updateGraphics(QSizeF(boundingRect().width(), boundingRect().height()));
+    d->updateTextLayouts(QSizeF(boundingRect().width(), boundingRect().height()));
+    update();
+}
+
+/*!
+Returns the button group state.
+
+\sa setEnabled
+*/
+bool HbInputButtonGroup::isEnabled() const
+{
+    Q_D(const HbInputButtonGroup);
+
+    return d->mEnabled;
+}
+
+/*!
+Draws the button group.
+*/
+void HbInputButtonGroup::paint(QPainter* painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+    Q_UNUSED(option);
+    Q_UNUSED(widget);
+
+    Q_D(HbInputButtonGroup);
+
+    if (d->mBackground) {
+        d->mBackground->paint(painter, QRectF(0, 0, boundingRect().width(), boundingRect().height()));
+    }
+
+    qreal cellWidth = boundingRect().width() / d->mGridSize.width();
+    qreal cellHeight = boundingRect().height() / d->mGridSize.height();
+
+    for (int i = 0; i < d->mButtonData.count(); ++i) {
+        HbInputButton *item = d->mButtonData.at(i);
+
+        if (d->mButtonDrawers.at(i)) {
+            qreal x = item->position().x() * cellWidth + d->mButtonBorderSize;
+            qreal y = item->position().y() * cellHeight + d->mButtonBorderSize;
+            qreal width = item->size().width() * cellWidth - 2 * d->mButtonBorderSize;
+            qreal height = item->size().height() * cellHeight - 2 * d->mButtonBorderSize;
+
+            painter->save();
+            painter->translate(x, y);
+            d->mButtonDrawers.at(i)->paint(painter, QRectF(0, 0, width, height));        
+            painter->restore();
+        }
+
+        if (!item->icon(HbInputButton::ButtonIconIndexPrimary).isNull()) {
+            qreal x = item->position().x() * cellWidth;
+            qreal y = item->position().y() * cellHeight;
+            qreal width = item->size().width() * cellWidth;
+            qreal height = item->size().height() * cellHeight;
+
+            if (!item->text(HbInputButton::ButtonTextIndexSecondaryFirstRow).isEmpty() ||
+                !item->text(HbInputButton::ButtonTextIndexSecondarySecondRow).isEmpty() ||
+                !item->icon(HbInputButton::ButtonIconIndexSecondaryFirstRow).isNull() ||
+                !item->icon(HbInputButton::ButtonIconIndexSecondarySecondRow).isNull()) {
+                x += HbHorizontalMarginInUnits * d->mUnitValue + d->mButtonBorderSize;
+                y += 0.5 * (item->size().height() * cellHeight - HbPrimaryIconSizeInUnits * d->mUnitValue);
+                width = HbPrimaryIconSizeInUnits * d->mUnitValue;
+                height = HbPrimaryIconSizeInUnits * d->mUnitValue;
+            }
+            item->icon(HbInputButton::ButtonIconIndexPrimary).paint(painter, QRectF(x, y, width, height));
+        }
+
+        if (!item->icon(HbInputButton::ButtonIconIndexSecondaryFirstRow).isNull()) {
+            qreal x = (item->position().x() + item->size().width()) * cellWidth -
+                HbSecondaryIconSizeInUnits * d->mUnitValue - HbHorizontalMarginInUnits * d->mUnitValue - d->mButtonBorderSize;
+            qreal y = (item->position().y() + item->size().height()) * cellHeight -
+                HbSecondaryIconSizeInUnits * d->mUnitValue - HbVerticalMarginInUnits * d->mUnitValue - d->mButtonBorderSize;
+            qreal width = HbSecondaryIconSizeInUnits * d->mUnitValue;
+            qreal height = HbSecondaryIconSizeInUnits * d->mUnitValue;
+
+            Qt::Alignment alignment = static_cast<Qt::Alignment>(Qt::AlignVCenter | Qt::AlignRight);
+            item->icon(HbInputButton::ButtonIconIndexSecondaryFirstRow).paint(painter, QRectF(x, y, width, height), Qt::KeepAspectRatio, alignment);
+        }
+
+        if (!item->icon(HbInputButton::ButtonIconIndexSecondarySecondRow).isNull()) {
+            qreal x = (item->position().x() + item->size().width()) * cellWidth -
+                HbSecondaryIconSizeInUnits * d->mUnitValue - HbHorizontalMarginInUnits * d->mUnitValue - d->mButtonBorderSize;
+            qreal y = item->position().y() * cellHeight + HbVerticalMarginInUnits * d->mUnitValue + d->mButtonBorderSize;
+            qreal width = HbSecondaryIconSizeInUnits * d->mUnitValue;
+            qreal height = HbSecondaryIconSizeInUnits * d->mUnitValue;
+
+            Qt::Alignment alignment = static_cast<Qt::Alignment>(Qt::AlignVCenter | Qt::AlignRight);
+            item->icon(HbInputButton::ButtonIconIndexSecondaryFirstRow).paint(painter, QRectF(x, y, width, height), Qt::KeepAspectRatio, alignment);
+        }
+
+    }
+
+    for (int i = 0; i < HbTextLayoutCount; ++i) {
+        painter->save();
+        painter->setPen(d->mColors.at(i % HbTextTypeCount));
+
+        if (d->mTextLayouts.at(i)) {
+            d->mTextLayouts.at(i)->draw(painter, QPointF(0, 0));
+        }
+        painter->restore();
+    }
+}
+
+/*!
+\reimp
+
+Handles touch events.
+*/
+bool HbInputButtonGroup::sceneEvent(QEvent *event)
+{
+    Q_D(HbInputButtonGroup);
+
+    if (!d->mEnabled) {
+        event->ignore();
+        return false;
+    }
+
+    if (event->type() == QEvent::TouchBegin) {
+        QTouchEvent *touchEvent = static_cast<QTouchEvent*>(event);
+        foreach (QTouchEvent::TouchPoint point, touchEvent->touchPoints()) {
+            if (!point.isPrimary() && d->mMultiTouchEnabled) {         
+                d->pressEvent(point.pos());
+            }
+        }
+    } else if (event->type() == QEvent::TouchUpdate) {
+        QTouchEvent *touchEvent = static_cast<QTouchEvent*>(event);
+        foreach (QTouchEvent::TouchPoint point, touchEvent->touchPoints()) {
+            if (!point.isPrimary() && d->mMultiTouchEnabled) {
+                if (point.state() & Qt::TouchPointPressed) {
+                    d->pressEvent(point.pos());
+                } else if (point.state() & Qt::TouchPointMoved) {
+                    d->moveEvent(point.lastPos(), point.pos());
+                } else if (point.state() & Qt::TouchPointReleased) {
+                    d->releaseEvent(point.pos());
+                }
+            }
+        }
+    } else if (event->type() == QEvent::TouchEnd) {
+        QTouchEvent *touchEvent = static_cast<QTouchEvent*>(event);
+        foreach (QTouchEvent::TouchPoint point, touchEvent->touchPoints()) {
+            if (!point.isPrimary() && d->mMultiTouchEnabled) {  
+                d->releaseEvent(point.pos());
+            }
+        }
+    } else if (event->type() == QEvent::GraphicsSceneMousePress) {
+        QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent*>(event);
+        d->pressEvent(mouseEvent->pos());
+    } else if (event->type() == QEvent::GraphicsSceneMouseDoubleClick) {
+        QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent*>(event);
+        d->doublePressEvent(mouseEvent->pos());
+    } else if (event->type() == QEvent::GraphicsSceneMouseMove) {
+        QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent*>(event);
+        d->moveEvent(mouseEvent->lastPos(), mouseEvent->pos());
+    } else if (event->type() == QEvent::GraphicsSceneMouseRelease) {
+        QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent*>(event);
+        d->releaseEvent(mouseEvent->pos());
+    } else {
+        return HbWidget::event(event);
+    }
+    return true;
+}
+
+/*!
+\reimp
+
+Updates button group geometry.
+*/
+void HbInputButtonGroup::setGeometry(const QRectF &rect)
+{
+    Q_D(HbInputButtonGroup);
+
+    HbWidget::setGeometry(rect);
+
+    setButtonBorderSize(d->mButtonBorderSize);
+    d->updateButtonGrid(QSizeF(rect.width(), rect.height()));
+    d->updateGraphics(QSizeF(rect.width(), rect.height()));
+    d->updateTextLayouts(QSizeF(rect.width(), rect.height()));
+}
+
+/*!
+\reimp
+
+Updates theme graphics
+ */
+void HbInputButtonGroup::changeEvent(QEvent *event)
+{
+    Q_D(HbInputButtonGroup);
+   
+    if (event->type() == HbEvent::ThemeChanged) {
+        if (d->mBackground) {
+            d->mBackground->themeChanged();
+        }
+
+        foreach (HbFrameDrawer *drawer, d->mButtonDrawers) {
+            drawer->themeChanged();
+        }
+
+        d->updateColorArray();
+
+        for (int i = 0; i < d->mButtonData.count(); ++i) {
+            HbInputButton *item = d->mButtonData.at(i);
+
+            QColor color;
+            if (d->mEnabled) {
+                color = d->mColors.at(item->type() * HbInputButton::ButtonStateCount + item->state());
+            } else {
+                color = d->mColors.at(item->type() * HbInputButton::ButtonStateCount + HbInputButton::ButtonStateDisabled);
+            }
+
+            if (!item->icon(HbInputButton::ButtonIconIndexPrimary).isNull()) {
+                HbIcon icon = item->icon(HbInputButton::ButtonIconIndexPrimary);
+                icon.setColor(color);
+                item->setIcon(icon, HbInputButton::ButtonIconIndexPrimary);
+            }
+        }
+    }
+    HbWidget::changeEvent(event);
+}
+
+/*!
+\reimp
+
+Enables touch events if multi touch is enabled.
+*/
+void HbInputButtonGroup::showEvent(QShowEvent *event)
+{
+    Q_D(HbInputButtonGroup);
+
+    setAcceptTouchEvents(d->mMultiTouchEnabled);
+
+    HbWidget::showEvent(event);
+}
+
+/*!
+\reimp
+
+Releases all pressed buttons when hidden.
+*/
+void HbInputButtonGroup::hideEvent(QHideEvent *event)
+{
+    cancelButtonPress();
+
+    HbWidget::hideEvent(event);
+}
+
+/*!
+Emits buttonPressed signal.
+*/
+void HbInputButtonGroup::emitButtonPressed(const QKeyEvent &event)
+{
+    emit buttonPressed(event);
+}
+
+/*!
+Emits buttonDoublePressed signal.
+*/
+void HbInputButtonGroup::emitButtonDoublePressed(const QKeyEvent &event)
+{
+    emit buttonDoublePressed(event);
+}
+
+/*!
+Emits buttonReleased signal.
+*/
+void HbInputButtonGroup::emitButtonReleased(const QKeyEvent &event)
+{
+    Q_D(HbInputButtonGroup);
+
+    if (d->mCharacterSelectionPreview) {
+        d->mCharacterSelectionPreview->hide();
+    }
+
+    emit buttonReleased(event);
+}
+
+/*!
+Emits buttonLongPressed signal.
+*/
+void HbInputButtonGroup::emitButtonLongPressed(const QKeyEvent &event)
+{
+    emit buttonLongPressed(event);
+}
+
+/*!
+Emits pressedButtonChanged signal.
+*/
+void HbInputButtonGroup::emitPressedButtonChanged(const QKeyEvent &releaseEvent, const QKeyEvent &pressEvent)
+{
+    emit pressedButtonChanged(releaseEvent, pressEvent);
+}
+
+/*!
+Cancels current button press and releases all buttons.
+*/
+void HbInputButtonGroup::cancelButtonPress()
+{
+    Q_D(HbInputButtonGroup);
+
+    ungrabMouse();
+
+    for (int i = 0; i < d->mButtonData.count(); ++i) {
+        if (d->mButtonData.at(i)->state() == HbInputButton::ButtonStatePressed) {
+            d->mButtonData.at(i)->setState(HbInputButton::ButtonStateReleased);
+        }
+        d->hideButtonPreview(d->mButtonData.at(i));
+
+        if (d->mLongPressButtons.contains(i)) {
+            int listIndex = d->mLongPressButtons.indexOf(i);
+            delete d->mLongPressTimers.at(listIndex);
+            d->mLongPressTimers.removeAt(listIndex);
+            d->mLongPressButtons.removeAt(listIndex);
+        }
+    }
+    if (d->mCharacterSelectionPreview) {
+        d->mCharacterSelectionPreview->hide();
+    }
+
+    d->updateGraphics(QSizeF(boundingRect().width(), boundingRect().height()));
+    d->updateTextLayouts(QSizeF(boundingRect().width(), boundingRect().height()));
+    update();
+}
+
+/*!
+Called when long press occurs.
+*/
+void HbInputButtonGroup::longPressEvent()
+{
+    Q_D(HbInputButtonGroup);
+
+    d->longPressEvent();
+}
+
+/*!
+Updates custom buttons with custom actions.
+
+\sa setCustomButtonActions
+*/
+void HbInputButtonGroup::updateCustomButtons()
+{
+    Q_D(HbInputButtonGroup);
+
+    d->updateCustomActions();
+    d->updateGraphics(QSizeF(boundingRect().width(), boundingRect().height()));
+    d->updateTextLayouts(QSizeF(boundingRect().width(), boundingRect().height()));
+    update();
+}
+
+// End of file