[pvr] observe PVRManager state to trigger epg create
[vuplus_xbmc] / xbmc / pvr / channels / PVRChannelGroupInternal.cpp
1 /*
2  *      Copyright (C) 2012-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 "PVRChannelGroupInternal.h"
22
23 #include "guilib/GUIWindowManager.h"
24 #include "dialogs/GUIDialogYesNo.h"
25 #include "dialogs/GUIDialogOK.h"
26 #include "settings/AdvancedSettings.h"
27 #include "utils/log.h"
28
29 #include "PVRChannelGroupsContainer.h"
30 #include "pvr/PVRDatabase.h"
31 #include "pvr/PVRManager.h"
32 #include "epg/EpgContainer.h"
33 #include "pvr/timers/PVRTimers.h"
34 #include "pvr/addons/PVRClients.h"
35
36 using namespace PVR;
37 using namespace EPG;
38 using namespace std;
39
40 CPVRChannelGroupInternal::CPVRChannelGroupInternal(bool bRadio) :
41   CPVRChannelGroup(bRadio, bRadio ? XBMC_INTERNAL_GROUP_RADIO : XBMC_INTERNAL_GROUP_TV, g_localizeStrings.Get(bRadio ? 19216 : 19217))
42 {
43   m_iHiddenChannels = 0;
44   m_iGroupType      = PVR_GROUP_TYPE_INTERNAL;
45 }
46
47 CPVRChannelGroupInternal::CPVRChannelGroupInternal(const CPVRChannelGroup &group) :
48     CPVRChannelGroup(group)
49 {
50   m_iHiddenChannels = group.GetNumHiddenChannels();
51 }
52
53 CPVRChannelGroupInternal::~CPVRChannelGroupInternal(void)
54 {
55   Unload();
56   g_PVRManager.UnregisterObserver(this);
57 }
58
59 bool CPVRChannelGroupInternal::Load(void)
60 {
61   if (CPVRChannelGroup::Load())
62   {
63     UpdateChannelPaths();
64     g_PVRManager.RegisterObserver(this);
65       
66     return true;
67   }
68
69   CLog::Log(LOGERROR, "PVRChannelGroupInternal - %s - failed to load channels", __FUNCTION__);
70   return false;
71 }
72
73 void CPVRChannelGroupInternal::CheckGroupName(void)
74 {
75   CSingleLock lock(m_critSection);
76
77   /* check whether the group name is still correct, or channels will fail to load after the language setting changed */
78   CStdString strNewGroupName = g_localizeStrings.Get(m_bRadio ? 19216 : 19217);
79   if (!m_strGroupName.Equals(strNewGroupName))
80   {
81     SetGroupName(strNewGroupName, true);
82     UpdateChannelPaths();
83   }
84 }
85
86 void CPVRChannelGroupInternal::UpdateChannelPaths(void)
87 {
88   for (unsigned int iChannelPtr = 0; iChannelPtr < m_members.size(); iChannelPtr++)
89   {
90     PVRChannelGroupMember member = m_members.at(iChannelPtr);
91     member.channel->UpdatePath(this, iChannelPtr);
92   }
93 }
94
95 void CPVRChannelGroupInternal::UpdateFromClient(const CPVRChannel &channel, unsigned int iChannelNumber /* = 0 */)
96 {
97   CSingleLock lock(m_critSection);
98   CPVRChannelPtr realChannel = GetByClient(channel.UniqueID(), channel.ClientID());
99   if (realChannel)
100     realChannel->UpdateFromClient(channel);
101   else
102   {
103     PVRChannelGroupMember newMember = { CPVRChannelPtr(new CPVRChannel(channel)), iChannelNumber > 0l ? iChannelNumber : (int)m_members.size() + 1 };
104     m_members.push_back(newMember);
105     m_bChanged = true;
106
107     SortAndRenumber();
108   }
109 }
110
111 bool CPVRChannelGroupInternal::InsertInGroup(CPVRChannel &channel, int iChannelNumber /* = 0 */)
112 {
113   CSingleLock lock(m_critSection);
114   return CPVRChannelGroup::AddToGroup(channel, iChannelNumber);
115 }
116
117 bool CPVRChannelGroupInternal::Update(void)
118 {
119   CPVRChannelGroupInternal PVRChannels_tmp(m_bRadio);
120   PVRChannels_tmp.SetPreventSortAndRenumber();
121   return PVRChannels_tmp.LoadFromClients() && UpdateGroupEntries(PVRChannels_tmp);
122 }
123
124 bool CPVRChannelGroupInternal::AddToGroup(CPVRChannel &channel, int iChannelNumber /* = 0 */)
125 {
126   CSingleLock lock(m_critSection);
127
128   bool bReturn(false);
129
130   /* get the actual channel since this is called from a fileitemlist copy */
131   CPVRChannelPtr realChannel = GetByChannelID(channel.ChannelID());
132   if (!realChannel)
133     return bReturn;
134
135   /* switch the hidden flag */
136   if (realChannel->IsHidden())
137   {
138     realChannel->SetHidden(false);
139     m_iHiddenChannels--;
140
141     SortAndRenumber();
142   }
143
144   /* move this channel and persist */
145   bReturn = (iChannelNumber > 0l) ?
146     MoveChannel(realChannel->ChannelNumber(), iChannelNumber, true) :
147     MoveChannel(realChannel->ChannelNumber(), m_members.size() - m_iHiddenChannels, true);
148
149   if (m_bLoaded)
150     realChannel->Persist();
151   return bReturn;
152 }
153
154 bool CPVRChannelGroupInternal::RemoveFromGroup(const CPVRChannel &channel)
155 {
156   CSingleLock lock(m_critSection);
157
158   /* check if this channel is currently playing if we are hiding it */
159   CPVRChannelPtr currentChannel;
160   if (g_PVRManager.GetCurrentChannel(currentChannel) && *currentChannel == channel)
161   {
162     CGUIDialogOK::ShowAndGetInput(19098,19101,0,19102);
163     return false;
164   }
165
166   /* get the actual channel since this is called from a fileitemlist copy */
167   CPVRChannelPtr realChannel = GetByChannelID(channel.ChannelID());
168   if (!realChannel)
169     return false;
170
171   /* switch the hidden flag */
172   if (!realChannel->IsHidden())
173   {
174     realChannel->SetHidden(true);
175     ++m_iHiddenChannels;
176   }
177   else
178   {
179     realChannel->SetHidden(false);
180     --m_iHiddenChannels;
181   }
182
183   /* renumber this list */
184   SortAndRenumber();
185
186   /* and persist */
187   return realChannel->Persist() &&
188       Persist();
189 }
190
191 bool CPVRChannelGroupInternal::MoveChannel(unsigned int iOldChannelNumber, unsigned int iNewChannelNumber, bool bSaveInDb /* = true */)
192 {
193   CSingleLock lock(m_critSection);
194   /* new channel number out of range */
195   if (iNewChannelNumber > m_members.size() - m_iHiddenChannels)
196     iNewChannelNumber = m_members.size() - m_iHiddenChannels;
197
198   return CPVRChannelGroup::MoveChannel(iOldChannelNumber, iNewChannelNumber, bSaveInDb);
199 }
200
201 int CPVRChannelGroupInternal::GetMembers(CFileItemList &results, bool bGroupMembers /* = true */) const
202 {
203   int iOrigSize = results.Size();
204   CSingleLock lock(m_critSection);
205
206   for (unsigned int iChannelPtr = 0; iChannelPtr < m_members.size(); iChannelPtr++)
207   {
208     CPVRChannelPtr channel = m_members.at(iChannelPtr).channel;
209     if (!channel)
210       continue;
211
212     if (bGroupMembers != channel->IsHidden())
213     {
214       CFileItemPtr pFileItem(new CFileItem(*channel));
215       results.Add(pFileItem);
216     }
217   }
218
219   return results.Size() - iOrigSize;
220 }
221
222 int CPVRChannelGroupInternal::LoadFromDb(bool bCompress /* = false */)
223 {
224   CPVRDatabase *database = GetPVRDatabase();
225   if (!database)
226     return -1;
227
228   int iChannelCount = Size();
229
230   if (database->Get(*this) > 0)
231   {
232     if (bCompress)
233       database->Compress(true);
234   }
235   else
236   {
237     CLog::Log(LOGINFO, "PVRChannelGroupInternal - %s - no channels in the database",
238         __FUNCTION__);
239   }
240
241   SortByChannelNumber();
242
243   return Size() - iChannelCount;
244 }
245
246 bool CPVRChannelGroupInternal::LoadFromClients(void)
247 {
248   /* get the channels from the backends */
249   return g_PVRClients->GetChannels(this) == PVR_ERROR_NO_ERROR;
250 }
251
252 bool CPVRChannelGroupInternal::Renumber(void)
253 {
254   CSingleLock lock(m_critSection);
255   bool bReturn(CPVRChannelGroup::Renumber());
256
257   m_iHiddenChannels = 0;
258   for (unsigned int iChannelPtr = 0; iChannelPtr < m_members.size();  iChannelPtr++)
259   {
260     if (m_members.at(iChannelPtr).channel->IsHidden())
261       m_iHiddenChannels++;
262     else
263       m_members.at(iChannelPtr).channel->UpdatePath(this, iChannelPtr);
264   }
265
266   return bReturn;
267 }
268
269 bool CPVRChannelGroupInternal::IsGroupMember(const CPVRChannel &channel) const
270 {
271   return !channel.IsHidden();
272 }
273
274 bool CPVRChannelGroupInternal::UpdateChannel(const CPVRChannel &channel)
275 {
276   CSingleLock lock(m_critSection);
277   CPVRChannelPtr updateChannel = GetByUniqueID(channel.UniqueID());
278
279   if (!updateChannel)
280   {
281     updateChannel = CPVRChannelPtr(new CPVRChannel(channel.IsRadio()));
282     PVRChannelGroupMember newMember = { updateChannel, 0 };
283     m_members.push_back(newMember);
284     updateChannel->SetUniqueID(channel.UniqueID());
285   }
286   updateChannel->UpdateFromClient(channel);
287
288   return updateChannel->Persist(!m_bLoaded);
289 }
290
291 bool CPVRChannelGroupInternal::AddAndUpdateChannels(const CPVRChannelGroup &channels, bool bUseBackendChannelNumbers)
292 {
293   bool bReturn(false);
294   SetPreventSortAndRenumber();
295
296   CSingleLock lock(m_critSection);
297
298   /* go through the channel list and check for updated or new channels */
299   for (unsigned int iChannelPtr = 0; iChannelPtr < channels.m_members.size(); iChannelPtr++)
300   {
301     PVRChannelGroupMember member = channels.m_members.at(iChannelPtr);
302     if (!member.channel)
303       continue;
304
305     /* check whether this channel is present in this container */
306     CPVRChannelPtr existingChannel = GetByClient(member.channel->UniqueID(), member.channel->ClientID());
307     if (existingChannel)
308     {
309       /* if it's present, update the current tag */
310       if (existingChannel->UpdateFromClient(*member.channel))
311       {
312         bReturn = true;
313         CLog::Log(LOGINFO,"PVRChannelGroupInternal - %s - updated %s channel '%s'", __FUNCTION__, m_bRadio ? "radio" : "TV", member.channel->ChannelName().c_str());
314       }
315     }
316     else
317     {
318       /* new channel */
319       UpdateFromClient(*member.channel, bUseBackendChannelNumbers ? member.channel->ClientChannelNumber() : 0);
320       bReturn = true;
321       CLog::Log(LOGINFO,"PVRChannelGroupInternal - %s - added %s channel '%s'", __FUNCTION__, m_bRadio ? "radio" : "TV", member.channel->ChannelName().c_str());
322     }
323   }
324
325   SetPreventSortAndRenumber(false);
326   if (m_bChanged)
327     SortAndRenumber();
328
329   return bReturn;
330 }
331
332 bool CPVRChannelGroupInternal::UpdateGroupEntries(const CPVRChannelGroup &channels)
333 {
334   bool bReturn(false);
335
336   if (CPVRChannelGroup::UpdateGroupEntries(channels))
337   {
338     /* try to find channel icons */
339     if (g_advancedSettings.m_bPVRChannelIconsAutoScan)
340       SearchAndSetChannelIcons();
341
342     g_PVRTimers->UpdateChannels();
343     Persist();
344
345     bReturn = true;
346   }
347
348   return bReturn;
349 }
350
351 void CPVRChannelGroupInternal::CreateChannelEpg(CPVRChannelPtr channel, bool bForce /* = false */)
352 {
353   if (!channel)
354     return;
355
356   CSingleLock lock(channel->m_critSection);
357   if (!channel->m_bEPGCreated || bForce)
358   {
359     CEpg *epg = g_EpgContainer.CreateChannelEpg(channel);
360     if (epg)
361     {
362       channel->m_bEPGCreated = true;
363       if (epg->EpgID() != channel->m_iEpgId)
364       {
365         channel->m_iEpgId = epg->EpgID();
366         channel->m_bChanged = true;
367       }
368     }
369   }
370 }
371
372 bool CPVRChannelGroupInternal::CreateChannelEpgs(bool bForce /* = false */)
373 {
374   if (!g_EpgContainer.IsStarted())
375     return false;
376   {
377     CSingleLock lock(m_critSection);
378     for (unsigned int iChannelPtr = 0; iChannelPtr < m_members.size(); iChannelPtr++)
379       CreateChannelEpg(m_members.at(iChannelPtr).channel);
380   }
381
382   if (HasChangedChannels())
383   {
384     g_EpgContainer.PersistTables();
385     return Persist();
386   }
387
388   return true;
389 }
390
391 void CPVRChannelGroupInternal::Notify(const Observable &obs, const ObservableMessage msg)
392 {
393   if (msg == ObservableMessageManagerStateChanged)
394   {
395     g_PVRManager.TriggerEpgsCreate();
396   }
397 }