1 /* 2 * Copyright (C) 2016-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 "PVRContextMenus.h" 10 11 #include "ContextMenuItem.h" 12 #include "ServiceBroker.h" 13 #include "guilib/LocalizeStrings.h" 14 #include "pvr/PVRManager.h" 15 #include "pvr/addons/PVRClient.h" 16 #include "pvr/addons/PVRClientMenuHooks.h" 17 #include "pvr/channels/PVRChannel.h" 18 #include "pvr/channels/PVRChannelGroupsContainer.h" 19 #include "pvr/epg/EpgInfoTag.h" 20 #include "pvr/guilib/PVRGUIActions.h" 21 #include "pvr/recordings/PVRRecording.h" 22 #include "pvr/recordings/PVRRecordings.h" 23 #include "pvr/recordings/PVRRecordingsPath.h" 24 #include "pvr/timers/PVRTimerInfoTag.h" 25 #include "pvr/timers/PVRTimers.h" 26 #include "pvr/timers/PVRTimersPath.h" 27 #include "utils/URIUtils.h" 28 29 #include <memory> 30 #include <string> 31 32 namespace PVR 33 { 34 namespace CONTEXTMENUITEM 35 { 36 #define DECL_STATICCONTEXTMENUITEM(clazz) \ 37 class clazz : public CStaticContextMenuAction \ 38 { \ 39 public: \ 40 explicit clazz(uint32_t label) : CStaticContextMenuAction(label) {} \ 41 bool IsVisible(const CFileItem& item) const override; \ 42 bool Execute(const CFileItemPtr& item) const override; \ 43 }; 44 45 #define DECL_CONTEXTMENUITEM(clazz) \ 46 class clazz : public IContextMenuItem \ 47 { \ 48 public: \ 49 std::string GetLabel(const CFileItem& item) const override; \ 50 bool IsVisible(const CFileItem& item) const override; \ 51 bool Execute(const CFileItemPtr& item) const override; \ 52 }; 53 54 DECL_STATICCONTEXTMENUITEM(PlayEpgTag); 55 DECL_STATICCONTEXTMENUITEM(PlayRecording); 56 DECL_CONTEXTMENUITEM(ShowInformation); 57 DECL_STATICCONTEXTMENUITEM(ShowChannelGuide); 58 DECL_STATICCONTEXTMENUITEM(FindSimilar); 59 DECL_STATICCONTEXTMENUITEM(StartRecording); 60 DECL_STATICCONTEXTMENUITEM(StopRecording); 61 DECL_STATICCONTEXTMENUITEM(AddTimerRule); 62 DECL_CONTEXTMENUITEM(EditTimerRule); 63 DECL_STATICCONTEXTMENUITEM(DeleteTimerRule); 64 DECL_CONTEXTMENUITEM(EditTimer); 65 DECL_CONTEXTMENUITEM(DeleteTimer); 66 DECL_STATICCONTEXTMENUITEM(EditRecording); 67 DECL_CONTEXTMENUITEM(DeleteRecording); 68 DECL_STATICCONTEXTMENUITEM(UndeleteRecording); 69 DECL_STATICCONTEXTMENUITEM(DeleteWatchedRecordings); 70 DECL_CONTEXTMENUITEM(ToggleTimerState); 71 DECL_STATICCONTEXTMENUITEM(AddReminder); 72 73 class PVRClientMenuHook : public IContextMenuItem 74 { 75 public: PVRClientMenuHook(const CPVRClientMenuHook & hook)76 PVRClientMenuHook(const CPVRClientMenuHook& hook) : m_hook(hook) {}; 77 78 std::string GetLabel(const CFileItem& item) const override; 79 bool IsVisible(const CFileItem& item) const override; 80 bool Execute(const CFileItemPtr& item) const override; 81 GetHook() const82 const CPVRClientMenuHook& GetHook() const { return m_hook; } 83 84 private: 85 const CPVRClientMenuHook m_hook; 86 }; 87 GetTimerInfoTagFromItem(const CFileItem & item)88 std::shared_ptr<CPVRTimerInfoTag> GetTimerInfoTagFromItem(const CFileItem& item) 89 { 90 std::shared_ptr<CPVRTimerInfoTag> timer; 91 92 const std::shared_ptr<CPVREpgInfoTag> epg(item.GetEPGInfoTag()); 93 if (epg) 94 timer = CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epg); 95 96 if (!timer) 97 timer = item.GetPVRTimerInfoTag(); 98 99 return timer; 100 } 101 102 /////////////////////////////////////////////////////////////////////////////// 103 // Play epg tag 104 IsVisible(const CFileItem & item) const105 bool PlayEpgTag::IsVisible(const CFileItem& item) const 106 { 107 const std::shared_ptr<CPVREpgInfoTag> epg(item.GetEPGInfoTag()); 108 if (epg) 109 return epg->IsPlayable(); 110 111 return false; 112 } 113 Execute(const CFileItemPtr & item) const114 bool PlayEpgTag::Execute(const CFileItemPtr& item) const 115 { 116 return CServiceBroker::GetPVRManager().GUIActions()->PlayEpgTag(item); 117 } 118 119 /////////////////////////////////////////////////////////////////////////////// 120 // Play recording 121 IsVisible(const CFileItem & item) const122 bool PlayRecording::IsVisible(const CFileItem& item) const 123 { 124 const std::shared_ptr<CPVRRecording> recording = CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(item.GetEPGInfoTag()); 125 if (recording) 126 return !recording->IsDeleted(); 127 128 return false; 129 } 130 Execute(const CFileItemPtr & item) const131 bool PlayRecording::Execute(const CFileItemPtr& item) const 132 { 133 return CServiceBroker::GetPVRManager().GUIActions()->PlayRecording(item, true /* bCheckResume */); 134 } 135 136 /////////////////////////////////////////////////////////////////////////////// 137 // Show information (epg, recording) 138 GetLabel(const CFileItem & item) const139 std::string ShowInformation::GetLabel(const CFileItem& item) const 140 { 141 if (item.GetPVRRecordingInfoTag()) 142 return g_localizeStrings.Get(19053); /* Recording Information */ 143 144 return g_localizeStrings.Get(19047); /* Programme information */ 145 } 146 IsVisible(const CFileItem & item) const147 bool ShowInformation::IsVisible(const CFileItem& item) const 148 { 149 const std::shared_ptr<CPVRChannel> channel(item.GetPVRChannelInfoTag()); 150 if (channel) 151 return channel->GetEPGNow().get() != nullptr; 152 153 if (item.HasEPGInfoTag()) 154 return !item.GetEPGInfoTag()->IsGapTag(); 155 156 const std::shared_ptr<CPVRTimerInfoTag> timer(item.GetPVRTimerInfoTag()); 157 if (timer && !URIUtils::PathEquals(item.GetPath(), CPVRTimersPath::PATH_ADDTIMER)) 158 return timer->GetEpgInfoTag().get() != nullptr; 159 160 if (item.GetPVRRecordingInfoTag()) 161 return true; 162 163 return false; 164 } 165 Execute(const CFileItemPtr & item) const166 bool ShowInformation::Execute(const CFileItemPtr& item) const 167 { 168 if (item->GetPVRRecordingInfoTag()) 169 return CServiceBroker::GetPVRManager().GUIActions()->ShowRecordingInfo(item); 170 171 return CServiceBroker::GetPVRManager().GUIActions()->ShowEPGInfo(item); 172 } 173 174 /////////////////////////////////////////////////////////////////////////////// 175 // Show channel guide 176 IsVisible(const CFileItem & item) const177 bool ShowChannelGuide::IsVisible(const CFileItem& item) const 178 { 179 const std::shared_ptr<CPVRChannel> channel(item.GetPVRChannelInfoTag()); 180 if (channel) 181 return channel->GetEPGNow().get() != nullptr; 182 183 return false; 184 } 185 Execute(const CFileItemPtr & item) const186 bool ShowChannelGuide::Execute(const CFileItemPtr& item) const 187 { 188 return CServiceBroker::GetPVRManager().GUIActions()->ShowChannelEPG(item); 189 } 190 191 /////////////////////////////////////////////////////////////////////////////// 192 // Find similar 193 IsVisible(const CFileItem & item) const194 bool FindSimilar::IsVisible(const CFileItem& item) const 195 { 196 const std::shared_ptr<CPVRChannel> channel(item.GetPVRChannelInfoTag()); 197 if (channel) 198 return channel->GetEPGNow().get() != nullptr; 199 200 if (item.HasEPGInfoTag()) 201 return !item.GetEPGInfoTag()->IsGapTag(); 202 203 const std::shared_ptr<CPVRTimerInfoTag> timer(item.GetPVRTimerInfoTag()); 204 if (timer && !URIUtils::PathEquals(item.GetPath(), CPVRTimersPath::PATH_ADDTIMER)) 205 return timer->GetEpgInfoTag().get() != nullptr; 206 207 const std::shared_ptr<CPVRRecording> recording(item.GetPVRRecordingInfoTag()); 208 if (recording) 209 return !recording->IsDeleted(); 210 211 return false; 212 } 213 Execute(const CFileItemPtr & item) const214 bool FindSimilar::Execute(const CFileItemPtr& item) const 215 { 216 return CServiceBroker::GetPVRManager().GUIActions()->FindSimilar(item); 217 } 218 219 /////////////////////////////////////////////////////////////////////////////// 220 // Start recording 221 IsVisible(const CFileItem & item) const222 bool StartRecording::IsVisible(const CFileItem& item) const 223 { 224 const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(item); 225 226 std::shared_ptr<CPVRChannel> channel = item.GetPVRChannelInfoTag(); 227 if (channel) 228 return client && client->GetClientCapabilities().SupportsTimers() && 229 !CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*channel); 230 231 const std::shared_ptr<CPVREpgInfoTag> epg = item.GetEPGInfoTag(); 232 if (epg && epg->IsRecordable()) 233 { 234 if (epg->IsGapTag()) 235 { 236 channel = CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelForEpgTag(epg); 237 if (channel) 238 { 239 return client && client->GetClientCapabilities().SupportsTimers() && 240 !CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*channel); 241 } 242 } 243 else 244 { 245 return client && client->GetClientCapabilities().SupportsTimers() && 246 !CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epg); 247 } 248 } 249 return false; 250 } 251 Execute(const CFileItemPtr & item) const252 bool StartRecording::Execute(const CFileItemPtr& item) const 253 { 254 const std::shared_ptr<CPVREpgInfoTag> epgTag = item->GetEPGInfoTag(); 255 if (!epgTag || epgTag->IsActive()) 256 { 257 // instant recording 258 std::shared_ptr<CPVRChannel> channel; 259 if (epgTag) 260 channel = CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelForEpgTag(epgTag); 261 262 if (!channel) 263 channel = item->GetPVRChannelInfoTag(); 264 265 if (channel) 266 return CServiceBroker::GetPVRManager().GUIActions()->SetRecordingOnChannel(channel, true); 267 } 268 269 return CServiceBroker::GetPVRManager().GUIActions()->AddTimer(item, false); 270 } 271 272 /////////////////////////////////////////////////////////////////////////////// 273 // Stop recording 274 IsVisible(const CFileItem & item) const275 bool StopRecording::IsVisible(const CFileItem& item) const 276 { 277 const std::shared_ptr<CPVRRecording> recording(item.GetPVRRecordingInfoTag()); 278 if (recording && recording->IsInProgress()) 279 return true; 280 281 std::shared_ptr<CPVRChannel> channel = item.GetPVRChannelInfoTag(); 282 if (channel) 283 return CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*channel); 284 285 const std::shared_ptr<CPVRTimerInfoTag> timer(GetTimerInfoTagFromItem(item)); 286 if (timer && !URIUtils::PathEquals(item.GetPath(), CPVRTimersPath::PATH_ADDTIMER)) 287 return timer->IsRecording(); 288 289 const std::shared_ptr<CPVREpgInfoTag> epg = item.GetEPGInfoTag(); 290 if (epg && epg->IsGapTag()) 291 { 292 channel = CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelForEpgTag(epg); 293 if (channel) 294 return CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*channel); 295 } 296 297 return false; 298 } 299 Execute(const CFileItemPtr & item) const300 bool StopRecording::Execute(const CFileItemPtr& item) const 301 { 302 const std::shared_ptr<CPVREpgInfoTag> epgTag = item->GetEPGInfoTag(); 303 if (epgTag && epgTag->IsGapTag()) 304 { 305 // instance recording 306 const std::shared_ptr<CPVRChannel> channel = 307 CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelForEpgTag(epgTag); 308 if (channel) 309 return CServiceBroker::GetPVRManager().GUIActions()->SetRecordingOnChannel(channel, 310 false); 311 } 312 313 return CServiceBroker::GetPVRManager().GUIActions()->StopRecording(item); 314 } 315 316 /////////////////////////////////////////////////////////////////////////////// 317 // Edit recording 318 IsVisible(const CFileItem & item) const319 bool EditRecording::IsVisible(const CFileItem& item) const 320 { 321 const std::shared_ptr<CPVRRecording> recording(item.GetPVRRecordingInfoTag()); 322 if (recording && !recording->IsDeleted() && !recording->IsInProgress()) 323 { 324 return CServiceBroker::GetPVRManager().GUIActions()->CanEditRecording(item); 325 } 326 return false; 327 } 328 Execute(const CFileItemPtr & item) const329 bool EditRecording::Execute(const CFileItemPtr& item) const 330 { 331 return CServiceBroker::GetPVRManager().GUIActions()->EditRecording(item); 332 } 333 334 /////////////////////////////////////////////////////////////////////////////// 335 // Delete recording 336 GetLabel(const CFileItem & item) const337 std::string DeleteRecording::GetLabel(const CFileItem& item) const 338 { 339 const std::shared_ptr<CPVRRecording> recording(item.GetPVRRecordingInfoTag()); 340 if (recording && recording->IsDeleted()) 341 return g_localizeStrings.Get(19291); /* Delete permanently */ 342 343 return g_localizeStrings.Get(117); /* Delete */ 344 } 345 IsVisible(const CFileItem & item) const346 bool DeleteRecording::IsVisible(const CFileItem& item) const 347 { 348 const std::shared_ptr<CPVRRecording> recording(item.GetPVRRecordingInfoTag()); 349 if (recording && !recording->IsInProgress()) 350 return true; 351 352 // recordings folder? 353 if (item.m_bIsFolder) 354 { 355 const CPVRRecordingsPath path(item.GetPath()); 356 return path.IsValid() && !path.IsRecordingsRoot(); 357 } 358 359 return false; 360 } 361 Execute(const CFileItemPtr & item) const362 bool DeleteRecording::Execute(const CFileItemPtr& item) const 363 { 364 return CServiceBroker::GetPVRManager().GUIActions()->DeleteRecording(item); 365 } 366 367 /////////////////////////////////////////////////////////////////////////////// 368 // Undelete recording 369 IsVisible(const CFileItem & item) const370 bool UndeleteRecording::IsVisible(const CFileItem& item) const 371 { 372 const std::shared_ptr<CPVRRecording> recording(item.GetPVRRecordingInfoTag()); 373 if (recording && recording->IsDeleted()) 374 return true; 375 376 return false; 377 } 378 Execute(const CFileItemPtr & item) const379 bool UndeleteRecording::Execute(const CFileItemPtr& item) const 380 { 381 return CServiceBroker::GetPVRManager().GUIActions()->UndeleteRecording(item); 382 } 383 384 /////////////////////////////////////////////////////////////////////////////// 385 // Delete watched recordings 386 IsVisible(const CFileItem & item) const387 bool DeleteWatchedRecordings::IsVisible(const CFileItem& item) const 388 { 389 // recordings folder? 390 if (item.m_bIsFolder && !item.IsParentFolder()) 391 return CPVRRecordingsPath(item.GetPath()).IsValid(); 392 393 return false; 394 } 395 Execute(const std::shared_ptr<CFileItem> & item) const396 bool DeleteWatchedRecordings::Execute(const std::shared_ptr<CFileItem>& item) const 397 { 398 return CServiceBroker::GetPVRManager().GUIActions()->DeleteWatchedRecordings(item); 399 } 400 401 /////////////////////////////////////////////////////////////////////////////// 402 // Add reminder 403 IsVisible(const CFileItem & item) const404 bool AddReminder::IsVisible(const CFileItem& item) const 405 { 406 const std::shared_ptr<CPVREpgInfoTag> epg = item.GetEPGInfoTag(); 407 if (epg && 408 !CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epg) && 409 epg->StartAsLocalTime() > CDateTime::GetCurrentDateTime()) 410 return true; 411 412 return false; 413 } 414 Execute(const std::shared_ptr<CFileItem> & item) const415 bool AddReminder::Execute(const std::shared_ptr<CFileItem>& item) const 416 { 417 return CServiceBroker::GetPVRManager().GUIActions()->AddReminder(item); 418 } 419 420 /////////////////////////////////////////////////////////////////////////////// 421 // Activate / deactivate timer or timer rule 422 GetLabel(const CFileItem & item) const423 std::string ToggleTimerState::GetLabel(const CFileItem& item) const 424 { 425 const std::shared_ptr<CPVRTimerInfoTag> timer(item.GetPVRTimerInfoTag()); 426 if (timer && timer->m_state != PVR_TIMER_STATE_DISABLED) 427 return g_localizeStrings.Get(844); /* Deactivate */ 428 429 return g_localizeStrings.Get(843); /* Activate */ 430 } 431 IsVisible(const CFileItem & item) const432 bool ToggleTimerState::IsVisible(const CFileItem& item) const 433 { 434 const std::shared_ptr<CPVRTimerInfoTag> timer(item.GetPVRTimerInfoTag()); 435 if (!timer || URIUtils::PathEquals(item.GetPath(), CPVRTimersPath::PATH_ADDTIMER) || timer->IsBroken()) 436 return false; 437 438 const std::shared_ptr<CPVRTimerType> timerType(timer->GetTimerType()); 439 return timerType && timerType->SupportsEnableDisable(); 440 } 441 Execute(const CFileItemPtr & item) const442 bool ToggleTimerState::Execute(const CFileItemPtr& item) const 443 { 444 return CServiceBroker::GetPVRManager().GUIActions()->ToggleTimerState(item); 445 } 446 447 /////////////////////////////////////////////////////////////////////////////// 448 // Add timer rule 449 IsVisible(const CFileItem & item) const450 bool AddTimerRule::IsVisible(const CFileItem& item) const 451 { 452 const std::shared_ptr<CPVREpgInfoTag> epg = item.GetEPGInfoTag(); 453 return (epg && !epg->IsGapTag() && 454 !CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epg)); 455 } 456 Execute(const CFileItemPtr & item) const457 bool AddTimerRule::Execute(const CFileItemPtr& item) const 458 { 459 return CServiceBroker::GetPVRManager().GUIActions()->AddTimerRule(item, true, true); 460 } 461 462 /////////////////////////////////////////////////////////////////////////////// 463 // Edit timer rule 464 GetLabel(const CFileItem & item) const465 std::string EditTimerRule::GetLabel(const CFileItem& item) const 466 { 467 const std::shared_ptr<CPVRTimerInfoTag> timer(GetTimerInfoTagFromItem(item)); 468 if (timer && !URIUtils::PathEquals(item.GetPath(), CPVRTimersPath::PATH_ADDTIMER)) 469 { 470 const std::shared_ptr<CPVRTimerInfoTag> parentTimer(CServiceBroker::GetPVRManager().Timers()->GetTimerRule(timer)); 471 if (parentTimer) 472 { 473 const std::shared_ptr<CPVRTimerType> parentTimerType(parentTimer->GetTimerType()); 474 if (parentTimerType && !parentTimerType->IsReadOnly()) 475 return g_localizeStrings.Get(19243); /* Edit timer rule */ 476 } 477 } 478 479 return g_localizeStrings.Get(19304); /* View timer rule */ 480 } 481 IsVisible(const CFileItem & item) const482 bool EditTimerRule::IsVisible(const CFileItem& item) const 483 { 484 const std::shared_ptr<CPVRTimerInfoTag> timer(GetTimerInfoTagFromItem(item)); 485 if (timer && !URIUtils::PathEquals(item.GetPath(), CPVRTimersPath::PATH_ADDTIMER)) 486 return timer->GetTimerRuleId() != PVR_TIMER_NO_PARENT; 487 488 return false; 489 } 490 Execute(const CFileItemPtr & item) const491 bool EditTimerRule::Execute(const CFileItemPtr& item) const 492 { 493 return CServiceBroker::GetPVRManager().GUIActions()->EditTimerRule(item); 494 } 495 496 /////////////////////////////////////////////////////////////////////////////// 497 // Delete timer rule 498 IsVisible(const CFileItem & item) const499 bool DeleteTimerRule::IsVisible(const CFileItem& item) const 500 { 501 const std::shared_ptr<CPVRTimerInfoTag> timer(GetTimerInfoTagFromItem(item)); 502 if (timer && !URIUtils::PathEquals(item.GetPath(), CPVRTimersPath::PATH_ADDTIMER)) 503 { 504 const std::shared_ptr<CPVRTimerInfoTag> parentTimer(CServiceBroker::GetPVRManager().Timers()->GetTimerRule(timer)); 505 if (parentTimer) 506 { 507 const std::shared_ptr<CPVRTimerType> parentTimerType(parentTimer->GetTimerType()); 508 return parentTimerType && parentTimerType->AllowsDelete(); 509 } 510 } 511 512 return false; 513 } 514 Execute(const CFileItemPtr & item) const515 bool DeleteTimerRule::Execute(const CFileItemPtr& item) const 516 { 517 const std::shared_ptr<CFileItem> parentTimer = CServiceBroker::GetPVRManager().GUIActions()->GetTimerRule(item); 518 if (parentTimer) 519 return CServiceBroker::GetPVRManager().GUIActions()->DeleteTimerRule(parentTimer); 520 521 return false; 522 } 523 524 /////////////////////////////////////////////////////////////////////////////// 525 // Edit / View timer 526 GetLabel(const CFileItem & item) const527 std::string EditTimer::GetLabel(const CFileItem& item) const 528 { 529 const std::shared_ptr<CPVRTimerInfoTag> timer(GetTimerInfoTagFromItem(item)); 530 if (timer) 531 { 532 const std::shared_ptr<CPVRTimerType> timerType(timer->GetTimerType()); 533 if (timerType) 534 { 535 if (item.GetEPGInfoTag()) 536 { 537 if (timerType->IsReminder()) 538 return g_localizeStrings.Get(timerType->IsReadOnly() ? 829 : 830); /* View/Edit reminder */ 539 else 540 return g_localizeStrings.Get(timerType->IsReadOnly() ? 19241 : 19242); /* View/Edit timer */ 541 } 542 else 543 return g_localizeStrings.Get(timerType->IsReadOnly() ? 21483 : 21450); /* View/Edit */ 544 } 545 } 546 return g_localizeStrings.Get(19241); /* View timer */ 547 } 548 IsVisible(const CFileItem & item) const549 bool EditTimer::IsVisible(const CFileItem& item) const 550 { 551 const std::shared_ptr<CPVRTimerInfoTag> timer(GetTimerInfoTagFromItem(item)); 552 return timer && (!item.GetEPGInfoTag() || !URIUtils::PathEquals(item.GetPath(), CPVRTimersPath::PATH_ADDTIMER)); 553 } 554 Execute(const CFileItemPtr & item) const555 bool EditTimer::Execute(const CFileItemPtr& item) const 556 { 557 return CServiceBroker::GetPVRManager().GUIActions()->EditTimer(item); 558 } 559 560 /////////////////////////////////////////////////////////////////////////////// 561 // Delete timer 562 GetLabel(const CFileItem & item) const563 std::string DeleteTimer::GetLabel(const CFileItem& item) const 564 { 565 if (item.GetPVRTimerInfoTag()) 566 return g_localizeStrings.Get(117); /* Delete */ 567 568 const std::shared_ptr<CPVREpgInfoTag> epg = item.GetEPGInfoTag(); 569 if (epg) 570 { 571 const std::shared_ptr<CPVRTimerInfoTag> timer = CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epg); 572 if (timer && timer->IsReminder()) 573 return g_localizeStrings.Get(827); /* Delete reminder */ 574 } 575 return g_localizeStrings.Get(19060); /* Delete timer */ 576 } 577 IsVisible(const CFileItem & item) const578 bool DeleteTimer::IsVisible(const CFileItem& item) const 579 { 580 const std::shared_ptr<CPVRTimerInfoTag> timer(GetTimerInfoTagFromItem(item)); 581 if (timer && (!item.GetEPGInfoTag() || !URIUtils::PathEquals(item.GetPath(), CPVRTimersPath::PATH_ADDTIMER)) && !timer->IsRecording()) 582 { 583 const std::shared_ptr<CPVRTimerType> timerType(timer->GetTimerType()); 584 return timerType && timerType->AllowsDelete(); 585 } 586 587 return false; 588 } 589 Execute(const CFileItemPtr & item) const590 bool DeleteTimer::Execute(const CFileItemPtr& item) const 591 { 592 return CServiceBroker::GetPVRManager().GUIActions()->DeleteTimer(item); 593 } 594 595 /////////////////////////////////////////////////////////////////////////////// 596 // PVR Client menu hook 597 GetLabel(const CFileItem & item) const598 std::string PVRClientMenuHook::GetLabel(const CFileItem& item) const 599 { 600 return m_hook.GetLabel(); 601 } 602 IsVisible(const CFileItem & item) const603 bool PVRClientMenuHook::IsVisible(const CFileItem& item) const 604 { 605 const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(item); 606 if (!client || m_hook.GetAddonId() != client->ID()) 607 return false; 608 609 if (m_hook.IsAllHook()) 610 return !item.m_bIsFolder && !URIUtils::PathEquals(item.GetPath(), CPVRTimersPath::PATH_ADDTIMER); 611 else if (m_hook.IsEpgHook()) 612 return item.IsEPG(); 613 else if (m_hook.IsChannelHook()) 614 return item.IsPVRChannel(); 615 else if (m_hook.IsDeletedRecordingHook()) 616 return item.IsDeletedPVRRecording(); 617 else if (m_hook.IsRecordingHook()) 618 return item.IsUsablePVRRecording(); 619 else if (m_hook.IsTimerHook()) 620 return item.IsPVRTimer(); 621 else 622 return false; 623 } 624 Execute(const CFileItemPtr & item) const625 bool PVRClientMenuHook::Execute(const CFileItemPtr& item) const 626 { 627 const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(*item); 628 if (!client) 629 return false; 630 631 if (item->IsEPG()) 632 return client->CallEpgTagMenuHook(m_hook, item->GetEPGInfoTag()) == PVR_ERROR_NO_ERROR; 633 else if (item->IsPVRChannel()) 634 return client->CallChannelMenuHook(m_hook, item->GetPVRChannelInfoTag()) == PVR_ERROR_NO_ERROR; 635 else if (item->IsDeletedPVRRecording()) 636 return client->CallRecordingMenuHook(m_hook, item->GetPVRRecordingInfoTag(), true) == PVR_ERROR_NO_ERROR; 637 else if (item->IsUsablePVRRecording()) 638 return client->CallRecordingMenuHook(m_hook, item->GetPVRRecordingInfoTag(), false) == PVR_ERROR_NO_ERROR; 639 else if (item->IsPVRTimer()) 640 return client->CallTimerMenuHook(m_hook, item->GetPVRTimerInfoTag()) == PVR_ERROR_NO_ERROR; 641 else 642 return false; 643 } 644 645 } // namespace CONEXTMENUITEM 646 GetInstance()647 CPVRContextMenuManager& CPVRContextMenuManager::GetInstance() 648 { 649 static CPVRContextMenuManager instance; 650 return instance; 651 } 652 CPVRContextMenuManager()653 CPVRContextMenuManager::CPVRContextMenuManager() 654 { 655 m_items = { 656 std::make_shared<CONTEXTMENUITEM::PlayEpgTag>(19190), /* Play programme */ 657 std::make_shared<CONTEXTMENUITEM::PlayRecording>(19687), /* Play recording */ 658 std::make_shared<CONTEXTMENUITEM::ShowInformation>(), 659 std::make_shared<CONTEXTMENUITEM::ShowChannelGuide>(19686), /* Channel guide */ 660 std::make_shared<CONTEXTMENUITEM::FindSimilar>(19003), /* Find similar */ 661 std::make_shared<CONTEXTMENUITEM::ToggleTimerState>(), 662 std::make_shared<CONTEXTMENUITEM::AddTimerRule>(19061), /* Add timer */ 663 std::make_shared<CONTEXTMENUITEM::EditTimerRule>(), 664 std::make_shared<CONTEXTMENUITEM::DeleteTimerRule>(19295), /* Delete timer rule */ 665 std::make_shared<CONTEXTMENUITEM::EditTimer>(), 666 std::make_shared<CONTEXTMENUITEM::DeleteTimer>(), 667 std::make_shared<CONTEXTMENUITEM::StartRecording>(264), /* Record */ 668 std::make_shared<CONTEXTMENUITEM::StopRecording>(19059), /* Stop recording */ 669 std::make_shared<CONTEXTMENUITEM::EditRecording>(21450), /* Edit */ 670 std::make_shared<CONTEXTMENUITEM::DeleteRecording>(), 671 std::make_shared<CONTEXTMENUITEM::UndeleteRecording>(19290), /* Undelete */ 672 std::make_shared<CONTEXTMENUITEM::DeleteWatchedRecordings>(19327), /* Delete watched */ 673 std::make_shared<CONTEXTMENUITEM::AddReminder>(826), /* Set reminder */ 674 }; 675 } 676 AddMenuHook(const CPVRClientMenuHook & hook)677 void CPVRContextMenuManager::AddMenuHook(const CPVRClientMenuHook& hook) 678 { 679 if (hook.IsSettingsHook()) 680 return; // settings hooks are not handled using context menus 681 682 const auto item = std::make_shared<CONTEXTMENUITEM::PVRClientMenuHook>(hook); 683 m_items.emplace_back(item); 684 m_events.Publish(PVRContextMenuEvent(PVRContextMenuEventAction::ADD_ITEM, item)); 685 } 686 RemoveMenuHook(const CPVRClientMenuHook & hook)687 void CPVRContextMenuManager::RemoveMenuHook(const CPVRClientMenuHook& hook) 688 { 689 if (hook.IsSettingsHook()) 690 return; // settings hooks are not handled using context menus 691 692 for (auto it = m_items.begin(); it < m_items.end(); ++it) 693 { 694 const CONTEXTMENUITEM::PVRClientMenuHook* cmh = dynamic_cast<const CONTEXTMENUITEM::PVRClientMenuHook*>((*it).get()); 695 if (cmh && cmh->GetHook() == hook) 696 { 697 m_events.Publish(PVRContextMenuEvent(PVRContextMenuEventAction::REMOVE_ITEM, *it)); 698 m_items.erase(it); 699 return; 700 } 701 } 702 } 703 704 } // namespace PVR 705