Merge pull request #1129 from jmarshallnz/remove_smb_auth_details_in_add_source
[vuplus_xbmc] / xbmc / dialogs / GUIDialogKeyboard.cpp
1 /*
2  *      Copyright (C) 2005-2008 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "GUIDialogKeyboard.h"
23 #include "settings/GUISettings.h"
24 #include "guilib/GUILabelControl.h"
25 #include "GUIDialogNumeric.h"
26 #include "GUIDialogOK.h"
27 #include "GUIUserMessages.h"
28 #include "guilib/GUIWindowManager.h"
29 #include "input/XBMC_vkeys.h"
30 #include "utils/RegExp.h"
31 #include "GUIPassword.h"
32 #include "utils/md5.h"
33 #include "utils/TimeUtils.h"
34 #include "Application.h"
35 #include "settings/AdvancedSettings.h"
36 #include "guilib/LocalizeStrings.h"
37 #include "interfaces/AnnouncementManager.h"
38
39 // Symbol mapping (based on MS virtual keyboard - may need improving)
40 static char symbol_map[37] = ")!@#$%^&*([]{}-_=+;:\'\",.<>/?\\|`~    ";
41
42 #define CTL_BUTTON_DONE       300
43 #define CTL_BUTTON_CANCEL     301
44 #define CTL_BUTTON_SHIFT      302
45 #define CTL_BUTTON_CAPS       303
46 #define CTL_BUTTON_SYMBOLS    304
47 #define CTL_BUTTON_LEFT       305
48 #define CTL_BUTTON_RIGHT      306
49 #define CTL_BUTTON_IP_ADDRESS 307
50
51 #define CTL_LABEL_EDIT        310
52 #define CTL_LABEL_HEADING     311
53
54 #define CTL_BUTTON_BACKSPACE    8
55
56 static char symbolButtons[] = "._-@/\\";
57 #define NUM_SYMBOLS sizeof(symbolButtons) - 1
58
59 #define SEARCH_DELAY         1000
60 #define REMOTE_SMS_DELAY     1000
61
62 CGUIDialogKeyboard::CGUIDialogKeyboard(void)
63 : CGUIDialog(WINDOW_DIALOG_KEYBOARD, "DialogKeyboard.xml")
64 {
65   m_bIsConfirmed = false;
66   m_bShift = false;
67   m_hiddenInput = false;
68   m_filtering = FILTERING_NONE;
69   m_keyType = LOWER;
70   m_strHeading = "";
71   m_lastRemoteClickTime = 0;
72 }
73
74 CGUIDialogKeyboard::~CGUIDialogKeyboard(void)
75 {}
76
77 void CGUIDialogKeyboard::OnInitWindow()
78 {
79   CGUIDialog::OnInitWindow();
80
81   m_bIsConfirmed = false;
82
83   // set alphabetic (capitals)
84   UpdateButtons();
85
86   CGUILabelControl* pEdit = ((CGUILabelControl*)GetControl(CTL_LABEL_EDIT));
87   if (pEdit)
88   {
89     pEdit->ShowCursor();
90   }
91
92   // set heading
93   if (!m_strHeading.IsEmpty())
94   {
95     SET_CONTROL_LABEL(CTL_LABEL_HEADING, m_strHeading);
96     SET_CONTROL_VISIBLE(CTL_LABEL_HEADING);
97   }
98   else
99   {
100     SET_CONTROL_HIDDEN(CTL_LABEL_HEADING);
101   }
102
103   CVariant data;
104   data["title"] = m_strHeading;
105   data["type"] = "keyboard";
106   ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Input, "xbmc", "OnInputRequested", data);
107 }
108
109 bool CGUIDialogKeyboard::OnAction(const CAction &action)
110 {
111   bool handled(true);
112   if (action.GetID() == ACTION_BACKSPACE)
113   {
114     Backspace();
115   }
116   else if (action.GetID() == ACTION_ENTER)
117   {
118     OnOK();
119   }
120   else if (action.GetID() == ACTION_CURSOR_LEFT)
121   {
122     MoveCursor( -1);
123   }
124   else if (action.GetID() == ACTION_CURSOR_RIGHT)
125   {
126     if ((unsigned int) GetCursorPos() == m_strEdit.size() && (m_strEdit.size() == 0 || m_strEdit[m_strEdit.size() - 1] != ' '))
127     { // add a space
128       Character(L' ');
129     }
130     else
131       MoveCursor(1);
132   }
133   else if (action.GetID() == ACTION_SHIFT)
134   {
135     OnShift();
136   }
137   else if (action.GetID() == ACTION_SYMBOLS)
138   {
139     OnSymbols();
140   }
141   else if (action.GetID() >= REMOTE_0 && action.GetID() <= REMOTE_9)
142   {
143     OnRemoteNumberClick(action.GetID());
144   }
145   else if (action.GetID() >= KEY_VKEY && action.GetID() < KEY_ASCII)
146   { // input from the keyboard (vkey, not ascii)
147     uint8_t b = action.GetID() & 0xFF;
148     if (b == XBMCVK_HOME)
149     {
150       MoveCursor(-GetCursorPos());
151     }
152     else if (b == XBMCVK_END)
153     {
154       MoveCursor(m_strEdit.GetLength() - GetCursorPos());
155     }
156     else if (b == XBMCVK_LEFT)
157     {
158       MoveCursor( -1);
159     }
160     else if (b == XBMCVK_RIGHT)
161     {
162       MoveCursor(1);
163     }
164     else if (b == XBMCVK_RETURN || b == XBMCVK_NUMPADENTER)
165     {
166       OnOK();
167     }
168     else if (b == XBMCVK_DELETE)
169     {
170       if (GetCursorPos() < m_strEdit.GetLength())
171       {
172         MoveCursor(1);
173         Backspace();
174       }
175     }
176     else if (b == XBMCVK_BACK) Backspace();
177     else if (b == XBMCVK_ESCAPE) Close();
178   }
179   else if (action.GetID() >= KEY_ASCII)
180   { // input from the keyboard
181     //char ch = action.GetID() & 0xFF;
182     switch (action.GetUnicode())
183     {
184     case 13:  // enter
185     case 10:  // enter
186       OnOK();
187       break;
188     case 8:   // backspace
189       Backspace();
190       break;
191     case 27:  // escape
192       Close();
193       break;
194     default:  //use character input
195       Character(action.GetUnicode());
196       break;
197     }
198   }
199   else // unhandled by us - let's see if the baseclass wants it
200     handled = CGUIDialog::OnAction(action);
201
202   if (handled && m_filtering == FILTERING_SEARCH)
203   { // we did _something_, so make sure our search message filter is reset
204     SendSearchMessage();
205   }
206   return handled;
207 }
208
209 bool CGUIDialogKeyboard::OnMessage(CGUIMessage& message)
210 {
211   CGUIDialog::OnMessage(message);
212
213
214   switch ( message.GetMessage() )
215   {
216   case GUI_MSG_CLICKED:
217     {
218       int iControl = message.GetSenderId();
219
220       switch (iControl)
221       {
222       case CTL_BUTTON_DONE:
223         {
224           OnOK();
225           break;
226         }
227       case CTL_BUTTON_CANCEL:
228         Close();
229         break;
230       case CTL_BUTTON_SHIFT:
231         OnShift();
232         break;
233       case CTL_BUTTON_CAPS:
234         if (m_keyType == LOWER)
235           m_keyType = CAPS;
236         else if (m_keyType == CAPS)
237           m_keyType = LOWER;
238         UpdateButtons();
239         break;
240       case CTL_BUTTON_SYMBOLS:
241         OnSymbols();
242         break;
243       case CTL_BUTTON_LEFT:
244         {
245           MoveCursor( -1);
246         }
247         break;
248       case CTL_BUTTON_RIGHT:
249         {
250           MoveCursor(1);
251         }
252         break;
253       case CTL_BUTTON_IP_ADDRESS:
254         {
255           OnIPAddress();
256         }
257       default:
258         m_lastRemoteKeyClicked = 0;
259         OnClickButton(iControl);
260         break;
261       }
262     }
263     break;
264
265   case GUI_MSG_SET_TEXT:
266     SetText(message.GetLabel());
267
268     // close the dialog if requested
269     if (message.GetParam1() > 0)
270       OnOK();
271     break;
272   }
273
274   return true;
275 }
276
277 void CGUIDialogKeyboard::SetText(const CStdString& aTextString)
278 {
279   m_strEdit.Empty();
280   g_charsetConverter.utf8ToW(aTextString, m_strEdit);
281   UpdateLabel();
282   MoveCursor(m_strEdit.size());
283 }
284
285 CStdString CGUIDialogKeyboard::GetText() const
286 {
287   CStdString utf8String;
288   g_charsetConverter.wToUTF8(m_strEdit, utf8String);
289   return utf8String;
290 }
291
292 void CGUIDialogKeyboard::Character(WCHAR ch)
293 {
294   if (!ch) return;
295   // TODO: May have to make this routine take a WCHAR for the symbols?
296   m_strEdit.Insert(GetCursorPos(), ch);
297   UpdateLabel();
298   MoveCursor(1);
299 }
300
301 void CGUIDialogKeyboard::FrameMove()
302 {
303   // reset the hide state of the label when the remote
304   // sms style input times out
305   if (m_lastRemoteClickTime && m_lastRemoteClickTime + REMOTE_SMS_DELAY < CTimeUtils::GetFrameTime())
306   {
307     // finished inputting a sms style character - turn off our shift and symbol states
308     ResetShiftAndSymbols();
309   }
310   CGUIDialog::FrameMove();
311 }
312
313 void CGUIDialogKeyboard::UpdateLabel() // FIXME seems to be called twice for one USB SDL keyboard action/character
314 {
315   CGUILabelControl* pEdit = ((CGUILabelControl*)GetControl(CTL_LABEL_EDIT));
316   if (pEdit)
317   {
318     CStdStringW edit = m_strEdit;
319     if (m_hiddenInput)
320     { // convert to *'s
321       edit.Empty();
322       if (m_lastRemoteClickTime + REMOTE_SMS_DELAY > CTimeUtils::GetFrameTime() && m_strEdit.size())
323       { // using the remove to input, so display the last key input
324         edit.append(m_strEdit.size() - 1, L'*');
325         edit.append(1, m_strEdit[m_strEdit.size() - 1]);
326       }
327       else
328         edit.append(m_strEdit.size(), L'*');
329     }
330     // convert back to utf8
331     CStdString utf8Edit;
332     g_charsetConverter.wToUTF8(edit, utf8Edit);
333     pEdit->SetLabel(utf8Edit);
334     // Send off a search message
335     unsigned int now = CTimeUtils::GetFrameTime();
336     // don't send until the REMOTE_SMS_DELAY has passed
337     if (m_lastRemoteClickTime && m_lastRemoteClickTime + REMOTE_SMS_DELAY >= now)
338       return;
339     if (m_filtering == FILTERING_CURRENT)
340     { // send our filter message
341       CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS);
342       message.SetStringParam(utf8Edit);
343       g_windowManager.SendMessage(message);
344     }
345
346     if (m_filtering == FILTERING_SEARCH)
347       SendSearchMessage();
348   }
349 }
350
351 void CGUIDialogKeyboard::SendSearchMessage()
352 {
353   CStdString utf8Edit;
354   g_charsetConverter.wToUTF8(m_strEdit, utf8Edit);
355   // send our search message (only the active window needs it)
356   CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_SEARCH_UPDATE);
357   message.SetStringParam(utf8Edit);
358   CGUIWindow *window = g_windowManager.GetWindow(g_windowManager.GetActiveWindow());
359   if (window)
360     window->OnMessage(message);
361 }
362
363 void CGUIDialogKeyboard::Backspace()
364 {
365   int iPos = GetCursorPos();
366   if (iPos > 0)
367   {
368     m_strEdit.erase(iPos - 1, 1);
369     MoveCursor(-1);
370     UpdateLabel();
371   }
372 }
373
374 void CGUIDialogKeyboard::OnClickButton(int iButtonControl)
375 {
376   if (iButtonControl == CTL_BUTTON_BACKSPACE)
377   {
378     Backspace();
379   }
380   else
381     Character(GetCharacter(iButtonControl));
382 }
383
384 void CGUIDialogKeyboard::OnRemoteNumberClick(int key)
385 {
386   unsigned int now = CTimeUtils::GetFrameTime();
387
388   if (m_lastRemoteClickTime)
389   { // a remote key has been pressed
390     if (key != m_lastRemoteKeyClicked || m_lastRemoteClickTime + REMOTE_SMS_DELAY < now)
391     { // a different key was clicked than last time, or we have timed out
392       m_lastRemoteKeyClicked = key;
393       m_indexInSeries = 0;
394       // reset our shift and symbol states, and update our label to ensure the search filter is sent
395       ResetShiftAndSymbols();
396       UpdateLabel();
397     }
398     else
399     { // same key as last time within the appropriate time period
400       m_indexInSeries++;
401       Backspace();
402     }
403   }
404   else
405   { // key is pressed for the first time
406     m_lastRemoteKeyClicked = key;
407     m_indexInSeries = 0;
408   }
409
410   int arrayIndex = key - REMOTE_0;
411   m_indexInSeries = m_indexInSeries % strlen(s_charsSeries[arrayIndex]);
412   m_lastRemoteClickTime = now;
413
414   // Select the character that will be pressed
415   const char* characterPressed = s_charsSeries[arrayIndex];
416   characterPressed += m_indexInSeries;
417
418   // use caps where appropriate
419   char ch = *characterPressed;
420   bool caps = (m_keyType == CAPS && !m_bShift) || (m_keyType == LOWER && m_bShift);
421   if (!caps && *characterPressed >= 'A' && *characterPressed <= 'Z')
422     ch += 32;
423   Character(ch);
424 }
425
426 char CGUIDialogKeyboard::GetCharacter(int iButton)
427 {
428   // First the numbers
429   if (iButton >= 48 && iButton <= 57)
430   {
431     if (m_keyType == SYMBOLS)
432     {
433       OnSymbols();
434       return symbol_map[iButton -48];
435     }
436     else
437       return (char)iButton;
438   }
439   else if (iButton == 32) // space
440     return (char)iButton;
441   else if (iButton >= 65 && iButton < 91)
442   {
443     if (m_keyType == SYMBOLS)
444     { // symbol
445       OnSymbols();
446       return symbol_map[iButton - 65 + 10];
447     }
448     if ((m_keyType == CAPS && m_bShift) || (m_keyType == LOWER && !m_bShift))
449     { // make lower case
450       iButton += 32;
451     }
452     if (m_bShift)
453     { // turn off the shift key
454       OnShift();
455     }
456     return (char) iButton;
457   }
458   else
459   { // check for symbols
460     for (unsigned int i = 0; i < NUM_SYMBOLS; i++)
461       if (iButton == symbolButtons[i])
462         return (char)iButton;
463   }
464   return 0;
465 }
466
467 void CGUIDialogKeyboard::UpdateButtons()
468 {
469   if (m_bShift)
470   { // show the button depressed
471     CGUIMessage msg(GUI_MSG_SELECTED, GetID(), CTL_BUTTON_SHIFT);
472     OnMessage(msg);
473   }
474   else
475   {
476     CGUIMessage msg(GUI_MSG_DESELECTED, GetID(), CTL_BUTTON_SHIFT);
477     OnMessage(msg);
478   }
479   if (m_keyType == CAPS)
480   {
481     CGUIMessage msg(GUI_MSG_SELECTED, GetID(), CTL_BUTTON_CAPS);
482     OnMessage(msg);
483   }
484   else
485   {
486     CGUIMessage msg(GUI_MSG_DESELECTED, GetID(), CTL_BUTTON_CAPS);
487     OnMessage(msg);
488   }
489   if (m_keyType == SYMBOLS)
490   {
491     CGUIMessage msg(GUI_MSG_SELECTED, GetID(), CTL_BUTTON_SYMBOLS);
492     OnMessage(msg);
493   }
494   else
495   {
496     CGUIMessage msg(GUI_MSG_DESELECTED, GetID(), CTL_BUTTON_SYMBOLS);
497     OnMessage(msg);
498   }
499   char szLabel[2];
500   szLabel[0] = 32;
501   szLabel[1] = 0;
502   CStdString aLabel = szLabel;
503
504   // set numerals
505   for (int iButton = 48; iButton <= 57; iButton++)
506   {
507     if (m_keyType == SYMBOLS)
508       aLabel[0] = symbol_map[iButton - 48];
509     else
510       aLabel[0] = iButton;
511     SetControlLabel(iButton, aLabel);
512   }
513
514   // set correct alphabet characters...
515
516   for (int iButton = 65; iButton <= 90; iButton++)
517   {
518     // set the correct case...
519     if ((m_keyType == CAPS && m_bShift) || (m_keyType == LOWER && !m_bShift))
520     { // make lower case
521       aLabel[0] = iButton + 32;
522     }
523     else if (m_keyType == SYMBOLS)
524     {
525       aLabel[0] = symbol_map[iButton - 65 + 10];
526     }
527     else
528     {
529       aLabel[0] = iButton;
530     }
531     SetControlLabel(iButton, aLabel);
532   }
533   for (unsigned int i = 0; i < NUM_SYMBOLS; i++)
534   {
535     aLabel[0] = symbolButtons[i];
536     SetControlLabel(symbolButtons[i], aLabel);
537   }
538 }
539
540 // Show keyboard with initial value (aTextString) and replace with result string.
541 // Returns: true  - successful display and input (empty result may return true or false depending on parameter)
542 //          false - unsucessful display of the keyboard or cancelled editing
543 bool CGUIDialogKeyboard::ShowAndGetInput(CStdString& aTextString, const CVariant &heading, bool allowEmptyResult, bool hiddenInput /* = false */)
544 {
545   CGUIDialogKeyboard *pKeyboard = (CGUIDialogKeyboard*)g_windowManager.GetWindow(WINDOW_DIALOG_KEYBOARD);
546
547   if (!pKeyboard)
548     return false;
549
550   // setup keyboard
551   pKeyboard->Initialize();
552   pKeyboard->SetHeading(heading);
553   pKeyboard->SetHiddenInput(hiddenInput);
554   pKeyboard->SetText(aTextString);
555   // do this using a thread message to avoid render() conflicts
556   ThreadMessage tMsg = {TMSG_DIALOG_DOMODAL, WINDOW_DIALOG_KEYBOARD, g_windowManager.GetActiveWindow()};
557   g_application.getApplicationMessenger().SendMessage(tMsg, true);
558   pKeyboard->Close();
559
560   // If have text - update this.
561   if (pKeyboard->IsConfirmed())
562   {
563     aTextString = pKeyboard->GetText();
564     if (!allowEmptyResult && aTextString.IsEmpty())
565       return false;
566     return true;
567   }
568   else return false;
569 }
570
571 bool CGUIDialogKeyboard::ShowAndGetInput(CStdString& aTextString, bool allowEmptyResult)
572 {
573   return ShowAndGetInput(aTextString, "", allowEmptyResult) != 0;
574 }
575
576 // Shows keyboard and prompts for a password.
577 // Differs from ShowAndVerifyNewPassword() in that no second verification is necessary.
578 bool CGUIDialogKeyboard::ShowAndGetNewPassword(CStdString& newPassword, const CVariant &heading, bool allowEmpty)
579 {
580   return ShowAndGetInput(newPassword, heading, allowEmpty, true);
581 }
582
583 // Shows keyboard and prompts for a password.
584 // Differs from ShowAndVerifyNewPassword() in that no second verification is necessary.
585 bool CGUIDialogKeyboard::ShowAndGetNewPassword(CStdString& newPassword)
586 {
587   return ShowAndGetNewPassword(newPassword, 12340, false);
588 }
589
590 // \brief Show keyboard twice to get and confirm a user-entered password string.
591 // \param newPassword Overwritten with user input if return=true.
592 // \param heading Heading to display
593 // \param allowEmpty Whether a blank password is valid or not.
594 // \return true if successful display and user input entry/re-entry. false if unsucessful display, no user input, or canceled editing.
595 bool CGUIDialogKeyboard::ShowAndVerifyNewPassword(CStdString& newPassword, const CVariant &heading, bool allowEmpty)
596 {
597   // Prompt user for password input
598   CStdString userInput = "";
599   if (!ShowAndGetInput(userInput, heading, allowEmpty, true))
600   { // user cancelled, or invalid input
601     return false;
602   }
603   // success - verify the password
604   CStdString checkInput = "";
605   if (!ShowAndGetInput(checkInput, 12341, allowEmpty, true))
606   { // user cancelled, or invalid input
607     return false;
608   }
609   // check the password
610   if (checkInput == userInput)
611   {
612     XBMC::XBMC_MD5 md5state;
613     md5state.append(userInput);
614     md5state.getDigest(newPassword);
615     newPassword.ToLower();
616     return true;
617   }
618   CGUIDialogOK::ShowAndGetInput(12341, 12344, 0, 0);
619   return false;
620 }
621
622 // \brief Show keyboard twice to get and confirm a user-entered password string.
623 // \param strNewPassword Overwritten with user input if return=true.
624 // \return true if successful display and user input entry/re-entry. false if unsucessful display, no user input, or canceled editing.
625 bool CGUIDialogKeyboard::ShowAndVerifyNewPassword(CStdString& newPassword)
626 {
627   CStdString heading = g_localizeStrings.Get(12340);
628   return ShowAndVerifyNewPassword(newPassword, heading, false);
629 }
630
631 // \brief Show keyboard and verify user input against strPassword.
632 // \param strPassword Value to compare against user input.
633 // \param dlgHeading String shown on dialog title. Converts to localized string if contains a positive integer.
634 // \param iRetries If greater than 0, shows "Incorrect password, %d retries left" on dialog line 2, else line 2 is blank.
635 // \return 0 if successful display and user input. 1 if unsucessful input. -1 if no user input or canceled editing.
636 int CGUIDialogKeyboard::ShowAndVerifyPassword(CStdString& strPassword, const CStdString& strHeading, int iRetries)
637 {
638   CStdString strHeadingTemp;
639   if (1 > iRetries && strHeading.size())
640     strHeadingTemp = strHeading;
641   else
642     strHeadingTemp.Format("%s - %i %s", g_localizeStrings.Get(12326).c_str(), g_guiSettings.GetInt("masterlock.maxretries") - iRetries, g_localizeStrings.Get(12343).c_str());
643
644   CStdString strUserInput = "";
645   if (!ShowAndGetInput(strUserInput, strHeadingTemp, false, true))  //bool hiddenInput = false/true ? TODO: GUI Setting to enable disable this feature y/n?
646     return -1; // user canceled out
647
648   if (!strPassword.IsEmpty())
649   {
650     if (strPassword == strUserInput)
651       return 0;
652
653     CStdString md5pword2;
654     XBMC::XBMC_MD5 md5state;
655     md5state.append(strUserInput);
656     md5state.getDigest(md5pword2);
657     if (strPassword.Equals(md5pword2))
658       return 0;     // user entered correct password
659     else return 1;  // user must have entered an incorrect password
660   }
661   else
662   {
663     if (!strUserInput.IsEmpty())
664     {
665       XBMC::XBMC_MD5 md5state;
666       md5state.append(strUserInput);
667       md5state.getDigest(strPassword);
668       strPassword.ToLower();
669       return 0; // user entered correct password
670     }
671     else return 1;
672   }
673 }
674
675 void CGUIDialogKeyboard::OnDeinitWindow(int nextWindowID)
676 {
677   // call base class
678   CGUIDialog::OnDeinitWindow(nextWindowID);
679   // reset the heading (we don't always have this)
680   m_strHeading = "";
681
682   ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Input, "xbmc", "OnInputFinished");
683 }
684
685 void CGUIDialogKeyboard::MoveCursor(int iAmount)
686 {
687   CGUILabelControl* pEdit = ((CGUILabelControl*)GetControl(CTL_LABEL_EDIT));
688   if (pEdit)
689   {
690     pEdit->SetCursorPos(pEdit->GetCursorPos() + iAmount);
691   }
692 }
693
694 int CGUIDialogKeyboard::GetCursorPos() const
695 {
696   const CGUILabelControl* pEdit = (const CGUILabelControl*)GetControl(CTL_LABEL_EDIT);
697   if (pEdit)
698   {
699     return pEdit->GetCursorPos();
700   }
701   return 0;
702 }
703
704 void CGUIDialogKeyboard::OnSymbols()
705 {
706   if (m_keyType == SYMBOLS)
707     m_keyType = LOWER;
708   else
709     m_keyType = SYMBOLS;
710   UpdateButtons();
711 }
712
713 void CGUIDialogKeyboard::OnShift()
714 {
715   m_bShift = !m_bShift;
716   UpdateButtons();
717 }
718
719 void CGUIDialogKeyboard::OnIPAddress()
720 {
721   // find any IP address in the current string if there is any
722   // We match to #.#.#.#
723   CStdString utf8String;
724   g_charsetConverter.wToUTF8(m_strEdit, utf8String);
725   CStdString ip;
726   CRegExp reg;
727   reg.RegComp("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+");
728   int start = reg.RegFind(utf8String.c_str());
729   int length = 0;
730   if (start > -1)
731   {
732     length = reg.GetSubLength(0);
733     ip = utf8String.Mid(start, length);
734   }
735   else
736     start = utf8String.size();
737   if (CGUIDialogNumeric::ShowAndGetIPAddress(ip, g_localizeStrings.Get(14068)))
738   {
739     utf8String = utf8String.Left(start) + ip + utf8String.Mid(start + length);
740     g_charsetConverter.utf8ToW(utf8String, m_strEdit);
741     UpdateLabel();
742     CGUILabelControl* pEdit = ((CGUILabelControl*)GetControl(CTL_LABEL_EDIT));
743     if (pEdit)
744       pEdit->SetCursorPos(m_strEdit.size());
745   }
746 }
747
748 void CGUIDialogKeyboard::ResetShiftAndSymbols()
749 {
750   if (m_bShift) OnShift();
751   if (m_keyType == SYMBOLS) OnSymbols();
752   m_lastRemoteClickTime = 0;
753 }
754
755 const char* CGUIDialogKeyboard::s_charsSeries[10] = { " 0!@#$%^&*()[]{}<>/\\|", ".,1;:\'\"-+_=?`~", "ABC2", "DEF3", "GHI4", "JKL5", "MNO6", "PQRS7", "TUV8", "WXYZ9" };
756
757 void CGUIDialogKeyboard::SetControlLabel(int id, const CStdString &label)
758 { // find all controls with this id, and set all their labels
759   CGUIMessage message(GUI_MSG_LABEL_SET, GetID(), id);
760   message.SetLabel(label);
761   for (unsigned int i = 0; i < m_children.size(); i++)
762   {
763     if (m_children[i]->GetID() == id || m_children[i]->IsGroup())
764       m_children[i]->OnMessage(message);
765   }
766 }
767
768 void CGUIDialogKeyboard::OnOK()
769 {
770   m_bIsConfirmed = true;
771   Close();
772 }
773
774 bool CGUIDialogKeyboard::ShowAndGetFilter(CStdString &filter, bool searching)
775 {
776   CGUIDialogKeyboard *pKeyboard = (CGUIDialogKeyboard*)g_windowManager.GetWindow(WINDOW_DIALOG_KEYBOARD);
777
778   if (!pKeyboard)
779     return false;
780
781   pKeyboard->m_filtering = searching ? FILTERING_SEARCH : FILTERING_CURRENT;
782   bool ret = ShowAndGetInput(filter, searching ? 16017 : 16028, true);
783   pKeyboard->m_filtering = FILTERING_NONE;
784   return ret;
785 }
786
787 void CGUIDialogKeyboard::SetHeading(const CVariant &heading)
788 {
789   if (heading.isString())
790     m_strHeading = heading.asString();
791   else if (heading.isInteger() && heading.asInteger())
792     m_strHeading = g_localizeStrings.Get((uint32_t)heading.asInteger());
793 }