1 /*
2 * Copyright (C) 2012-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 "PVRChannelNumberInputHandler.h"
10
11 #include "ServiceBroker.h"
12 #include "settings/AdvancedSettings.h"
13 #include "settings/SettingsComponent.h"
14 #include "threads/SingleLock.h"
15 #include "utils/StringUtils.h"
16
17 #include <algorithm>
18 #include <cstdlib>
19 #include <string>
20
21 namespace PVR
22 {
23
CPVRChannelNumberInputHandler()24 CPVRChannelNumberInputHandler::CPVRChannelNumberInputHandler()
25 : CPVRChannelNumberInputHandler(CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_iPVRNumericChannelSwitchTimeout, CHANNEL_NUMBER_INPUT_MAX_DIGITS)
26 {
27 }
28
CPVRChannelNumberInputHandler(int iDelay,int iMaxDigits)29 CPVRChannelNumberInputHandler::CPVRChannelNumberInputHandler(int iDelay, int iMaxDigits /* = CHANNEL_NUMBER_INPUT_MAX_DIGITS */)
30 : m_iDelay(iDelay),
31 m_iMaxDigits(iMaxDigits),
32 m_timer(this)
33 {
34 }
35
OnTimeout()36 void CPVRChannelNumberInputHandler::OnTimeout()
37 {
38 if (m_inputBuffer.empty())
39 {
40 CSingleLock lock(m_mutex);
41 m_label.erase();
42 }
43 else
44 {
45 // call the overridden worker method
46 OnInputDone();
47
48 CSingleLock lock(m_mutex);
49
50 // erase input buffer immediately , but...
51 m_inputBuffer.erase();
52
53 // ... display the label for another .5 secs if we stopped the timer before regular timeout.
54 if (m_timer.IsRunning())
55 m_label.erase();
56 else
57 m_timer.Start(500);
58 }
59 }
60
ExecuteAction()61 void CPVRChannelNumberInputHandler::ExecuteAction()
62 {
63 m_timer.Stop();
64 OnTimeout();
65 }
66
CheckInputAndExecuteAction()67 bool CPVRChannelNumberInputHandler::CheckInputAndExecuteAction()
68 {
69 const CPVRChannelNumber channelNumber = GetChannelNumber();
70 if (channelNumber.IsValid())
71 {
72 // we have a valid channel number; execute the associated action now.
73 ExecuteAction();
74 return true;
75 }
76 return false;
77 }
78
AppendChannelNumberCharacter(char cCharacter)79 void CPVRChannelNumberInputHandler::AppendChannelNumberCharacter(char cCharacter)
80 {
81 if (cCharacter != CPVRChannelNumber::SEPARATOR && (cCharacter < '0' || cCharacter > '9'))
82 return;
83
84 CSingleLock lock(m_mutex);
85
86 if (cCharacter == CPVRChannelNumber::SEPARATOR)
87 {
88 // no leading separator
89 if (m_inputBuffer.empty())
90 return;
91
92 // max one separator
93 if (m_inputBuffer.find(CPVRChannelNumber::SEPARATOR) != std::string::npos)
94 return;
95 }
96
97 if (m_inputBuffer.size() == static_cast<size_t>(m_iMaxDigits))
98 {
99 m_inputBuffer.erase(m_inputBuffer.begin());
100 m_label = m_inputBuffer;
101 }
102 else if (m_inputBuffer.empty())
103 {
104 m_sortedChannelNumbers.clear();
105 GetChannelNumbers(m_sortedChannelNumbers);
106
107 std::sort(m_sortedChannelNumbers.begin(), m_sortedChannelNumbers.end());
108 }
109
110 m_inputBuffer.append(&cCharacter, 1);
111 m_label = m_inputBuffer;
112
113 for (auto it = m_sortedChannelNumbers.begin(); it != m_sortedChannelNumbers.end();)
114 {
115 const std::string channel = *it;
116 ++it;
117
118 if (StringUtils::StartsWith(channel, m_inputBuffer))
119 {
120 if (it != m_sortedChannelNumbers.end() && StringUtils::StartsWith(*it, m_inputBuffer))
121 {
122 // there are alternative numbers; wait for more input
123 break;
124 }
125
126 // no alternatives; complete the number and fire immediately
127 m_inputBuffer = channel;
128 m_label = m_inputBuffer;
129 ExecuteAction();
130 return;
131 }
132 }
133
134 if (!m_timer.IsRunning())
135 m_timer.Start(m_iDelay);
136 else
137 m_timer.Restart();
138 }
139
GetChannelNumber() const140 CPVRChannelNumber CPVRChannelNumberInputHandler::GetChannelNumber() const
141 {
142 int iChannelNumber = 0;
143 int iSubChannelNumber = 0;
144
145 CSingleLock lock(m_mutex);
146
147 size_t pos = m_inputBuffer.find(CPVRChannelNumber::SEPARATOR);
148 if (pos != std::string::npos)
149 {
150 // main + sub
151 if (pos != 0)
152 {
153 iChannelNumber = std::atoi(m_inputBuffer.substr(0, pos).c_str());
154 if (pos != m_inputBuffer.size() - 1)
155 iSubChannelNumber = std::atoi(m_inputBuffer.substr(pos + 1).c_str());
156 }
157 }
158 else
159 {
160 // only main
161 iChannelNumber = std::atoi(m_inputBuffer.c_str());
162 }
163
164 return CPVRChannelNumber(iChannelNumber, iSubChannelNumber);
165 }
166
HasChannelNumber() const167 bool CPVRChannelNumberInputHandler::HasChannelNumber() const
168 {
169 return !m_inputBuffer.empty();
170 }
171
GetChannelNumberLabel() const172 std::string CPVRChannelNumberInputHandler::GetChannelNumberLabel() const
173 {
174 CSingleLock lock(m_mutex);
175 return m_label;
176 }
177
178 } // namespace PVR
179