telutils/dialpad/src/dialpadkeypad.cpp
changeset 31 a2467631ae02
parent 27 7eb70891911c
child 32 1f002146abb4
equal deleted inserted replaced
27:7eb70891911c 31:a2467631ae02
    13 *
    13 *
    14 * Description: Dialpad keypad
    14 * Description: Dialpad keypad
    15 *
    15 *
    16 */
    16 */
    17 
    17 
    18 #include <QtGui>
    18 #include <QLocale>
       
    19 #include <QSignalMapper>
       
    20 
    19 #include <hbinstance.h>
    21 #include <hbinstance.h>
    20 #include <hbinputkeymapfactory.h>
    22 #include <hbinputkeymapfactory.h>
    21 #include <hbinputkeymap.h>
    23 #include <hbinputkeymap.h>
    22 #include <hbinpututils.h>
    24 #include <hbinpututils.h>
    23 #include <hbinputsettingproxy.h>
    25 #include <hbinputsettingproxy.h>
    24 #include <hbinputlanguage.h>
    26 #include <hbinputlanguage.h>
    25 #include <hbapplication.h>
    27 #include <hbapplication.h>
    26 #include <hblineedit.h>
    28 #include <hblineedit.h>
       
    29 #include <hbinputbutton.h>
    27 
    30 
    28 #include "dialpadkeypad.h"
    31 #include "dialpadkeypad.h"
    29 #include "dialpadbutton.h"
    32 #include "dialpadbutton.h"
    30 #include "dialpadinputfield.h"
    33 #include "dialpadinputfield.h"
    31 
    34 
    32 static const int DialpadRowCount = 5;
    35 static const int DialpadRowCount = 4;
    33 static const int DialpadColumnCount = 3;
    36 static const int DialpadColumnCount = 3;
    34 static const QString handsetIcon("qtg_mono_call");
    37 static const QString handsetIcon("qtg_mono_call");
    35 static const QString vmbxIcon("qtg_mono_voice_mailbox");
    38 static const QString vmbxIcon("qtg_mono_voice_mailbox");
    36 
    39 static const qreal DialpadKeypadBorderWidth = 0.25;
    37 static const int DialpadButtonToKeyCodeTable[DialpadButtonCount] =
    40 
       
    41 static const int DialpadKeyCodeTable[DialpadRowCount*DialpadColumnCount] =
    38 {
    42 {
    39     Qt::Key_1,        Qt::Key_2,      Qt::Key_3,
    43     Qt::Key_1,        Qt::Key_2,      Qt::Key_3,
    40     Qt::Key_4,        Qt::Key_5,      Qt::Key_6,
    44     Qt::Key_4,        Qt::Key_5,      Qt::Key_6,
    41     Qt::Key_7,        Qt::Key_8,      Qt::Key_9,
    45     Qt::Key_7,        Qt::Key_8,      Qt::Key_9,
    42     Qt::Key_Asterisk, Qt::Key_0,      Qt::Key_NumberSign,
    46     Qt::Key_Asterisk, Qt::Key_0,      Qt::Key_NumberSign
    43                       Qt::Key_Yes
    47     // Qt::Key_Yes and Qt::Key_BackSpace are handled separately
    44     // Qt::Key_BackSpace is in input field
       
    45 };
    48 };
    46 
    49 
    47 DialpadKeypad::DialpadKeypad(
    50 DialpadKeypad::DialpadKeypad(
    48     const HbMainWindow& mainWindow,
    51     const HbMainWindow& mainWindow,
    49     DialpadInputField& inputField,
    52     DialpadInputField& inputField,
    50     QGraphicsItem* parent) :
    53     QGraphicsItem* parent) :
    51     HbWidget(parent),
    54     HbInputButtonGroup(parent),
    52     mMainWindow(mainWindow),
    55     mMainWindow(mainWindow),
    53     mInputField(inputField),
    56     mInputField(inputField)
    54     mLongPressDuration(0)
    57 {
    55 {
    58     setObjectName("keypad");
    56     // create signal mappers
    59 
    57     mKeyPressedSignalMapper = new QSignalMapper(this);
    60     // create clicked signal mapper
    58     connect(mKeyPressedSignalMapper,SIGNAL(mapped(int)),
       
    59             SLOT(handleKeyPressed(int)));
       
    60     mKeyClickedSignalMapper = new QSignalMapper(this);
    61     mKeyClickedSignalMapper = new QSignalMapper(this);
    61     connect(mKeyClickedSignalMapper,SIGNAL(mapped(int)),
    62     connect(mKeyClickedSignalMapper,SIGNAL(mapped(int)),
    62             SLOT(handleKeyClicked(int)));
    63             SLOT(handleKeyClicked(int)));
    63     mKeyReleasedSignalMapper = new QSignalMapper(this);
    64 
    64     connect(mKeyReleasedSignalMapper,SIGNAL(mapped(int)),
    65     // connect backspace signals
    65             SLOT(handleKeyReleased(int)));
       
    66 
       
    67     connect(&mInputField.backspaceButton(),SIGNAL(clicked()),
    66     connect(&mInputField.backspaceButton(),SIGNAL(clicked()),
    68             mKeyClickedSignalMapper,SLOT(map()));
    67             mKeyClickedSignalMapper,SLOT(map()));
    69     mKeyClickedSignalMapper->setMapping(&mInputField.backspaceButton(),
    68     mKeyClickedSignalMapper->setMapping(&mInputField.backspaceButton(),
    70                                         Qt::Key_Backspace);
    69                                         Qt::Key_Backspace);
    71 
    70 
    72     // create keypad
    71     // create keypad
    73     for (int i = 0; i < DialpadButtonCount; i++) {
    72     setGridSize(QSize(DialpadColumnCount, DialpadRowCount));
    74         int keyCode = DialpadButtonToKeyCodeTable[i];
    73     setButtonBorderSize(DialpadKeypadBorderWidth);
    75 
    74 
    76         DialpadButton* button = new DialpadButton(this);
    75     QList<HbInputButton*> buttons;
    77         mButtons[i] = button;
    76 
    78 
    77     for (int i = 0; i < DialpadRowCount * DialpadColumnCount; ++i) {
    79         button->setStretched(true);
    78         HbInputButton *item = new HbInputButton(
    80         button->setFocusPolicy(Qt::NoFocus);
    79             DialpadKeyCodeTable[i],
    81         button->setFlag(QGraphicsItem::ItemIsFocusable,false);
    80             QPoint(i % DialpadColumnCount, i / DialpadColumnCount));
    82 
    81         buttons.append(item);
    83         QString buttonName;
    82 
    84         buttonName.setNum(keyCode);
    83         item->setType(HbInputButton::ButtonTypeNormal);
    85         button->setObjectName(buttonName);
       
    86 
       
    87         if (keyCode==Qt::Key_Yes) {
       
    88             HbIcon callIcon(handsetIcon); // todo correct icon
       
    89             button->setIcon(callIcon);
       
    90             button->setButtonType(DialpadButton::CallButton); // for css
       
    91         } else {
       
    92             button->setButtonType(DialpadButton::NumericButton); // for css
       
    93         }
       
    94 
       
    95         if (keyCode==Qt::Key_1) {
       
    96             HbIcon mboxIcon(vmbxIcon);
       
    97             button->setIcon(mboxIcon);
       
    98         }
       
    99 
       
   100         if (keyCode!=Qt::Key_Yes) {
       
   101             connect(button,SIGNAL(pressed()),
       
   102                     mKeyPressedSignalMapper,SLOT(map()));
       
   103             mKeyPressedSignalMapper->setMapping(button,keyCode);
       
   104 
       
   105             connect(button,SIGNAL(released()),
       
   106                     mKeyReleasedSignalMapper,SLOT(map()));
       
   107             mKeyReleasedSignalMapper->setMapping(button,keyCode);
       
   108         } else {
       
   109             // for Yes-key longPress() functionality is same as clicked()
       
   110             connect(button,SIGNAL(longPress(QPointF)),
       
   111                     mKeyClickedSignalMapper,SLOT(map()));
       
   112             mKeyClickedSignalMapper->setMapping(button,keyCode);
       
   113         }
       
   114 
       
   115         connect(button,SIGNAL(clicked()),mKeyClickedSignalMapper,SLOT(map()));
       
   116         mKeyClickedSignalMapper->setMapping(button,keyCode);
       
   117     }
    84     }
       
    85 
       
    86     setButtons(buttons);
       
    87 
       
    88     // connect keypad signals
       
    89     QObject::connect(this, SIGNAL(buttonPressed(const QKeyEvent&)),
       
    90                      this, SLOT(sendKeyPressEvent(const QKeyEvent&)));
       
    91     QObject::connect(this, SIGNAL(buttonReleased(const QKeyEvent&)),
       
    92                      this, SLOT(sendKeyReleaseEvent(const QKeyEvent&)));
       
    93     QObject::connect(this, SIGNAL(buttonLongPressed(const QKeyEvent&)),
       
    94                      this, SLOT(sendLongPressEvent(const QKeyEvent&)));
       
    95     QObject::connect(this, SIGNAL(pressedButtonChanged(const QKeyEvent&,
       
    96                                                        const QKeyEvent&)),
       
    97                      this, SLOT(handleKeyChangeEvent(const QKeyEvent&,
       
    98                                                      const QKeyEvent&)));
       
    99 
       
   100     // create call button (parent layouts this)
       
   101     mCallButton = new DialpadButton(parent);
       
   102     mCallButton->setButtonType(DialpadButton::CallButton);
       
   103     mCallButton->setIcon(HbIcon(handsetIcon));
       
   104     QString buttonName;
       
   105     buttonName.setNum(Qt::Key_Yes);
       
   106     mCallButton->setObjectName(buttonName);
       
   107     connect(mCallButton,SIGNAL(clicked()),
       
   108             mKeyClickedSignalMapper,SLOT(map()));
       
   109     connect(mCallButton,SIGNAL(longPress(QPointF)),
       
   110             mKeyClickedSignalMapper,SLOT(map()));
       
   111     mKeyClickedSignalMapper->setMapping(mCallButton,
       
   112                                         Qt::Key_Yes);
   118 
   113 
   119     // set button texts
   114     // set button texts
   120     setButtonTexts();
   115     setButtonTexts();
       
   116     // set button icons
       
   117     button(0)->setIcon(HbIcon(vmbxIcon),
       
   118         HbInputButton::ButtonIconIndexSecondaryFirstRow);
       
   119 
   121     // update button texts when input language is changed
   120     // update button texts when input language is changed
   122     connect(HbInputSettingProxy::instance(),
   121     connect(HbInputSettingProxy::instance(),
   123             SIGNAL(globalInputLanguageChanged(HbInputLanguage)),
   122             SIGNAL(globalInputLanguageChanged(HbInputLanguage)),
   124             this,SLOT(setButtonTexts()));
   123             this,SLOT(setButtonTexts()));
   125 
       
   126     createButtonGrid();
       
   127 
       
   128     // timer to handle long press
       
   129     mLongPressTimer = new QTimer(this);
       
   130     mLongPressTimer->setSingleShot(true);
       
   131     connect(mLongPressTimer,SIGNAL(timeout()),SLOT(handleLongPress()));
       
   132 }
   124 }
   133 
   125 
   134 DialpadKeypad::~DialpadKeypad()
   126 DialpadKeypad::~DialpadKeypad()
   135 {
   127 {
   136 }
       
   137 
       
   138 void DialpadKeypad::createButtonGrid()
       
   139 {
       
   140     // button grid
       
   141     mGridLayout = new QGraphicsGridLayout;
       
   142 
       
   143     // 12 numeric buttons
       
   144     int i=0;
       
   145     for (int row = 0; row < DialpadRowCount-1; row++) {
       
   146         for (int col = 0; col < DialpadColumnCount; col++) {
       
   147            mGridLayout->addItem(mButtons[i],row,col);
       
   148            i++;
       
   149         }
       
   150     }
       
   151 
       
   152     // call button take the last row
       
   153     mGridLayout->addItem(mButtons[12],4,0,1,3);
       
   154     mGridLayout->setSpacing(0);
       
   155     mGridLayout->setContentsMargins(0,0,0,0);
       
   156 
       
   157     setLayout(mGridLayout);
       
   158 }
   128 }
   159 
   129 
   160 void DialpadKeypad::setButtonTexts()
   130 void DialpadKeypad::setButtonTexts()
   161 {
   131 {
   162     HbInputLanguage inputLanguage =
   132     HbInputLanguage inputLanguage =
   165         HbKeymapFactory::instance()->keymap(inputLanguage.language());
   135         HbKeymapFactory::instance()->keymap(inputLanguage.language());
   166 
   136 
   167     mGeneratedChar.clear();
   137     mGeneratedChar.clear();
   168 
   138 
   169     if (keymap) {
   139     if (keymap) {
   170         for (int i = 0; i < DialpadButtonCount-1; i++) {
   140         int buttonCount = (DialpadRowCount*DialpadColumnCount);
   171             int keyCode = DialpadButtonToKeyCodeTable[i];
   141         for (int i = 0; i < buttonCount; i++) {
       
   142             int keyCode = DialpadKeyCodeTable[i];
   172 
   143 
   173             if (keyCode == Qt::Key_Asterisk) {
   144             if (keyCode == Qt::Key_Asterisk) {
   174                 // asterisk is not localized
   145                 // asterisk is not localized
   175                 QChar asterisk('*');
   146                 QChar asterisk('*');
   176                 mButtons[i]->setText(asterisk);
   147                 button(i)->setText(asterisk,
   177                 mButtons[i]->setAdditionalText("+");
   148                     HbInputButton::ButtonTextIndexPrimary);
       
   149                 button(i)->setText("+",
       
   150                     HbInputButton::ButtonTextIndexSecondaryFirstRow);
   178                 mGeneratedChar.insert(Qt::Key_Asterisk, asterisk);
   151                 mGeneratedChar.insert(Qt::Key_Asterisk, asterisk);
   179                 continue;
   152                 continue;
   180             }
   153             }
   181 
   154 
   182             if (keyCode == Qt::Key_NumberSign) {
   155             if (keyCode == Qt::Key_NumberSign) {
   183                 // number sign is not localized
   156                 // number sign is not localized
   184                 QChar numberSign('#');
   157                 QChar numberSign('#');
   185                 mButtons[i]->setText(numberSign);
   158                 button(i)->setText(numberSign,
   186                 mButtons[i]->setAdditionalText(" ");
   159                     HbInputButton::ButtonTextIndexPrimary);
       
   160                 button(i)->setText(" ",
       
   161                     HbInputButton::ButtonTextIndexSecondaryFirstRow);
   187                 mGeneratedChar.insert(Qt::Key_NumberSign, numberSign);
   162                 mGeneratedChar.insert(Qt::Key_NumberSign, numberSign);
   188                 continue;
   163                 continue;
   189             }
   164             }
   190 
   165 
   191             int index = i;
   166             int index = i;
   201                     HbInputUtils::findFirstNumberCharacterBoundToKey(
   176                     HbInputUtils::findFirstNumberCharacterBoundToKey(
   202                         key,
   177                         key,
   203                         inputLanguage.language());
   178                         inputLanguage.language());
   204 
   179 
   205                 // button text
   180                 // button text
   206                 mButtons[i]->setText(numberChar);
   181                 button(i)->setText(numberChar,
       
   182                     HbInputButton::ButtonTextIndexPrimary);
   207                 mGeneratedChar.insert(keyCode,numberChar);
   183                 mGeneratedChar.insert(keyCode,numberChar);
   208 
   184 
   209                 // additional text (letters)
   185                 // additional text (letters)
   210                 int numberOfCharacters;
   186                 int numberOfCharacters;
   211                 if (keyCode==Qt::Key_7 || keyCode == Qt::Key_9) {
   187                 if (keyCode==Qt::Key_7 || keyCode == Qt::Key_9) {
   217                 }
   193                 }
   218 
   194 
   219                 QString characters = key->characters(HbModifierNone);
   195                 QString characters = key->characters(HbModifierNone);
   220 
   196 
   221                 if (numberOfCharacters==0 && keyCode!=Qt::Key_1) {
   197                 if (numberOfCharacters==0 && keyCode!=Qt::Key_1) {
   222                     mButtons[i]->setAdditionalText(" ");
   198                     button(i)->setText(" ",
       
   199                         HbInputButton::ButtonTextIndexSecondaryFirstRow);
   223                 } else {
   200                 } else {
   224                     mButtons[i]->setAdditionalText(
   201                     button(i)->setText(characters.left(numberOfCharacters),
   225                         characters.left(numberOfCharacters));
   202                         HbInputButton::ButtonTextIndexSecondaryFirstRow);
   226                 }
   203                 }
   227             }
   204             }
   228         }
   205         }
   229     }
   206     }
   230 }
   207 }
   231 
   208 
   232 void DialpadKeypad::handleKeyPressed(int key)
   209 void DialpadKeypad::handleKeyClicked(int key)
   233 {
   210 {
   234     // Editor is updated on key release (clicked()) or on long press,
   211     // concerns only yes and backspace keys
   235     // to prevent editor being updated during swipe.
       
   236     mPressedNumericKey = key;
       
   237     mLongPressTimer->start(mLongPressDuration);
       
   238 
       
   239     postKeyEvent(QEvent::KeyPress, key);
   212     postKeyEvent(QEvent::KeyPress, key);
   240 }
       
   241 
       
   242 void DialpadKeypad::handleKeyClicked(int key)
       
   243 {
       
   244     if (!isNumericKey(key)) {
       
   245         postKeyEvent(QEvent::KeyPress, key);
       
   246         postKeyEvent(QEvent::KeyRelease, key);
       
   247     } else if (mPressedNumericKey) {
       
   248         // update editor: generate key press event.
       
   249         sendKeyEventToEditor(QEvent::KeyPress, key);
       
   250     }
       
   251 }
       
   252 
       
   253 void DialpadKeypad::handleKeyReleased(int key)
       
   254 {
       
   255     mLongPressTimer->stop();
       
   256 
       
   257     postKeyEvent(QEvent::KeyRelease, key);
   213     postKeyEvent(QEvent::KeyRelease, key);
   258 }
   214 }
   259 
   215 
   260 void DialpadKeypad::postKeyEvent(QEvent::Type type, int key)
   216 void DialpadKeypad::postKeyEvent(QEvent::Type type, int key)
   261 {
   217 {
       
   218     // send simulated key to application
   262     QKeyEvent *keyEvent = new QKeyEvent(type, key, Qt::NoModifier);
   219     QKeyEvent *keyEvent = new QKeyEvent(type, key, Qt::NoModifier);
   263     HbApplication::postEvent(const_cast<HbMainWindow*>(&mMainWindow),keyEvent);
   220     HbApplication::postEvent(const_cast<HbMainWindow*>(&mMainWindow),keyEvent);
   264 }
   221 }
   265 
   222 
   266 void DialpadKeypad::sendKeyEventToEditor(QEvent::Type type, int key)
   223 void DialpadKeypad::sendKeyEventToEditor(QEvent::Type type, int key)
   267 {
   224 {
       
   225     // send key event to editor
   268     QKeyEvent keyEvent(type, key, Qt::NoModifier, mGeneratedChar.value(key));
   226     QKeyEvent keyEvent(type, key, Qt::NoModifier, mGeneratedChar.value(key));
   269     HbApplication::sendEvent(&mInputField.editor(), &keyEvent);
   227     HbApplication::sendEvent(&mInputField.editor(), &keyEvent);
   270 }
   228 }
   271 
   229 
   272 void DialpadKeypad::handleLongPress()
   230 void DialpadKeypad::sendKeyPressEvent(const QKeyEvent& event)
   273 {
   231 {
   274     // key press
   232     mPressedNumericKey = event.key();
   275     sendKeyEventToEditor(QEvent::KeyPress, mPressedNumericKey);
   233     postKeyEvent(QEvent::KeyPress, event.key());
       
   234 }
       
   235 
       
   236 void DialpadKeypad::sendKeyReleaseEvent(const QKeyEvent& event)
       
   237 {
       
   238     if (mPressedNumericKey) {
       
   239         // short press, update editor here
       
   240         sendKeyEventToEditor(QEvent::KeyPress, event.key());
       
   241     }
       
   242 
       
   243     postKeyEvent(QEvent::KeyRelease, event.key());    
       
   244 }
       
   245 
       
   246 void DialpadKeypad::sendLongPressEvent(const QKeyEvent& event)
       
   247 {
       
   248     sendKeyEventToEditor(QEvent::KeyPress, event.key());
   276     mPressedNumericKey = 0;
   249     mPressedNumericKey = 0;
   277 }
   250 }
   278 
   251 
   279 bool DialpadKeypad::isNumericKey(int key)
   252 void DialpadKeypad::handleKeyChangeEvent(
   280 {
   253     const QKeyEvent& releaseEvent,
   281     if (key==Qt::Key_Yes || key==Qt::Key_Backspace) {
   254     const QKeyEvent& pressEvent)
   282         return false;
   255 {
   283     } else {
   256     Q_UNUSED(pressEvent)
   284         return true;
   257 
   285     }
   258     postKeyEvent(QEvent::KeyRelease, releaseEvent.key());
   286 }
   259     cancelButtonPress();
   287 
       
   288 void DialpadKeypad::setLongPressDuration(int duration)
       
   289 {
       
   290     mLongPressDuration = duration;
       
   291 }
   260 }
   292 
   261 
   293 void DialpadKeypad::setCallButtonEnabled(bool enabled)
   262 void DialpadKeypad::setCallButtonEnabled(bool enabled)
   294 {
   263 {
   295     mButtons[DialpadButtonCount-1]->setEnabled(enabled);
   264     mCallButton->setEnabled(enabled);
   296 }
       
   297 
       
   298 void DialpadKeypad::showEvent(QShowEvent *event)
       
   299 {
       
   300     HbWidget::showEvent(event);
       
   301 
       
   302     if (parentWidget()->isVisible()) {
       
   303         // first show event comes before dialpad is open
       
   304         // set fixed row and column dimensions
       
   305         QSizeF effectiveSize(rect().width(),
       
   306                              rect().height());
       
   307 
       
   308         qreal width = effectiveSize.width() / DialpadColumnCount;
       
   309         qreal height = effectiveSize.height() / DialpadRowCount;
       
   310 
       
   311         for (int i=0; i < DialpadColumnCount ;i++) {
       
   312             mGridLayout->setColumnFixedWidth(i, width);
       
   313         }
       
   314 
       
   315         for (int i=0; i < DialpadRowCount ;i++) {
       
   316             mGridLayout->setRowFixedHeight(i, height);
       
   317         }
       
   318     }
       
   319 }
   265 }
   320 
   266 
   321 void DialpadKeypad::resetButtons()
   267 void DialpadKeypad::resetButtons()
   322 {
   268 {
   323     for(int i = 0; i < DialpadButtonCount; i++) {
   269     cancelButtonPress();
   324         mButtons[i]->setDown(false);
   270     mCallButton->setDown(false);
   325     }
   271 }
   326 }
   272 
       
   273 DialpadButton& DialpadKeypad::callButton() const
       
   274 {
       
   275     return *mCallButton;
       
   276 }