PageRenderTime 87ms CodeModel.GetById 12ms app.highlight 69ms RepoModel.GetById 1ms app.codeStats 0ms

/xbmc/guilib/GUIEditControl.cpp

http://github.com/xbmc/xbmc
C++ | 738 lines | 634 code | 70 blank | 34 comment | 179 complexity | 87020e53afcc8adf498c16d8115c86a4 MD5 | raw file
  1/*
  2 *  Copyright (C) 2005-2018 Team Kodi
  3 *  This file is part of Kodi - https://kodi.tv
  4 *
  5 *  SPDX-License-Identifier: GPL-2.0-or-later
  6 *  See LICENSES/README.md for more information.
  7 */
  8
  9#include "GUIEditControl.h"
 10
 11#include "GUIKeyboardFactory.h"
 12#include "GUIUserMessages.h"
 13#include "GUIWindowManager.h"
 14#include "LocalizeStrings.h"
 15#include "ServiceBroker.h"
 16#include "XBDateTime.h"
 17#include "dialogs/GUIDialogNumeric.h"
 18#include "input/Key.h"
 19#include "input/XBMC_vkeys.h"
 20#include "utils/CharsetConverter.h"
 21#include "utils/Color.h"
 22#include "utils/Digest.h"
 23#include "utils/Variant.h"
 24#include "windowing/WinSystem.h"
 25
 26using namespace KODI::GUILIB;
 27
 28using KODI::UTILITY::CDigest;
 29
 30const char* CGUIEditControl::smsLetters[10] = { " !@#$%^&*()[]{}<>/\\|0", ".,;:\'\"-+_=?`~1", "abc2ABC", "def3DEF", "ghi4GHI", "jkl5JKL", "mno6MNO", "pqrs7PQRS", "tuv8TUV", "wxyz9WXYZ" };
 31const unsigned int CGUIEditControl::smsDelay = 1000;
 32
 33#ifdef TARGET_WINDOWS
 34extern HWND g_hWnd;
 35#endif
 36
 37CGUIEditControl::CGUIEditControl(int parentID, int controlID, float posX, float posY,
 38                                 float width, float height, const CTextureInfo &textureFocus, const CTextureInfo &textureNoFocus,
 39                                 const CLabelInfo& labelInfo, const std::string &text)
 40    : CGUIButtonControl(parentID, controlID, posX, posY, width, height, textureFocus, textureNoFocus, labelInfo)
 41{
 42  DefaultConstructor();
 43  SetLabel(text);
 44}
 45
 46void CGUIEditControl::DefaultConstructor()
 47{
 48  ControlType = GUICONTROL_EDIT;
 49  m_textOffset = 0;
 50  m_textWidth = GetWidth();
 51  m_cursorPos = 0;
 52  m_cursorBlink = 0;
 53  m_inputHeading = g_localizeStrings.Get(16028);
 54  m_inputType = INPUT_TYPE_TEXT;
 55  m_smsLastKey = 0;
 56  m_smsKeyIndex = 0;
 57  m_label.SetAlign(m_label.GetLabelInfo().align & XBFONT_CENTER_Y); // left align
 58  m_label2.GetLabelInfo().offsetX = 0;
 59  m_isMD5 = false;
 60  m_invalidInput = false;
 61  m_inputValidator = NULL;
 62  m_inputValidatorData = NULL;
 63  m_editLength = 0;
 64  m_editOffset = 0;
 65}
 66
 67CGUIEditControl::CGUIEditControl(const CGUIButtonControl &button)
 68    : CGUIButtonControl(button)
 69{
 70  DefaultConstructor();
 71}
 72
 73CGUIEditControl::~CGUIEditControl(void) = default;
 74
 75bool CGUIEditControl::OnMessage(CGUIMessage &message)
 76{
 77  if (message.GetMessage() == GUI_MSG_SET_TYPE)
 78  {
 79    SetInputType((INPUT_TYPE)message.GetParam1(), message.GetParam2());
 80    return true;
 81  }
 82  else if (message.GetMessage() == GUI_MSG_ITEM_SELECTED)
 83  {
 84    message.SetLabel(GetLabel2());
 85    return true;
 86  }
 87  else if (message.GetMessage() == GUI_MSG_SET_TEXT &&
 88          ((message.GetControlId() <= 0 && HasFocus()) || (message.GetControlId() == GetID())))
 89  {
 90    SetLabel2(message.GetLabel());
 91    UpdateText();
 92  }
 93  return CGUIButtonControl::OnMessage(message);
 94}
 95
 96bool CGUIEditControl::OnAction(const CAction &action)
 97{
 98  ValidateCursor();
 99
100  if (m_inputType != INPUT_TYPE_READONLY)
101  {
102    if (action.GetID() == ACTION_BACKSPACE)
103    {
104      // backspace
105      if (m_cursorPos)
106      {
107        if (!ClearMD5())
108          m_text2.erase(--m_cursorPos, 1);
109        UpdateText();
110      }
111      return true;
112    }
113    else if (action.GetID() == ACTION_MOVE_LEFT ||
114             action.GetID() == ACTION_CURSOR_LEFT)
115    {
116      if (m_cursorPos > 0)
117      {
118        m_cursorPos--;
119        UpdateText(false);
120        return true;
121      }
122    }
123    else if (action.GetID() == ACTION_MOVE_RIGHT ||
124             action.GetID() == ACTION_CURSOR_RIGHT)
125    {
126      if (m_cursorPos < m_text2.size())
127      {
128        m_cursorPos++;
129        UpdateText(false);
130        return true;
131      }
132    }
133    else if (action.GetID() == ACTION_PASTE)
134    {
135      ClearMD5();
136      OnPasteClipboard();
137      return true;
138    }
139    else if (action.GetID() >= KEY_VKEY && action.GetID() < KEY_UNICODE && m_edit.empty())
140    {
141      // input from the keyboard (vkey, not ascii)
142      unsigned char b = action.GetID() & 0xFF;
143      if (b == XBMCVK_HOME)
144      {
145        m_cursorPos = 0;
146        UpdateText(false);
147        return true;
148      }
149      else if (b == XBMCVK_END)
150      {
151        m_cursorPos = m_text2.length();
152        UpdateText(false);
153        return true;
154      }
155      if (b == XBMCVK_LEFT && m_cursorPos > 0)
156      {
157        m_cursorPos--;
158        UpdateText(false);
159        return true;
160      }
161      if (b == XBMCVK_RIGHT && m_cursorPos < m_text2.length())
162      {
163        m_cursorPos++;
164        UpdateText(false);
165        return true;
166      }
167      if (b == XBMCVK_DELETE)
168      {
169        if (m_cursorPos < m_text2.length())
170        {
171          if (!ClearMD5())
172            m_text2.erase(m_cursorPos, 1);
173          UpdateText();
174          return true;
175        }
176      }
177      if (b == XBMCVK_BACK)
178      {
179        if (m_cursorPos > 0)
180        {
181          if (!ClearMD5())
182            m_text2.erase(--m_cursorPos, 1);
183          UpdateText();
184        }
185        return true;
186      }
187      else if (b == XBMCVK_RETURN || b == XBMCVK_NUMPADENTER)
188      {
189        // enter - send click message, but otherwise ignore
190        SEND_CLICK_MESSAGE(GetID(), GetParentID(), 1);
191        return true;
192      }
193      else if (b == XBMCVK_ESCAPE)
194      { // escape - fallthrough to default action
195        return CGUIButtonControl::OnAction(action);
196      }
197    }
198    else if (action.GetID() == KEY_UNICODE)
199    {
200      // input from the keyboard
201      int ch = action.GetUnicode();
202      // ignore non-printing characters
203      if ( !((0 <= ch && ch < 0x8) || (0xE <= ch && ch < 0x1B) || (0x1C <= ch && ch < 0x20)) )
204      {
205      switch (ch)
206      {
207      case 9:  // tab, ignore
208      case 11: // Non-printing character, ignore
209      case 12: // Non-printing character, ignore
210        break;
211      case 10:
212      case 13:
213        {
214          // enter - send click message, but otherwise ignore
215          SEND_CLICK_MESSAGE(GetID(), GetParentID(), 1);
216          return true;
217        }
218      case 27:
219        { // escape - fallthrough to default action
220          return CGUIButtonControl::OnAction(action);
221        }
222      case 8:
223        {
224          // backspace
225          if (m_cursorPos)
226          {
227            if (!ClearMD5())
228              m_text2.erase(--m_cursorPos, 1);
229          }
230          break;
231        }
232      case 127:
233        { // delete
234          if (m_cursorPos < m_text2.length())
235          {
236            if (!ClearMD5())
237              m_text2.erase(m_cursorPos, 1);
238          }
239        break;
240        }
241      default:
242        {
243          ClearMD5();
244          m_edit.clear();
245          m_text2.insert(m_text2.begin() + m_cursorPos++, action.GetUnicode());
246          break;
247        }
248      }
249      UpdateText();
250      return true;
251      }
252    }
253    else if (action.GetID() >= REMOTE_0 && action.GetID() <= REMOTE_9)
254    { // input from the remote
255      ClearMD5();
256      m_edit.clear();
257      OnSMSCharacter(action.GetID() - REMOTE_0);
258      return true;
259    }
260    else if (action.GetID() == ACTION_INPUT_TEXT)
261    {
262      m_edit.clear();
263      std::wstring str;
264      g_charsetConverter.utf8ToW(action.GetText(), str, false);
265      m_text2.insert(m_cursorPos, str);
266      m_cursorPos += str.size();
267      UpdateText();
268      return true;
269    }
270  }
271  return CGUIButtonControl::OnAction(action);
272}
273
274void CGUIEditControl::OnClick()
275{
276  // we received a click - it's not from the keyboard, so pop up the virtual keyboard, unless
277  // that is where we reside!
278  if (GetParentID() == WINDOW_DIALOG_KEYBOARD)
279    return;
280
281  std::string utf8;
282  g_charsetConverter.wToUTF8(m_text2, utf8);
283  bool textChanged = false;
284  switch (m_inputType)
285  {
286    case INPUT_TYPE_READONLY:
287      textChanged = false;
288      break;
289    case INPUT_TYPE_NUMBER:
290      textChanged = CGUIDialogNumeric::ShowAndGetNumber(utf8, m_inputHeading);
291      break;
292    case INPUT_TYPE_SECONDS:
293      textChanged = CGUIDialogNumeric::ShowAndGetSeconds(utf8, g_localizeStrings.Get(21420));
294      break;
295    case INPUT_TYPE_TIME:
296    {
297      CDateTime dateTime;
298      dateTime.SetFromDBTime(utf8);
299      KODI::TIME::SystemTime time;
300      dateTime.GetAsSystemTime(time);
301      if (CGUIDialogNumeric::ShowAndGetTime(time, !m_inputHeading.empty() ? m_inputHeading : g_localizeStrings.Get(21420)))
302      {
303        dateTime = CDateTime(time);
304        utf8 = dateTime.GetAsLocalizedTime("", false);
305        textChanged = true;
306      }
307      break;
308    }
309    case INPUT_TYPE_DATE:
310    {
311      CDateTime dateTime;
312      dateTime.SetFromDBDate(utf8);
313      if (dateTime < CDateTime(2000,1, 1, 0, 0, 0))
314        dateTime = CDateTime(2000, 1, 1, 0, 0, 0);
315      KODI::TIME::SystemTime date;
316      dateTime.GetAsSystemTime(date);
317      if (CGUIDialogNumeric::ShowAndGetDate(date, !m_inputHeading.empty() ? m_inputHeading : g_localizeStrings.Get(21420)))
318      {
319        dateTime = CDateTime(date);
320        utf8 = dateTime.GetAsDBDate();
321        textChanged = true;
322      }
323      break;
324    }
325    case INPUT_TYPE_IPADDRESS:
326      textChanged = CGUIDialogNumeric::ShowAndGetIPAddress(utf8, m_inputHeading);
327      break;
328    case INPUT_TYPE_SEARCH:
329      textChanged = CGUIKeyboardFactory::ShowAndGetFilter(utf8, true);
330      break;
331    case INPUT_TYPE_FILTER:
332      textChanged = CGUIKeyboardFactory::ShowAndGetFilter(utf8, false);
333      break;
334    case INPUT_TYPE_PASSWORD_NUMBER_VERIFY_NEW:
335      textChanged = CGUIDialogNumeric::ShowAndVerifyNewPassword(utf8);
336      break;
337    case INPUT_TYPE_PASSWORD_MD5:
338      utf8 = ""; //! @todo Ideally we'd send this to the keyboard and tell the keyboard we have this type of input
339      // fallthrough
340    case INPUT_TYPE_TEXT:
341    default:
342      textChanged = CGUIKeyboardFactory::ShowAndGetInput(utf8, m_inputHeading, true, m_inputType == INPUT_TYPE_PASSWORD || m_inputType == INPUT_TYPE_PASSWORD_MD5);
343      break;
344  }
345  if (textChanged)
346  {
347    ClearMD5();
348    m_edit.clear();
349    g_charsetConverter.utf8ToW(utf8, m_text2);
350    m_cursorPos = m_text2.size();
351    UpdateText();
352    m_cursorPos = m_text2.size();
353  }
354}
355
356void CGUIEditControl::UpdateText(bool sendUpdate)
357{
358  m_smsTimer.Stop();
359  if (sendUpdate)
360  {
361    ValidateInput();
362
363    SEND_CLICK_MESSAGE(GetID(), GetParentID(), 0);
364
365    m_textChangeActions.ExecuteActions(GetID(), GetParentID());
366  }
367  SetInvalid();
368}
369
370void CGUIEditControl::SetInputType(CGUIEditControl::INPUT_TYPE type, CVariant heading)
371{
372  m_inputType = type;
373  if (heading.isString())
374    m_inputHeading = heading.asString();
375  else if (heading.isInteger() && heading.asInteger())
376    m_inputHeading = g_localizeStrings.Get(static_cast<uint32_t>(heading.asInteger()));
377  //! @todo Verify the current input string?
378}
379
380void CGUIEditControl::RecalcLabelPosition()
381{
382  // ensure that our cursor is within our width
383  ValidateCursor();
384
385  std::wstring text = GetDisplayedText();
386  m_textWidth = m_label.CalcTextWidth(text + L'|');
387  float beforeCursorWidth = m_label.CalcTextWidth(text.substr(0, m_cursorPos));
388  float afterCursorWidth = m_label.CalcTextWidth(text.substr(0, m_cursorPos) + L'|');
389  float leftTextWidth = m_label.GetRenderRect().Width();
390  float maxTextWidth = m_label.GetMaxWidth();
391  if (leftTextWidth > 0)
392    maxTextWidth -= leftTextWidth + spaceWidth;
393
394  // if skinner forgot to set height :p
395  if (m_height == 0 && m_label.GetLabelInfo().font)
396    m_height = m_label.GetLabelInfo().font->GetTextHeight(1);
397
398  if (m_textWidth > maxTextWidth)
399  { // we render taking up the full width, so make sure our cursor position is
400    // within the render window
401    if (m_textOffset + afterCursorWidth > maxTextWidth)
402    {
403      // move the position to the left (outside of the viewport)
404      m_textOffset = maxTextWidth - afterCursorWidth;
405    }
406    else if (m_textOffset + beforeCursorWidth < 0) // offscreen to the left
407    {
408      // otherwise use original position
409      m_textOffset = -beforeCursorWidth;
410    }
411    else if (m_textOffset + m_textWidth < maxTextWidth)
412    { // we have more text than we're allowed, but we aren't filling all the space
413      m_textOffset = maxTextWidth - m_textWidth;
414    }
415  }
416  else
417    m_textOffset = 0;
418}
419
420void CGUIEditControl::ProcessText(unsigned int currentTime)
421{
422  if (m_smsTimer.IsRunning() && m_smsTimer.GetElapsedMilliseconds() > smsDelay)
423    UpdateText();
424
425  if (m_bInvalidated)
426  {
427    m_label.SetMaxRect(m_posX, m_posY, m_width, m_height);
428    m_label.SetText(m_info.GetLabel(GetParentID()));
429    RecalcLabelPosition();
430  }
431
432  bool changed = false;
433
434  m_clipRect.x1 = m_label.GetRenderRect().x1;
435  m_clipRect.x2 = m_clipRect.x1 + m_label.GetMaxWidth();
436  m_clipRect.y1 = m_posY;
437  m_clipRect.y2 = m_posY + m_height;
438
439  // start by rendering the normal text
440  float leftTextWidth = m_label.GetRenderRect().Width();
441  if (leftTextWidth > 0)
442  {
443    // render the text on the left
444    changed |= m_label.SetColor(GetTextColor());
445    changed |= m_label.Process(currentTime);
446
447    m_clipRect.x1 += leftTextWidth + spaceWidth;
448  }
449
450  if (CServiceBroker::GetWinSystem()->GetGfxContext().SetClipRegion(m_clipRect.x1, m_clipRect.y1, m_clipRect.Width(), m_clipRect.Height()))
451  {
452    uint32_t align = m_label.GetLabelInfo().align & XBFONT_CENTER_Y; // start aligned left
453    if (m_label2.GetTextWidth() < m_clipRect.Width())
454    { // align text as our text fits
455      if (leftTextWidth > 0)
456      { // right align as we have 2 labels
457        align |= XBFONT_RIGHT;
458      }
459      else
460      { // align by whatever the skinner requests
461        align |= (m_label2.GetLabelInfo().align & 3);
462      }
463    }
464    changed |= m_label2.SetMaxRect(m_clipRect.x1 + m_textOffset, m_posY, m_clipRect.Width() - m_textOffset, m_height);
465
466    std::wstring text = GetDisplayedText();
467    std::string hint = m_hintInfo.GetLabel(GetParentID());
468
469    if (!HasFocus() && text.empty() && !hint.empty())
470    {
471      changed |= m_label2.SetText(hint);
472    }
473    else if ((HasFocus() || GetParentID() == WINDOW_DIALOG_KEYBOARD) &&
474             m_inputType != INPUT_TYPE_READONLY)
475    {
476      changed |= SetStyledText(text);
477    }
478    else
479      changed |= m_label2.SetTextW(text);
480
481    changed |= m_label2.SetAlign(align);
482    changed |= m_label2.SetColor(GetTextColor());
483    changed |= m_label2.SetOverflow(CGUILabel::OVER_FLOW_CLIP);
484    changed |= m_label2.Process(currentTime);
485    CServiceBroker::GetWinSystem()->GetGfxContext().RestoreClipRegion();
486  }
487  if (changed)
488    MarkDirtyRegion();
489}
490
491void CGUIEditControl::RenderText()
492{
493  m_label.Render();
494
495  if (CServiceBroker::GetWinSystem()->GetGfxContext().SetClipRegion(m_clipRect.x1, m_clipRect.y1, m_clipRect.Width(), m_clipRect.Height()))
496  {
497    m_label2.Render();
498    CServiceBroker::GetWinSystem()->GetGfxContext().RestoreClipRegion();
499  }
500}
501
502CGUILabel::COLOR CGUIEditControl::GetTextColor() const
503{
504  CGUILabel::COLOR color = CGUIButtonControl::GetTextColor();
505  if (color != CGUILabel::COLOR_DISABLED && HasInvalidInput())
506    return CGUILabel::COLOR_INVALID;
507
508  return color;
509}
510
511void CGUIEditControl::SetHint(const GUIINFO::CGUIInfoLabel& hint)
512{
513  m_hintInfo = hint;
514}
515
516std::wstring CGUIEditControl::GetDisplayedText() const
517{
518  std::wstring text(m_text2);
519  if (m_inputType == INPUT_TYPE_PASSWORD || m_inputType == INPUT_TYPE_PASSWORD_MD5 || m_inputType == INPUT_TYPE_PASSWORD_NUMBER_VERIFY_NEW)
520  {
521    text.clear();
522    if (m_smsTimer.IsRunning())
523    { // using the remove to input, so display the last key input
524      text.append(m_cursorPos - 1, L'*');
525      text.append(1, m_text2[m_cursorPos - 1]);
526      text.append(m_text2.size() - m_cursorPos, L'*');
527    }
528    else
529      text.append(m_text2.size(), L'*');
530  }
531  else if (!m_edit.empty())
532    text.insert(m_editOffset, m_edit);
533  return text;
534}
535
536bool CGUIEditControl::SetStyledText(const std::wstring &text)
537{
538  vecText styled;
539  styled.reserve(text.size() + 1);
540
541  std::vector<UTILS::Color> colors;
542  colors.push_back(m_label.GetLabelInfo().textColor);
543  colors.push_back(m_label.GetLabelInfo().disabledColor);
544  UTILS::Color select = m_label.GetLabelInfo().selectedColor;
545  if (!select)
546    select = 0xFFFF0000;
547  colors.push_back(select);
548  colors.push_back(0x00FFFFFF);
549
550  unsigned int startHighlight = m_cursorPos;
551  unsigned int endHighlight   = m_cursorPos + m_edit.size();
552  unsigned int startSelection = m_cursorPos + m_editOffset;
553  unsigned int endSelection   = m_cursorPos + m_editOffset + m_editLength;
554
555  for (unsigned int i = 0; i < text.size(); i++)
556  {
557    unsigned int ch = text[i];
558    if (m_editLength > 0 && startSelection <= i && i < endSelection)
559      ch |= (2 << 16); // highlight the letters we're playing with
560    else if (!m_edit.empty() && (i < startHighlight || i >= endHighlight))
561      ch |= (1 << 16); // dim the bits we're not editing
562    styled.push_back(ch);
563  }
564
565  // show the cursor
566  unsigned int ch = L'|';
567  if ((++m_cursorBlink % 64) > 32)
568    ch = L' ';
569  styled.insert(styled.begin() + m_cursorPos, ch);
570
571  return m_label2.SetStyledText(styled, colors);
572}
573
574void CGUIEditControl::ValidateCursor()
575{
576  if (m_cursorPos > m_text2.size())
577    m_cursorPos = m_text2.size();
578}
579
580void CGUIEditControl::SetLabel(const std::string &text)
581{
582  CGUIButtonControl::SetLabel(text);
583  SetInvalid();
584}
585
586void CGUIEditControl::SetLabel2(const std::string &text)
587{
588  m_edit.clear();
589  std::wstring newText;
590  g_charsetConverter.utf8ToW(text, newText, false);
591  if (newText != m_text2)
592  {
593    m_isMD5 = (m_inputType == INPUT_TYPE_PASSWORD_MD5 || m_inputType == INPUT_TYPE_PASSWORD_NUMBER_VERIFY_NEW);
594    m_text2 = newText;
595    m_cursorPos = m_text2.size();
596    ValidateInput();
597    SetInvalid();
598  }
599}
600
601std::string CGUIEditControl::GetLabel2() const
602{
603  std::string text;
604  g_charsetConverter.wToUTF8(m_text2, text);
605  if (m_inputType == INPUT_TYPE_PASSWORD_MD5 && !m_isMD5)
606    return CDigest::Calculate(CDigest::Type::MD5, text);
607  return text;
608}
609
610bool CGUIEditControl::ClearMD5()
611{
612  if (!(m_inputType == INPUT_TYPE_PASSWORD_MD5 || m_inputType == INPUT_TYPE_PASSWORD_NUMBER_VERIFY_NEW) || !m_isMD5)
613    return false;
614
615  m_text2.clear();
616  m_cursorPos = 0;
617  if (m_inputType != INPUT_TYPE_PASSWORD_NUMBER_VERIFY_NEW)
618    m_isMD5 = false;
619  return true;
620}
621
622unsigned int CGUIEditControl::GetCursorPosition() const
623{
624  return m_cursorPos;
625}
626
627void CGUIEditControl::SetCursorPosition(unsigned int iPosition)
628{
629  m_cursorPos = iPosition;
630}
631
632void CGUIEditControl::OnSMSCharacter(unsigned int key)
633{
634  assert(key < 10);
635  if (m_smsTimer.IsRunning())
636  {
637    // we're already entering an SMS character
638    if (key != m_smsLastKey || m_smsTimer.GetElapsedMilliseconds() > smsDelay)
639    { // a different key was clicked than last time, or we have timed out
640      m_smsLastKey = key;
641      m_smsKeyIndex = 0;
642    }
643    else
644    { // same key as last time within the appropriate time period
645      m_smsKeyIndex++;
646      if (m_cursorPos)
647        m_text2.erase(--m_cursorPos, 1);
648    }
649  }
650  else
651  { // key is pressed for the first time
652    m_smsLastKey = key;
653    m_smsKeyIndex = 0;
654  }
655
656  m_smsKeyIndex = m_smsKeyIndex % strlen(smsLetters[key]);
657
658  m_text2.insert(m_text2.begin() + m_cursorPos++, smsLetters[key][m_smsKeyIndex]);
659  UpdateText();
660  m_smsTimer.StartZero();
661}
662
663void CGUIEditControl::OnPasteClipboard()
664{
665  std::wstring unicode_text;
666  std::string utf8_text;
667
668  // Get text from the clipboard
669  utf8_text = CServiceBroker::GetWinSystem()->GetClipboardText();
670  g_charsetConverter.utf8ToW(utf8_text, unicode_text);
671
672  // Insert the pasted text at the current cursor position.
673  if (unicode_text.length() > 0)
674  {
675    std::wstring left_end = m_text2.substr(0, m_cursorPos);
676    std::wstring right_end = m_text2.substr(m_cursorPos);
677
678    m_text2 = left_end;
679    m_text2.append(unicode_text);
680    m_text2.append(right_end);
681    m_cursorPos += unicode_text.length();
682    UpdateText();
683  }
684}
685
686void CGUIEditControl::SetInputValidation(StringValidation::Validator inputValidator, void *data /* = NULL */)
687{
688  if (m_inputValidator == inputValidator)
689    return;
690
691  m_inputValidator = inputValidator;
692  m_inputValidatorData = data;
693  // the input validator has changed, so re-validate the current data
694  ValidateInput();
695}
696
697bool CGUIEditControl::ValidateInput(const std::wstring &data) const
698{
699  if (m_inputValidator == NULL)
700    return true;
701
702  return m_inputValidator(GetLabel2(), m_inputValidatorData != NULL ? m_inputValidatorData : const_cast<void*>((const void*)this));
703}
704
705void CGUIEditControl::ValidateInput()
706{
707  // validate the input
708  bool invalid = !ValidateInput(m_text2);
709  // nothing to do if still valid/invalid
710  if (invalid != m_invalidInput)
711  {
712    // the validity state has changed so we need to update the control
713    m_invalidInput = invalid;
714
715    // let the window/dialog know that the validity has changed
716    CGUIMessage msg(GUI_MSG_VALIDITY_CHANGED, GetID(), GetID(), m_invalidInput ? 0 : 1);
717    SendWindowMessage(msg);
718
719    SetInvalid();
720  }
721}
722
723void CGUIEditControl::SetFocus(bool focus)
724{
725  m_smsTimer.Stop();
726  CGUIControl::SetFocus(focus);
727  SetInvalid();
728}
729
730std::string CGUIEditControl::GetDescriptionByIndex(int index) const
731{
732  if (index == 0)
733    return GetDescription();
734  else if(index == 1)
735    return GetLabel2();
736
737  return "";
738}