changed: Add logic to properly handle subtitles for stacked files
[vuplus_xbmc] / xbmc / peripherals / devices / Peripheral.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://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, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "Peripheral.h"
22 #include "peripherals/Peripherals.h"
23 #include "utils/log.h"
24 #include "utils/StringUtils.h"
25 #include "settings/lib/Setting.h"
26 #include "utils/XBMCTinyXML.h"
27 #include "utils/URIUtils.h"
28 #include "guilib/LocalizeStrings.h"
29
30 using namespace PERIPHERALS;
31 using namespace std;
32
33 CPeripheral::CPeripheral(const PeripheralScanResult& scanResult) :
34   m_type(scanResult.m_mappedType),
35   m_busType(scanResult.m_busType),
36   m_mappedBusType(scanResult.m_mappedBusType),
37   m_strLocation(scanResult.m_strLocation),
38   m_strDeviceName(scanResult.m_strDeviceName),
39   m_strFileLocation(StringUtils::EmptyString),
40   m_iVendorId(scanResult.m_iVendorId),
41   m_iProductId(scanResult.m_iProductId),
42   m_strVersionInfo(g_localizeStrings.Get(13205)), // "unknown"
43   m_bInitialised(false),
44   m_bHidden(false),
45   m_bError(false)
46 {
47   PeripheralTypeTranslator::FormatHexString(scanResult.m_iVendorId, m_strVendorId);
48   PeripheralTypeTranslator::FormatHexString(scanResult.m_iProductId, m_strProductId);
49   m_strFileLocation = StringUtils::Format(scanResult.m_iSequence > 0 ? "peripherals://%s/%s_%d.dev" : "peripherals://%s/%s.dev",
50                                           PeripheralTypeTranslator::BusTypeToString(scanResult.m_busType),
51                                           scanResult.m_strLocation.c_str(),
52                                           scanResult.m_iSequence);
53 }
54
55 CPeripheral::~CPeripheral(void)
56 {
57   PersistSettings(true);
58
59   for (unsigned int iSubdevicePtr = 0; iSubdevicePtr < m_subDevices.size(); iSubdevicePtr++)
60     delete m_subDevices.at(iSubdevicePtr);
61   m_subDevices.clear();
62
63   ClearSettings();
64 }
65
66 bool CPeripheral::operator ==(const CPeripheral &right) const
67 {
68   return m_type == right.m_type &&
69       m_strLocation == right.m_strLocation &&
70       m_iVendorId == right.m_iVendorId &&
71       m_iProductId == right.m_iProductId;
72 }
73
74 bool CPeripheral::operator !=(const CPeripheral &right) const
75 {
76   return !(*this == right);
77 }
78
79 bool CPeripheral::HasFeature(const PeripheralFeature feature) const
80 {
81   bool bReturn(false);
82
83   for (unsigned int iFeaturePtr = 0; iFeaturePtr < m_features.size(); iFeaturePtr++)
84   {
85     if (m_features.at(iFeaturePtr) == feature)
86     {
87       bReturn = true;
88       break;
89     }
90   }
91
92   if (!bReturn)
93   {
94     for (unsigned int iSubdevicePtr = 0; iSubdevicePtr < m_subDevices.size(); iSubdevicePtr++)
95     {
96       if (m_subDevices.at(iSubdevicePtr)->HasFeature(feature))
97       {
98         bReturn = true;
99         break;
100       }
101     }
102   }
103
104   return bReturn;
105 }
106
107 void CPeripheral::GetFeatures(std::vector<PeripheralFeature> &features) const
108 {
109   for (unsigned int iFeaturePtr = 0; iFeaturePtr < m_features.size(); iFeaturePtr++)
110     features.push_back(m_features.at(iFeaturePtr));
111
112   for (unsigned int iSubdevicePtr = 0; iSubdevicePtr < m_subDevices.size(); iSubdevicePtr++)
113     m_subDevices.at(iSubdevicePtr)->GetFeatures(features);
114 }
115
116 bool CPeripheral::Initialise(void)
117 {
118   bool bReturn(false);
119
120   if (m_bError)
121     return bReturn;
122
123   bReturn = true;
124   if (m_bInitialised)
125     return bReturn;
126
127   g_peripherals.GetSettingsFromMapping(*this);
128   m_strSettingsFile = StringUtils::Format("special://profile/peripheral_data/%s_%s_%s.xml",
129                                           PeripheralTypeTranslator::BusTypeToString(m_mappedBusType),
130                                           m_strVendorId.c_str(),
131                                           m_strProductId.c_str());
132   LoadPersistedSettings();
133
134   for (unsigned int iFeaturePtr = 0; iFeaturePtr < m_features.size(); iFeaturePtr++)
135   {
136     PeripheralFeature feature = m_features.at(iFeaturePtr);
137     bReturn &= InitialiseFeature(feature);
138   }
139
140   for (unsigned int iSubdevicePtr = 0; iSubdevicePtr < m_subDevices.size(); iSubdevicePtr++)
141     bReturn &= m_subDevices.at(iSubdevicePtr)->Initialise();
142
143   if (bReturn)
144   {
145     CLog::Log(LOGDEBUG, "%s - initialised peripheral on '%s' with %d features and %d sub devices",
146       __FUNCTION__, m_strLocation.c_str(), (int)m_features.size(), (int)m_subDevices.size());
147     m_bInitialised = true;
148   }
149
150   return bReturn;
151 }
152
153 void CPeripheral::GetSubdevices(vector<CPeripheral *> &subDevices) const
154 {
155   for (unsigned int iSubdevicePtr = 0; iSubdevicePtr < m_subDevices.size(); iSubdevicePtr++)
156     subDevices.push_back(m_subDevices.at(iSubdevicePtr));
157 }
158
159 bool CPeripheral::IsMultiFunctional(void) const
160 {
161   return m_subDevices.size() > 0;
162 }
163
164 vector<CSetting *> CPeripheral::GetSettings(void) const
165 {
166   vector<CSetting *> settings;
167   for (map<CStdString, CSetting *>::const_iterator it = m_settings.begin(); it != m_settings.end(); it++)
168     settings.push_back(it->second);
169   return settings;
170 }
171
172 void CPeripheral::AddSetting(const CStdString &strKey, const CSetting *setting)
173 {
174   if (!setting)
175   {
176     CLog::Log(LOGERROR, "%s - invalid setting", __FUNCTION__);
177     return;
178   }
179
180   if (!HasSetting(strKey))
181   {
182     switch(setting->GetType())
183     {
184     case SettingTypeBool:
185       {
186         const CSettingBool *mappedSetting = (const CSettingBool *) setting;
187         CSettingBool *boolSetting = new CSettingBool(strKey, *mappedSetting);
188         if (boolSetting)
189         {
190           boolSetting->SetVisible(mappedSetting->IsVisible());
191           m_settings.insert(make_pair(strKey, boolSetting));
192         }
193       }
194       break;
195     case SettingTypeInteger:
196       {
197         const CSettingInt *mappedSetting = (const CSettingInt *) setting;
198         CSettingInt *intSetting = new CSettingInt(strKey, *mappedSetting);
199         if (intSetting)
200         {
201           intSetting->SetVisible(mappedSetting->IsVisible());
202           m_settings.insert(make_pair(strKey, intSetting));
203         }
204       }
205       break;
206     case SettingTypeNumber:
207       {
208         const CSettingNumber *mappedSetting = (const CSettingNumber *) setting;
209         CSettingNumber *floatSetting = new CSettingNumber(strKey, *mappedSetting);
210         if (floatSetting)
211         {
212           floatSetting->SetVisible(mappedSetting->IsVisible());
213           m_settings.insert(make_pair(strKey, floatSetting));
214         }
215       }
216       break;
217     case SettingTypeString:
218       {
219         const CSettingString *mappedSetting = (const CSettingString *) setting;
220         CSettingString *stringSetting = new CSettingString(strKey, *mappedSetting);
221         if (stringSetting)
222         {
223           stringSetting->SetVisible(mappedSetting->IsVisible());
224           m_settings.insert(make_pair(strKey, stringSetting));
225         }
226       }
227       break;
228     default:
229       //TODO add more types if needed
230       break;
231     }
232   }
233 }
234
235 bool CPeripheral::HasSetting(const CStdString &strKey) const
236 {
237   map<CStdString, CSetting *>:: const_iterator it = m_settings.find(strKey);
238   return it != m_settings.end();
239 }
240
241 bool CPeripheral::HasSettings(void) const
242 {
243   return !m_settings.empty();
244 }
245
246 bool CPeripheral::HasConfigurableSettings(void) const
247 {
248   bool bReturn(false);
249   map<CStdString, CSetting *>::const_iterator it = m_settings.begin();
250   while (it != m_settings.end() && !bReturn)
251   {
252     if ((*it).second->IsVisible())
253     {
254       bReturn = true;
255       break;
256     }
257
258     ++it;
259   }
260
261   return bReturn;
262 }
263
264 bool CPeripheral::GetSettingBool(const CStdString &strKey) const
265 {
266   map<CStdString, CSetting *>::const_iterator it = m_settings.find(strKey);
267   if (it != m_settings.end() && (*it).second->GetType() == SettingTypeBool)
268   {
269       CSettingBool *boolSetting = (CSettingBool *) (*it).second;
270     if (boolSetting)
271       return boolSetting->GetValue();
272   }
273
274   return false;
275 }
276
277 int CPeripheral::GetSettingInt(const CStdString &strKey) const
278 {
279   map<CStdString, CSetting *>::const_iterator it = m_settings.find(strKey);
280   if (it != m_settings.end() && (*it).second->GetType() == SettingTypeInteger)
281   {
282       CSettingInt *intSetting = (CSettingInt *) (*it).second;
283     if (intSetting)
284       return intSetting->GetValue();
285   }
286
287   return 0;
288 }
289
290 float CPeripheral::GetSettingFloat(const CStdString &strKey) const
291 {
292   map<CStdString, CSetting *>::const_iterator it = m_settings.find(strKey);
293   if (it != m_settings.end() && (*it).second->GetType() == SettingTypeNumber)
294   {
295       CSettingNumber *floatSetting = (CSettingNumber *) (*it).second;
296     if (floatSetting)
297       return (float)floatSetting->GetValue();
298   }
299
300   return 0;
301 }
302
303 const CStdString CPeripheral::GetSettingString(const CStdString &strKey) const
304 {
305   map<CStdString, CSetting *>::const_iterator it = m_settings.find(strKey);
306   if (it != m_settings.end() && (*it).second->GetType() == SettingTypeString)
307   {
308       CSettingString *stringSetting = (CSettingString *) (*it).second;
309     if (stringSetting)
310       return stringSetting->GetValue();
311   }
312
313   return StringUtils::EmptyString;
314 }
315
316 bool CPeripheral::SetSetting(const CStdString &strKey, bool bValue)
317 {
318   bool bChanged(false);
319   map<CStdString, CSetting *>::iterator it = m_settings.find(strKey);
320   if (it != m_settings.end() && (*it).second->GetType() == SettingTypeBool)
321   {
322       CSettingBool *boolSetting = (CSettingBool *) (*it).second;
323     if (boolSetting)
324     {
325       bChanged = boolSetting->GetValue() != bValue;
326       boolSetting->SetValue(bValue);
327       if (bChanged && m_bInitialised)
328         m_changedSettings.insert(strKey);
329     }
330   }
331   return bChanged;
332 }
333
334 bool CPeripheral::SetSetting(const CStdString &strKey, int iValue)
335 {
336   bool bChanged(false);
337   map<CStdString, CSetting *>::iterator it = m_settings.find(strKey);
338   if (it != m_settings.end() && (*it).second->GetType() == SettingTypeInteger)
339   {
340       CSettingInt *intSetting = (CSettingInt *) (*it).second;
341     if (intSetting)
342     {
343       bChanged = intSetting->GetValue() != iValue;
344       intSetting->SetValue(iValue);
345       if (bChanged && m_bInitialised)
346         m_changedSettings.insert(strKey);
347     }
348   }
349   return bChanged;
350 }
351
352 bool CPeripheral::SetSetting(const CStdString &strKey, float fValue)
353 {
354   bool bChanged(false);
355   map<CStdString, CSetting *>::iterator it = m_settings.find(strKey);
356   if (it != m_settings.end() && (*it).second->GetType() == SettingTypeNumber)
357   {
358       CSettingNumber *floatSetting = (CSettingNumber *) (*it).second;
359     if (floatSetting)
360     {
361       bChanged = floatSetting->GetValue() != fValue;
362       floatSetting->SetValue(fValue);
363       if (bChanged && m_bInitialised)
364         m_changedSettings.insert(strKey);
365     }
366   }
367   return bChanged;
368 }
369
370 void CPeripheral::SetSettingVisible(const CStdString &strKey, bool bSetTo)
371 {
372   map<CStdString, CSetting *>::iterator it = m_settings.find(strKey);
373   if (it != m_settings.end())
374     (*it).second->SetVisible(bSetTo);
375 }
376
377 bool CPeripheral::IsSettingVisible(const CStdString &strKey) const
378 {
379   map<CStdString, CSetting *>::const_iterator it = m_settings.find(strKey);
380   if (it != m_settings.end())
381     return (*it).second->IsVisible();
382   return false;
383 }
384
385 bool CPeripheral::SetSetting(const CStdString &strKey, const CStdString &strValue)
386 {
387   bool bChanged(false);
388   map<CStdString, CSetting *>::iterator it = m_settings.find(strKey);
389   if (it != m_settings.end())
390   {
391     if ((*it).second->GetType() == SettingTypeString)
392     {
393         CSettingString *stringSetting = (CSettingString *) (*it).second;
394       if (stringSetting)
395       {
396         bChanged = !StringUtils::EqualsNoCase(stringSetting->GetValue(), strValue);
397         stringSetting->SetValue(strValue);
398         if (bChanged && m_bInitialised)
399           m_changedSettings.insert(strKey);
400       }
401     }
402     else if ((*it).second->GetType() == SettingTypeInteger)
403       bChanged = SetSetting(strKey, (int) (strValue.empty() ? 0 : atoi(strValue.c_str())));
404     else if ((*it).second->GetType() == SettingTypeNumber)
405       bChanged = SetSetting(strKey, (float) (strValue.empty() ? 0 : atof(strValue.c_str())));
406     else if ((*it).second->GetType() == SettingTypeBool)
407       bChanged = SetSetting(strKey, strValue.Equals("1"));
408   }
409   return bChanged;
410 }
411
412 void CPeripheral::PersistSettings(bool bExiting /* = false */)
413 {
414   CXBMCTinyXML doc;
415   TiXmlElement node("settings");
416   doc.InsertEndChild(node);
417   for (map<CStdString, CSetting *>::const_iterator itr = m_settings.begin(); itr != m_settings.end(); itr++)
418   {
419     TiXmlElement nodeSetting("setting");
420     nodeSetting.SetAttribute("id", itr->first.c_str());
421     CStdString strValue;
422     switch ((*itr).second->GetType())
423     {
424     case SettingTypeString:
425       {
426         CSettingString *stringSetting = (CSettingString *) (*itr).second;
427         if (stringSetting)
428           strValue = stringSetting->GetValue();
429       }
430       break;
431     case SettingTypeInteger:
432       {
433         CSettingInt *intSetting = (CSettingInt *) (*itr).second;
434         if (intSetting)
435           strValue = StringUtils::Format("%d", intSetting->GetValue());
436       }
437       break;
438     case SettingTypeNumber:
439       {
440         CSettingNumber *floatSetting = (CSettingNumber *) (*itr).second;
441         if (floatSetting)
442           strValue = StringUtils::Format("%.2f", floatSetting->GetValue());
443       }
444       break;
445     case SettingTypeBool:
446       {
447         CSettingBool *boolSetting = (CSettingBool *) (*itr).second;
448         if (boolSetting)
449           strValue = StringUtils::Format("%d", boolSetting->GetValue() ? 1:0);
450       }
451       break;
452     default:
453       break;
454     }
455     nodeSetting.SetAttribute("value", strValue.c_str());
456     doc.RootElement()->InsertEndChild(nodeSetting);
457   }
458
459   doc.SaveFile(m_strSettingsFile);
460
461   if (!bExiting)
462   {
463     for (set<CStdString>::const_iterator it = m_changedSettings.begin(); it != m_changedSettings.end(); it++)
464       OnSettingChanged(*it);
465   }
466   m_changedSettings.clear();
467 }
468
469 void CPeripheral::LoadPersistedSettings(void)
470 {
471   CXBMCTinyXML doc;
472   if (doc.LoadFile(m_strSettingsFile))
473   {
474     const TiXmlElement *setting = doc.RootElement()->FirstChildElement("setting");
475     while (setting)
476     {
477       CStdString strId(setting->Attribute("id"));
478       CStdString strValue(setting->Attribute("value"));
479       SetSetting(strId, strValue);
480
481       setting = setting->NextSiblingElement("setting");
482     }
483   }
484 }
485
486 void CPeripheral::ResetDefaultSettings(void)
487 {
488   ClearSettings();
489   g_peripherals.GetSettingsFromMapping(*this);
490
491   map<CStdString, CSetting *>::iterator it = m_settings.begin();
492   while (it != m_settings.end())
493   {
494     m_changedSettings.insert((*it).first);
495     ++it;
496   }
497
498   PersistSettings();
499 }
500
501 void CPeripheral::ClearSettings(void)
502 {
503   map<CStdString, CSetting *>::iterator it = m_settings.begin();
504   while (it != m_settings.end())
505   {
506     delete (*it).second;
507     ++it;
508   }
509   m_settings.clear();
510 }
511
512 bool CPeripheral::operator ==(const PeripheralScanResult& right) const
513 {
514   return m_strLocation.Equals(right.m_strLocation);
515 }
516
517 bool CPeripheral::operator !=(const PeripheralScanResult& right) const
518 {
519   return !(*this == right);
520 }