Changeset d418754c9 in mythtv


Ignore:
Timestamp:
May 21, 2012, 10:01:01 PM (12 years ago)
Author:
David Engel <dengel@…>
Branches:
devel/2020-player, devel/ffmpeg-resync, devel/gpu-commflag, fixes/0.26, fixes/0.27, fixes/0.28, fixes/29, fixes/30, fixes/31, github-templates, master
Children:
461f42d14
Parents:
f38e299719
Message:

Schedule editor flexibility and other enhancements.

Note: no theme changes are required with this commit, however, two
changes are recommended. See below.

The primary change in this commit allows options from the schedule,
storage and post processing options screens to optionally appear on
the main screen. This serves two purposes. One, a theme can be
targeted at novice users by putting only the most basic options on the
main screen and requiring use of the menu to access the more advanced
options. Two, power users can put the options they use most
frequently on the amin screen.

Other enhancements to the schedule editor in this commit include the
following.

All buttons on the main screen except those for rule type and save are
now optional. Any applicable functionality is always available by
pressing MENU so there is no longer a need to have a button for each
child option screen. This change is mainly to make room on the main
screen for the new, optional settings.

A new, optional setting called "newrepeat" splits the kDupsNewEpi
functionality out from the poorly overloaded "dupscope" setting. If
the "newrepeat" setting is found in the theme, the "dupscope" setting
does not include the "Record new episodes only" option.

The INFO and UPCOMING actions now work like they do in most other
places in mythfrontend.

The PREVVIEW and NEXTVIEW actions cycle through the main screen and
all of the applicable child screens.

The Filter options screen is logically at the same level as the other
child option screens. If the theme includes a "Filter" button on the
Schedule options screen, it should either be removed or moved to the
main screen. If the theme cascades the child option screens, the
Filter options screen should use the same positioning as the other
child option screens.

The Metadata options screen no longer performs an automatic lookup
when the inetref is not set.

An optional save button can be on any of the child options screens.

Location:
mythtv/programs/mythfrontend
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • mythtv/programs/mythfrontend/scheduleeditor.cpp

    rf38e299719 rd418754c9  
    7979                               RecordingInfo *recInfo, TV *player)
    8080          : ScheduleCommon(parent, "ScheduleEditor"),
     81            SchedOptMixin(*this, NULL), StoreOptMixin(*this, NULL),
     82            PostProcMixin(*this, NULL),
    8183            m_recInfo(new RecordingInfo(*recInfo)), m_recordingRule(NULL),
    8284            m_sendSig(false),
     
    8587            m_postProcButton(NULL), m_schedInfoButton(NULL),
    8688            m_previewButton(NULL), m_metadataButton(NULL),
    87             m_player(player)
     89            m_filtersButton(NULL),
     90            m_player(player), m_loaded(false), m_view(kMainView), m_child(NULL)
    8891{
    8992    m_recordingRule = new RecordingRule();
    9093    m_recordingRule->m_recordID = m_recInfo->GetRecordingRuleID();
     94    SchedOptMixin::SetRule(m_recordingRule);
     95    StoreOptMixin::SetRule(m_recordingRule);
     96    PostProcMixin::SetRule(m_recordingRule);
    9197}
    9298
     
    94100                               RecordingRule *recRule, TV *player)
    95101          : ScheduleCommon(parent, "ScheduleEditor"),
     102            SchedOptMixin(*this, recRule),
     103            StoreOptMixin(*this, recRule),
     104            PostProcMixin(*this, recRule),
    96105            m_recInfo(NULL), m_recordingRule(recRule),
    97106            m_sendSig(false),
     
    100109            m_postProcButton(NULL), m_schedInfoButton(NULL),
    101110            m_previewButton(NULL), m_metadataButton(NULL),
    102             m_player(player)
     111            m_filtersButton(NULL),
     112            m_player(player), m_loaded(false), m_view(kMainView), m_child(NULL)
    103113{
    104114}
     
    125135    UIUtilE::Assign(this, m_rulesList, "rules", &err);
    126136
    127     UIUtilE::Assign(this, m_schedOptButton, "schedoptions", &err);
    128     UIUtilE::Assign(this, m_storeOptButton, "storeoptions", &err);
    129     UIUtilE::Assign(this, m_postProcButton, "postprocessing", &err);
    130     UIUtilE::Assign(this, m_schedInfoButton, "schedinfo", &err);
    131     UIUtilE::Assign(this, m_previewButton, "preview", &err);
    132     UIUtilE::Assign(this, m_metadataButton, "metadata", &err);
    133 
    134     UIUtilE::Assign(this, m_cancelButton, "cancel", &err);
     137    UIUtilW::Assign(this, m_schedOptButton, "schedoptions");
     138    UIUtilW::Assign(this, m_storeOptButton, "storeoptions");
     139    UIUtilW::Assign(this, m_postProcButton, "postprocessing");
     140    UIUtilW::Assign(this, m_metadataButton, "metadata");
     141    UIUtilW::Assign(this, m_schedInfoButton, "schedinfo");
     142    UIUtilW::Assign(this, m_previewButton, "preview");
     143    UIUtilW::Assign(this, m_filtersButton, "filters");
     144
     145    SchedOptMixin::Create(&err);
     146    StoreOptMixin::Create(&err);
     147    PostProcMixin::Create(&err);
     148
     149    UIUtilW::Assign(this, m_cancelButton, "cancel");
    135150    UIUtilE::Assign(this, m_saveButton, "save", &err);
    136151
     
    145160                         SLOT(RuleChanged(MythUIButtonListItem *)));
    146161
    147     connect(m_schedOptButton, SIGNAL(Clicked()), SLOT(ShowSchedOpt()));
    148     connect(m_storeOptButton, SIGNAL(Clicked()), SLOT(ShowStoreOpt()));
    149     connect(m_postProcButton, SIGNAL(Clicked()), SLOT(ShowPostProc()));
    150     connect(m_schedInfoButton, SIGNAL(Clicked()), SLOT(ShowSchedInfo()));
    151     connect(m_previewButton, SIGNAL(Clicked()), SLOT(ShowPreview()));
    152     connect(m_metadataButton, SIGNAL(Clicked()), SLOT(ShowMetadataOptions()));
    153 
    154     connect(m_cancelButton, SIGNAL(Clicked()), SLOT(Close()));
     162    if (m_schedOptButton)
     163        connect(m_schedOptButton, SIGNAL(Clicked()), SLOT(ShowSchedOpt()));
     164    if (m_filtersButton)
     165        connect(m_filtersButton, SIGNAL(Clicked()), SLOT(ShowFilters()));
     166    if (m_storeOptButton)
     167        connect(m_storeOptButton, SIGNAL(Clicked()), SLOT(ShowStoreOpt()));
     168    if (m_postProcButton)
     169        connect(m_postProcButton, SIGNAL(Clicked()), SLOT(ShowPostProc()));
     170    if (m_schedInfoButton)
     171        connect(m_schedInfoButton, SIGNAL(Clicked()), SLOT(ShowSchedInfo()));
     172    if (m_previewButton)
     173        connect(m_previewButton, SIGNAL(Clicked()), SLOT(ShowPreview()));
     174    if (m_metadataButton)
     175        connect(m_metadataButton, SIGNAL(Clicked()), SLOT(ShowMetadataOptions()));
     176
     177    if (m_cancelButton)
     178        connect(m_cancelButton, SIGNAL(Clicked()), SLOT(Close()));
    155179    connect(m_saveButton, SIGNAL(Clicked()), SLOT(Save()));
    156180
    157     m_schedInfoButton->SetEnabled(!m_recordingRule->m_isTemplate);
    158     m_previewButton->SetEnabled(!m_recordingRule->m_isTemplate);
    159     m_metadataButton->SetEnabled(!m_recordingRule->m_isTemplate);
     181    if (m_metadataButton)
     182        m_metadataButton->SetEnabled(!m_recordingRule->m_isTemplate);
     183    if (m_schedInfoButton)
     184        m_schedInfoButton->SetEnabled(!m_recordingRule->m_isTemplate);
     185    if (m_previewButton)
     186        m_previewButton->SetEnabled(!m_recordingRule->m_isTemplate);
     187
     188    if (m_dupmethodList)
     189        connect(m_dupmethodList, SIGNAL(itemSelected(MythUIButtonListItem *)),
     190                SLOT(DupMethodChanged(MythUIButtonListItem *)));
     191    if (m_maxepSpin)
     192        connect(m_maxepSpin, SIGNAL(itemSelected(MythUIButtonListItem *)),
     193                SLOT(MaxEpisodesChanged(MythUIButtonListItem *)));
     194    if (m_recgroupList)
     195        connect(m_recgroupList, SIGNAL(LosingFocus()),
     196                SLOT(PromptForRecGroup()));
     197    if (m_transcodeCheck)
     198        connect(m_transcodeCheck, SIGNAL(toggled(bool)),
     199                SLOT(TranscodeChanged(bool)));
    160200
    161201    BuildFocusList();
     
    184224void ScheduleEditor::Close()
    185225{
     226    if (m_child)
     227        m_child->Close();
     228
    186229    // don't fade the screen if we are returning to the player
    187230    if (m_player)
     
    193236void ScheduleEditor::Load()
    194237{
    195     // Copy this now, it will change briefly after the first item is inserted
    196     // into the list by design of MythUIButtonList::itemSelected()
    197     RecordingType type = m_recordingRule->m_type;
    198 
    199     // Rules List
    200     if (m_recordingRule->m_isTemplate)
    201     {
    202         if (m_recordingRule->m_category
    203             .compare("Default", Qt::CaseInsensitive) != 0)
    204         {
     238    SchedOptMixin::Load();
     239    StoreOptMixin::Load();
     240    PostProcMixin::Load();
     241
     242    if (!m_loaded)
     243    {
     244        // Copy this now, it will change briefly after the first item
     245        // is inserted into the list by design of
     246        // MythUIButtonList::itemSelected()
     247        RecordingType type = m_recordingRule->m_type;
     248
     249        // Rules List
     250        if (m_recordingRule->m_isTemplate)
     251        {
     252            if (m_recordingRule->m_category
     253                .compare("Default", Qt::CaseInsensitive) != 0)
     254            {
     255                new MythUIButtonListItem(m_rulesList,
     256                                     tr("Delete this recording rule template"),
     257                                         ENUM_TO_QVARIANT(kNotRecording));
     258            }
    205259            new MythUIButtonListItem(m_rulesList,
    206                                      tr("Delete this recording rule template"),
     260                                     tr("Modify this recording rule template"),
     261                                     ENUM_TO_QVARIANT(kTemplateRecord));
     262        }
     263        else if (m_recordingRule->m_isOverride)
     264        {
     265            new MythUIButtonListItem(m_rulesList,
     266                                 tr("Record this showing with normal options"),
    207267                                     ENUM_TO_QVARIANT(kNotRecording));
    208         }
    209         new MythUIButtonListItem(m_rulesList,
    210                                  tr("Modify this recording rule template"),
    211                                  ENUM_TO_QVARIANT(kTemplateRecord));
    212     }
    213     else if (m_recordingRule->m_isOverride)
    214     {
    215         new MythUIButtonListItem(m_rulesList,
    216                                  tr("Record this showing with normal options"),
    217                                  ENUM_TO_QVARIANT(kNotRecording));
    218         new MythUIButtonListItem(m_rulesList,
    219                                  tr("Record this showing with override options"),
    220                                  ENUM_TO_QVARIANT(kOverrideRecord));
    221         new MythUIButtonListItem(m_rulesList,
    222                                  tr("Do not allow this showing to be recorded"),
    223                                  ENUM_TO_QVARIANT(kDontRecord));
    224     }
    225     else
    226     {
    227         bool hasChannel = !m_recordingRule->m_station.isEmpty();
    228         bool isManual = (m_recordingRule->m_searchType == kManualSearch);
    229 
    230         new MythUIButtonListItem(m_rulesList, tr("Do not record this program"),
    231                                  ENUM_TO_QVARIANT(kNotRecording));
    232 
    233         if (hasChannel)
    234268            new MythUIButtonListItem(m_rulesList,
    235                                      tr("Record only this showing"),
    236                                      ENUM_TO_QVARIANT(kSingleRecord));
    237         if (!isManual)
     269                               tr("Record this showing with override options"),
     270                                     ENUM_TO_QVARIANT(kOverrideRecord));
    238271            new MythUIButtonListItem(m_rulesList,
    239                                      tr("Record one showing of this title"),
    240                                      ENUM_TO_QVARIANT(kFindOneRecord));
    241         if (hasChannel)
    242             new MythUIButtonListItem(m_rulesList,
    243                                      tr("Record in this timeslot every week"),
    244                                      ENUM_TO_QVARIANT(kWeekslotRecord));
    245         if (!isManual)
    246             new MythUIButtonListItem(m_rulesList,
    247                                      tr("Record one showing of this title every week"),
    248                                      ENUM_TO_QVARIANT(kFindWeeklyRecord));
    249         if (hasChannel)
    250             new MythUIButtonListItem(m_rulesList,
    251                                      tr("Record in this timeslot every day"),
    252                                      ENUM_TO_QVARIANT(kTimeslotRecord));
    253         if (!isManual)
    254             new MythUIButtonListItem(m_rulesList,
    255                                      tr("Record one showing of this title every day"),
    256                                      ENUM_TO_QVARIANT(kFindDailyRecord));
    257         if (hasChannel && !isManual)
    258             new MythUIButtonListItem(m_rulesList,
    259                                      tr("Record at any time on this channel"),
    260                                      ENUM_TO_QVARIANT(kChannelRecord));
    261         if (!isManual)
    262             new MythUIButtonListItem(m_rulesList,
    263                                      tr("Record at any time on any channel"),
    264                                      ENUM_TO_QVARIANT(kAllRecord));
    265     }
    266     m_rulesList->SetValueByData(ENUM_TO_QVARIANT(type));
     272                                tr("Do not allow this showing to be recorded"),
     273                                     ENUM_TO_QVARIANT(kDontRecord));
     274        }
     275        else
     276        {
     277            bool hasChannel = !m_recordingRule->m_station.isEmpty();
     278            bool isManual = (m_recordingRule->m_searchType == kManualSearch);
     279
     280            new MythUIButtonListItem(m_rulesList,
     281                                     tr("Do not record this program"),
     282                                     ENUM_TO_QVARIANT(kNotRecording));
     283
     284            if (hasChannel)
     285                new MythUIButtonListItem(m_rulesList,
     286                                         tr("Record only this showing"),
     287                                         ENUM_TO_QVARIANT(kSingleRecord));
     288            if (!isManual)
     289                new MythUIButtonListItem(m_rulesList,
     290                                        tr("Record one showing of this title"),
     291                                         ENUM_TO_QVARIANT(kFindOneRecord));
     292            if (hasChannel)
     293                new MythUIButtonListItem(m_rulesList,
     294                                      tr("Record in this timeslot every week"),
     295                                         ENUM_TO_QVARIANT(kWeekslotRecord));
     296            if (!isManual)
     297                new MythUIButtonListItem(m_rulesList,
     298                             tr("Record one showing of this title every week"),
     299                                         ENUM_TO_QVARIANT(kFindWeeklyRecord));
     300            if (hasChannel)
     301                new MythUIButtonListItem(m_rulesList,
     302                                       tr("Record in this timeslot every day"),
     303                                         ENUM_TO_QVARIANT(kTimeslotRecord));
     304            if (!isManual)
     305                new MythUIButtonListItem(m_rulesList,
     306                              tr("Record one showing of this title every day"),
     307                                         ENUM_TO_QVARIANT(kFindDailyRecord));
     308            if (hasChannel && !isManual)
     309                new MythUIButtonListItem(m_rulesList,
     310                                      tr("Record at any time on this channel"),
     311                                         ENUM_TO_QVARIANT(kChannelRecord));
     312            if (!isManual)
     313                new MythUIButtonListItem(m_rulesList,
     314                                         ("Record at any time on any channel"),
     315                                         ENUM_TO_QVARIANT(kAllRecord));
     316        }
     317
     318        m_recordingRule->m_type = type;
     319    }
     320    m_rulesList->SetValueByData(ENUM_TO_QVARIANT(m_recordingRule->m_type));
    267321
    268322    InfoMap progMap;
     
    274328
    275329    SetTextFromMap(progMap);
     330
     331    m_loaded = true;
    276332}
    277333
     
    279335{
    280336    m_recordingRule->LoadTemplate(name);
    281 
    282     InfoMap progMap;
    283     m_recordingRule->ToMap(progMap);
    284     if (m_recInfo)
    285         m_recInfo->ToMap(progMap);
    286     SetTextFromMap(progMap);
     337    Load();
     338    emit templateLoaded();
    287339}
    288340
     
    292344        return;
    293345
    294     RecordingType type = static_cast<RecordingType>(item->GetData().toInt());
    295 
    296     bool isScheduled = (type != kNotRecording);
    297 
    298     m_schedOptButton->SetEnabled(isScheduled);
    299     m_storeOptButton->SetEnabled(isScheduled);
    300     m_postProcButton->SetEnabled(isScheduled);
    301 
    302     m_recordingRule->m_type = type;
     346    m_recordingRule->m_type = static_cast<RecordingType>
     347        (item->GetData().toInt());
     348
     349    bool isScheduled = (m_recordingRule->m_type != kNotRecording &&
     350                        m_recordingRule->m_type != kDontRecord);
     351
     352    if (m_schedOptButton)
     353        m_schedOptButton->SetEnabled(isScheduled);
     354    if (m_filtersButton)
     355        m_filtersButton->SetEnabled(isScheduled);
     356    if (m_storeOptButton)
     357        m_storeOptButton->SetEnabled(isScheduled);
     358    if (m_postProcButton)
     359        m_postProcButton->SetEnabled(isScheduled);
     360
     361    SchedOptMixin::RuleChanged();
     362    StoreOptMixin::RuleChanged();
     363    PostProcMixin::RuleChanged();
     364}
     365
     366void ScheduleEditor::DupMethodChanged(MythUIButtonListItem *item)
     367{
     368    SchedOptMixin::DupMethodChanged(item);
     369}
     370
     371void ScheduleEditor::MaxEpisodesChanged(MythUIButtonListItem *item)
     372{
     373    StoreOptMixin::MaxEpisodesChanged(item);
     374}
     375
     376void ScheduleEditor::PromptForRecGroup(void)
     377{
     378    StoreOptMixin::PromptForRecGroup();
     379}
     380
     381void ScheduleEditor::TranscodeChanged(bool enable)
     382{
     383    PostProcMixin::TranscodeChanged(enable);
    303384}
    304385
    305386void ScheduleEditor::Save()
    306387{
    307     MythUIButtonListItem *item = m_rulesList->GetItemCurrent();
    308     if (item)
    309     {
    310         RecordingType type = static_cast<RecordingType>(item->GetData().toInt());
    311         if (type == kNotRecording)
    312         {
    313             int recid = m_recordingRule->m_recordID;
    314             DeleteRule();
    315             if (recid)
    316                 emit ruleDeleted(recid);
    317             Close();
    318             return;
    319         }
    320         else
    321             m_recordingRule->m_type = type;
    322     }
    323 
     388    if (m_child)
     389        m_child->Close();
     390
     391    if (m_recordingRule->m_type == kNotRecording)
     392    {
     393        int recid = m_recordingRule->m_recordID;
     394        DeleteRule();
     395        if (recid)
     396            emit ruleDeleted(recid);
     397        Close();
     398        return;
     399    }
     400
     401    SchedOptMixin::Save();
     402    StoreOptMixin::Save();
     403    PostProcMixin::Save();
    324404    m_recordingRule->Save(true);
    325405    emit ruleSaved(m_recordingRule->m_recordID);
     406
    326407    Close();
    327408}
     
    334415void ScheduleEditor::ShowSchedOpt()
    335416{
     417    if (m_recordingRule->m_type == kNotRecording ||
     418        m_recordingRule->m_type == kDontRecord)
     419        return;
     420
     421    if (m_child)
     422        m_child->Close();
     423
     424    SchedOptMixin::Save();
     425
    336426    MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
    337     SchedOptEditor *schedoptedit = new SchedOptEditor(mainStack, m_recInfo,
    338                                                       m_recordingRule);
    339     if (schedoptedit->Create())
    340         mainStack->AddScreen(schedoptedit);
    341     else
     427    SchedOptEditor *schedoptedit = new SchedOptEditor(mainStack, *this,
     428                                                  *m_recordingRule, m_recInfo);
     429    if (!schedoptedit->Create())
     430    {
    342431        delete schedoptedit;
     432        return;
     433    }
     434
     435    m_view = kSchedOptView;
     436    m_child = schedoptedit;
     437    mainStack->AddScreen(schedoptedit);
    343438}
    344439
    345440void ScheduleEditor::ShowStoreOpt()
    346441{
     442    if (m_recordingRule->m_type == kNotRecording ||
     443        m_recordingRule->m_type == kDontRecord)
     444        return;
     445
     446    if (m_child)
     447        m_child->Close();
     448
     449    StoreOptMixin::Save();
     450
    347451    MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
    348     StoreOptEditor *storeoptedit = new StoreOptEditor(mainStack, m_recInfo,
    349                                                       m_recordingRule);
    350     if (storeoptedit->Create())
    351         mainStack->AddScreen(storeoptedit);
    352     else
     452    StoreOptEditor *storeoptedit = new StoreOptEditor(mainStack, *this,
     453                                                  *m_recordingRule, m_recInfo);
     454    if (!storeoptedit->Create())
     455    {
    353456        delete storeoptedit;
     457        return;
     458    }
     459
     460    m_view = kStoreOptView;
     461    m_child = storeoptedit;
     462    mainStack->AddScreen(storeoptedit);
    354463}
    355464
    356465void ScheduleEditor::ShowPostProc()
    357466{
     467    if (m_recordingRule->m_type == kNotRecording ||
     468        m_recordingRule->m_type == kDontRecord)
     469        return;
     470
     471    if (m_child)
     472        m_child->Close();
     473
     474    PostProcMixin::Save();
     475
    358476    MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
    359     PostProcEditor *ppedit = new PostProcEditor(mainStack, m_recInfo,
    360                                                 m_recordingRule);
    361     if (ppedit->Create())
    362         mainStack->AddScreen(ppedit);
    363     else
     477    PostProcEditor *ppedit = new PostProcEditor(mainStack, *this,
     478                                                *m_recordingRule, m_recInfo);
     479    if (!ppedit->Create())
     480    {
    364481        delete ppedit;
     482        return;
     483    }
     484
     485    m_view = kPostProcView;
     486    m_child = ppedit;
     487    mainStack->AddScreen(ppedit);
    365488}
    366489
    367490void ScheduleEditor::ShowSchedInfo()
    368491{
     492    if (m_recordingRule->m_type == kTemplateRecord)
     493        return;
     494
    369495    QString label = tr("Schedule Information");
    370496
     
    376502        menuPopup->SetReturnEvent(this, "schedinfo");
    377503
    378         menuPopup->AddButton(tr("Program Details"));
    379         menuPopup->AddButton(tr("Upcoming episodes"));
    380         menuPopup->AddButton(tr("Upcoming recordings"));
    381         menuPopup->AddButton(tr("Previously scheduled"));
     504        if (m_recInfo)
     505            menuPopup->AddButton(tr("Program Details"));
     506        menuPopup->AddButton(tr("Upcoming Episodes"));
     507        menuPopup->AddButton(tr("Upcoming Recordings"));
     508        menuPopup->AddButton(tr("Previously Scheduled"));
    382509
    383510        popupStack->AddScreen(menuPopup);
     
    404531        if (action == "MENU")
    405532            showMenu();
     533        else if (action == "INFO")
     534            ShowDetails(m_recInfo);
     535        else if (action == "UPCOMING")
     536            showUpcomingByTitle();
     537        else if (action == "PREVVIEW")
     538            ShowPreviousView();
     539        else if (action == "NEXTVIEW")
     540            ShowNextView();
    406541        else
    407542            handled = false;
     
    422557        QString resultid  = dce->GetId();
    423558        QString resulttext = dce->GetResultText();
    424         int     buttonnum = dce->GetResult();
    425559
    426560        if (resultid == "menu")
    427         {   
    428             if (resulttext == tr("Use Template"))
    429             {
     561        {
     562            if (resulttext == tr("Main Options"))
     563                m_child->Close();
     564            if (resulttext == tr("Schedule Options"))
     565                ShowSchedOpt();
     566            else if (resulttext == tr("Filter Options"))
     567                ShowFilters();
     568            else if (resulttext == tr("Storage Options"))
     569                ShowStoreOpt();
     570            else if (resulttext == tr("Post Processing"))
     571                ShowPostProc();
     572            else if (resulttext == tr("Metadata Options"))
     573                ShowMetadataOptions();
     574            else if (resulttext == tr("Use Template"))
    430575                showTemplateMenu();
    431             }
     576            else if (resulttext == tr("Schedule Info"))
     577                ShowSchedInfo();
     578            else if (resulttext == tr("Preview Changes"))
     579                ShowPreview();
    432580        }
    433581        else if (resultid == "templatemenu")
     
    437585        else if (resultid == "schedinfo")
    438586        {
    439             switch (buttonnum)
    440             {
    441                 case 0 :
    442                     if (m_recInfo)
    443                         ShowDetails(m_recInfo);
    444                     break;
    445                 case 1 :
    446                     showUpcomingByTitle();
    447                     break;
    448                 case 2 :
    449                     showUpcomingByRule();
    450                     break;
    451                 case 3 :
    452                     showPrevious();
    453                     break;
    454             }
     587            if (resulttext == tr("Program Details"))
     588                ShowDetails(m_recInfo);
     589            else if (resulttext == tr("Upcoming Episodes"))
     590                showUpcomingByTitle();
     591            else if (resulttext == tr("Upcoming Recordings"))
     592                showUpcomingByRule();
     593            else if (resulttext == tr("Previously Scheduled"))
     594                showPrevious();
     595        }
     596        else if (resultid == "newrecgroup")
     597        {
     598            StoreOptMixin::SetRecGroup(resulttext);
    455599        }
    456600    }
     
    459603void ScheduleEditor::showPrevious(void)
    460604{
     605    if (m_recordingRule->m_type == kTemplateRecord)
     606        return;
     607
    461608    QString title;
    462609    if (m_recInfo)
     
    473620void ScheduleEditor::showUpcomingByRule(void)
    474621{
     622    if (m_recordingRule->m_type == kTemplateRecord)
     623        return;
     624
    475625    // No rule? Search by title
    476626    if (m_recordingRule->m_recordID <= 0)
     
    493643void ScheduleEditor::showUpcomingByTitle(void)
    494644{
     645    if (m_recordingRule->m_type == kTemplateRecord)
     646        return;
     647
     648    // Existing rule and search?  Search by rule
     649    if (m_recordingRule->m_recordID > 0 &&
     650        m_recordingRule->m_searchType != kNoSearch)
     651        showUpcomingByRule();
     652
    495653    QString title = m_recordingRule->m_title;
    496654
     
    503661void ScheduleEditor::ShowPreview(void)
    504662{
     663    if (m_recordingRule->m_type == kTemplateRecord)
     664        return;
     665
     666    if (m_child)
     667    {
     668        m_child->Save();
     669        if (m_view == kSchedOptView)
     670            SchedOptMixin::Load();
     671        else if (m_view == kStoreOptView)
     672            StoreOptMixin::Load();
     673        else if (m_view == kPostProcView)
     674            PostProcMixin::Load();
     675    }
     676
     677    SchedOptMixin::Save();
     678    StoreOptMixin::Save();
     679    PostProcMixin::Save();
     680
    505681    QString ttable = "record_tmp";
    506682    m_recordingRule->UseTempTable(true, ttable);
     
    520696void ScheduleEditor::ShowMetadataOptions(void)
    521697{
     698    if (m_recordingRule->m_type == kNotRecording ||
     699        m_recordingRule->m_type == kDontRecord ||
     700        m_recordingRule->m_type == kTemplateRecord)
     701        return;
     702
     703    if (m_child)
     704        m_child->Close();
     705
    522706    MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
    523     MetadataOptions *rad = new MetadataOptions(mainStack, m_recInfo,
    524                                                     m_recordingRule);
    525     if (rad->Create())
    526         mainStack->AddScreen(rad);
    527     else
     707    MetadataOptions *rad = new MetadataOptions(mainStack, *this,
     708                                               *m_recordingRule, m_recInfo);
     709    if (!rad->Create())
     710    {
    528711        delete rad;
     712        return;
     713    }
     714
     715    m_view = kMetadataView;
     716    m_child = rad;
     717    mainStack->AddScreen(rad);
     718}
     719
     720void ScheduleEditor::ShowFilters(void)
     721{
     722    if (m_recordingRule->m_type == kNotRecording ||
     723        m_recordingRule->m_type == kDontRecord)
     724        return;
     725
     726    if (m_child)
     727        m_child->Close();
     728
     729    MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
     730    SchedFilterEditor *schedfilteredit = new SchedFilterEditor(mainStack,
     731                                           *this, *m_recordingRule, m_recInfo);
     732    if (!schedfilteredit->Create())
     733    {
     734        delete schedfilteredit;
     735        return;
     736    }
     737
     738    m_view = kFilterView;
     739    m_child = schedfilteredit;
     740    mainStack->AddScreen(schedfilteredit);
     741}
     742
     743void ScheduleEditor::ShowPreviousView(void)
     744{
     745    if (m_recordingRule->m_type == kNotRecording ||
     746        m_recordingRule->m_type == kDontRecord)
     747        return;
     748
     749    if (m_view == kMainView && !m_recordingRule->m_isTemplate)
     750        ShowMetadataOptions();
     751    else if (m_view == kMainView)
     752        ShowPostProc();
     753    else if (m_view == kSchedOptView)
     754        m_child->Close();
     755    else if (m_view == kFilterView)
     756        ShowSchedOpt();
     757    else if (m_view == kStoreOptView)
     758        ShowFilters();
     759    else if (m_view == kPostProcView)
     760        ShowStoreOpt();
     761    else if (m_view == kMetadataView)
     762        ShowPostProc();
     763}
     764
     765void ScheduleEditor::ShowNextView(void)
     766{
     767    if (m_recordingRule->m_type == kNotRecording ||
     768        m_recordingRule->m_type == kDontRecord)
     769        return;
     770
     771    if (m_view == kMainView)
     772        ShowSchedOpt();
     773    else if (m_view == kSchedOptView)
     774        ShowFilters();
     775    else if (m_view == kFilterView)
     776        ShowStoreOpt();
     777    else if (m_view == kStoreOptView)
     778        ShowPostProc();
     779    else if (m_view == kPostProcView && !m_recordingRule->m_isTemplate)
     780        ShowMetadataOptions();
     781    else if (m_view == kPostProcView)
     782        m_child->Close();
     783    else if (m_view == kMetadataView)
     784        m_child->Close();
     785}
     786
     787void ScheduleEditor::ChildClosing(void)
     788{
     789    if (m_view == kSchedOptView)
     790        SchedOptMixin::Load();
     791    else if (m_view == kStoreOptView)
     792        StoreOptMixin::Load();
     793    else if (m_view == kPostProcView)
     794        PostProcMixin::Load();
     795
     796    m_child = NULL;
     797    m_view = kMainView;
    529798}
    530799
     
    536805        new MythDialogBox(label, popupStack, "menuPopup");
    537806
     807    MythUIButtonListItem *item = m_rulesList->GetItemCurrent();
     808    RecordingType type = static_cast<RecordingType>(item->GetData().toInt());
     809    bool isScheduled = (type != kNotRecording && type != kDontRecord);
     810
    538811    if (menuPopup->Create())
    539812    {
    540813        menuPopup->SetReturnEvent(this, "menu");
     814        if (m_view != kMainView)
     815            menuPopup->AddButton(tr("Main Options"));
     816        if (isScheduled && m_view != kSchedOptView)
     817            menuPopup->AddButton(tr("Schedule Options"));
     818        if (isScheduled && m_view != kFilterView)
     819            menuPopup->AddButton(tr("Filter Options"));
     820        if (isScheduled && m_view != kStoreOptView)
     821            menuPopup->AddButton(tr("Storage Options"));
     822        if (isScheduled && m_view != kPostProcView)
     823            menuPopup->AddButton(tr("Post Processing"));
     824        if (isScheduled && !m_recordingRule->m_isTemplate &&
     825            m_view != kMetadataView)
     826            menuPopup->AddButton(tr("Metadata Options"));
     827        if (!m_recordingRule->m_isTemplate)
     828            menuPopup->AddButton(tr("Schedule Info"));
     829        if (!m_recordingRule->m_isTemplate)
     830            menuPopup->AddButton(tr("Preview Changes"));
    541831        menuPopup->AddButton(tr("Use Template"));
    542832        popupStack->AddScreen(menuPopup);
     
    584874////////////////////////////////////////////////////////
    585875
     876/** \class SchedEditerChild
     877 *
     878 */
     879
     880SchedEditChild::SchedEditChild(MythScreenStack *parent, const QString name,
     881                               ScheduleEditor &editor, RecordingRule &rule,
     882                               RecordingInfo *recInfo)
     883    : MythScreenType(parent, name),
     884      m_editor(&editor), m_recordingRule(&rule), m_recInfo(recInfo),
     885      m_backButton(NULL), m_saveButton(NULL), m_previewButton(NULL)
     886{
     887}
     888
     889SchedEditChild::~SchedEditChild(void)
     890{
     891}
     892
     893bool SchedEditChild::keyPressEvent(QKeyEvent *event)
     894{
     895    if (GetFocusWidget()->keyPressEvent(event))
     896        return true;
     897
     898    bool handled = false;
     899    QStringList actions;
     900    handled = GetMythMainWindow()->
     901        TranslateKeyPress("TV Frontend", event, actions);
     902
     903    for (int i = 0; i < actions.size() && !handled; i++)
     904    {
     905        QString action = actions[i];
     906        handled = true;
     907
     908        if (action == "MENU")
     909            m_editor->showMenu();
     910        else if (action == "INFO")
     911            m_editor->ShowDetails(m_recInfo);
     912        else if (action == "UPCOMING")
     913            m_editor->showUpcomingByTitle();
     914        if (action == "ESCAPE")
     915            Close();
     916        else if (action == "PREVVIEW")
     917            m_editor->ShowPreviousView();
     918        else if (action == "NEXTVIEW")
     919            m_editor->ShowNextView();
     920        else
     921            handled = false;
     922    }
     923
     924    if (!handled && MythScreenType::keyPressEvent(event))
     925        handled = true;
     926
     927    return handled;
     928}
     929
     930bool SchedEditChild::Create(const QString xmlfile, const QString winname,
     931                            bool isTemplate)
     932{
     933    if (!LoadWindowFromXML(xmlfile, winname, this))
     934        return false;
     935
     936    UIUtilW::Assign(this, m_backButton, "back");
     937    UIUtilW::Assign(this, m_saveButton, "save");
     938    UIUtilW::Assign(this, m_previewButton, "preview");
     939
     940    connect(this, SIGNAL(Closing()), m_editor, SLOT(ChildClosing()));
     941    connect(m_editor, SIGNAL(templateLoaded()), SLOT(Load()));
     942
     943    if (m_backButton)
     944        connect(m_backButton, SIGNAL(Clicked()), SLOT(Close()));
     945    if (m_saveButton)
     946        connect(m_saveButton, SIGNAL(Clicked()), m_editor, SLOT(Save()));
     947    if (m_previewButton)
     948        connect(m_previewButton, SIGNAL(Clicked()),
     949                m_editor, SLOT(ShowPreview()));
     950
     951    if (m_previewButton)
     952        m_previewButton->SetEnabled(!isTemplate);
     953
     954    return true;
     955}
     956
     957void SchedEditChild::SetTextFromMaps(void)
     958{
     959    InfoMap progMap;
     960
     961    m_recordingRule->ToMap(progMap);
     962
     963    if (m_recInfo)
     964        m_recInfo->ToMap(progMap);
     965
     966    SetTextFromMap(progMap);
     967}
     968
     969void SchedEditChild::Close(void)
     970{
     971    Save();
     972    emit Closing();
     973    MythScreenType::Close();
     974}
     975
     976////////////////////////////////////////////////////////
     977
    586978/** \class SchedOptEditor
    587979 *  \brief Select schedule options
     
    590982
    591983SchedOptEditor::SchedOptEditor(MythScreenStack *parent,
    592                                RecordingInfo *recInfo,
    593                                RecordingRule *rule)
    594     : MythScreenType(parent, "ScheduleOptionsEditor"),
    595       m_recInfo(NULL), m_recordingRule(rule),
    596       m_backButton(NULL),
    597       m_prioritySpin(NULL), m_inputList(NULL), m_startoffsetSpin(NULL),
    598       m_endoffsetSpin(NULL), m_dupmethodList(NULL), m_dupscopeList(NULL),
    599       m_filtersButton(NULL), m_ruleactiveCheck(NULL)
    600 {
    601     if (recInfo)
    602         m_recInfo = new RecordingInfo(*recInfo);
     984                               ScheduleEditor &editor,
     985                               RecordingRule &rule,
     986                               RecordingInfo *recInfo)
     987    : SchedEditChild(parent, "ScheduleOptionsEditor", editor, rule, recInfo),
     988      SchedOptMixin(*this, &rule, &editor), m_filtersButton(NULL)
     989{
    603990}
    604991
     
    609996bool SchedOptEditor::Create()
    610997{
    611     if (!LoadWindowFromXML("schedule-ui.xml", "scheduleoptionseditor", this))
     998    if (!SchedEditChild::Create("schedule-ui.xml", "scheduleoptionseditor",
     999                                m_recordingRule->m_isTemplate))
    6121000        return false;
    6131001
    6141002    bool err = false;
    6151003
    616     UIUtilE::Assign(this, m_prioritySpin, "priority", &err);
    617     UIUtilE::Assign(this, m_inputList, "input", &err);
    618     UIUtilE::Assign(this, m_startoffsetSpin, "startoffset", &err);
    619     UIUtilE::Assign(this, m_endoffsetSpin, "endoffset", &err);
    620     UIUtilE::Assign(this, m_dupmethodList, "dupmethod", &err);
    621     UIUtilE::Assign(this, m_dupscopeList, "dupscope", &err);
     1004    SchedOptMixin::Create(&err);
    6221005
    6231006    UIUtilW::Assign(this, m_filtersButton, "filters");
    624     UIUtilW::Assign(this, m_backButton, "back");
    625 
    626     UIUtilE::Assign(this, m_ruleactiveCheck, "ruleactive", &err);
    6271007
    6281008    if (err)
     
    6331013    }
    6341014
    635     if (m_backButton)
    636         connect(m_backButton, SIGNAL(Clicked()), SLOT(Close()));
    637 
    638     if (m_filtersButton && m_recordingRule->m_type == kOverrideRecord)
    639         m_filtersButton->SetEnabled(false);
    640     if (m_recordingRule->m_type == kSingleRecord ||
    641         m_recordingRule->m_type == kOverrideRecord)
    642     {
    643         m_dupmethodList->SetEnabled(false);
    644         m_dupscopeList->SetEnabled(false);
    645     }
    646 
    647     connect(m_dupmethodList, SIGNAL(itemSelected(MythUIButtonListItem *)),
    648             SLOT(dupMatchChanged(MythUIButtonListItem *)));
     1015    if (m_dupmethodList)
     1016        connect(m_dupmethodList, SIGNAL(itemSelected(MythUIButtonListItem *)),
     1017                SLOT(DupMethodChanged(MythUIButtonListItem *)));
    6491018
    6501019    if (m_filtersButton)
    651         connect(m_filtersButton, SIGNAL(Clicked()), SLOT(ShowFilters()));
     1020        connect(m_filtersButton, SIGNAL(Clicked()),
     1021                m_editor, SLOT(ShowFilters()));
    6521022
    6531023    BuildFocusList();
     
    6581028void SchedOptEditor::Load()
    6591029{
    660     MSqlQuery query(MSqlQuery::InitCon());
    661 
    662     // Priority
    663     m_prioritySpin->SetRange(-99,99,1,5);
    664     m_prioritySpin->SetValue(m_recordingRule->m_recPriority);
    665 
    666     // Preferred Input
    667     new MythUIButtonListItem(m_inputList, tr("Use any available input"),
    668                              qVariantFromValue(0));
    669 
    670     vector<uint> inputids = CardUtil::GetAllInputIDs();
    671     for (uint i = 0; i < inputids.size(); ++i)
    672     {
    673         new MythUIButtonListItem(m_inputList, tr("Prefer input %1")
    674                                  .arg(CardUtil::GetDisplayName(inputids[i])),
    675                                  inputids[i]);
    676     }
    677 
    678     m_inputList->SetValueByData(m_recordingRule->m_prefInput);
    679 
    680     // Start Offset
    681     m_startoffsetSpin->SetRange(480,-480,1,10);
    682     m_startoffsetSpin->SetValue(m_recordingRule->m_startOffset);
    683 
    684     // End Offset
    685     m_endoffsetSpin->SetRange(-480,480,1,10);
    686     m_endoffsetSpin->SetValue(m_recordingRule->m_endOffset);
    687 
    688     // Duplicate Match Type
    689     new MythUIButtonListItem(m_dupmethodList,
    690                              tr("Match duplicates using subtitle & "
    691                                 "description"),
    692                              ENUM_TO_QVARIANT(kDupCheckSubDesc));
    693     new MythUIButtonListItem(m_dupmethodList,
    694                              tr("Match duplicates using subtitle then "
    695                                 "description"),
    696                              ENUM_TO_QVARIANT(kDupCheckSubThenDesc));
    697     new MythUIButtonListItem(m_dupmethodList,
    698                              tr("Match duplicates using subtitle"),
    699                              ENUM_TO_QVARIANT(kDupCheckSub));
    700     new MythUIButtonListItem(m_dupmethodList,
    701                              tr("Match duplicates using description"),
    702                              ENUM_TO_QVARIANT(kDupCheckDesc));
    703     new MythUIButtonListItem(m_dupmethodList,
    704                              tr("Don't match duplicates"),
    705                              ENUM_TO_QVARIANT(kDupCheckNone));
    706 
    707     m_dupmethodList->SetValueByData(
    708                                 ENUM_TO_QVARIANT(m_recordingRule->m_dupMethod));
    709 
    710     // Duplicate Matching Scope
    711     new MythUIButtonListItem(m_dupscopeList,
    712                              tr("Look for duplicates in current and previous "
    713                                 "recordings"),
    714                              ENUM_TO_QVARIANT(kDupsInAll));
    715     new MythUIButtonListItem(m_dupscopeList,
    716                              tr("Look for duplicates in current recordings "
    717                                 "only"),
    718                              ENUM_TO_QVARIANT(kDupsInRecorded));
    719     new MythUIButtonListItem(m_dupscopeList,
    720                              tr("Look for duplicates in previous recordings "
    721                                 "only"),
    722                              ENUM_TO_QVARIANT(kDupsInOldRecorded));
    723 
    724     if (gCoreContext->GetNumSetting("HaveRepeats", 0))
    725     {
    726         new MythUIButtonListItem(m_dupscopeList,
    727                                  tr("Record new episodes only"),
    728                                  ENUM_TO_QVARIANT(kDupsNewEpi | kDupsInAll));
    729     }
    730 
    731     m_dupscopeList->SetValueByData(ENUM_TO_QVARIANT(m_recordingRule->m_dupIn));
    732 
    733     // Active/Disabled
    734     m_ruleactiveCheck->SetCheckState(!m_recordingRule->m_isInactive);
    735 
    736     InfoMap progMap;
    737 
    738     m_recordingRule->ToMap(progMap);
    739 
    740     if (m_recInfo)
    741         m_recInfo->ToMap(progMap);
    742 
    743     SetTextFromMap(progMap);
    744 }
    745 
    746 void SchedOptEditor::dupMatchChanged(MythUIButtonListItem *item)
    747 {
    748     if (!item)
    749         return;
    750 
    751     int dupMethod = item->GetData().toInt();
    752 
    753     if (dupMethod <= 0)
    754         m_dupscopeList->SetEnabled(false);
    755     else
    756         m_dupscopeList->SetEnabled(true);
     1030    SchedOptMixin::Load();
     1031    SetTextFromMaps();
    7571032}
    7581033
    7591034void SchedOptEditor::Save()
    7601035{
    761     // Priority
    762     m_recordingRule->m_recPriority = m_prioritySpin->GetIntValue();
    763 
    764     // Preferred Input
    765     m_recordingRule->m_prefInput = m_inputList->GetDataValue().toInt();
    766 
    767     // Start Offset
    768     m_recordingRule->m_startOffset = m_startoffsetSpin->GetIntValue();
    769 
    770     // End Offset
    771     m_recordingRule->m_endOffset = m_endoffsetSpin->GetIntValue();
    772 
    773     // Duplicate Match Type
    774     m_recordingRule->m_dupMethod = static_cast<RecordingDupMethodType>
    775                                     (m_dupmethodList->GetDataValue().toInt());
    776 
    777     // Duplicate Matching Scope
    778     m_recordingRule->m_dupIn = static_cast<RecordingDupInType>
    779                                     (m_dupscopeList->GetDataValue().toInt());
    780 
    781     // Active/Disabled
    782     m_recordingRule->m_isInactive = (!m_ruleactiveCheck->GetBooleanCheckState());
    783 }
    784 
    785 void SchedOptEditor::Close()
    786 {
    787     Save();
    788     MythScreenType::Close();
    789 }
    790 
    791 void SchedOptEditor::ShowFilters(void)
    792 {
    793     MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
    794     SchedFilterEditor *schedfilteredit = new SchedFilterEditor(mainStack,
    795                                                                m_recInfo,
    796                                                                m_recordingRule);
    797     if (schedfilteredit->Create())
    798         mainStack->AddScreen(schedfilteredit);
    799     else
    800         delete schedfilteredit;
     1036    SchedOptMixin::Save();
     1037}
     1038
     1039void SchedOptEditor::DupMethodChanged(MythUIButtonListItem *item)
     1040{
     1041    SchedOptMixin::DupMethodChanged(item);
    8011042}
    8021043
     
    8091050
    8101051SchedFilterEditor::SchedFilterEditor(MythScreenStack *parent,
    811                                      RecordingInfo *recInfo,
    812                                      RecordingRule *rule)
    813     : MythScreenType(parent, "ScheduleFilterEditor"),
    814       m_recInfo(NULL), m_recordingRule(rule),
    815       m_backButton(NULL), m_filtersList(NULL)
    816 {
    817     if (recInfo)
    818         m_recInfo = new RecordingInfo(*recInfo);
     1052                                     ScheduleEditor &editor,
     1053                                     RecordingRule &rule,
     1054                                     RecordingInfo *recInfo)
     1055    : SchedEditChild(parent, "ScheduleFilterEditor", editor, rule, recInfo),
     1056      m_filtersList(NULL), m_loaded(false)
     1057{
    8191058}
    8201059
     
    8251064bool SchedFilterEditor::Create()
    8261065{
    827     if (!LoadWindowFromXML("schedule-ui.xml", "schedulefiltereditor", this))
     1066    if (!SchedEditChild::Create("schedule-ui.xml", "schedulefiltereditor",
     1067                                m_recordingRule->m_isTemplate))
    8281068        return false;
    8291069
     
    8311071
    8321072    UIUtilE::Assign(this, m_filtersList, "filters", &err);
    833     UIUtilW::Assign(this, m_backButton, "back");
    8341073
    8351074    if (err)
     
    8401079    }
    8411080
    842     if (m_backButton)
    843         connect(m_backButton, SIGNAL(Clicked()), SLOT(Close()));
    844 
    8451081    connect(m_filtersList, SIGNAL(itemClicked(MythUIButtonListItem *)),
    8461082            SLOT(ToggleSelected(MythUIButtonListItem *)));
     1083
    8471084    BuildFocusList();
    8481085
     
    8521089void SchedFilterEditor::Load()
    8531090{
    854     MSqlQuery query(MSqlQuery::InitCon());
    855 
    856     query.prepare("SELECT filterid, description, newruledefault "
    857                   "FROM recordfilter ORDER BY filterid");
    858 
    859     if (query.exec())
    860     {
    861         MythUIButtonListItem *button;
    862 
    863         while (query.next())
    864         {
    865             uint32_t filterid       = query.value(0).toInt();
    866             QString  description    = tr(query.value(1).toString()
     1091    int filterid;
     1092    MythUIButtonListItem *button;
     1093
     1094    if (!m_loaded)
     1095    {
     1096        MSqlQuery query(MSqlQuery::InitCon());
     1097
     1098        query.prepare("SELECT filterid, description, newruledefault "
     1099                      "FROM recordfilter ORDER BY filterid");
     1100
     1101        if (query.exec())
     1102        {
     1103            while (query.next())
     1104            {
     1105                filterid = query.value(0).toInt();
     1106                QString description = tr(query.value(1).toString()
    8671107                                         .toUtf8().constData());
    868             // bool     filter_default = query.value(2).toInt();
    869 
    870             // Fill in list of possible filters
    871             button = new MythUIButtonListItem(m_filtersList, description,
    872                                               filterid);
    873             button->setCheckable(true);
    874             button->setChecked(m_recordingRule->m_filter & (1 << filterid) ?
    875                                MythUIButtonListItem::FullChecked :
    876                                MythUIButtonListItem::NotChecked);
    877         }
    878     }
    879 
    880     InfoMap progMap;
    881 
    882     m_recordingRule->ToMap(progMap);
    883 
    884     if (m_recInfo)
    885         m_recInfo->ToMap(progMap);
    886 
    887     SetTextFromMap(progMap);
     1108                // Fill in list of possible filters
     1109                button = new MythUIButtonListItem(m_filtersList, description,
     1110                                                  filterid);
     1111                button->setCheckable(true);
     1112            }
     1113        }
     1114    }
     1115
     1116    int idx, end = m_filtersList->GetCount();
     1117    for (idx = 0; idx < end; ++idx)
     1118    {
     1119        button = m_filtersList->GetItemAt(idx);
     1120        int filterid = qVariantValue<int>(button->GetData());
     1121        button->setChecked(m_recordingRule->m_filter & (1 << filterid) ?
     1122                           MythUIButtonListItem::FullChecked :
     1123                           MythUIButtonListItem::NotChecked);
     1124    }
     1125
     1126    SetTextFromMaps();
     1127
     1128    m_loaded = true;
    8881129}
    8891130
     
    9121153}
    9131154
    914 void SchedFilterEditor::Close()
    915 {
    916     Save();
    917     MythScreenType::Close();
    918 }
    919 
    9201155/////////////////////////////
    9211156
     
    9261161
    9271162StoreOptEditor::StoreOptEditor(MythScreenStack *parent,
    928                                RecordingInfo *recInfo,
    929                                RecordingRule *rule)
    930           : MythScreenType(parent, "StorageOptionsEditor"),
    931             m_recInfo(NULL), m_recordingRule(rule),
    932             m_backButton(NULL),
    933             m_recprofileList(NULL), m_recgroupList(NULL),
    934             m_storagegroupList(NULL), m_playgroupList(NULL),
    935             m_autoexpireCheck(NULL), m_maxepSpin(NULL), m_maxbehaviourList(NULL)
    936 {
    937     if (recInfo)
    938         m_recInfo = new RecordingInfo(*recInfo);
     1163                               ScheduleEditor &editor,
     1164                               RecordingRule &rule,
     1165                               RecordingInfo *recInfo)
     1166    : SchedEditChild(parent, "StorageOptionsEditor", editor, rule, recInfo),
     1167      StoreOptMixin(*this, &rule, &editor)
     1168{
    9391169}
    9401170
     
    9451175bool StoreOptEditor::Create()
    9461176{
    947     if (!LoadWindowFromXML("schedule-ui.xml", "storageoptionseditor", this))
     1177    if (!SchedEditChild::Create("schedule-ui.xml", "storageoptionseditor",
     1178                                m_recordingRule->m_isTemplate))
    9481179        return false;
    9491180
    9501181    bool err = false;
    9511182
    952     UIUtilE::Assign(this, m_recprofileList, "recprofile", &err);
    953     UIUtilE::Assign(this, m_recgroupList, "recgroup", &err);
    954     UIUtilE::Assign(this, m_storagegroupList, "storagegroup", &err);
    955     UIUtilE::Assign(this, m_playgroupList, "playgroup", &err);
    956     UIUtilE::Assign(this, m_maxepSpin, "maxepisodes", &err);
    957     UIUtilE::Assign(this, m_maxbehaviourList, "maxnewest", &err);
    958 
    959     UIUtilE::Assign(this, m_autoexpireCheck, "autoexpire", &err);
    960     UIUtilW::Assign(this, m_backButton, "back");
     1183    StoreOptMixin::Create(&err);
    9611184
    9621185    if (err)
     
    9671190    }
    9681191
    969     if (m_backButton)
    970         connect(m_backButton, SIGNAL(Clicked()), SLOT(Close()));
    971 
    972     connect(m_maxepSpin, SIGNAL(itemSelected(MythUIButtonListItem *)),
    973                          SLOT(maxEpChanged(MythUIButtonListItem *)));
    974 
    975     connect(m_recgroupList, SIGNAL(LosingFocus()),
    976                             SLOT(PromptForRecgroup()));
     1192    if (m_maxepSpin)
     1193        connect(m_maxepSpin, SIGNAL(itemSelected(MythUIButtonListItem *)),
     1194                SLOT(MaxEpisodesChanged(MythUIButtonListItem *)));
     1195    if (m_recgroupList)
     1196        connect(m_recgroupList, SIGNAL(LosingFocus()),
     1197                SLOT(PromptForRecGroup()));
    9771198
    9781199    BuildFocusList();
     
    9831204void StoreOptEditor::Load()
    9841205{
    985     MSqlQuery query(MSqlQuery::InitCon());
    986 
    987     // Recording Profile
    988     QString label = tr("Record using the %1 profile");
    989     QMap<int, QString> profiles = RecordingProfile::listProfiles(0);
    990     QMap<int, QString>::iterator pit;
    991     for (pit = profiles.begin(); pit != profiles.end(); ++pit)
    992     {
    993         new MythUIButtonListItem(m_recprofileList, label.arg(pit.value()),
    994                                  qVariantFromValue(pit.value()));
    995     }
    996     m_recprofileList->SetValueByData(m_recordingRule->m_recProfile);
    997 
    998     // Recording Group
    999     QStringList groups;
    1000     QStringList::Iterator it;
    1001     QString value, dispValue;
    1002     bool foundDefault = false;
    1003 
    1004         // Count the ways the following is _wrong_
    1005 
    1006     new MythUIButtonListItem(m_recgroupList,
    1007                              tr("Create a new recording group"),
    1008                              qVariantFromValue(QString("__NEW_GROUP__")));
    1009 
    1010     query.prepare("SELECT DISTINCT recgroup FROM recorded");
    1011     if (query.exec())
    1012     {
    1013         while (query.next())
    1014         {
    1015             value = query.value(0).toString();
    1016 
    1017             if (value != "Deleted")
    1018             {
    1019                 groups += value;
    1020                 if (value == "Default")
    1021                     foundDefault = true;
    1022             }
    1023         }
    1024     }
    1025 
    1026     query.prepare("SELECT DISTINCT recgroup FROM record");
    1027     if (query.exec())
    1028     {
    1029         while (query.next())
    1030         {
    1031             value = query.value(0).toString();
    1032             groups += value;
    1033 
    1034             if (value == "Default")
    1035                 foundDefault = true;
    1036         }
    1037     }
    1038 
    1039     groups.sort();
    1040     groups.removeDuplicates();
    1041     for (it = groups.begin(); it != groups.end(); ++it)
    1042     {
    1043         label = tr("Include in the \"%1\" recording group");
    1044         if (!foundDefault && *it > tr("Default"))
    1045         {
    1046             new MythUIButtonListItem(m_recgroupList, label.arg(tr("Default")),
    1047                                      qVariantFromValue(QString("Default")));
    1048             foundDefault = true;
    1049         }
    1050 
    1051         if (*it == "Default")
    1052             dispValue = tr("Default");
    1053         else
    1054             dispValue = *it;
    1055 
    1056         new MythUIButtonListItem(m_recgroupList, label.arg(dispValue),
    1057                                  qVariantFromValue(*it));
    1058     }
    1059 
    1060     m_recgroupList->SetValueByData(m_recordingRule->m_recGroup);
    1061 
    1062     // Storage Group
    1063     groups = StorageGroup::getRecordingsGroups();
    1064     foundDefault = false;
    1065     for (it = groups.begin(); it != groups.end(); ++it)
    1066     {
    1067         if (*it == "Default")
    1068             foundDefault = true;
    1069     }
    1070 
    1071     for (it = groups.begin(); it != groups.end(); ++it)
    1072     {
    1073         label = tr("Store in the \"%1\" storage group");
    1074         if (!foundDefault && *it > tr("Default"))
    1075         {
    1076             new MythUIButtonListItem(m_storagegroupList,
    1077                                      label.arg(tr("Default")),
    1078                                      qVariantFromValue(QString("Default")));
    1079             foundDefault = true;
    1080         }
    1081 
    1082         if (*it == "Default")
    1083             dispValue = tr("Default");
    1084         else if (*it == "LiveTV")
    1085             dispValue = tr("Live TV");
    1086         else
    1087             dispValue = *it;
    1088 
    1089         new MythUIButtonListItem(m_storagegroupList, label.arg(dispValue),
    1090                                  qVariantFromValue(*it));
    1091     }
    1092 
    1093     m_storagegroupList->SetValueByData(m_recordingRule->m_storageGroup);
    1094 
    1095     // Playback Group
    1096     label = tr("Use \"%1\" playback group settings");
    1097     new MythUIButtonListItem(m_playgroupList, label.arg(tr("Default")),
    1098                              qVariantFromValue(QString("Default")));
    1099 
    1100     groups = PlayGroup::GetNames();
    1101 
    1102     for (it = groups.begin(); it != groups.end(); ++it)
    1103     {
    1104         new MythUIButtonListItem(m_playgroupList, label.arg(*it),
    1105                                  qVariantFromValue(*it));
    1106     }
    1107 
    1108     m_playgroupList->SetValueByData(m_recordingRule->m_playGroup);
    1109 
    1110     // Auto-Expire
    1111     m_autoexpireCheck->SetCheckState(m_recordingRule->m_autoExpire);
    1112 
    1113     // Max Episodes
    1114     m_maxepSpin->SetRange(0,100,1,5);
    1115     m_maxepSpin->SetValue(m_recordingRule->m_maxEpisodes);
    1116 
    1117     // Max Episode Behaviour
    1118     new MythUIButtonListItem(m_maxbehaviourList,
    1119                              tr("Don't record if this would exceed the max "
    1120                                 "episodes"), qVariantFromValue(false));
    1121     new MythUIButtonListItem(m_maxbehaviourList,
    1122                              tr("Delete oldest if this would exceed the max "
    1123                                 "episodes"), qVariantFromValue(true));
    1124     m_maxbehaviourList->SetValueByData(m_recordingRule->m_maxNewest);
    1125 
    1126 
    1127     InfoMap progMap;
    1128 
    1129     m_recordingRule->ToMap(progMap);
    1130 
    1131     if (m_recInfo)
    1132         m_recInfo->ToMap(progMap);
    1133 
    1134     SetTextFromMap(progMap);
    1135 }
    1136 
    1137 void StoreOptEditor::maxEpChanged(MythUIButtonListItem *item)
    1138 {
    1139     if (!item)
    1140         return;
    1141 
    1142     if (item->GetData().toInt() == 0)
    1143         m_maxbehaviourList->SetEnabled(false);
    1144     else
    1145         m_maxbehaviourList->SetEnabled(true);
    1146 }
    1147 
    1148 void StoreOptEditor::PromptForRecgroup()
    1149 {
    1150     if (m_recgroupList->GetDataValue().toString() != "__NEW_GROUP__")
    1151         return;
    1152 
    1153     MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
    1154 
    1155     QString label = tr("Create New Recording Group. Enter group name: ");
    1156 
    1157     MythTextInputDialog *textDialog = new MythTextInputDialog(popupStack, label,
    1158                          static_cast<InputFilter>(FilterSymbols | FilterPunct));
    1159 
    1160     textDialog->SetReturnEvent(this, "newrecgroup");
    1161 
    1162     if (textDialog->Create())
    1163         popupStack->AddScreen(textDialog, false);
    1164     return;
     1206    StoreOptMixin::Load();
     1207    SetTextFromMaps();
     1208}
     1209
     1210void StoreOptEditor::MaxEpisodesChanged(MythUIButtonListItem *item)
     1211{
     1212    StoreOptMixin::MaxEpisodesChanged(item);
     1213}
     1214
     1215void StoreOptEditor::PromptForRecGroup(void)
     1216{
     1217    StoreOptMixin::PromptForRecGroup();
    11651218}
    11661219
     
    11761229        if (resultid == "newrecgroup")
    11771230        {
    1178             if (!resulttext.isEmpty())
    1179             {
    1180                 QString label = tr("Include in the \"%1\" recording group");
    1181                 MythUIButtonListItem *item =
    1182                                     new MythUIButtonListItem(m_recgroupList,
    1183                                                 label.arg(resulttext),
    1184                                                 qVariantFromValue(resulttext));
    1185                 m_recgroupList->SetItemCurrent(item);
    1186             }
    1187             else
    1188                 m_recgroupList->SetValueByData(m_recordingRule->m_recGroup);
     1231            StoreOptMixin::SetRecGroup(resulttext);
    11891232        }
    11901233    }
     
    11931236void StoreOptEditor::Save()
    11941237{
    1195     // If the user has selected 'Create a new regroup' but failed to enter a
    1196     // name when prompted, restore the original value
    1197     if (m_recgroupList->GetDataValue().toString() == "__NEW_GROUP__")
    1198         m_recgroupList->SetValueByData(m_recordingRule->m_recGroup);
    1199 
    1200     // Recording Profile
    1201     m_recordingRule->m_recProfile = m_recprofileList->GetDataValue().toString();
    1202 
    1203     // Recording Group
    1204     m_recordingRule->m_recGroup = m_recgroupList->GetDataValue().toString();
    1205 
    1206     // Storage Group
    1207     m_recordingRule->m_storageGroup = m_storagegroupList->GetDataValue()
    1208                                                                     .toString();
    1209 
    1210     // Playback Group
    1211     m_recordingRule->m_playGroup = m_playgroupList->GetDataValue().toString();
    1212 
    1213     // Auto-Expire
    1214     m_recordingRule->m_autoExpire = m_autoexpireCheck->GetBooleanCheckState();
    1215 
    1216     // Max Episodes
    1217     m_recordingRule->m_maxEpisodes = m_maxepSpin->GetIntValue();
    1218 
    1219     // Max Episode Behaviour
    1220     m_recordingRule->m_maxNewest = m_maxbehaviourList->GetDataValue().toBool();
    1221 }
    1222 
    1223 void StoreOptEditor::Close()
    1224 {
    1225     Save();
    1226     MythScreenType::Close();
     1238    StoreOptMixin::Save();
    12271239}
    12281240
     
    12351247
    12361248PostProcEditor::PostProcEditor(MythScreenStack *parent,
    1237                                RecordingInfo *recInfo,
    1238                                RecordingRule *rule)
    1239           : MythScreenType(parent, "PostProcOptionsEditor"),
    1240             m_recInfo(NULL), m_recordingRule(rule),
    1241             m_backButton(NULL),
    1242             m_commflagCheck(NULL), m_transcodeCheck(NULL),
    1243             m_transcodeprofileList(NULL), m_userjob1Check(NULL),
    1244             m_userjob2Check(NULL), m_userjob3Check(NULL),
    1245             m_userjob4Check(NULL), m_metadataLookupCheck(NULL)
    1246 {
    1247     if (recInfo)
    1248         m_recInfo = new RecordingInfo(*recInfo);
     1249                               ScheduleEditor &editor,
     1250                               RecordingRule &rule,
     1251                               RecordingInfo *recInfo)
     1252    : SchedEditChild(parent, "PostProcOptionsEditor", editor, rule, recInfo),
     1253      PostProcMixin(*this, &rule, &editor)
     1254{
    12491255}
    12501256
     
    12551261bool PostProcEditor::Create()
    12561262{
    1257     if (!LoadWindowFromXML("schedule-ui.xml", "postproceditor", this))
     1263    if (!SchedEditChild::Create("schedule-ui.xml", "postproceditor",
     1264                                m_recordingRule->m_isTemplate))
    12581265        return false;
    12591266
    12601267    bool err = false;
    12611268
    1262     UIUtilE::Assign(this, m_commflagCheck, "autocommflag", &err);
    1263     UIUtilE::Assign(this, m_transcodeCheck, "autotranscode", &err);
    1264     UIUtilE::Assign(this, m_transcodeprofileList, "transcodeprofile", &err);
    1265     UIUtilE::Assign(this, m_userjob1Check, "userjob1", &err);
    1266     UIUtilE::Assign(this, m_userjob2Check, "userjob2", &err);
    1267     UIUtilE::Assign(this, m_userjob3Check, "userjob3", &err);
    1268     UIUtilE::Assign(this, m_userjob4Check, "userjob4", &err);
    1269     UIUtilW::Assign(this, m_metadataLookupCheck, "metadatalookup");
    1270     UIUtilW::Assign(this, m_backButton, "back");
     1269    PostProcMixin::Create(&err);
    12711270
    12721271    if (err)
     
    12771276    }
    12781277
    1279     if (m_backButton)
    1280         connect(m_backButton, SIGNAL(Clicked()), SLOT(Close()));
    1281 
    1282     connect(m_transcodeCheck, SIGNAL(toggled(bool)),
    1283             SLOT(transcodeEnable(bool)));
     1278    if (m_transcodeCheck)
     1279        connect(m_transcodeCheck, SIGNAL(toggled(bool)),
     1280                SLOT(TranscodeChanged(bool)));
    12841281
    12851282    BuildFocusList();
     
    12901287void PostProcEditor::Load()
    12911288{
    1292     // Auto-commflag
    1293     m_commflagCheck->SetCheckState(m_recordingRule->m_autoCommFlag);
    1294 
    1295     // Auto-transcode
    1296     m_transcodeCheck->SetCheckState(m_recordingRule->m_autoTranscode);
    1297 
    1298     // Transcode Method
    1299     QMap<int, QString> profiles = RecordingProfile::listProfiles(
    1300                                             RecordingProfile::TranscoderGroup);
    1301     QMap<int, QString>::iterator it;
    1302     for (it = profiles.begin(); it != profiles.end(); ++it)
    1303     {
    1304         new MythUIButtonListItem(m_transcodeprofileList, it.value(),
    1305                                  qVariantFromValue(it.key()));
    1306     }
    1307     m_transcodeprofileList->SetValueByData(m_recordingRule->m_transcoder);
    1308 
    1309     // User Job #1
    1310     m_userjob1Check->SetCheckState(m_recordingRule->m_autoUserJob1);
    1311     MythUIText *userjob1Text = NULL;
    1312     UIUtilW::Assign(this, userjob1Text, "userjob1text");
    1313     if (userjob1Text)
    1314         userjob1Text->SetText(tr("Run '%1'")
    1315                     .arg(gCoreContext->GetSetting("UserJobDesc1"), "User Job 1"));
    1316 
    1317     // User Job #2
    1318     m_userjob2Check->SetCheckState(m_recordingRule->m_autoUserJob2);
    1319     MythUIText *userjob2Text = NULL;
    1320     UIUtilW::Assign(this, userjob2Text, "userjob2text");
    1321     if (userjob2Text)
    1322         userjob2Text->SetText(tr("Run '%1'")
    1323                     .arg(gCoreContext->GetSetting("UserJobDesc2", "User Job 2")));
    1324 
    1325     // User Job #3
    1326     m_userjob3Check->SetCheckState(m_recordingRule->m_autoUserJob3);
    1327     MythUIText *userjob3Text = NULL;
    1328     UIUtilW::Assign(this, userjob3Text, "userjob3text");
    1329     if (userjob3Text)
    1330         userjob3Text->SetText(tr("Run '%1'")
    1331                     .arg(gCoreContext->GetSetting("UserJobDesc3", "User Job 3")));
    1332 
    1333     // User Job #4
    1334     m_userjob4Check->SetCheckState(m_recordingRule->m_autoUserJob4);
    1335     MythUIText *userjob4Text = NULL;
    1336     UIUtilW::Assign(this, userjob4Text, "userjob4text");
    1337     if (userjob4Text)
    1338         userjob4Text->SetText(tr("Run '%1'")
    1339                     .arg(gCoreContext->GetSetting("UserJobDesc4", "User Job 4")));
    1340 
    1341     // Auto Metadata Lookup
    1342     if (m_metadataLookupCheck)
    1343         m_metadataLookupCheck->SetCheckState(m_recordingRule->m_autoMetadataLookup);
    1344 
    1345     InfoMap progMap;
    1346 
    1347     m_recordingRule->ToMap(progMap);
    1348 
    1349     if (m_recInfo)
    1350         m_recInfo->ToMap(progMap);
    1351 
    1352     SetTextFromMap(progMap);
    1353 }
    1354 
    1355 void PostProcEditor::transcodeEnable(bool enable)
    1356 {
    1357     m_transcodeprofileList->SetEnabled(enable);
     1289    PostProcMixin::Load();
     1290    SetTextFromMaps();
     1291}
     1292
     1293void PostProcEditor::TranscodeChanged(bool enable)
     1294{
     1295    PostProcMixin::TranscodeChanged(enable);
    13581296}
    13591297
    13601298void PostProcEditor::Save()
    13611299{
    1362     // Auto-commflag
    1363     m_recordingRule->m_autoCommFlag = m_commflagCheck->GetBooleanCheckState();
    1364 
    1365     // Auto-transcode
    1366     m_recordingRule->m_autoTranscode = m_transcodeCheck->GetBooleanCheckState();
    1367 
    1368     // Transcode Method
    1369     m_recordingRule->m_transcoder = m_transcodeprofileList->GetDataValue().toInt();
    1370 
    1371     // User Job #1
    1372     m_recordingRule->m_autoUserJob1 = m_userjob1Check->GetBooleanCheckState();
    1373 
    1374     // User Job #2
    1375     m_recordingRule->m_autoUserJob2 = m_userjob2Check->GetBooleanCheckState();
    1376 
    1377     // User Job #3
    1378     m_recordingRule->m_autoUserJob3 = m_userjob3Check->GetBooleanCheckState();
    1379 
    1380     // User Job #4
    1381     m_recordingRule->m_autoUserJob4 = m_userjob4Check->GetBooleanCheckState();
    1382 
    1383     // Auto Metadata Lookup
    1384     if (m_metadataLookupCheck)
    1385         m_recordingRule->m_autoMetadataLookup = m_metadataLookupCheck->GetBooleanCheckState();
    1386 }
    1387 
    1388 void PostProcEditor::Close()
    1389 {
    1390     Save();
    1391     MythScreenType::Close();
     1300    PostProcMixin::Save();
    13921301}
    13931302
     
    14001309
    14011310MetadataOptions::MetadataOptions(MythScreenStack *parent,
    1402                                RecordingInfo *recInfo,
    1403                                RecordingRule *rule)
    1404           : MythScreenType(parent, "MetadataOptions"),
    1405             m_recInfo(NULL), m_recordingRule(rule), m_lookup(NULL),
    1406             m_busyPopup(NULL),  m_fanart(NULL), m_coverart(NULL),
    1407             m_banner(NULL), m_inetrefEdit(NULL), m_seasonSpin(NULL),
    1408             m_episodeSpin(NULL), m_queryButton(NULL), m_localFanartButton(NULL),
    1409             m_localCoverartButton(NULL), m_localBannerButton(NULL),
    1410             m_onlineFanartButton(NULL), m_onlineCoverartButton(NULL),
    1411             m_onlineBannerButton(NULL), m_backButton(NULL)
     1311                                 ScheduleEditor &editor,
     1312                                 RecordingRule &rule,
     1313                                 RecordingInfo *recInfo)
     1314    : SchedEditChild(parent, "MetadataOptions", editor, rule, recInfo),
     1315      m_lookup(NULL),
     1316      m_busyPopup(NULL), m_fanart(NULL), m_coverart(NULL),
     1317      m_banner(NULL), m_inetrefEdit(NULL), m_seasonSpin(NULL),
     1318      m_episodeSpin(NULL), m_queryButton(NULL), m_localFanartButton(NULL),
     1319      m_localCoverartButton(NULL), m_localBannerButton(NULL),
     1320      m_onlineFanartButton(NULL), m_onlineCoverartButton(NULL),
     1321      m_onlineBannerButton(NULL)
    14121322{
    14131323    m_popupStack = GetMythMainWindow()->GetStack("popup stack");
     
    14191329    m_artworkMap = GetArtwork(m_recordingRule->m_inetref,
    14201330                              m_recordingRule->m_season);
    1421 
    1422     if (recInfo)
    1423         m_recInfo = new RecordingInfo(*recInfo);
    14241331}
    14251332
     
    14431350bool MetadataOptions::Create()
    14441351{
    1445     if (!LoadWindowFromXML("schedule-ui.xml", "metadataoptions", this))
     1352    if (!SchedEditChild::Create("schedule-ui.xml", "metadataoptions",
     1353                                m_recordingRule->m_isTemplate))
    14461354        return false;
    14471355
     
    14611369    UIUtilW::Assign(this, m_coverart, "coverart");
    14621370    UIUtilW::Assign(this, m_banner, "banner");
    1463     UIUtilW::Assign(this, m_backButton, "back");
    14641371
    14651372    if (err)
     
    14701377    }
    14711378
    1472     if (m_backButton)
    1473         connect(m_backButton, SIGNAL(Clicked()), SLOT(Close()));
    14741379    connect(m_queryButton, SIGNAL(Clicked()),
    14751380            SLOT(PerformQuery()));
     
    15261431void MetadataOptions::Load()
    15271432{
    1528     if (m_recordingRule->m_inetref.isEmpty())
    1529     {
    1530         CreateBusyDialog(tr("Trying to automatically find this "
    1531                             "recording online..."));
    1532 
    1533         m_metadataFactory->Lookup(m_recordingRule, false, false, true);
    1534     }
    1535 
    1536     InfoMap progMap;
    1537 
    1538     m_recordingRule->ToMap(progMap);
    1539 
    1540     if (m_recInfo)
    1541         m_recInfo->ToMap(progMap);
    1542 
    1543     SetTextFromMap(progMap);
     1433    SetTextFromMaps();
    15441434}
    15451435
     
    16621552{
    16631553    FindNetArt(kArtworkBanner);
    1664 }
    1665 
    1666 void MetadataOptions::Close()
    1667 {
    1668     Save();
    1669     MythScreenType::Close();
    16701554}
    16711555
     
    21041988}
    21051989
     1990////////////////////////////////////////////////////////
     1991
     1992/** \class SchedOptMixin
     1993 *  \brief Mixin for schedule options
     1994 *
     1995 */
     1996
     1997SchedOptMixin::SchedOptMixin(MythScreenType &screen, RecordingRule *rule,
     1998                             SchedOptMixin *other)
     1999    : m_prioritySpin(NULL), m_startoffsetSpin(NULL), m_endoffsetSpin(NULL),
     2000      m_dupmethodList(NULL), m_dupscopeList(NULL), m_inputList(NULL),
     2001      m_ruleactiveCheck(NULL), m_newrepeatList(NULL),
     2002      m_screen(&screen), m_rule(rule), m_other(other), m_loaded(false),
     2003      m_haveRepeats(gCoreContext->GetNumSetting("HaveRepeats", 0))
     2004{
     2005}
     2006
     2007void SchedOptMixin::Create(bool *err)
     2008{
     2009    if (!m_rule)
     2010        return;
     2011
     2012    if (m_other && !m_other->m_prioritySpin)
     2013        UIUtilE::Assign(m_screen, m_prioritySpin, "priority", err);
     2014    else
     2015        UIUtilW::Assign(m_screen, m_prioritySpin, "priority");
     2016
     2017    if (m_other && !m_other->m_startoffsetSpin)
     2018        UIUtilE::Assign(m_screen, m_startoffsetSpin, "startoffset", err);
     2019    else
     2020        UIUtilW::Assign(m_screen, m_startoffsetSpin, "startoffset");
     2021
     2022    if (m_other && !m_other->m_endoffsetSpin)
     2023        UIUtilE::Assign(m_screen, m_endoffsetSpin, "endoffset", err);
     2024    else
     2025        UIUtilW::Assign(m_screen, m_endoffsetSpin, "endoffset");
     2026
     2027    if (m_other && !m_other->m_dupmethodList)
     2028        UIUtilE::Assign(m_screen, m_dupmethodList, "dupmethod", err);
     2029    else
     2030        UIUtilW::Assign(m_screen, m_dupmethodList, "dupmethod");
     2031
     2032    if (m_other && !m_other->m_dupscopeList)
     2033        UIUtilE::Assign(m_screen, m_dupscopeList, "dupscope", err);
     2034    else
     2035        UIUtilW::Assign(m_screen, m_dupscopeList, "dupscope");
     2036
     2037    if (m_other && !m_other->m_inputList)
     2038        UIUtilE::Assign(m_screen, m_inputList, "input", err);
     2039    else
     2040        UIUtilW::Assign(m_screen, m_inputList, "input");
     2041
     2042    if (m_other && !m_other->m_ruleactiveCheck)
     2043        UIUtilE::Assign(m_screen, m_ruleactiveCheck, "ruleactive", err);
     2044    else
     2045        UIUtilW::Assign(m_screen, m_ruleactiveCheck, "ruleactive");
     2046
     2047    UIUtilW::Assign(m_screen, m_newrepeatList, "newrepeat");
     2048}
     2049
     2050void SchedOptMixin::Load(void)
     2051{
     2052    if (!m_rule)
     2053        return;
     2054
     2055    // Priority
     2056    if (m_prioritySpin)
     2057    {
     2058        if (!m_loaded)
     2059            m_prioritySpin->SetRange(-99,99,1,5);
     2060        m_prioritySpin->SetValue(m_rule->m_recPriority);
     2061    }
     2062
     2063    // Start Offset
     2064    if (m_startoffsetSpin)
     2065    {
     2066        if (!m_loaded)
     2067            m_startoffsetSpin->SetRange(480,-480,1,10);
     2068        m_startoffsetSpin->SetValue(m_rule->m_startOffset);
     2069    }
     2070
     2071    // End Offset
     2072    if (m_endoffsetSpin)
     2073    {
     2074        if (!m_loaded)
     2075            m_endoffsetSpin->SetRange(-480,480,1,10);
     2076        m_endoffsetSpin->SetValue(m_rule->m_endOffset);
     2077    }
     2078
     2079    // Duplicate Match Type
     2080    if (m_dupmethodList)
     2081    {
     2082        if (!m_loaded)
     2083        {
     2084            RecordingDupMethodType dupMethod = m_rule->m_dupMethod;
     2085
     2086            new MythUIButtonListItem(m_dupmethodList,
     2087               QObject::tr("Match duplicates using subtitle & description"),
     2088                                     ENUM_TO_QVARIANT(kDupCheckSubDesc));
     2089            new MythUIButtonListItem(m_dupmethodList,
     2090               QObject::tr("Match duplicates using subtitle then description"),
     2091                                     ENUM_TO_QVARIANT(kDupCheckSubThenDesc));
     2092            new MythUIButtonListItem(m_dupmethodList,
     2093               QObject::tr("Match duplicates using subtitle"),
     2094                                     ENUM_TO_QVARIANT(kDupCheckSub));
     2095            new MythUIButtonListItem(m_dupmethodList,
     2096               QObject::tr("Match duplicates using description"),
     2097                                     ENUM_TO_QVARIANT(kDupCheckDesc));
     2098            new MythUIButtonListItem(m_dupmethodList,
     2099               QObject::tr("Don't match duplicates"),
     2100                                     ENUM_TO_QVARIANT(kDupCheckNone));
     2101
     2102            m_rule->m_dupMethod = dupMethod;
     2103        }
     2104        m_dupmethodList->SetValueByData(ENUM_TO_QVARIANT(m_rule->m_dupMethod));
     2105    }
     2106
     2107    // Duplicate Matching Scope
     2108    if (m_dupscopeList)
     2109    {
     2110        if (!m_loaded)
     2111        {
     2112            new MythUIButtonListItem(m_dupscopeList,
     2113                QObject::tr("Look for duplicates in current and previous "
     2114                            "recordings"), ENUM_TO_QVARIANT(kDupsInAll));
     2115            new MythUIButtonListItem(m_dupscopeList,
     2116                QObject::tr("Look for duplicates in current recordings only"),
     2117                                     ENUM_TO_QVARIANT(kDupsInRecorded));
     2118            new MythUIButtonListItem(m_dupscopeList,
     2119                QObject::tr("Look for duplicates in previous recordings only"),
     2120                                     ENUM_TO_QVARIANT(kDupsInOldRecorded));
     2121            if (m_haveRepeats && !m_newrepeatList &&
     2122                (!m_other || !m_other->m_newrepeatList))
     2123            {
     2124                new MythUIButtonListItem(m_dupscopeList,
     2125                    QObject::tr("Record new episodes only"),
     2126                                 ENUM_TO_QVARIANT(kDupsNewEpi|kDupsInAll));
     2127            }
     2128        }
     2129        m_dupscopeList->SetValueByData(ENUM_TO_QVARIANT(m_rule->m_dupIn));
     2130    }
     2131
     2132    // Preferred Input
     2133    if (m_inputList)
     2134    {
     2135        if (!m_loaded)
     2136        {
     2137            new MythUIButtonListItem(m_inputList,
     2138                                     QObject::tr("Use any available input"),
     2139                                     qVariantFromValue(0));
     2140
     2141            vector<uint> inputids = CardUtil::GetAllInputIDs();
     2142            for (uint i = 0; i < inputids.size(); ++i)
     2143            {
     2144                new MythUIButtonListItem(m_inputList,
     2145                    QObject::tr("Prefer input %1")
     2146                    .arg(CardUtil::GetDisplayName(inputids[i])), inputids[i]);
     2147            }
     2148        }
     2149        m_inputList->SetValueByData(m_rule->m_prefInput);
     2150    }
     2151
     2152    // Active/Disabled
     2153    if (m_ruleactiveCheck)
     2154    {
     2155        m_ruleactiveCheck->SetCheckState(!m_rule->m_isInactive);
     2156    }
     2157
     2158    // Record new and repeat
     2159    if (m_newrepeatList)
     2160    {
     2161        if (!m_loaded)
     2162        {
     2163            new MythUIButtonListItem(m_newrepeatList,
     2164                                     QObject::tr("Record new and repeat "
     2165                                         "episodes"), ENUM_TO_QVARIANT(0));
     2166            new MythUIButtonListItem(m_newrepeatList,
     2167                                     QObject::tr("Record new episodes only"),
     2168                                     ENUM_TO_QVARIANT(kDupsNewEpi));
     2169        }
     2170        m_newrepeatList->SetValueByData(ENUM_TO_QVARIANT
     2171                                        (m_rule->m_dupIn & kDupsNewEpi));
     2172    }
     2173
     2174    m_loaded = true;
     2175
     2176    RuleChanged();
     2177}
     2178
     2179void SchedOptMixin::Save(void)
     2180{
     2181    if (!m_rule)
     2182        return;
     2183
     2184    if (m_prioritySpin)
     2185        m_rule->m_recPriority = m_prioritySpin->GetIntValue();
     2186    if (m_startoffsetSpin)
     2187        m_rule->m_startOffset = m_startoffsetSpin->GetIntValue();
     2188    if (m_endoffsetSpin)
     2189        m_rule->m_endOffset = m_endoffsetSpin->GetIntValue();
     2190    if (m_dupmethodList)
     2191        m_rule->m_dupMethod = static_cast<RecordingDupMethodType>
     2192            (m_dupmethodList->GetDataValue().toInt());
     2193    if (m_dupscopeList)
     2194    {
     2195        int mask = ((m_other && m_other->m_newrepeatList) ||
     2196                    m_newrepeatList) ? kDupsInAll : ~0;
     2197        int val = ((m_rule->m_dupIn & ~mask) |
     2198                   m_dupscopeList->GetDataValue().toInt());
     2199        m_rule->m_dupIn = static_cast<RecordingDupInType>(val);
     2200    }
     2201    if (m_inputList)
     2202        m_rule->m_prefInput = m_inputList->GetDataValue().toInt();
     2203    if (m_ruleactiveCheck)
     2204        m_rule->m_isInactive = !m_ruleactiveCheck->GetBooleanCheckState();
     2205    if (m_newrepeatList)
     2206    {
     2207        int val = ((m_rule->m_dupIn & ~kDupsNewEpi) |
     2208                   m_newrepeatList->GetDataValue().toInt());
     2209        m_rule->m_dupIn = static_cast<RecordingDupInType>(val);
     2210    }
     2211}
     2212
     2213void SchedOptMixin::RuleChanged(void)
     2214{
     2215    if (!m_rule)
     2216        return;
     2217
     2218    bool isScheduled = (m_rule->m_type != kNotRecording &&
     2219                        m_rule->m_type != kDontRecord);
     2220    bool isSingle = (m_rule->m_type == kSingleRecord ||
     2221                     m_rule->m_type == kOverrideRecord);
     2222
     2223    if (m_prioritySpin)
     2224        m_prioritySpin->SetEnabled(isScheduled);
     2225    if (m_startoffsetSpin)
     2226        m_startoffsetSpin->SetEnabled(isScheduled);
     2227    if (m_endoffsetSpin)
     2228        m_endoffsetSpin->SetEnabled(isScheduled);
     2229    if (m_dupmethodList)
     2230        m_dupmethodList->SetEnabled(isScheduled && !isSingle);
     2231    if (m_dupscopeList)
     2232        m_dupscopeList->SetEnabled(isScheduled && !isSingle &&
     2233                                   m_rule->m_dupMethod != kDupCheckNone);
     2234    if (m_inputList)
     2235        m_inputList->SetEnabled(isScheduled);
     2236    if (m_ruleactiveCheck)
     2237        m_ruleactiveCheck->SetEnabled(isScheduled);
     2238    if (m_newrepeatList)
     2239        m_newrepeatList->SetEnabled(isScheduled && !isSingle && m_haveRepeats);
     2240}
     2241
     2242void SchedOptMixin::DupMethodChanged(MythUIButtonListItem *item)
     2243{
     2244    if (!item || !m_rule)
     2245        return;
     2246
     2247    m_rule->m_dupMethod = static_cast<RecordingDupMethodType>
     2248        (item->GetData().toInt());
     2249
     2250    if (m_dupscopeList)
     2251        m_dupscopeList->SetEnabled(m_rule->m_dupMethod != kDupCheckNone);
     2252}
     2253
     2254////////////////////////////////////////////////////////
     2255
     2256/** \class StoreOptMixin
     2257 *  \brief Mixin for storage options
     2258 *
     2259 */
     2260
     2261StoreOptMixin::StoreOptMixin(MythScreenType &screen, RecordingRule *rule,
     2262                             StoreOptMixin *other)
     2263    : m_recprofileList(NULL), m_recgroupList(NULL), m_storagegroupList(NULL),
     2264      m_playgroupList(NULL), m_maxepSpin(NULL), m_maxbehaviourList(NULL),
     2265      m_autoexpireCheck(NULL),
     2266      m_screen(&screen), m_rule(rule), m_other(other), m_loaded(false)
     2267{
     2268}
     2269
     2270void StoreOptMixin::Create(bool *err)
     2271{
     2272    if (!m_rule)
     2273        return;
     2274
     2275    if (m_other && !m_other->m_recprofileList)
     2276        UIUtilE::Assign(m_screen, m_recprofileList, "recprofile", err);
     2277    else
     2278        UIUtilW::Assign(m_screen, m_recprofileList, "recprofile");
     2279
     2280    if (m_other && !m_other->m_recgroupList)
     2281        UIUtilE::Assign(m_screen, m_recgroupList, "recgroup", err);
     2282    else
     2283        UIUtilW::Assign(m_screen, m_recgroupList, "recgroup");
     2284
     2285    if (m_other && !m_other->m_storagegroupList)
     2286        UIUtilE::Assign(m_screen, m_storagegroupList, "storagegroup", err);
     2287    else
     2288        UIUtilW::Assign(m_screen, m_storagegroupList, "storagegroup");
     2289
     2290    if (m_other && !m_other->m_playgroupList)
     2291        UIUtilE::Assign(m_screen, m_playgroupList, "playgroup", err);
     2292    else
     2293        UIUtilW::Assign(m_screen, m_playgroupList, "playgroup");
     2294
     2295    if (m_other && !m_other->m_maxepSpin)
     2296        UIUtilE::Assign(m_screen, m_maxepSpin, "maxepisodes", err);
     2297    else
     2298        UIUtilW::Assign(m_screen, m_maxepSpin, "maxepisodes");
     2299
     2300    if (m_other && !m_other->m_maxbehaviourList)
     2301        UIUtilE::Assign(m_screen, m_maxbehaviourList, "maxnewest", err);
     2302    else
     2303        UIUtilW::Assign(m_screen, m_maxbehaviourList, "maxnewest");
     2304
     2305    if (m_other && !m_other->m_autoexpireCheck)
     2306        UIUtilE::Assign(m_screen, m_autoexpireCheck, "autoexpire", err);
     2307    else
     2308        UIUtilW::Assign(m_screen, m_autoexpireCheck, "autoexpire");
     2309}
     2310
     2311void StoreOptMixin::Load(void)
     2312{
     2313    if (!m_rule)
     2314        return;
     2315
     2316    QString label;
     2317    QStringList groups;
     2318    QStringList::Iterator it;
     2319    MSqlQuery query(MSqlQuery::InitCon());
     2320
     2321    // Recording Profile
     2322    if (m_recprofileList)
     2323    {
     2324        if (!m_loaded)
     2325        {
     2326            label = QObject::tr("Record using the %1 profile");
     2327            QMap<int, QString> profiles = RecordingProfile::listProfiles(0);
     2328            QMap<int, QString>::iterator pit;
     2329            for (pit = profiles.begin(); pit != profiles.end(); ++pit)
     2330            {
     2331                new MythUIButtonListItem(m_recprofileList,
     2332                                         label.arg(pit.value()),
     2333                                         qVariantFromValue(pit.value()));
     2334            }
     2335        }
     2336        m_recprofileList->SetValueByData(m_rule->m_recProfile);
     2337    }
     2338
     2339    // Recording Group
     2340    if (m_recgroupList)
     2341    {
     2342        if (!m_loaded)
     2343        {
     2344            label = QObject::tr("Include in the \"%1\" recording group");
     2345            new MythUIButtonListItem(m_recgroupList,
     2346                                  QObject::tr("Create a new recording group"),
     2347                                  qVariantFromValue(QString("__NEW_GROUP__")));
     2348            new MythUIButtonListItem(m_recgroupList,
     2349                                     label.arg(QObject::tr("Default")),
     2350                                     qVariantFromValue(QString("Default")));
     2351
     2352            groups.clear();
     2353            if (m_rule->m_recGroup != "Default" &&
     2354                m_rule->m_recGroup != "__NEW_GROUP__")
     2355                groups << m_rule->m_recGroup;
     2356            query.prepare("SELECT DISTINCT recgroup FROM recorded "
     2357                          "WHERE recgroup <> 'Default' AND "
     2358                          "      recgroup <> 'Deleted'");
     2359            if (query.exec())
     2360            {
     2361                while (query.next())
     2362                    groups += query.value(0).toString();
     2363            }
     2364            query.prepare("SELECT DISTINCT recgroup FROM record "
     2365                          "WHERE recgroup <> 'Default'");
     2366            if (query.exec())
     2367            {
     2368                while (query.next())
     2369                    groups += query.value(0).toString();
     2370            }
     2371
     2372            groups.sort();
     2373            groups.removeDuplicates();
     2374            for (it = groups.begin(); it != groups.end(); ++it)
     2375            {
     2376                new MythUIButtonListItem(m_recgroupList, label.arg(*it),
     2377                                         qVariantFromValue(*it));
     2378            }
     2379        }
     2380        m_recgroupList->SetValueByData(m_rule->m_recGroup);
     2381    }
     2382
     2383    // Storage Group
     2384    if (m_storagegroupList)
     2385    {
     2386        if (!m_loaded)
     2387        {
     2388            label = QObject::tr("Store in the \"%1\" storage group");
     2389            new MythUIButtonListItem(m_storagegroupList,
     2390                                     label.arg(QObject::tr("Default")),
     2391                                     qVariantFromValue(QString("Default")));
     2392
     2393            groups = StorageGroup::getRecordingsGroups();
     2394            for (it = groups.begin(); it != groups.end(); ++it)
     2395            {
     2396                if ((*it).compare("Default", Qt::CaseInsensitive) != 0)
     2397                    new MythUIButtonListItem(m_storagegroupList,
     2398                                       label.arg(*it), qVariantFromValue(*it));
     2399            }
     2400        }
     2401        m_storagegroupList->SetValueByData(m_rule->m_storageGroup);
     2402    }
     2403
     2404    // Playback Group
     2405    if (m_playgroupList)
     2406    {
     2407        if (!m_loaded)
     2408        {
     2409            label = QObject::tr("Use \"%1\" playback group settings");
     2410            new MythUIButtonListItem(m_playgroupList,
     2411                                     label.arg(QObject::tr("Default")),
     2412                                     qVariantFromValue(QString("Default")));
     2413
     2414            groups = PlayGroup::GetNames();
     2415            for (it = groups.begin(); it != groups.end(); ++it)
     2416            {
     2417                new MythUIButtonListItem(m_playgroupList, label.arg(*it),
     2418                                         qVariantFromValue(*it));
     2419            }
     2420        }
     2421        m_playgroupList->SetValueByData(m_rule->m_playGroup);
     2422    }
     2423
     2424    // Max Episodes
     2425    if (m_maxepSpin)
     2426    {
     2427        if (!m_loaded)
     2428        {
     2429            int maxEpisodes = m_rule->m_maxEpisodes;
     2430            m_maxepSpin->SetRange(0,100,1,5);
     2431            m_rule->m_maxEpisodes = maxEpisodes;
     2432        }
     2433        m_maxepSpin->SetValue(m_rule->m_maxEpisodes);
     2434    }
     2435
     2436    // Max Episode Behaviour
     2437    if (m_maxbehaviourList)
     2438    {
     2439        if (!m_loaded)
     2440        {
     2441            new MythUIButtonListItem(m_maxbehaviourList,
     2442                      QObject::tr("Don't record if this would exceed the max "
     2443                                  "episodes"), qVariantFromValue(false));
     2444            new MythUIButtonListItem(m_maxbehaviourList,
     2445                      QObject::tr("Delete oldest if this would exceed the max "
     2446                                  "episodes"), qVariantFromValue(true));
     2447        }
     2448        m_maxbehaviourList->SetValueByData(m_rule->m_maxNewest);
     2449    }
     2450
     2451    // Auto-Expire
     2452    if (m_autoexpireCheck)
     2453    {
     2454        m_autoexpireCheck->SetCheckState(m_rule->m_autoExpire);
     2455    }
     2456
     2457    m_loaded = true;
     2458
     2459    RuleChanged();
     2460}
     2461
     2462void StoreOptMixin::Save(void)
     2463{
     2464    if (!m_rule)
     2465        return;
     2466
     2467    if (m_recprofileList)
     2468        m_rule->m_recProfile = m_recprofileList->GetDataValue().toString();
     2469
     2470    if (m_recgroupList)
     2471    {
     2472        // If the user selected 'Create a new regroup' but failed to enter a
     2473        // name when prompted, restore the original value
     2474        if (m_recgroupList->GetDataValue().toString() == "__NEW_GROUP__")
     2475            m_recgroupList->SetValueByData(m_rule->m_recGroup);
     2476        m_rule->m_recGroup = m_recgroupList->GetDataValue().toString();
     2477    }
     2478
     2479    if (m_storagegroupList)
     2480        m_rule->m_storageGroup = m_storagegroupList->GetDataValue().toString();
     2481
     2482    if (m_playgroupList)
     2483        m_rule->m_playGroup = m_playgroupList->GetDataValue().toString();
     2484
     2485    if (m_maxepSpin)
     2486        m_rule->m_maxEpisodes = m_maxepSpin->GetIntValue();
     2487
     2488    if (m_maxbehaviourList)
     2489        m_rule->m_maxNewest = m_maxbehaviourList->GetDataValue().toBool();
     2490
     2491    if (m_autoexpireCheck)
     2492        m_rule->m_autoExpire = m_autoexpireCheck->GetBooleanCheckState();
     2493}
     2494
     2495void StoreOptMixin::RuleChanged(void)
     2496{
     2497    if (!m_rule)
     2498        return;
     2499
     2500    bool isScheduled = (m_rule->m_type != kNotRecording &&
     2501                        m_rule->m_type != kDontRecord);
     2502    bool isSingle = (m_rule->m_type == kSingleRecord ||
     2503                     m_rule->m_type == kOverrideRecord);
     2504
     2505    if (m_recprofileList)
     2506        m_recprofileList->SetEnabled(isScheduled);
     2507    if (m_recgroupList)
     2508        m_recgroupList->SetEnabled(isScheduled);
     2509    if (m_storagegroupList)
     2510        m_storagegroupList->SetEnabled(isScheduled);
     2511    if (m_playgroupList)
     2512        m_playgroupList->SetEnabled(isScheduled);
     2513    if (m_maxepSpin)
     2514        m_maxepSpin->SetEnabled(isScheduled && !isSingle);
     2515    if (m_maxbehaviourList)
     2516        m_maxbehaviourList->SetEnabled(isScheduled && !isSingle &&
     2517                                       m_rule->m_maxEpisodes != 0);
     2518    if (m_autoexpireCheck)
     2519        m_autoexpireCheck->SetEnabled(isScheduled);
     2520}
     2521
     2522void StoreOptMixin::MaxEpisodesChanged(MythUIButtonListItem *item)
     2523{
     2524    if (!item || !m_rule)
     2525        return;
     2526
     2527    m_rule->m_maxEpisodes = item->GetData().toInt();
     2528
     2529    if (m_maxbehaviourList)
     2530        m_maxbehaviourList->SetEnabled(m_rule->m_maxEpisodes != 0);
     2531}
     2532
     2533void StoreOptMixin::PromptForRecGroup(void)
     2534{
     2535    if (!m_rule)
     2536        return;
     2537
     2538    if (m_recgroupList->GetDataValue().toString() != "__NEW_GROUP__")
     2539        return;
     2540
     2541    MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
     2542
     2543    QString label =
     2544        QObject::tr("Create New Recording Group. Enter group name: ");
     2545
     2546    MythTextInputDialog *textDialog =
     2547        new MythTextInputDialog(popupStack, label,
     2548                static_cast<InputFilter>(FilterSymbols | FilterPunct));
     2549
     2550    textDialog->SetReturnEvent(m_screen, "newrecgroup");
     2551
     2552    if (textDialog->Create())
     2553        popupStack->AddScreen(textDialog, false);
     2554}
     2555
     2556void StoreOptMixin::SetRecGroup(QString recgroup)
     2557{
     2558    if (!m_rule)
     2559        return;
     2560
     2561    if (m_recgroupList)
     2562    {
     2563        recgroup = recgroup.trimmed();
     2564        if (recgroup.isEmpty())
     2565            return;
     2566
     2567        QString label = QObject::tr("Include in the \"%1\" recording group");
     2568        MythUIButtonListItem *item =
     2569            new MythUIButtonListItem(m_recgroupList, label.arg(recgroup),
     2570                                     qVariantFromValue(recgroup));
     2571        m_recgroupList->SetItemCurrent(item);
     2572
     2573        if (m_other && m_other->m_recgroupList)
     2574        {
     2575            item = new MythUIButtonListItem(m_other->m_recgroupList,
     2576                             label.arg(recgroup), qVariantFromValue(recgroup));
     2577            m_other->m_recgroupList->SetItemCurrent(item);
     2578        }
     2579    }
     2580}
     2581
     2582////////////////////////////////////////////////////////
     2583
     2584/** \class PostProcMixin
     2585 *  \brief Mixin for post processing
     2586 *
     2587 */
     2588
     2589PostProcMixin::PostProcMixin(MythScreenType &screen, RecordingRule *rule,
     2590                             PostProcMixin *other)
     2591    : m_commflagCheck(NULL), m_transcodeCheck(NULL),
     2592      m_transcodeprofileList(NULL), m_userjob1Check(NULL),
     2593      m_userjob2Check(NULL), m_userjob3Check(NULL), m_userjob4Check(NULL),
     2594      m_metadataLookupCheck(NULL),
     2595      m_screen(&screen), m_rule(rule), m_other(other), m_loaded(false)
     2596{
     2597}
     2598
     2599void PostProcMixin::Create(bool *err)
     2600{
     2601    if (!m_rule)
     2602        return;
     2603
     2604    if (m_other && !m_other->m_commflagCheck)
     2605        UIUtilE::Assign(m_screen, m_commflagCheck, "autocommflag", err);
     2606    else
     2607        UIUtilW::Assign(m_screen, m_commflagCheck, "autocommflag");
     2608
     2609    if (m_other && !m_other->m_transcodeCheck)
     2610        UIUtilE::Assign(m_screen, m_transcodeCheck, "autotranscode", err);
     2611    else
     2612        UIUtilW::Assign(m_screen, m_transcodeCheck, "autotranscode");
     2613
     2614    if (m_other && !m_other->m_transcodeprofileList)
     2615        UIUtilE::Assign(m_screen, m_transcodeprofileList, "transcodeprofile", err);
     2616    else
     2617        UIUtilW::Assign(m_screen, m_transcodeprofileList, "transcodeprofile");
     2618
     2619    if (m_other && !m_other->m_userjob1Check)
     2620        UIUtilE::Assign(m_screen, m_userjob1Check, "userjob1", err);
     2621    else
     2622        UIUtilW::Assign(m_screen, m_userjob1Check, "userjob1");
     2623
     2624    if (m_other && !m_other->m_userjob2Check)
     2625        UIUtilE::Assign(m_screen, m_userjob2Check, "userjob2", err);
     2626    else
     2627        UIUtilW::Assign(m_screen, m_userjob2Check, "userjob2");
     2628
     2629    if (m_other && !m_other->m_userjob3Check)
     2630        UIUtilE::Assign(m_screen, m_userjob3Check, "userjob3", err);
     2631    else
     2632        UIUtilW::Assign(m_screen, m_userjob3Check, "userjob3");
     2633
     2634    if (m_other && !m_other->m_userjob4Check)
     2635        UIUtilE::Assign(m_screen, m_userjob4Check, "userjob4", err);
     2636    else
     2637        UIUtilW::Assign(m_screen, m_userjob4Check, "userjob4");
     2638
     2639    UIUtilW::Assign(m_screen, m_metadataLookupCheck, "metadatalookup");
     2640}
     2641
     2642void PostProcMixin::Load(void)
     2643{
     2644    if (!m_rule)
     2645        return;
     2646
     2647    // Auto-commflag
     2648    if (m_commflagCheck)
     2649    {
     2650        m_commflagCheck->SetCheckState(m_rule->m_autoCommFlag);
     2651    }
     2652
     2653    // Auto-transcode
     2654    if (m_transcodeCheck)
     2655    {
     2656        m_transcodeCheck->SetCheckState(m_rule->m_autoTranscode);
     2657    }
     2658
     2659    // Transcode Method
     2660    if (m_transcodeprofileList)
     2661    {
     2662        if (!m_loaded)
     2663        {
     2664        QMap<int, QString> profiles =
     2665            RecordingProfile::listProfiles(RecordingProfile::TranscoderGroup);
     2666        QMap<int, QString>::iterator it;
     2667        for (it = profiles.begin(); it != profiles.end(); ++it)
     2668        {
     2669            new MythUIButtonListItem(m_transcodeprofileList, it.value(),
     2670                                     qVariantFromValue(it.key()));
     2671        }
     2672        }
     2673        m_transcodeprofileList->SetValueByData(m_rule->m_transcoder);
     2674    }
     2675
     2676    // User Job #1
     2677    if (m_userjob1Check)
     2678    {
     2679        if (!m_loaded)
     2680        {
     2681        MythUIText *userjob1Text = NULL;
     2682        UIUtilW::Assign(m_screen, userjob1Text, "userjob1text");
     2683        if (userjob1Text)
     2684            userjob1Text->SetText(QObject::tr("Run '%1'")
     2685                .arg(gCoreContext->GetSetting("UserJobDesc1"), "User Job 1"));
     2686        }
     2687        m_userjob1Check->SetCheckState(m_rule->m_autoUserJob1);
     2688    }
     2689
     2690    // User Job #2
     2691    if (m_userjob2Check)
     2692    {
     2693        if (!m_loaded)
     2694        {
     2695        MythUIText *userjob2Text = NULL;
     2696        UIUtilW::Assign(m_screen, userjob2Text, "userjob2text");
     2697        if (userjob2Text)
     2698            userjob2Text->SetText(QObject::tr("Run '%1'")
     2699                .arg(gCoreContext->GetSetting("UserJobDesc2"), "User Job 2"));
     2700        }
     2701        m_userjob2Check->SetCheckState(m_rule->m_autoUserJob2);
     2702    }
     2703
     2704    // User Job #3
     2705    if (m_userjob3Check)
     2706    {
     2707        if (!m_loaded)
     2708        {
     2709        MythUIText *userjob3Text = NULL;
     2710        UIUtilW::Assign(m_screen, userjob3Text, "userjob3text");
     2711        if (userjob3Text)
     2712            userjob3Text->SetText(QObject::tr("Run '%1'")
     2713                .arg(gCoreContext->GetSetting("UserJobDesc3"), "User Job 3"));
     2714        }
     2715        m_userjob3Check->SetCheckState(m_rule->m_autoUserJob3);
     2716    }
     2717
     2718    // User Job #4
     2719    if (m_userjob4Check)
     2720    {
     2721        if (!m_loaded)
     2722        {
     2723        MythUIText *userjob4Text = NULL;
     2724        UIUtilW::Assign(m_screen, userjob4Text, "userjob4text");
     2725        if (userjob4Text)
     2726            userjob4Text->SetText(QObject::tr("Run '%1'")
     2727                .arg(gCoreContext->GetSetting("UserJobDesc4"), "User Job 4"));
     2728        }
     2729        m_userjob4Check->SetCheckState(m_rule->m_autoUserJob4);
     2730    }
     2731
     2732    // Auto Metadata Lookup
     2733    if (m_metadataLookupCheck)
     2734    {
     2735        m_metadataLookupCheck->SetCheckState(m_rule->m_autoMetadataLookup);
     2736    }
     2737
     2738    m_loaded = true;
     2739
     2740    RuleChanged();
     2741}
     2742
     2743void PostProcMixin::Save(void)
     2744{
     2745    if (!m_rule)
     2746        return;
     2747
     2748    if (m_commflagCheck)
     2749        m_rule->m_autoCommFlag = m_commflagCheck->GetBooleanCheckState();
     2750    if (m_transcodeCheck)
     2751        m_rule->m_autoTranscode = m_transcodeCheck->GetBooleanCheckState();
     2752    if (m_transcodeprofileList)
     2753        m_rule->m_transcoder = m_transcodeprofileList->GetDataValue().toInt();
     2754    if (m_userjob1Check)
     2755        m_rule->m_autoUserJob1 = m_userjob1Check->GetBooleanCheckState();
     2756    if (m_userjob2Check)
     2757        m_rule->m_autoUserJob2 = m_userjob2Check->GetBooleanCheckState();
     2758    if (m_userjob3Check)
     2759        m_rule->m_autoUserJob3 = m_userjob3Check->GetBooleanCheckState();
     2760    if (m_userjob4Check)
     2761        m_rule->m_autoUserJob4 = m_userjob4Check->GetBooleanCheckState();
     2762    if (m_metadataLookupCheck)
     2763        m_rule->m_autoMetadataLookup =
     2764            m_metadataLookupCheck->GetBooleanCheckState();
     2765}
     2766
     2767void PostProcMixin::RuleChanged(void)
     2768{
     2769    if (!m_rule)
     2770        return;
     2771
     2772    bool isScheduled = (m_rule->m_type != kNotRecording &&
     2773                        m_rule->m_type != kDontRecord);
     2774
     2775    if (m_commflagCheck)
     2776        m_commflagCheck->SetEnabled(isScheduled);
     2777    if (m_transcodeCheck)
     2778        m_transcodeCheck->SetEnabled(isScheduled);
     2779    if (m_transcodeprofileList)
     2780        m_transcodeprofileList->SetEnabled(isScheduled &&
     2781                                           m_rule->m_autoTranscode);
     2782    if (m_userjob1Check)
     2783        m_userjob1Check->SetEnabled(isScheduled);
     2784    if (m_userjob2Check)
     2785        m_userjob2Check->SetEnabled(isScheduled);
     2786    if (m_userjob3Check)
     2787        m_userjob3Check->SetEnabled(isScheduled);
     2788    if (m_userjob4Check)
     2789        m_userjob4Check->SetEnabled(isScheduled);
     2790    if (m_metadataLookupCheck)
     2791        m_metadataLookupCheck->SetEnabled(isScheduled);
     2792}
     2793
     2794void PostProcMixin::TranscodeChanged(bool enable)
     2795{
     2796    if (!m_rule)
     2797        return;
     2798
     2799    m_rule->m_autoTranscode = enable;
     2800
     2801    if (m_transcodeprofileList)
     2802        m_transcodeprofileList->SetEnabled(m_rule->m_autoTranscode);
     2803}
     2804
  • mythtv/programs/mythfrontend/scheduleeditor.h

    rf38e299719 rd418754c9  
    2727class TV;
    2828
    29 class ScheduleEditor : public ScheduleCommon
     29class ScheduleEditor;
     30class SchedEditChild;
     31
     32class SchedOptMixin
     33{
     34  protected:
     35    SchedOptMixin(MythScreenType &screen, RecordingRule *rule,
     36                  SchedOptMixin *other = NULL);
     37    void SetRule(RecordingRule *rule) { m_rule = rule; };
     38    void Create(bool *err);
     39    void Load(void);
     40    void Save(void);
     41    void RuleChanged(void);
     42    void DupMethodChanged(MythUIButtonListItem *item);
     43
     44    MythUISpinBox    *m_prioritySpin;
     45    MythUISpinBox    *m_startoffsetSpin;
     46    MythUISpinBox    *m_endoffsetSpin;
     47    MythUIButtonList *m_dupmethodList;
     48    MythUIButtonList *m_dupscopeList;
     49    MythUIButtonList *m_inputList;
     50    MythUICheckBox   *m_ruleactiveCheck;
     51    MythUIButtonList *m_newrepeatList;
     52
     53  private:
     54    MythScreenType   *m_screen;
     55    RecordingRule    *m_rule;
     56    SchedOptMixin    *m_other;
     57    bool              m_loaded;
     58    bool              m_haveRepeats;
     59};
     60
     61class StoreOptMixin
     62{
     63  protected:
     64    StoreOptMixin(MythScreenType &screen, RecordingRule *rule,
     65                  StoreOptMixin *other = NULL);
     66    void SetRule(RecordingRule *rule) { m_rule = rule; };
     67    void Create(bool *err);
     68    void Load(void);
     69    void Save(void);
     70    void RuleChanged(void);
     71    void MaxEpisodesChanged(MythUIButtonListItem *);
     72    void PromptForRecGroup(void);
     73    void SetRecGroup(QString recgroup);
     74
     75    MythUIButtonList *m_recprofileList;
     76    MythUIButtonList *m_recgroupList;
     77    MythUIButtonList *m_storagegroupList;
     78    MythUIButtonList *m_playgroupList;
     79    MythUISpinBox    *m_maxepSpin;
     80    MythUIButtonList *m_maxbehaviourList;
     81    MythUICheckBox   *m_autoexpireCheck;
     82
     83  private:
     84    MythScreenType   *m_screen;
     85    RecordingRule    *m_rule;
     86    StoreOptMixin    *m_other;
     87    bool              m_loaded;
     88};
     89
     90class PostProcMixin
     91{
     92  protected:
     93    PostProcMixin(MythScreenType &screen, RecordingRule *rule,
     94                  PostProcMixin *other= NULL);
     95    void SetRule(RecordingRule *rule) { m_rule = rule; };
     96    void Create(bool *err);
     97    void Load(void);
     98    void Save(void);
     99    void RuleChanged(void);
     100    void TranscodeChanged(bool enable);
     101
     102    MythUICheckBox   *m_commflagCheck;
     103    MythUICheckBox   *m_transcodeCheck;
     104    MythUIButtonList *m_transcodeprofileList;
     105    MythUICheckBox   *m_userjob1Check;
     106    MythUICheckBox   *m_userjob2Check;
     107    MythUICheckBox   *m_userjob3Check;
     108    MythUICheckBox   *m_userjob4Check;
     109    MythUICheckBox   *m_metadataLookupCheck;
     110
     111  private:
     112    MythScreenType   *m_screen;
     113    RecordingRule    *m_rule;
     114    PostProcMixin    *m_other;
     115    bool              m_loaded;
     116};
     117
     118class ScheduleEditor : public ScheduleCommon,
     119    public SchedOptMixin, public StoreOptMixin, public PostProcMixin
    30120{
    31121  Q_OBJECT
     
    41131    void customEvent(QEvent *event);
    42132
     133    void showMenu(void);
     134    void showPrevious(void);
     135    void showUpcomingByRule(void);
     136    void showUpcomingByTitle(void);
     137    void ShowDetails(ProgramInfo *pginfo) const
     138    { ScheduleCommon::ShowDetails(pginfo); };
     139
    43140    /// Callback
    44141    static void *RunScheduleEditor(ProgramInfo *proginfo, void *player = NULL);
     
    47144    void ruleSaved(int ruleId);
    48145    void ruleDeleted(int ruleId);
    49 
    50   protected slots:
    51     void RuleChanged(MythUIButtonListItem *item);
     146    void templateLoaded(void);
     147
     148  public slots:
    52149    void ShowSchedOpt(void);
     150    void ShowFilters(void);
    53151    void ShowStoreOpt(void);
    54152    void ShowPostProc(void);
     153    void ShowMetadataOptions(void);
     154    void ShowPreviousView(void);
     155    void ShowNextView(void);
     156    void ShowPreview(void);
     157    void Save(void);
     158
     159  protected slots:
     160    void RuleChanged(MythUIButtonListItem *item);
     161    void DupMethodChanged(MythUIButtonListItem *);
     162    void MaxEpisodesChanged(MythUIButtonListItem *);
     163    void PromptForRecGroup(void);
     164    void TranscodeChanged(bool enable);
    55165    void ShowSchedInfo(void);
    56     void ShowPreview(void);
    57     void ShowMetadataOptions(void);
    58     void Save(void);
     166    void ChildClosing(void);
    59167    void Close(void);
    60168
     
    64172    void DeleteRule(void);
    65173
    66     void showPrevious(void);
    67     void showUpcomingByRule(void);
    68     void showUpcomingByTitle(void);
    69 
    70     void showMenu(void);
    71174    void showTemplateMenu(void);
    72175
     
    87190    MythUIButton    *m_previewButton;
    88191    MythUIButton    *m_metadataButton;
     192    MythUIButton    *m_filtersButton;
    89193
    90194    TV *m_player;
    91 };
    92 
    93 class SchedOptEditor : public MythScreenType
    94 {
    95   Q_OBJECT
    96   public:
    97     SchedOptEditor(MythScreenStack *parent, RecordingInfo *recinfo,
    98                    RecordingRule *rule);
     195
     196    bool             m_loaded;
     197
     198    enum View
     199    {
     200        kMainView,
     201        kSchedOptView,
     202        kFilterView,
     203        kStoreOptView,
     204        kPostProcView,
     205        kMetadataView
     206    };
     207
     208    int              m_view;
     209    SchedEditChild  *m_child;
     210};
     211
     212class SchedEditChild : public MythScreenType
     213{
     214  Q_OBJECT
     215  protected:
     216    SchedEditChild(MythScreenStack *parent, const QString name,
     217                   ScheduleEditor &editor, RecordingRule &rule,
     218                   RecordingInfo *recinfo);
     219   ~SchedEditChild();
     220
     221    virtual bool keyPressEvent(QKeyEvent *event);
     222    virtual bool Create(const QString xmlfile, const QString winname,
     223                        bool isTemplate);
     224
     225  signals:
     226    void Closing(void);
     227
     228  public slots:
     229    virtual void Close(void);
     230    virtual void Load(void) = 0;
     231    virtual void Save(void) = 0;
     232
     233  protected:
     234    void SetTextFromMaps(void);
     235
     236    ScheduleEditor *m_editor;
     237    RecordingRule  *m_recordingRule;
     238    RecordingInfo  *m_recInfo;
     239
     240    MythUIButton   *m_backButton;
     241    MythUIButton   *m_saveButton;
     242    MythUIButton   *m_previewButton;
     243};
     244
     245class SchedOptEditor : public SchedEditChild, public SchedOptMixin
     246{
     247  Q_OBJECT
     248  public:
     249    SchedOptEditor(MythScreenStack *parent, ScheduleEditor &editor,
     250                   RecordingRule &rule, RecordingInfo *recinfo);
    99251   ~SchedOptEditor();
    100252
     
    102254
    103255  protected slots:
    104     void dupMatchChanged(MythUIButtonListItem *item);
    105     void ShowFilters(void);
    106     void Close(void);
    107 
    108   private:
    109     void Load(void);
    110     void Save(void);
    111 
    112     RecordingInfo *m_recInfo;
    113     RecordingRule *m_recordingRule;
    114 
    115     MythUIButton    *m_backButton;
    116 
    117     MythUISpinBox *m_prioritySpin;
    118     MythUIButtonList *m_inputList;
    119     MythUISpinBox *m_startoffsetSpin;
    120     MythUISpinBox *m_endoffsetSpin;
    121     MythUIButtonList *m_dupmethodList;
    122     MythUIButtonList *m_dupscopeList;
     256    void DupMethodChanged(MythUIButtonListItem *);
     257
     258  private:
     259    void Load(void);
     260    void Save(void);
     261
    123262    MythUIButton  *m_filtersButton;
    124 
    125     MythUICheckBox *m_ruleactiveCheck;
    126 };
    127 
    128 class SchedFilterEditor : public MythScreenType
    129 {
    130   Q_OBJECT
    131   public:
    132     SchedFilterEditor(MythScreenStack *parent, RecordingInfo *recinfo,
    133                       RecordingRule *rule);
     263};
     264
     265class SchedFilterEditor : public SchedEditChild
     266{
     267  Q_OBJECT
     268  public:
     269    SchedFilterEditor(MythScreenStack *parent, ScheduleEditor &editor,
     270                      RecordingRule &rule, RecordingInfo *recinfo);
    134271   ~SchedFilterEditor();
    135272
     
    137274
    138275  protected slots:
    139     void Close(void);
    140276    void ToggleSelected(MythUIButtonListItem *item);
    141277
     
    144280    void Save(void);
    145281
    146     RecordingInfo *m_recInfo;
    147     RecordingRule *m_recordingRule;
    148 
    149     MythUIButton    *m_backButton;
    150282    MythUIButtonList *m_filtersList;
    151 };
    152 
    153 class StoreOptEditor : public MythScreenType
    154 {
    155   Q_OBJECT
    156   public:
    157     StoreOptEditor(MythScreenStack *parent, RecordingInfo *recinfo,
    158                    RecordingRule *rule);
     283    bool m_loaded;
     284};
     285
     286class StoreOptEditor : public SchedEditChild, public StoreOptMixin
     287{
     288  Q_OBJECT
     289  public:
     290    StoreOptEditor(MythScreenStack *parent, ScheduleEditor &editor,
     291                   RecordingRule &rule, RecordingInfo *recinfo);
    159292   ~StoreOptEditor();
    160293
     
    163296
    164297  protected slots:
    165     void maxEpChanged(MythUIButtonListItem *item);
    166     void PromptForRecgroup(void);
    167     void Close(void);
    168 
    169   private:
    170     void Load(void);
    171     void Save(void);
    172 
    173     RecordingInfo *m_recInfo;
    174     RecordingRule *m_recordingRule;
    175 
    176     MythUIButton    *m_backButton;
    177 
    178     MythUIButtonList *m_recprofileList;
    179     MythUIButtonList *m_recgroupList;
    180     MythUIButtonList *m_storagegroupList;
    181     MythUIButtonList *m_playgroupList;
    182     MythUICheckBox *m_autoexpireCheck;
    183     MythUISpinBox *m_maxepSpin;
    184     MythUIButtonList *m_maxbehaviourList;
    185 };
    186 
    187 class PostProcEditor : public MythScreenType
    188 {
    189   Q_OBJECT
    190   public:
    191     PostProcEditor(MythScreenStack *parent, RecordingInfo *recinfo,
    192                    RecordingRule *rule);
     298    void MaxEpisodesChanged(MythUIButtonListItem *);
     299    void PromptForRecGroup(void);
     300
     301  private:
     302    void Load(void);
     303    void Save(void);
     304};
     305
     306class PostProcEditor : public SchedEditChild, public PostProcMixin
     307{
     308  Q_OBJECT
     309  public:
     310    PostProcEditor(MythScreenStack *parent, ScheduleEditor &editor,
     311                   RecordingRule &rule, RecordingInfo *recinfo);
    193312   ~PostProcEditor();
    194313
     
    196315
    197316  protected slots:
    198     void transcodeEnable(bool enable);
    199     void Close(void);
    200 
    201   private:
    202     void Load(void);
    203     void Save(void);
    204 
    205     RecordingInfo *m_recInfo;
    206     RecordingRule *m_recordingRule;
    207 
    208     MythUIButton    *m_backButton;
    209 
    210     MythUICheckBox *m_commflagCheck;
    211     MythUICheckBox *m_transcodeCheck;
    212     MythUIButtonList *m_transcodeprofileList;
    213     MythUICheckBox *m_userjob1Check;
    214     MythUICheckBox *m_userjob2Check;
    215     MythUICheckBox *m_userjob3Check;
    216     MythUICheckBox *m_userjob4Check;
    217     MythUICheckBox *m_metadataLookupCheck;
    218 };
    219 
    220 class MetadataOptions : public MythScreenType
    221 {
    222   Q_OBJECT
    223   public:
    224     MetadataOptions(MythScreenStack *parent, RecordingInfo *recinfo,
    225                    RecordingRule *rule);
     317    void TranscodeChanged(bool enable);
     318
     319  private:
     320    void Load(void);
     321    void Save(void);
     322};
     323
     324class MetadataOptions : public SchedEditChild
     325{
     326  Q_OBJECT
     327  public:
     328    MetadataOptions(MythScreenStack *parent, ScheduleEditor &editor,
     329                    RecordingRule &rule, RecordingInfo *recinfo);
    226330   ~MetadataOptions();
    227331
     
    245349    void ValuesChanged();
    246350
    247     void Close(void);
    248 
    249351  private:
    250352    void Load(void);
     
    263365
    264366    void customEvent(QEvent *event);
    265 
    266     RecordingInfo   *m_recInfo;
    267     RecordingRule   *m_recordingRule;
    268367
    269368    // For all metadata downloads
     
    296395    MythUIButton    *m_onlineBannerButton;
    297396
    298     MythUIButton    *m_backButton;
    299 
    300397    ArtworkMap       m_artworkMap;
    301398};
Note: See TracChangeset for help on using the changeset viewer.