2 * Copyright (C) 2012-2013 Team XBMC
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)
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.
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/>.
21 #include "dialogs/GUIDialogKaiToast.h"
22 #include "dialogs/GUIDialogOK.h"
23 #include "dialogs/GUIDialogYesNo.h"
24 #include "settings/AdvancedSettings.h"
25 #include "settings/Settings.h"
26 #include "utils/log.h"
27 #include "utils/StringUtils.h"
29 #include "PVRTimers.h"
30 #include "pvr/PVRManager.h"
31 #include "pvr/channels/PVRChannelGroupsContainer.h"
32 #include "pvr/channels/PVRChannelGroupInternal.h"
33 #include "epg/EpgContainer.h"
34 #include "pvr/addons/PVRClients.h"
42 CPVRTimerInfoTag::CPVRTimerInfoTag(void)
44 m_strTitle = g_localizeStrings.Get(19056); // New Timer
46 m_strSummary = StringUtils::EmptyString;
47 m_iClientId = g_PVRClients->GetFirstConnectedClientID();
49 m_iClientChannelUid = PVR_VIRTUAL_CHANNEL_UID;
50 m_iPriority = CSettings::Get().GetInt("pvrrecord.defaultpriority");
51 m_iLifetime = CSettings::Get().GetInt("pvrrecord.defaultlifetime");
52 m_bIsRepeating = false;
54 m_strFileNameAndPath = StringUtils::EmptyString;
57 CEpgInfoTagPtr emptyTag;
59 m_iMarginStart = CSettings::Get().GetInt("pvrrecord.marginstart");
60 m_iMarginEnd = CSettings::Get().GetInt("pvrrecord.marginend");
63 m_StartTime = CDateTime::GetUTCDateTime();
64 m_StopTime = m_StartTime;
65 m_state = PVR_TIMER_STATE_SCHEDULED;
66 m_FirstDay.SetValid(false);
69 CPVRTimerInfoTag::CPVRTimerInfoTag(const PVR_TIMER &timer, CPVRChannelPtr channel, unsigned int iClientId)
71 m_strTitle = timer.strTitle;
72 m_strDirectory = timer.strDirectory;
73 m_strSummary = StringUtils::EmptyString;
74 m_iClientId = iClientId;
75 m_iClientIndex = timer.iClientIndex;
76 m_iClientChannelUid = channel ? channel->UniqueID() : timer.iClientChannelUid;
77 m_iChannelNumber = channel ? g_PVRChannelGroups->GetGroupAll(channel->IsRadio())->GetChannelNumber(*channel) : 0;
78 m_StartTime = timer.startTime + g_advancedSettings.m_iPVRTimeCorrection;
79 m_StopTime = timer.endTime + g_advancedSettings.m_iPVRTimeCorrection;
80 m_bIsRepeating = timer.bIsRepeating;
81 m_FirstDay = timer.firstDay + g_advancedSettings.m_iPVRTimeCorrection;
82 m_iWeekdays = timer.iWeekdays;
83 m_iPriority = timer.iPriority;
84 m_iLifetime = timer.iLifetime;
85 m_iMarginStart = timer.iMarginStart;
86 m_iMarginEnd = timer.iMarginEnd;
87 m_genre = StringUtils::Split(CEpg::ConvertGenreIdToString(timer.iGenreType, timer.iGenreSubType), g_advancedSettings.m_videoItemSeparator);
88 m_iGenreType = timer.iGenreType;
89 m_iGenreSubType = timer.iGenreSubType;
90 CEpgInfoTagPtr emptyTag;
93 m_bIsRadio = channel && channel->IsRadio();
94 m_state = timer.state;
95 m_strFileNameAndPath = StringUtils::Format("pvr://client%i/timers/%i", m_iClientId, m_iClientIndex);
100 bool CPVRTimerInfoTag::operator ==(const CPVRTimerInfoTag& right) const
102 bool bChannelsMatch = true;
103 if (m_channel && right.m_channel)
104 bChannelsMatch = *m_channel == *right.m_channel;
105 else if (m_channel != right.m_channel)
106 bChannelsMatch = false;
108 return (bChannelsMatch &&
109 m_iClientIndex == right.m_iClientIndex &&
110 m_strSummary == right.m_strSummary &&
111 m_iClientChannelUid == right.m_iClientChannelUid &&
112 m_bIsRadio == right.m_bIsRadio &&
113 m_bIsRepeating == right.m_bIsRepeating &&
114 m_StartTime == right.m_StartTime &&
115 m_StopTime == right.m_StopTime &&
116 m_FirstDay == right.m_FirstDay &&
117 m_iWeekdays == right.m_iWeekdays &&
118 m_iPriority == right.m_iPriority &&
119 m_iLifetime == right.m_iLifetime &&
120 m_strFileNameAndPath == right.m_strFileNameAndPath &&
121 m_strTitle == right.m_strTitle &&
122 m_strDirectory == right.m_strDirectory &&
123 m_iClientId == right.m_iClientId &&
124 m_iMarginStart == right.m_iMarginStart &&
125 m_iMarginEnd == right.m_iMarginEnd &&
126 m_state == right.m_state);
129 CPVRTimerInfoTag &CPVRTimerInfoTag::operator=(const CPVRTimerInfoTag &orig)
131 m_channel = orig.m_channel;
132 m_iClientIndex = orig.m_iClientIndex;
133 m_strSummary = orig.m_strSummary;
134 m_iClientChannelUid = orig.m_iClientChannelUid;
135 m_bIsRadio = orig.m_bIsRadio;
136 m_bIsRepeating = orig.m_bIsRepeating;
137 m_StartTime = orig.m_StartTime;
138 m_StopTime = orig.m_StopTime;
139 m_FirstDay = orig.m_FirstDay;
140 m_iWeekdays = orig.m_iWeekdays;
141 m_iPriority = orig.m_iPriority;
142 m_iLifetime = orig.m_iLifetime;
143 m_strFileNameAndPath = orig.m_strFileNameAndPath;
144 m_strTitle = orig.m_strTitle;
145 m_strDirectory = orig.m_strDirectory;
146 m_iClientId = orig.m_iClientId;
147 m_iMarginStart = orig.m_iMarginStart;
148 m_iMarginEnd = orig.m_iMarginEnd;
149 m_state = orig.m_state;
150 m_iChannelNumber = orig.m_iChannelNumber;
155 CPVRTimerInfoTag::~CPVRTimerInfoTag(void)
161 * Compare not equal for two CPVRTimerInfoTag
163 bool CPVRTimerInfoTag::operator !=(const CPVRTimerInfoTag& right) const
165 return !(*this == right);
168 int CPVRTimerInfoTag::Compare(const CPVRTimerInfoTag &timer) const
170 CSingleLock lock(m_critSection);
172 if (StartAsUTC() != timer.StartAsUTC())
174 CDateTimeSpan timerDelta = StartAsUTC() - timer.StartAsUTC();
175 iTimerDelta = (timerDelta.GetSeconds() + timerDelta.GetMinutes() * 60 + timerDelta.GetHours() * 3600 + timerDelta.GetDays() * 86400);
178 /* if the start times are equal, compare the priority of the timers */
179 return iTimerDelta == 0 ?
180 timer.m_iPriority - m_iPriority :
184 void CPVRTimerInfoTag::UpdateSummary(void)
186 CSingleLock lock(m_critSection);
187 m_strSummary.clear();
189 if (!m_bIsRepeating || !m_iWeekdays)
191 m_strSummary = StringUtils::Format("%s %s %s %s %s",
192 StartAsLocalTime().GetAsLocalizedDate().c_str(),
193 g_localizeStrings.Get(19159).c_str(),
194 StartAsLocalTime().GetAsLocalizedTime(StringUtils::EmptyString, false).c_str(),
195 g_localizeStrings.Get(19160).c_str(),
196 EndAsLocalTime().GetAsLocalizedTime(StringUtils::EmptyString, false).c_str());
198 else if (m_FirstDay.IsValid())
200 m_strSummary = StringUtils::Format("%s-%s-%s-%s-%s-%s-%s %s %s %s %s %s %s",
201 m_iWeekdays & 0x01 ? g_localizeStrings.Get(19149).c_str() : "__",
202 m_iWeekdays & 0x02 ? g_localizeStrings.Get(19150).c_str() : "__",
203 m_iWeekdays & 0x04 ? g_localizeStrings.Get(19151).c_str() : "__",
204 m_iWeekdays & 0x08 ? g_localizeStrings.Get(19152).c_str() : "__",
205 m_iWeekdays & 0x10 ? g_localizeStrings.Get(19153).c_str() : "__",
206 m_iWeekdays & 0x20 ? g_localizeStrings.Get(19154).c_str() : "__",
207 m_iWeekdays & 0x40 ? g_localizeStrings.Get(19155).c_str() : "__",
208 g_localizeStrings.Get(19156).c_str(),
209 FirstDayAsLocalTime().GetAsLocalizedDate(false).c_str(),
210 g_localizeStrings.Get(19159).c_str(),
211 StartAsLocalTime().GetAsLocalizedTime(StringUtils::EmptyString, false).c_str(),
212 g_localizeStrings.Get(19160).c_str(),
213 EndAsLocalTime().GetAsLocalizedTime(StringUtils::EmptyString, false).c_str());
217 m_strSummary = StringUtils::Format("%s-%s-%s-%s-%s-%s-%s %s %s %s %s",
218 m_iWeekdays & 0x01 ? g_localizeStrings.Get(19149).c_str() : "__",
219 m_iWeekdays & 0x02 ? g_localizeStrings.Get(19150).c_str() : "__",
220 m_iWeekdays & 0x04 ? g_localizeStrings.Get(19151).c_str() : "__",
221 m_iWeekdays & 0x08 ? g_localizeStrings.Get(19152).c_str() : "__",
222 m_iWeekdays & 0x10 ? g_localizeStrings.Get(19153).c_str() : "__",
223 m_iWeekdays & 0x20 ? g_localizeStrings.Get(19154).c_str() : "__",
224 m_iWeekdays & 0x40 ? g_localizeStrings.Get(19155).c_str() : "__",
225 g_localizeStrings.Get(19159).c_str(),
226 StartAsLocalTime().GetAsLocalizedTime(StringUtils::EmptyString, false).c_str(),
227 g_localizeStrings.Get(19160).c_str(),
228 EndAsLocalTime().GetAsLocalizedTime(StringUtils::EmptyString, false).c_str());
233 * Get the status string of this Timer, is used by the GUIInfoManager
235 CStdString CPVRTimerInfoTag::GetStatus() const
237 CStdString strReturn = g_localizeStrings.Get(305);
238 CSingleLock lock(m_critSection);
239 if (m_strFileNameAndPath == "pvr://timers/add.timer")
240 strReturn = g_localizeStrings.Get(19026);
241 else if (m_state == PVR_TIMER_STATE_CANCELLED || m_state == PVR_TIMER_STATE_ABORTED)
242 strReturn = g_localizeStrings.Get(13106);
243 else if (m_state == PVR_TIMER_STATE_RECORDING)
244 strReturn = g_localizeStrings.Get(19162);
245 else if (m_state == PVR_TIMER_STATE_CONFLICT_OK)
246 strReturn = g_localizeStrings.Get(19275);
247 else if (m_state == PVR_TIMER_STATE_CONFLICT_NOK)
248 strReturn = g_localizeStrings.Get(19276);
249 else if (m_state == PVR_TIMER_STATE_ERROR)
250 strReturn = g_localizeStrings.Get(257);
255 bool CPVRTimerInfoTag::AddToClient(void) const
257 PVR_ERROR error = g_PVRClients->AddTimer(*this);
258 if (error != PVR_ERROR_NO_ERROR)
267 bool CPVRTimerInfoTag::DeleteFromClient(bool bForce /* = false */) const
269 PVR_ERROR error = g_PVRClients->DeleteTimer(*this, bForce);
270 if (error == PVR_ERROR_RECORDING_RUNNING)
272 // recording running. ask the user if it should be deleted anyway
273 if (!CGUIDialogYesNo::ShowAndGetInput(122,0,19122,0))
276 error = g_PVRClients->DeleteTimer(*this, true);
279 if (error != PVR_ERROR_NO_ERROR)
289 bool CPVRTimerInfoTag::RenameOnClient(const CStdString &strNewName)
292 CSingleLock lock(m_critSection);
293 m_strTitle = strNewName;
296 PVR_ERROR error = g_PVRClients->RenameTimer(*this, strNewName);
297 if (error != PVR_ERROR_NO_ERROR)
299 if (error == PVR_ERROR_NOT_IMPLEMENTED)
300 return UpdateOnClient();
309 bool CPVRTimerInfoTag::UpdateEntry(const CPVRTimerInfoTag &tag)
311 CSingleLock lock(m_critSection);
313 m_iClientId = tag.m_iClientId;
314 m_iClientIndex = tag.m_iClientIndex;
315 m_strTitle = tag.m_strTitle;
316 m_strDirectory = tag.m_strDirectory;
317 m_iClientChannelUid = tag.m_iClientChannelUid;
318 m_StartTime = tag.m_StartTime;
319 m_StopTime = tag.m_StopTime;
320 m_FirstDay = tag.m_FirstDay;
321 m_iPriority = tag.m_iPriority;
322 m_iLifetime = tag.m_iLifetime;
323 m_state = tag.m_state;
324 m_bIsRepeating = tag.m_bIsRepeating;
325 m_iWeekdays = tag.m_iWeekdays;
326 m_iChannelNumber = tag.m_iChannelNumber;
327 m_bIsRadio = tag.m_bIsRadio;
328 m_iMarginStart = tag.m_iMarginStart;
329 m_iMarginEnd = tag.m_iMarginEnd;
330 m_epgTag = tag.m_epgTag;
331 m_genre = tag.m_genre;
332 m_iGenreType = tag.m_iGenreType;
333 m_iGenreSubType = tag.m_iGenreSubType;
334 m_strSummary = tag.m_strSummary;
336 if (m_strSummary.IsEmpty())
342 bool CPVRTimerInfoTag::UpdateOnClient()
344 PVR_ERROR error = g_PVRClients->UpdateTimer(*this);
345 if (error != PVR_ERROR_NO_ERROR)
354 void CPVRTimerInfoTag::DisplayError(PVR_ERROR err) const
356 if (err == PVR_ERROR_SERVER_ERROR)
357 CGUIDialogOK::ShowAndGetInput(19033,19111,19110,0); /* print info dialog "Server error!" */
358 else if (err == PVR_ERROR_REJECTED)
359 CGUIDialogOK::ShowAndGetInput(19033,19109,19110,0); /* print info dialog "Couldn't delete timer!" */
360 else if (err == PVR_ERROR_ALREADY_PRESENT)
361 CGUIDialogOK::ShowAndGetInput(19033,19109,0,19067); /* print info dialog */
363 CGUIDialogOK::ShowAndGetInput(19033,19147,19110,0); /* print info dialog "Unknown error!" */
366 void CPVRTimerInfoTag::SetEpgInfoTag(CEpgInfoTagPtr tag)
368 CSingleLock lock(m_critSection);
369 if (tag && m_epgTag != tag)
370 CLog::Log(LOGINFO, "cPVRTimerInfoTag: timer %s set to epg event %s", m_strTitle.c_str(), tag->Title().c_str());
371 else if (!tag && m_epgTag)
372 CLog::Log(LOGINFO, "cPVRTimerInfoTag: timer %s set to no epg event", m_strTitle.c_str());
376 int CPVRTimerInfoTag::ChannelNumber() const
378 CPVRChannelPtr channeltag = ChannelTag();
379 return channeltag ? channeltag->ChannelNumber() : 0;
382 CStdString CPVRTimerInfoTag::ChannelName() const
384 CStdString strReturn;
385 CPVRChannelPtr channeltag = ChannelTag();
387 strReturn = channeltag->ChannelName();
391 CStdString CPVRTimerInfoTag::ChannelIcon() const
393 CStdString strReturn;
394 CPVRChannelPtr channeltag = ChannelTag();
396 strReturn = channeltag->IconPath();
400 bool CPVRTimerInfoTag::SetDuration(int iDuration)
402 CSingleLock lock(m_critSection);
403 if (m_StartTime.IsValid())
405 m_StopTime = m_StartTime + CDateTimeSpan(0, iDuration / 60, iDuration % 60, 0);
412 CPVRTimerInfoTag *CPVRTimerInfoTag::CreateFromEpg(const CEpgInfoTag &tag)
414 /* create a new timer */
415 CPVRTimerInfoTag *newTag = new CPVRTimerInfoTag();
418 CLog::Log(LOGERROR, "%s - couldn't create new timer", __FUNCTION__);
422 /* check if a valid channel is set */
423 CPVRChannelPtr channel = tag.ChannelTag();
426 CLog::Log(LOGERROR, "%s - no channel set", __FUNCTION__);
431 /* check if the epg end date is in the future */
432 if (tag.EndAsLocalTime() < CDateTime::GetCurrentDateTime())
434 CLog::Log(LOGERROR, "%s - end time is in the past", __FUNCTION__);
439 /* set the timer data */
440 CDateTime newStart = tag.StartAsUTC();
441 CDateTime newEnd = tag.EndAsUTC();
442 newTag->m_iClientIndex = -1;
443 newTag->m_strTitle = tag.Title().empty() ? channel->ChannelName() : tag.Title();
444 newTag->m_iChannelNumber = channel->ChannelNumber();
445 newTag->m_iClientChannelUid = channel->UniqueID();
446 newTag->m_iClientId = channel->ClientID();
447 newTag->m_bIsRadio = channel->IsRadio();
448 newTag->m_iGenreType = tag.GenreType();
449 newTag->m_iGenreSubType = tag.GenreSubType();
450 newTag->m_channel = channel;
451 newTag->SetStartFromUTC(newStart);
452 newTag->SetEndFromUTC(newEnd);
454 if (tag.Plot().empty())
456 newTag->m_strSummary= StringUtils::Format("%s %s %s %s %s",
457 newTag->StartAsLocalTime().GetAsLocalizedDate().c_str(),
458 g_localizeStrings.Get(19159).c_str(),
459 newTag->StartAsLocalTime().GetAsLocalizedTime(StringUtils::EmptyString, false).c_str(),
460 g_localizeStrings.Get(19160).c_str(),
461 newTag->EndAsLocalTime().GetAsLocalizedTime(StringUtils::EmptyString, false).c_str());
465 newTag->m_strSummary = tag.Plot();
468 newTag->m_epgTag = g_EpgContainer.GetById(tag.EpgID())->GetTag(tag.StartAsUTC());
470 /* unused only for reference */
471 newTag->m_strFileNameAndPath = "pvr://timers/new";
476 CDateTime CPVRTimerInfoTag::StartAsUTC(void) const
478 CDateTime retVal = m_StartTime;
482 CDateTime CPVRTimerInfoTag::StartAsLocalTime(void) const
485 retVal.SetFromUTCDateTime(m_StartTime);
489 CDateTime CPVRTimerInfoTag::EndAsUTC(void) const
491 CDateTime retVal = m_StopTime;
495 CDateTime CPVRTimerInfoTag::EndAsLocalTime(void) const
498 retVal.SetFromUTCDateTime(m_StopTime);
502 CDateTime CPVRTimerInfoTag::FirstDayAsUTC(void) const
504 CDateTime retVal = m_FirstDay;
508 CDateTime CPVRTimerInfoTag::FirstDayAsLocalTime(void) const
511 retVal.SetFromUTCDateTime(m_FirstDay);
515 void CPVRTimerInfoTag::GetNotificationText(CStdString &strText) const
517 CSingleLock lock(m_critSection);
520 case PVR_TIMER_STATE_ABORTED:
521 case PVR_TIMER_STATE_CANCELLED:
522 strText = StringUtils::Format("%s: '%s'", g_localizeStrings.Get(19224).c_str(), m_strTitle.c_str());
524 case PVR_TIMER_STATE_SCHEDULED:
525 strText = StringUtils::Format("%s: '%s'", g_localizeStrings.Get(19225).c_str(), m_strTitle.c_str());
527 case PVR_TIMER_STATE_RECORDING:
528 strText = StringUtils::Format("%s: '%s'", g_localizeStrings.Get(19226).c_str(), m_strTitle.c_str());
530 case PVR_TIMER_STATE_COMPLETED:
531 strText = StringUtils::Format("%s: '%s'", g_localizeStrings.Get(19227).c_str(), m_strTitle.c_str());
533 case PVR_TIMER_STATE_CONFLICT_OK:
534 case PVR_TIMER_STATE_CONFLICT_NOK:
535 strText = StringUtils::Format("%s: '%s'", g_localizeStrings.Get(19277).c_str(), m_strTitle.c_str());
537 case PVR_TIMER_STATE_ERROR:
538 strText = StringUtils::Format("%s: '%s'", g_localizeStrings.Get(19278).c_str(), m_strTitle.c_str());
545 void CPVRTimerInfoTag::QueueNotification(void) const
547 if (CSettings::Get().GetBool("pvrrecord.timernotifications"))
549 CStdString strMessage;
550 GetNotificationText(strMessage);
552 if (!strMessage.IsEmpty())
553 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, g_localizeStrings.Get(19166), strMessage);
557 CEpgInfoTagPtr CPVRTimerInfoTag::GetEpgInfoTag(void) const
562 bool CPVRTimerInfoTag::SupportsFolders() const
564 return g_PVRClients->SupportsRecordingFolders(m_iClientId);
567 void CPVRTimerInfoTag::ClearEpgTag(void)
569 CEpgInfoTagPtr deletedTag;
572 CSingleLock lock(m_critSection);
573 deletedTag = m_epgTag;
575 CEpgInfoTagPtr emptyTag;
580 deletedTag->ClearTimer();
583 CPVRChannelPtr CPVRTimerInfoTag::ChannelTag(void) const
588 void CPVRTimerInfoTag::UpdateChannel(void)
590 CSingleLock lock(m_critSection);
591 m_channel = g_PVRChannelGroups->Get(m_bIsRadio)->GetGroupAll()->GetByClient(m_iClientChannelUid, m_iClientId);
594 CStdString CPVRTimerInfoTag::Title(void) const
596 CStdString strReturn;
597 strReturn = m_strTitle;
601 CStdString CPVRTimerInfoTag::Summary(void) const
603 CStdString strReturn;
604 strReturn = m_strSummary;
608 CStdString CPVRTimerInfoTag::Path(void) const
610 CStdString strReturn;
611 strReturn = m_strFileNameAndPath;