MythTV  0.27pre
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
programrecpriority.cpp
Go to the documentation of this file.
1 
2 // own header
3 #include "programrecpriority.h"
4 
5 // C/C++ headers
6 #include <vector> // For std::vector
7 using namespace std;
8 
9 // QT headers
10 #include <QDateTime>
11 #include <QRegExp>
12 
13 // libmythtv headers
14 #include "recordingrule.h"
15 #include "scheduledrecording.h"
16 
17 // libmythbase
18 #include "mythdb.h"
19 #include "mythlogging.h"
20 #include "remoteutil.h"
21 
22 // libmythui
23 #include "mythuihelper.h"
24 #include "mythuibuttonlist.h"
25 #include "mythuitext.h"
26 #include "mythuistatetype.h"
27 #include "mythdialogbox.h"
28 
29 // mythfrontend
30 #include "customedit.h"
31 #include "proglist.h"
32 #include "scheduleeditor.h"
33 
34 // overloaded version of RecordingInfo with additional recording priority
35 // values so we can keep everything together and don't
36 // have to hit the db mulitiple times
38  RecordingInfo(),
39  recType(kNotRecording),
40  matchCount(0), recCount(0),
41  last_record(QDateTime()),
42  avg_delay(0),
43  profile("")
44 {
45 }
46 
48  const ProgramRecPriorityInfo &other) :
49  RecordingInfo(other),
50  recType(other.recType),
51  matchCount(other.matchCount),
52  recCount(other.recCount),
53  last_record(other.last_record),
54  avg_delay(other.avg_delay),
55  profile(other.profile)
56 {
57 }
58 
60  const ProgramRecPriorityInfo &other, bool ignore_non_serialized_data)
61 {
62  RecordingInfo::clone(other, ignore_non_serialized_data);
63 
64  if (!ignore_non_serialized_data)
65  {
66  recType = other.recType;
67  matchCount = other.matchCount;
68  recCount = other.recCount;
69  last_record = other.last_record;
70  avg_delay = other.avg_delay;
71  profile = other.profile;
72  }
73 }
74 
76  const RecordingInfo &other, bool ignore_non_serialized_data)
77 {
78  RecordingInfo::clone(other, ignore_non_serialized_data);
79 
80  if (!ignore_non_serialized_data)
81  {
83  matchCount = 0;
84  recCount = 0;
85  last_record = QDateTime();
86  avg_delay = 0;
87  profile.clear();
88  }
89 }
90 
92  const ProgramInfo &other, bool ignore_non_serialized_data)
93 {
94  RecordingInfo::clone(other, ignore_non_serialized_data);
95 
96  if (!ignore_non_serialized_data)
97  {
99  matchCount = 0;
100  recCount = 0;
101  last_record = QDateTime();
102  avg_delay = 0;
103  profile.clear();
104  }
105 }
106 
108 {
110 
112  matchCount = 0;
113  recCount = 0;
114  last_record = QDateTime();
115  avg_delay = 0;
116  profile.clear();
117 }
118 
119 void ProgramRecPriorityInfo::ToMap(QHash<QString, QString> &progMap,
120  bool showrerecord, uint star_range) const
121 {
122  RecordingInfo::ToMap(progMap, showrerecord, star_range);
123  progMap["title"] = (title == "Default (Template)") ?
124  QObject::tr("Default (Template)") : title;;
125  progMap["category"] = (category == "Default") ?
126  QObject::tr("Default") : category;
127 }
128 
130 {
131  public:
132  TitleSort(bool reverse) : m_reverse(reverse) {}
133 
135  const ProgramRecPriorityInfo *b) const
136  {
137  if (a->sortTitle != b->sortTitle)
138  {
139  if (m_reverse)
140  return (a->sortTitle > b->sortTitle);
141  else
142  return (a->sortTitle < b->sortTitle);
143  }
144 
145  int finalA = a->GetRecordingPriority();
146  int finalB = b->GetRecordingPriority();
147 
148  if (finalA != finalB)
149  {
150  if (m_reverse)
151  return finalA < finalB;
152  else
153  return finalA > finalB;
154  }
155 
156  int typeA = RecTypePrecedence(a->recType);
157  int typeB = RecTypePrecedence(b->recType);
158 
159  if (typeA != typeB)
160  {
161  if (m_reverse)
162  return typeA > typeB;
163  else
164  return typeA < typeB;
165  }
166 
167  if (m_reverse)
168  return (a->GetRecordingRuleID() >
169  b->GetRecordingRuleID());
170  else
171  return (a->GetRecordingRuleID() <
172  b->GetRecordingRuleID());
173  }
174 
175  private:
176  bool m_reverse;
177 };
178 
180 {
181  public:
182  ProgramRecPrioritySort(bool reverse) : m_reverse(reverse) {}
183 
185  const ProgramRecPriorityInfo *b) const
186  {
187  int finalA = a->GetRecordingPriority();
188  int finalB = b->GetRecordingPriority();
189 
190  if (finalA != finalB)
191  {
192  if (m_reverse)
193  return finalA < finalB;
194  else
195  return finalA > finalB;
196  }
197 
198  int typeA = RecTypePrecedence(a->recType);
199  int typeB = RecTypePrecedence(b->recType);
200 
201  if (typeA != typeB)
202  {
203  if (m_reverse)
204  return typeA > typeB;
205  else
206  return typeA < typeB;
207  }
208 
209  if (m_reverse)
210  return (a->GetRecordingRuleID() >
211  b->GetRecordingRuleID());
212  else
213  return (a->GetRecordingRuleID() <
214  b->GetRecordingRuleID());
215  }
216 
217  private:
218  bool m_reverse;
219 };
220 
222 {
223  public:
224  ProgramRecTypeSort(bool reverse) : m_reverse(reverse) {}
225 
227  const ProgramRecPriorityInfo *b) const
228  {
229  int typeA = RecTypePrecedence(a->recType);
230  int typeB = RecTypePrecedence(b->recType);
231 
232  if (typeA != typeB)
233  {
234  if (m_reverse)
235  return (typeA > typeB);
236  else
237  return (typeA < typeB);
238  }
239 
240  int finalA = a->GetRecordingPriority();
241  int finalB = b->GetRecordingPriority();
242 
243  if (finalA != finalB)
244  {
245  if (m_reverse)
246  return finalA < finalB;
247  else
248  return finalA > finalB;
249  }
250 
251  if (m_reverse)
252  return (a->GetRecordingRuleID() >
253  b->GetRecordingRuleID());
254  else
255  return (a->GetRecordingRuleID() <
256  b->GetRecordingRuleID());
257  }
258 
259  private:
260  bool m_reverse;
261 };
262 
264 {
265  public:
266  ProgramCountSort(bool reverse) : m_reverse(reverse) {}
267 
269  const ProgramRecPriorityInfo *b) const
270  {
271  int countA = a->matchCount;
272  int countB = b->matchCount;
273  int recCountA = a->recCount;
274  int recCountB = b->recCount;
275 
276  if (countA != countB)
277  {
278  if (m_reverse)
279  return countA < countB;
280  else
281  return countA > countB;
282  }
283 
284  if (recCountA != recCountB)
285  {
286  if (m_reverse)
287  return recCountA < recCountB;
288  else
289  return recCountA > recCountB;
290  }
291 
292  if (m_reverse)
293  return (a->sortTitle > b->sortTitle);
294  else
295  return (a->sortTitle < b->sortTitle);
296  }
297 
298  private:
299  bool m_reverse;
300 };
301 
303 {
304  public:
305  ProgramRecCountSort(bool reverse) : m_reverse(reverse) {}
306 
308  const ProgramRecPriorityInfo *b) const
309  {
310  int countA = a->matchCount;
311  int countB = b->matchCount;
312  int recCountA = a->recCount;
313  int recCountB = b->recCount;
314 
315  if (recCountA != recCountB)
316  {
317  if (m_reverse)
318  return recCountA < recCountB;
319  else
320  return recCountA > recCountB;
321  }
322 
323  if (countA != countB)
324  {
325  if (m_reverse)
326  return countA < countB;
327  else
328  return countA > countB;
329  }
330 
331  if (m_reverse)
332  return (a->sortTitle > b->sortTitle);
333  else
334  return (a->sortTitle < b->sortTitle);
335  }
336 
337  private:
338  bool m_reverse;
339 };
340 
342 {
343  public:
344  ProgramLastRecordSort(bool reverse) : m_reverse(reverse) {}
345 
347  const ProgramRecPriorityInfo *b) const
348  {
349  QDateTime lastRecA = a->last_record;
350  QDateTime lastRecB = b->last_record;
351 
352  if (lastRecA != lastRecB)
353  {
354  if (m_reverse)
355  return lastRecA < lastRecB;
356  else
357  return lastRecA > lastRecB;
358  }
359 
360  if (m_reverse)
361  return (a->sortTitle > b->sortTitle);
362  else
363  return (a->sortTitle < b->sortTitle);
364  }
365 
366  private:
367  bool m_reverse;
368 };
369 
371 {
372  public:
373  ProgramAvgDelaySort(bool reverse) : m_reverse(reverse) {}
374 
376  const ProgramRecPriorityInfo *b) const
377  {
378  int avgA = a->avg_delay;
379  int avgB = b->avg_delay;
380 
381  if (avgA != avgB)
382  {
383  if (m_reverse)
384  return avgA > avgB;
385  else
386  return avgA < avgB;
387  }
388 
389  if (m_reverse)
390  return (a->sortTitle > b->sortTitle);
391  else
392  return (a->sortTitle < b->sortTitle);
393  }
394 
395  private:
396  bool m_reverse;
397 };
398 
400 
402  const QString &name)
403  : ScheduleCommon(parent, name),
404  m_programList(NULL), m_schedInfoText(NULL),
405  m_recPriorityText(NULL),
406  m_recPriorityBText(NULL), m_finalPriorityText(NULL),
407  m_lastRecordedText(NULL), m_lastRecordedDateText(NULL),
408  m_lastRecordedTimeText(NULL), m_channameText(NULL),
409  m_channumText(NULL), m_callsignText(NULL),
410  m_recProfileText(NULL), m_currentItem(NULL)
411 {
412  m_sortType = (SortType)gCoreContext->GetNumSetting("ProgramRecPrioritySorting",
413  (int)byTitle);
414  m_reverseSort = gCoreContext->GetNumSetting("ProgramRecPriorityReverse", 0);
415 }
416 
418 {
419 }
420 
422 {
423  if (!LoadWindowFromXML("schedule-ui.xml", "managerecrules", this))
424  return false;
425 
426  m_programList = dynamic_cast<MythUIButtonList *> (GetChild("programs"));
427 
428  m_schedInfoText = dynamic_cast<MythUIText *> (GetChild("scheduleinfo"));
429  m_recPriorityText = dynamic_cast<MythUIText *> (GetChild("recpriority"));
430  m_recPriorityBText = dynamic_cast<MythUIText *> (GetChild("recpriorityB"));
431  m_finalPriorityText = dynamic_cast<MythUIText *> (GetChild("finalpriority"));
432  m_lastRecordedText = dynamic_cast<MythUIText *> (GetChild("lastrecorded"));
433  m_lastRecordedDateText = dynamic_cast<MythUIText *> (GetChild("lastrecordeddate"));
434  m_lastRecordedTimeText = dynamic_cast<MythUIText *> (GetChild("lastrecordedtime"));
435  m_channameText = dynamic_cast<MythUIText *> (GetChild("channel"));
436  m_channumText = dynamic_cast<MythUIText *> (GetChild("channum"));
437  m_callsignText = dynamic_cast<MythUIText *> (GetChild("callsign"));
438  m_recProfileText = dynamic_cast<MythUIText *> (GetChild("recordingprofile"));
439 
440  if (!m_programList)
441  {
442  LOG(VB_GENERAL, LOG_ERR, "Theme is missing critical theme elements.");
443  return false;
444  }
445 
446  connect(m_programList, SIGNAL(itemSelected(MythUIButtonListItem*)),
448  connect(m_programList, SIGNAL(itemClicked(MythUIButtonListItem*)),
449  SLOT(edit(MythUIButtonListItem*)));
450 
451  m_programList->SetLCDTitles(tr("Schedule Priorities"),
452  "rec_type|titlesubtitle|progpriority");
453  m_programList->SetSearchFields("titlesubtitle");
454 
455  BuildFocusList();
457 
458  return true;
459 }
460 
462 {
463  FillList();
464 }
465 
467 {
468  SortList();
469 }
470 
471 bool ProgramRecPriority::keyPressEvent(QKeyEvent *event)
472 {
473  if (GetFocusWidget()->keyPressEvent(event))
474  return true;
475 
476  bool handled = false;
477  QStringList actions;
478  handled = GetMythMainWindow()->TranslateKeyPress("TV Frontend", event, actions);
479 
480  for (int i = 0; i < actions.size() && !handled; i++)
481  {
482  QString action = actions[i];
483  handled = true;
484 
485  if (action == "RANKINC")
487  else if (action == "RANKDEC")
488  changeRecPriority(-1);
489  else if (action == "ESCAPE")
490  {
491  saveRecPriority();
492  gCoreContext->SaveSetting("ProgramRecPrioritySorting",
493  (int)m_sortType);
494  gCoreContext->SaveSetting("ProgramRecPriorityReverse",
495  (int)m_reverseSort);
496  Close();
497  }
498  else if (action == "1")
499  {
500  if (m_sortType != byTitle)
501  {
503  m_reverseSort = false;
504  }
505  else
507  SortList();
508  }
509  else if (action == "2")
510  {
511  if (m_sortType != byRecPriority)
512  {
514  m_reverseSort = false;
515  }
516  else
518  SortList();
519  }
520  else if (action == "4")
521  {
522  if (m_sortType != byRecType)
523  {
525  m_reverseSort = false;
526  }
527  else
529  SortList();
530  }
531  else if (action == "5")
532  {
533  if (m_sortType != byCount)
534  {
536  m_reverseSort = false;
537  }
538  else
539  {
541  }
542  SortList();
543  }
544  else if (action == "6")
545  {
546  if (m_sortType != byRecCount)
547  {
549  m_reverseSort = false;
550  }
551  else
553  SortList();
554  }
555  else if (action == "7")
556  {
557  if (m_sortType != byLastRecord)
558  {
560  m_reverseSort = false;
561  }
562  else
564  SortList();
565  }
566  else if (action == "8")
567  {
568  if (m_sortType != byAvgDelay)
569  {
571  m_reverseSort = false;
572  }
573  else
575  SortList();
576  }
577  else if (action == "PREVVIEW" || action == "NEXTVIEW")
578  {
579  m_reverseSort = false;
580  if (m_sortType == byTitle)
582  else if (m_sortType == byRecPriority)
584  else
586  SortList();
587  }
588  else if (action == "SELECT" || action == "EDIT")
589  {
590  saveRecPriority();
592  }
593  else if (action == "MENU")
594  {
595  showMenu();
596  }
597  else if (action == "CUSTOMEDIT")
598  {
599  saveRecPriority();
600  customEdit();
601  }
602  else if (action == "DELETE")
603  {
604  saveRecPriority();
605  remove();
606  }
607  else if (action == "UPCOMING")
608  {
609  saveRecPriority();
610  upcoming();
611  }
612  else if (action == "INFO" || action == "DETAILS")
613  details();
614  else
615  handled = false;
616  }
617 
618  if (!handled && MythScreenType::keyPressEvent(event))
619  handled = true;
620 
621  return handled;
622 }
623 
625 {
626  QString label = tr("Options");
627 
628  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
629  MythDialogBox *menuPopup = new MythDialogBox(label, popupStack, "menuPopup");
630 
631  if (menuPopup->Create())
632  {
633  menuPopup->SetReturnEvent(this, "menu");
634 
635  menuPopup->AddButton(tr("Increase Priority"));
636  menuPopup->AddButton(tr("Decrease Priority"));
637  menuPopup->AddButton(tr("Sort"), NULL, true);
638  menuPopup->AddButton(tr("Program Details"));
639  menuPopup->AddButton(tr("Upcoming"));
640  menuPopup->AddButton(tr("Custom Edit"));
641  menuPopup->AddButton(tr("Delete Rule"));
642  menuPopup->AddButton(tr("New Template"));
643 
644  popupStack->AddScreen(menuPopup);
645  }
646  else
647  {
648  delete menuPopup;
649  }
650 }
651 
653 {
654  QString label = tr("Sort Options");
655 
656  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
657  MythDialogBox *menuPopup = new MythDialogBox(label, popupStack, "menuPopup");
658 
659  if (menuPopup->Create())
660  {
661  menuPopup->SetReturnEvent(this, "sortmenu");
662 
663  menuPopup->AddButton(tr("Reverse Sort Order"));
664  menuPopup->AddButton(tr("Sort By Title"));
665  menuPopup->AddButton(tr("Sort By Priority"));
666  menuPopup->AddButton(tr("Sort By Type"));
667  menuPopup->AddButton(tr("Sort By Count"));
668  menuPopup->AddButton(tr("Sort By Record Count"));
669  menuPopup->AddButton(tr("Sort By Last Recorded"));
670  menuPopup->AddButton(tr("Sort By Average Delay"));
671 
672  popupStack->AddScreen(menuPopup);
673  }
674  else
675  {
676  delete menuPopup;
677  }
678 }
679 
681 {
682  if (event->type() == DialogCompletionEvent::kEventType)
683  {
685 
686  QString resultid = dce->GetId();
687  QString resulttext = dce->GetResultText();
688  int buttonnum = dce->GetResult();
689 
690  if (resultid == "menu")
691  {
692  if (resulttext == tr("Increase Priority"))
693  {
695  }
696  else if (resulttext == tr("Decrease Priority"))
697  {
698  changeRecPriority(-1);
699  }
700  else if (resulttext == tr("Sort"))
701  {
702  showSortMenu();
703  }
704  else if (resulttext == tr("Program Details"))
705  {
706  details();
707  }
708  else if (resulttext == tr("Upcoming"))
709  {
710  saveRecPriority();
711  upcoming();
712  }
713  else if (resulttext == tr("Custom Edit"))
714  {
715  saveRecPriority();
716  customEdit();
717  }
718  else if (resulttext == tr("Delete Rule"))
719  {
720  saveRecPriority();
721  remove();
722  }
723  else if (resulttext == tr("New Template"))
724  {
725  MythScreenStack *popupStack =
726  GetMythMainWindow()->GetStack("popup stack");
727  MythTextInputDialog *textInput =
728  new MythTextInputDialog(popupStack,
729  tr("Template Name"));
730  if (textInput->Create())
731  {
732  textInput->SetReturnEvent(this, "templatecat");
733  popupStack->AddScreen(textInput);
734  }
735  }
736  }
737  else if (resultid == "sortmenu")
738  {
739  if (resulttext == tr("Reverse Sort Order"))
740  {
742  SortList();
743  }
744  else if (resulttext == tr("Sort By Title"))
745  {
746  if (m_sortType != byTitle)
747  {
749  m_reverseSort = false;
750  }
751  else
753  SortList();
754  }
755  else if (resulttext == tr("Sort By Priority"))
756  {
757  if (m_sortType != byRecPriority)
758  {
760  m_reverseSort = false;
761  }
762  else
764  SortList();
765  }
766  else if (resulttext == tr("Sort By Type"))
767  {
768  if (m_sortType != byRecType)
769  {
771  m_reverseSort = false;
772  }
773  else
775  SortList();
776  }
777  else if (resulttext == tr("Sort By Count"))
778  {
779  if (m_sortType != byCount)
780  {
782  m_reverseSort = false;
783  }
784  else
785  {
787  }
788  SortList();
789  }
790  else if (resulttext == tr("Sort By Record Count"))
791  {
792  if (m_sortType != byRecCount)
793  {
795  m_reverseSort = false;
796  }
797  else
799  SortList();
800  }
801  else if (resulttext == tr("Sort By Last Recorded"))
802  {
803  if (m_sortType != byLastRecord)
804  {
806  m_reverseSort = false;
807  }
808  else
810  SortList();
811  }
812  else if (resulttext == tr("Sort By Average Delay"))
813  {
814  if (m_sortType != byAvgDelay)
815  {
817  m_reverseSort = false;
818  }
819  else
821  SortList();
822  }
823  }
824  else if (resultid == "deleterule")
825  {
826  RecordingRule *record =
827  qVariantValue<RecordingRule *>(dce->GetData());
828  if (record)
829  {
830  if (buttonnum > 0)
831  {
832  MythUIButtonListItem *item =
834 
835  if (record->Delete() && item)
836  RemoveItemFromList(item);
837  else
838  LOG(VB_GENERAL, LOG_ERR,
839  "Failed to delete recording rule");
840  }
841  delete record;
842  }
843  }
844  else if (resultid == "templatecat")
845  {
846  newTemplate(resulttext);
847  }
848  else
850  }
851 }
852 
854 {
855  if (!item)
856  return;
857 
858  ProgramRecPriorityInfo *pgRecInfo =
859  qVariantValue<ProgramRecPriorityInfo*>(item->GetData());
860 
861  if (!pgRecInfo)
862  return;
863 
864  RecordingRule *record = new RecordingRule();
865  record->m_recordID = pgRecInfo->GetRecordingRuleID();
866  if (record->m_searchType == kNoSearch)
867  record->LoadByProgram(pgRecInfo);
868 
870  ScheduleEditor *schededit = new ScheduleEditor(mainStack, record);
871  if (schededit->Create())
872  {
873  mainStack->AddScreen(schededit);
874  connect(schededit, SIGNAL(ruleSaved(int)), SLOT(scheduleChanged(int)));
875  connect(schededit, SIGNAL(ruleDeleted(int)), SLOT(scheduleChanged(int)));
876  }
877  else
878  delete schededit;
879 }
880 
881 void ProgramRecPriority::newTemplate(QString category)
882 {
883  category = category.trimmed();
884  if (category.isEmpty())
885  return;
886 
887  // Try to find an existing template and use it.
888  QMap<int, ProgramRecPriorityInfo>::Iterator it;
889  for (it = m_programData.begin(); it != m_programData.end(); ++it)
890  {
891  ProgramRecPriorityInfo *progInfo = &(*it);
892  if (progInfo->GetRecordingRuleType() == kTemplateRecord &&
893  category.compare(progInfo->GetCategory(),
894  Qt::CaseInsensitive) == 0)
895  {
896  m_programList->SetValueByData(qVariantFromValue(progInfo));
898  return;
899  }
900  }
901 
902  RecordingRule *record = new RecordingRule();
903  if (!record)
904  return;
905  record->MakeTemplate(category);
906 
908  ScheduleEditor *schededit = new ScheduleEditor(mainStack, record);
909  if (schededit->Create())
910  {
911  mainStack->AddScreen(schededit);
912  connect(schededit, SIGNAL(ruleSaved(int)), SLOT(scheduleChanged(int)));
913  connect(schededit, SIGNAL(ruleDeleted(int)), SLOT(scheduleChanged(int)));
914  }
915  else
916  delete schededit;
917 }
918 
920 {
921  // Assumes that the current item didn't change, which isn't guaranteed
923  ProgramRecPriorityInfo *pgRecInfo = NULL;
924  if (item)
925  pgRecInfo = qVariantValue<ProgramRecPriorityInfo*>(item->GetData());
926 
927  // If the recording id doesn't match, the user created a new
928  // template.
929  if (!pgRecInfo || recid != pgRecInfo->getRecordID())
930  {
931  RecordingRule record;
932  record.m_recordID = recid;
933  if (!record.Load() || record.m_type == kNotRecording)
934  return;
935 
936  ProgramRecPriorityInfo progInfo;
937  progInfo.SetRecordingRuleID(record.m_recordID);
938  progInfo.SetRecordingRuleType(record.m_type);
939  progInfo.SetTitle(record.m_title);
940  progInfo.SetCategory(record.m_category);
941  progInfo.SetRecordingPriority(record.m_recPriority);
942  progInfo.recType = record.m_type;
943  progInfo.sortTitle = record.m_title;
944  progInfo.recstatus = record.m_isInactive ?
946  progInfo.profile = record.m_recProfile;
947  progInfo.last_record = record.m_lastRecorded;
948 
949  m_programData[recid] = progInfo;
951  record.m_recPriority;
952  SortList(&m_programData[recid]);
953 
954  return;
955  }
956 
957  // We need to refetch the recording priority values since the Advanced
958  // Recording Options page could've been used to change them
959 
960  MSqlQuery query(MSqlQuery::InitCon());
961  query.prepare("SELECT recpriority, type, inactive "
962  "FROM record "
963  "WHERE recordid = :RECORDID");
964  query.bindValue(":RECORDID", recid);
965  if (!query.exec())
966  {
967  MythDB::DBError("Get new recording priority query", query);
968  }
969  else if (query.next())
970  {
971  int recPriority = query.value(0).toInt();
972  int rectype = query.value(1).toInt();
973  int inactive = query.value(2).toInt();
974 
975  // set the recording priorities of that program
976  pgRecInfo->SetRecordingPriority(recPriority);
977  pgRecInfo->recType = (RecordingType)rectype;
978  // also set the m_origRecPriorityData with new recording
979  // priority so we don't save to db again when we exit
981  pgRecInfo->GetRecordingPriority();
982  // also set the active/inactive state
983  pgRecInfo->recstatus = inactive ? rsInactive : rsUnknown;
984 
985  SortList();
986  }
987  else
988  {
989  RemoveItemFromList(item);
990  }
991 
992  countMatches();
993 }
994 
996 {
998  if (!item)
999  return;
1000 
1001  ProgramRecPriorityInfo *pgRecInfo =
1002  qVariantValue<ProgramRecPriorityInfo*>(item->GetData());
1003 
1004  EditCustom(pgRecInfo);
1005 }
1006 
1008 {
1010  if (!item)
1011  return;
1012 
1013  ProgramRecPriorityInfo *pgRecInfo =
1014  qVariantValue<ProgramRecPriorityInfo*>(item->GetData());
1015 
1016  if (!pgRecInfo ||
1017  (pgRecInfo->recType == kTemplateRecord &&
1018  pgRecInfo->GetCategory()
1019  .compare("Default", Qt::CaseInsensitive) == 0))
1020  {
1021  return;
1022  }
1023 
1024  RecordingRule *record = new RecordingRule();
1025  record->m_recordID = pgRecInfo->GetRecordingRuleID();
1026  if (!record->Load())
1027  {
1028  delete record;
1029  return;
1030  }
1031 
1032  QString message = tr("Delete '%1' %2 rule?").arg(record->m_title)
1033  .arg(toString(pgRecInfo->GetRecordingRuleType()));
1034 
1035  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1036 
1037  MythConfirmationDialog *okPopup = new MythConfirmationDialog(popupStack,
1038  message, true);
1039 
1040  okPopup->SetReturnEvent(this, "deleterule");
1041  okPopup->SetData(qVariantFromValue(record));
1042 
1043  if (okPopup->Create())
1044  popupStack->AddScreen(okPopup);
1045  else
1046  delete okPopup;
1047 }
1048 
1050 {
1052  if (!item)
1053  return;
1054 
1055  ProgramRecPriorityInfo *pgRecInfo =
1056  qVariantValue<ProgramRecPriorityInfo*>(item->GetData());
1057 
1058  if (pgRecInfo)
1059  {
1060  MSqlQuery query(MSqlQuery::InitCon());
1061 
1062  query.prepare("SELECT inactive "
1063  "FROM record "
1064  "WHERE recordid = :RECID");
1065  query.bindValue(":RECID", pgRecInfo->GetRecordingRuleID());
1066 
1067 
1068  if (!query.exec())
1069  {
1070  MythDB::DBError("ProgramRecPriority::deactivate()", query);
1071  }
1072  else if (query.next())
1073  {
1074  int inactive = query.value(0).toInt();
1075  if (inactive)
1076  inactive = 0;
1077  else
1078  inactive = 1;
1079 
1080  query.prepare("UPDATE record "
1081  "SET inactive = :INACTIVE "
1082  "WHERE recordid = :RECID");
1083  query.bindValue(":INACTIVE", inactive);
1084  query.bindValue(":RECID", pgRecInfo->GetRecordingRuleID());
1085 
1086  if (!query.exec())
1087  {
1089  "Update recording schedule inactive query", query);
1090  }
1091  else
1092  {
1094  QString("DeactivateRule %1 %2")
1095  .arg(pgRecInfo->GetRecordingRuleID())
1096  .arg(pgRecInfo->GetTitle()));
1097  pgRecInfo->recstatus = inactive ? rsInactive : rsUnknown;
1098  item->DisplayState("disabled", "status");
1099  }
1100  }
1101  }
1102 }
1103 
1105 {
1107  if (!item)
1108  return;
1109 
1110  ProgramRecPriorityInfo *pgRecInfo =
1111  qVariantValue<ProgramRecPriorityInfo*>(item->GetData());
1112 
1113  if (!pgRecInfo)
1114  return;
1115 
1116  if (m_listMatch[pgRecInfo->GetRecordingRuleID()] > 0)
1117  {
1119  ProgLister *pl = new ProgLister(
1120  mainStack, plRecordid,
1121  QString::number(pgRecInfo->GetRecordingRuleID()), "");
1122 
1123  if (pl->Create())
1124  mainStack->AddScreen(pl);
1125  else
1126  delete pl;
1127  }
1128  else
1129  {
1130  ProgLister *pl = NULL;
1131  QString trimTitle = pgRecInfo->title;
1132  trimTitle.remove(QRegExp(" \\(.*\\)$"));
1134  pl = new ProgLister(mainStack, plTitle, trimTitle,
1135  pgRecInfo->GetSeriesID());
1136  if (pl->Create())
1137  mainStack->AddScreen(pl);
1138  else
1139  delete pl;
1140  }
1141 }
1142 
1144 {
1146  if (!item)
1147  return;
1148 
1149  ProgramRecPriorityInfo *pgRecInfo = qVariantValue<ProgramRecPriorityInfo *>
1150  (item->GetData());
1151 
1152  ShowDetails(pgRecInfo);
1153 }
1154 
1156 {
1158  if (!item)
1159  return;
1160 
1161  ProgramRecPriorityInfo *pgRecInfo =
1162  qVariantValue<ProgramRecPriorityInfo*>(item->GetData());
1163 
1164  if (!pgRecInfo)
1165  return;
1166 
1167  int tempRecPriority;
1168  // inc/dec recording priority
1169  tempRecPriority = pgRecInfo->GetRecordingPriority() + howMuch;
1170  if (tempRecPriority > -100 && tempRecPriority < 100)
1171  {
1172  pgRecInfo->recpriority = tempRecPriority;
1173 
1174  // order may change if sorting by recording priority, so resort
1175  if (m_sortType == byRecPriority)
1176  SortList();
1177  else
1178  {
1179  // No need to re-fill the entire list, just update this entry
1180  int progRecPriority = pgRecInfo->GetRecordingPriority();
1181 
1182  item->SetText(QString::number(progRecPriority), "progpriority");
1183  item->SetText(QString::number(progRecPriority), "recpriority");
1184  if (m_recPriorityText)
1185  m_recPriorityText->SetText(QString::number(progRecPriority));
1186 
1187  item->SetText(QString::number(progRecPriority), "recpriorityB");
1188  if (m_recPriorityBText)
1189  m_recPriorityBText->SetText(QString::number(progRecPriority));
1190 
1191  item->SetText(QString::number(progRecPriority), "finalpriority");
1192  if (m_finalPriorityText)
1193  m_finalPriorityText->SetText(QString::number(progRecPriority));
1194  }
1195  }
1196 }
1197 
1199 {
1200  QMap<int, ProgramRecPriorityInfo>::Iterator it;
1201 
1202  for (it = m_programData.begin(); it != m_programData.end(); ++it)
1203  {
1204  ProgramRecPriorityInfo *progInfo = &(*it);
1205  int key = progInfo->GetRecordingRuleID();
1206 
1207  // if this program's recording priority changed from when we entered
1208  // save new value out to db
1209  if (progInfo->GetRecordingPriority() != m_origRecPriorityData[key])
1210  progInfo->ApplyRecordRecPriorityChange(
1211  progInfo->GetRecordingPriority());
1212  }
1213 }
1214 
1216 {
1217  vector<ProgramInfo *> recordinglist;
1218 
1219  m_programData.clear();
1220 
1221  RemoteGetAllScheduledRecordings(recordinglist);
1222 
1223  vector<ProgramInfo *>::iterator pgiter = recordinglist.begin();
1224 
1225  for (; pgiter != recordinglist.end(); ++pgiter)
1226  {
1227  ProgramInfo *progInfo = *pgiter;
1228  m_programData[(*pgiter)->GetRecordingRuleID()] =
1229  (*progInfo);
1230 
1231  // save recording priority value in map so we don't have to
1232  // save all program's recording priority values when we exit
1233  m_origRecPriorityData[(*pgiter)->GetRecordingRuleID()] =
1234  (*pgiter)->GetRecordingPriority();
1235 
1236  delete (*pgiter);
1237  }
1238 
1239  // get recording types associated with each program from db
1240  // (hope this is ok to do here, it's so much lighter doing
1241  // it all at once than once per program)
1242 
1243  MSqlQuery result(MSqlQuery::InitCon());
1244  result.prepare("SELECT recordid, title, chanid, starttime, startdate, "
1245  "type, inactive, last_record, avg_delay, profile "
1246  "FROM record;");
1247 
1248  if (!result.exec())
1249  {
1250  MythDB::DBError("Get program recording priorities query", result);
1251  }
1252  else if (result.next())
1253  {
1254  countMatches();
1255  do {
1256  uint recordid = result.value(0).toUInt();
1257  QString title = result.value(1).toString();
1258  QString chanid = result.value(2).toString();
1259  QString tempTime = result.value(3).toString();
1260  QString tempDate = result.value(4).toString();
1261  RecordingType recType = (RecordingType)result.value(5).toInt();
1262  int inactive = result.value(6).toInt();
1263  QDateTime lastrec = MythDate::as_utc(result.value(7).toDateTime());
1264  int avgd = result.value(8).toInt();
1265  QString profile = result.value(9).toString();
1266 
1267  // find matching program in m_programData and set
1268  // recType
1269  QMap<int, ProgramRecPriorityInfo>::Iterator it;
1270  it = m_programData.find(recordid);
1271  if (it != m_programData.end())
1272  {
1273  ProgramRecPriorityInfo *progInfo = &(*it);
1274 
1275  progInfo->sortTitle = progInfo->title;
1276  progInfo->sortTitle.remove(QRegExp(tr("^(The |A |An )")));
1277 
1278  progInfo->recType = recType;
1279  progInfo->matchCount =
1280  m_listMatch[progInfo->GetRecordingRuleID()];
1281  progInfo->recCount =
1282  m_recMatch[progInfo->GetRecordingRuleID()];
1283  progInfo->last_record = lastrec;
1284  progInfo->avg_delay = avgd;
1285  progInfo->profile = profile;
1286 
1287  if (inactive)
1288  progInfo->recstatus = rsInactive;
1289  else if (m_conMatch[progInfo->GetRecordingRuleID()] > 0)
1290  progInfo->recstatus = rsConflict;
1291  else if (m_nowMatch[progInfo->GetRecordingRuleID()] > 0)
1292  progInfo->recstatus = rsRecording;
1293  else if (m_recMatch[progInfo->GetRecordingRuleID()] > 0)
1294  progInfo->recstatus = rsWillRecord;
1295  else
1296  progInfo->recstatus = rsUnknown;
1297  }
1298  } while (result.next());
1299  }
1300 }
1301 
1303 {
1304  m_listMatch.clear();
1305  m_conMatch.clear();
1306  m_nowMatch.clear();
1307  m_recMatch.clear();
1308  ProgramList schedList;
1309  LoadFromScheduler(schedList);
1310  QDateTime now = MythDate::current();
1311 
1312  ProgramList::const_iterator it = schedList.begin();
1313  for (; it != schedList.end(); ++it)
1314  {
1315  const RecStatusType recstatus = (**it).GetRecordingStatus();
1316  const uint recordid = (**it).GetRecordingRuleID();
1317  if ((**it).GetRecordingEndTime() > now && recstatus != rsNotListed)
1318  {
1319  m_listMatch[recordid]++;
1320  if (recstatus == rsConflict || recstatus == rsOffLine)
1321  m_conMatch[recordid]++;
1322  else if (recstatus == rsWillRecord)
1323  m_recMatch[recordid]++;
1324  else if (recstatus == rsRecording)
1325  {
1326  m_nowMatch[recordid]++;
1327  m_recMatch[recordid]++;
1328  }
1329  }
1330  }
1331 }
1332 
1334 {
1335  if (newCurrentItem)
1336  m_currentItem = newCurrentItem;
1337  else
1338  {
1340  if (item)
1341  m_currentItem =
1342  qVariantValue<ProgramRecPriorityInfo*>(item->GetData());
1343  }
1344 
1345  QMap<int, ProgramRecPriorityInfo>::Iterator pit;
1346  vector<ProgramRecPriorityInfo *>::iterator sit;
1347 
1348  // copy m_programData into m_sortedProgram
1349  m_sortedProgram.clear();
1350  for (pit = m_programData.begin(); pit != m_programData.end(); ++pit)
1351  {
1352  ProgramRecPriorityInfo *progInfo = &(*pit);
1353  m_sortedProgram.push_back(progInfo);
1354  }
1355 
1356  // sort m_sortedProgram
1357  switch (m_sortType)
1358  {
1359  case byTitle :
1360  sort(m_sortedProgram.begin(), m_sortedProgram.end(),
1362  break;
1363  case byRecPriority :
1364  sort(m_sortedProgram.begin(), m_sortedProgram.end(),
1366  break;
1367  case byRecType :
1368  sort(m_sortedProgram.begin(), m_sortedProgram.end(),
1370  break;
1371  case byCount :
1372  sort(m_sortedProgram.begin(), m_sortedProgram.end(),
1374  break;
1375  case byRecCount :
1376  sort(m_sortedProgram.begin(), m_sortedProgram.end(),
1378  break;
1379  case byLastRecord :
1380  sort(m_sortedProgram.begin(), m_sortedProgram.end(),
1382  break;
1383  case byAvgDelay :
1384  sort(m_sortedProgram.begin(), m_sortedProgram.end(),
1386  break;
1387  }
1388 
1389  UpdateList();
1390 }
1391 
1393 {
1394  if (!m_currentItem && !m_programList->IsEmpty())
1395  m_currentItem = qVariantValue<ProgramRecPriorityInfo*>
1397 
1398  m_programList->Reset();
1399 
1400  vector<ProgramRecPriorityInfo*>::iterator it;
1401  MythUIButtonListItem *item;
1402  for (it = m_sortedProgram.begin(); it != m_sortedProgram.end(); ++it)
1403  {
1404  ProgramRecPriorityInfo *progInfo = *it;
1405 
1406  item = new MythUIButtonListItem(m_programList, "",
1407  qVariantFromValue(progInfo));
1408 
1409  int progRecPriority = progInfo->GetRecordingPriority();
1410 
1411  if ((progInfo->rectype == kSingleRecord ||
1412  progInfo->rectype == kOverrideRecord ||
1413  progInfo->rectype == kDontRecord) &&
1414  !(progInfo->GetSubtitle()).trimmed().isEmpty())
1415  {
1416  QString rating = QString::number(progInfo->GetStars(10));
1417 
1418  item->DisplayState(rating, "ratingstate");
1419  }
1420  else
1421  progInfo->subtitle.clear();
1422 
1423  QString state;
1424  if (progInfo->recType == kDontRecord ||
1425  (progInfo->recType != kTemplateRecord &&
1426  progInfo->recstatus == rsInactive))
1427  state = "disabled";
1428  else if (m_conMatch[progInfo->GetRecordingRuleID()] > 0)
1429  state = "error";
1430  else if (m_recMatch[progInfo->GetRecordingRuleID()] > 0 ||
1431  progInfo->recType == kTemplateRecord)
1432  state = "normal";
1433  else if (m_nowMatch[progInfo->GetRecordingRuleID()] > 0)
1434  state = "running";
1435  else
1436  state = "warning";
1437 
1438  InfoMap infoMap;
1439  progInfo->ToMap(infoMap);
1440  item->SetTextFromMap(infoMap, state);
1441 
1442  QString subtitle;
1443  if (progInfo->subtitle != "(null)" &&
1444  (progInfo->rectype == kSingleRecord ||
1445  progInfo->rectype == kOverrideRecord ||
1446  progInfo->rectype == kDontRecord))
1447  {
1448  subtitle = progInfo->subtitle;
1449  }
1450 
1451  QString matchInfo;
1452  if (progInfo->GetRecordingStatus() == rsInactive)
1453  {
1454  matchInfo = QString("%1 %2")
1455  .arg(m_listMatch[progInfo->GetRecordingRuleID()])
1456  .arg(toString(progInfo->GetRecordingStatus(),
1457  progInfo->GetRecordingRuleType()));
1458  }
1459  else
1460  matchInfo = tr("Recording %1 of %2")
1461  .arg(m_recMatch[progInfo->GetRecordingRuleID()])
1462  .arg(m_listMatch[progInfo->GetRecordingRuleID()]);
1463 
1464  subtitle = QString("(%1) %2").arg(matchInfo).arg(subtitle);
1465  item->SetText(subtitle, "scheduleinfo", state);
1466 
1467  item->SetText(QString::number(progRecPriority), "progpriority", state);
1468  item->SetText(QString::number(progRecPriority), "finalpriority", state);
1469 
1470  item->SetText(QString::number(progRecPriority), "recpriority", state);
1471  item->SetText(QString::number(progRecPriority), "recpriorityB", state);
1472 
1473  QString tempDateTime = MythDate::toString(progInfo->last_record,
1476  item->SetText(tempDateTime, "lastrecorded", state);
1477  QString tempDate = MythDate::toString(progInfo->last_record,
1480  item->SetText(tempDate, "lastrecordeddate", state);
1481  QString tempTime = MythDate::toString(
1482  progInfo->last_record, MythDate::kTime);
1483  item->SetText(tempTime, "lastrecordedtime", state);
1484 
1485  QString channame = progInfo->channame;
1486  if ((progInfo->recType == kAllRecord) ||
1487  (progInfo->recType == kOneRecord) ||
1488  (progInfo->recType == kDailyRecord) ||
1489  (progInfo->recType == kWeeklyRecord))
1490  channame = tr("Any");
1491  item->SetText(channame, "channel", state);
1492  QString channum = progInfo->chanstr;
1493  if ((progInfo->recType == kAllRecord) ||
1494  (progInfo->recType == kOneRecord) ||
1495  (progInfo->recType == kDailyRecord) ||
1496  (progInfo->recType == kWeeklyRecord))
1497  channum = tr("Any");
1498  item->SetText(channum, "channum", state);
1499  QString callsign = progInfo->chansign;
1500  if ((progInfo->recType == kAllRecord) ||
1501  (progInfo->recType == kOneRecord) ||
1502  (progInfo->recType == kDailyRecord) ||
1503  (progInfo->recType == kWeeklyRecord))
1504  callsign = tr("Any");
1505  item->SetText(callsign, "callsign", state);
1506 
1507  QString profile = progInfo->profile;
1508  if ((profile == "Default") || (profile == "Live TV") ||
1509  (profile == "High Quality") || (profile == "Low Quality"))
1510  profile = tr(profile.toUtf8().constData());
1511  item->SetText(profile, "recordingprofile", state);
1512  item->DisplayState(state, "status");
1513 
1514  if (m_currentItem == progInfo)
1516  }
1517 
1518  m_currentItem = NULL;
1519 
1520  MythUIText *norecordingText = dynamic_cast<MythUIText*>
1521  (GetChild("norecordings_info"));
1522 
1523  if (norecordingText)
1524  norecordingText->SetVisible(m_programData.isEmpty());
1525 }
1526 
1528 {
1529  if (!item)
1530  return;
1531 
1532  ProgramRecPriorityInfo *pgRecInfo = qVariantValue<ProgramRecPriorityInfo *>
1533  (item->GetData());
1534 
1535  if (!pgRecInfo)
1536  return;
1537 
1538  int progRecPriority = pgRecInfo->GetRecordingPriority();
1539 
1540  QString subtitle;
1541  if (pgRecInfo->subtitle != "(null)" &&
1542  (pgRecInfo->rectype == kSingleRecord ||
1543  pgRecInfo->rectype == kOverrideRecord ||
1544  pgRecInfo->rectype == kDontRecord))
1545  {
1546  subtitle = pgRecInfo->subtitle;
1547  }
1548 
1549  QString matchInfo;
1550  if (pgRecInfo->GetRecordingStatus() == rsInactive)
1551  {
1552  matchInfo = QString("%1 %2")
1553  .arg(m_listMatch[pgRecInfo->GetRecordingRuleID()])
1554  .arg(toString(pgRecInfo->GetRecordingStatus(),
1555  pgRecInfo->GetRecordingRuleType()));
1556  }
1557  else
1558  matchInfo = tr("Recording %1 of %2")
1559  .arg(m_recMatch[pgRecInfo->GetRecordingRuleID()])
1560  .arg(m_listMatch[pgRecInfo->GetRecordingRuleID()]);
1561 
1562  subtitle = QString("(%1) %2").arg(matchInfo).arg(subtitle);
1563 
1564  InfoMap infoMap;
1565  pgRecInfo->ToMap(infoMap);
1566  SetTextFromMap(infoMap);
1567 
1568  if (m_schedInfoText)
1569  m_schedInfoText->SetText(subtitle);
1570 
1571  if (m_recPriorityText)
1572  m_recPriorityText->SetText(QString::number(progRecPriority));
1573 
1574  if (m_recPriorityBText)
1575  m_recPriorityBText->SetText(QString::number(progRecPriority));
1576 
1577  if (m_finalPriorityText)
1578  m_finalPriorityText->SetText(QString::number(progRecPriority));
1579 
1580  if (m_lastRecordedText)
1581  {
1582  QString tempDateTime = MythDate::toString(pgRecInfo->last_record,
1585  m_lastRecordedText->SetText(tempDateTime);
1586  }
1587 
1589  {
1590  QString tempDate = MythDate::toString(pgRecInfo->last_record,
1593  m_lastRecordedDateText->SetText(tempDate);
1594  }
1595 
1597  {
1598  QString tempTime = MythDate::toString(
1599  pgRecInfo->last_record, MythDate::kTime);
1600  m_lastRecordedTimeText->SetText(tempTime);
1601  }
1602 
1603  if (m_channameText)
1604  {
1605  QString channame = pgRecInfo->channame;
1606  if ((pgRecInfo->rectype == kAllRecord) ||
1607  (pgRecInfo->rectype == kOneRecord) ||
1608  (pgRecInfo->rectype == kDailyRecord) ||
1609  (pgRecInfo->rectype == kWeeklyRecord))
1610  channame = tr("Any");
1611  m_channameText->SetText(channame);
1612  }
1613 
1614  if (m_channumText)
1615  {
1616  QString channum = pgRecInfo->chanstr;
1617  if ((pgRecInfo->rectype == kAllRecord) ||
1618  (pgRecInfo->rectype == kOneRecord) ||
1619  (pgRecInfo->rectype == kDailyRecord) ||
1620  (pgRecInfo->rectype == kWeeklyRecord))
1621  channum = tr("Any");
1622  m_channumText->SetText(channum);
1623  }
1624 
1625  if (m_callsignText)
1626  {
1627  QString callsign = pgRecInfo->chansign;
1628  if ((pgRecInfo->rectype == kAllRecord) ||
1629  (pgRecInfo->rectype == kOneRecord) ||
1630  (pgRecInfo->rectype == kDailyRecord) ||
1631  (pgRecInfo->rectype == kWeeklyRecord))
1632  callsign = tr("Any");
1633  m_callsignText->SetText(callsign);
1634  }
1635 
1636  if (m_recProfileText)
1637  {
1638  QString profile = pgRecInfo->profile;
1639  if ((profile == "Default") || (profile == "Live TV") ||
1640  (profile == "High Quality") || (profile == "Low Quality"))
1641  profile = tr(profile.toUtf8().constData());
1642  m_recProfileText->SetText(profile);
1643  }
1644 
1645 }
1646 
1648 {
1649  if (!item)
1650  return;
1651 
1652  ProgramRecPriorityInfo *pgRecInfo = qVariantValue<ProgramRecPriorityInfo *>
1653  (item->GetData());
1654 
1655  if (!pgRecInfo)
1656  return;
1657 
1658  QMap<int, ProgramRecPriorityInfo>::iterator it;
1659  it = m_programData.find(pgRecInfo->GetRecordingRuleID());
1660  if (it != m_programData.end())
1661  m_programData.erase(it);
1662 
1663  m_programList->RemoveItem(item);
1664 }
1665 
1666 /* vim: set expandtab tabstop=4 shiftwidth=4: */