[mythtv] [PATCH] Playlist UI Updated

Kevin Kuphal kuphal at dls.net
Thu Jan 27 20:43:37 EST 2005


This patch updates the playlist UI with feedback from Chris Pinkham.  It 
does the following:

- Moves all Playlist functions to a "Playlist Options" button off the 
MENU key as they are more appropriately accessed from that universal 
menu rather than the INFO menu of an individual recording.  Before a 
playlist is created the button will allow adding the selected title or 
highlighted group to a playlist. 

- Playlist Options popup includes the Play, Shuffle Play, Clear 
Playlist, and Toggle Playlist for selected item actions.  It also 
includes options which affect all items in the playlist: Change 
Recording Group and Delete

- The INFO menu adds a single new option to Add/Remove the highlighted 
recording to the Playlist

- The INFO play button returns to playing the individual recording.  
Pressing PLAY acts as it did prior to the playlist functionality.  The 
only way to Play a Playlist is to enter the MENU, choose Playlist 
Options, and select Play.  This was done to maintain the individual item 
functionality currently in the system while adding Playlist options and 
not changing the default behavior people have come to expect.

All the keybindings remain the same.

Thanks,
Kevin
-------------- next part --------------
Index: mythtv/programs/mythfrontend/playbackbox.cpp
===================================================================
RCS file: /var/lib/mythcvs/mythtv/programs/mythfrontend/playbackbox.cpp,v
retrieving revision 1.184
diff -n -u -r1.184 playbackbox.cpp
--- mythtv/programs/mythfrontend/playbackbox.cpp	21 Jan 2005 20:38:46 -0000	1.184
+++ mythtv/programs/mythfrontend/playbackbox.cpp	28 Jan 2005 01:00:30 -0000
@@ -56,6 +56,7 @@
     progIndex = 0;
     titleIndex = 0;
     playList.clear();
+    onPlaylist = false;
 
     skipUpdate = false;
     skipCnt = 0;
@@ -1332,36 +1333,46 @@
     }
 }
 
-void PlaybackBox::playSelected()
+void PlaybackBox::playSelectedPlaylist(bool random)
 {
     state = kStopping;
 
     if (!curitem)
         return;
 
-    if (!playList.count())
-    {
-        play(curitem);
-    }
-    else
+    ProgramInfo *tmpItem;
+    QStringList::Iterator it = playList.begin();
+    QStringList randomList = playList;
+    bool playNext = true;
+    int i = 0;
+   
+    while (randomList.count() && playNext)
     {
-        ProgramInfo *tmpItem;
-        QStringList::Iterator it;
-        bool playNext = true;
+        if (random)
+            i = (int)(1.0 * randomList.count() * rand() / (RAND_MAX + 1.0));
 
-        for (it = playList.begin(); it != playList.end() && playNext; ++it )
+        it = randomList.at(i);
+        tmpItem = findMatchingProg(*it);
+        if (tmpItem)
         {
-            tmpItem = findMatchingProg(*it);
-            if (tmpItem)
-            {
-                ProgramInfo *rec = new ProgramInfo(*tmpItem);
-                playNext = play(rec);
-                delete rec;
-            }
+            ProgramInfo *rec = new ProgramInfo(*tmpItem);
+            playNext = play(rec);
+            delete rec;
         }
+        randomList.remove(it);
     }
 }
 
+void PlaybackBox::playSelected()
+{
+    state = kStopping;
+
+    if (!curitem)
+        return;
+
+    play(curitem);
+}
+
 void PlaybackBox::stopSelected()
 {
     state = kStopping;
@@ -1485,6 +1496,17 @@
         popup->addButton(tr("Show group list as titles"), this,
                          SLOT(toggleTitleView()));
 
+    if (playList.count())
+        popup->addButton(tr("Playlist options"), this, SLOT(showPlaylistPopup()));
+    else
+        if (inTitle)
+            if (titleView)
+                popup->addButton(tr("Add this Category/Title Group to Playlist"), this, SLOT(togglePlayListItem()));
+            else 
+                popup->addButton(tr("Add this Recording Group to Playlist"), this, SLOT(togglePlayListItem()));
+        else 
+            popup->addButton(tr("Add this recording to Playlist"), this, SLOT(togglePlayListItem()));
+
     popup->addButton(tr("Cancel"), this, SLOT(doCancel()));
 
     popup->ShowPopup(this, SLOT(doCancel()));
@@ -1721,6 +1743,57 @@
     expectingPopup = true;
 }
 
+void PlaybackBox::showPlaylistPopup()
+{
+    if (expectingPopup)
+       cancelPopup();
+
+    backup.begin(this);
+    grayOut(&backup);
+    backup.end();
+
+    popup = new MythPopupBox(gContext->GetMainWindow(), graphicPopup,
+                             popupForeground, popupBackground,
+                             popupHighlight, "playlist popup");
+
+    QLabel *tlabel = NULL;
+    if (playList.count() > 1)
+    {
+        tlabel = popup->addLabel(tr("There are %1 items in the playlist.")
+                                       .arg(playList.count()));
+    } else {
+        tlabel = popup->addLabel(tr("There is %1 item in the playlist.")
+                                       .arg(playList.count()));
+    }
+    tlabel->setAlignment(Qt::AlignCenter | Qt::WordBreak);
+
+    QButton *playButton = popup->addButton(tr("Play"), this, SLOT(doPlayList()));
+    
+    popup->addButton(tr("Shuffle Play"), this, SLOT(doPlayListRandom()));
+    popup->addButton(tr("Clear Playlist"), this, SLOT(doClearPlaylist()));
+ 
+    QString addText = "Toggle playlist for this recording";
+    if (inTitle)
+        if (titleView)
+            addText = "Toggle playlist for this Category/Title";
+        else 
+            addText = "Toggle playlist for this Recording Group";
+
+    popup->addButton(tr(addText), this, SLOT(togglePlayListItem()));
+
+    QLabel *label = popup->addLabel(tr("These actions affect all items in the playlist"));
+    label->setAlignment(Qt::AlignCenter | Qt::WordBreak);
+
+    popup->addButton(tr("Change Recording Group"), this, SLOT(doPlaylistChangeRecGroup()));
+    popup->addButton(tr("Delete"), this, SLOT(doPlaylistDelete()));
+
+    playButton->setFocus();
+
+    popup->ShowPopup(this, SLOT(doCancel()));
+  
+    expectingPopup = true;
+}
+
 void PlaybackBox::showPlayFromPopup()
 {
     if (expectingPopup)
@@ -1780,7 +1853,7 @@
 
     popup->ShowPopup(this, SLOT(doCancel()));
     storageButton->setFocus();
-    
+
     expectingPopup = true;
 }
 
@@ -1861,62 +1934,47 @@
                              popupForeground, popupBackground,
                              popupHighlight, "action popup");
 
-    if (playList.count())
-    {
-        QLabel *label;
-        label = popup->addLabel(tr("Playlist Actions"), MythPopupBox::Large,
-                               false);
-        label->setAlignment(Qt::AlignCenter | Qt::WordBreak);
-
-        label = popup->addLabel(tr("There are %1 items in the list.")
-                                   .arg(playList.count()));
-        label->setAlignment(Qt::AlignCenter | Qt::WordBreak);
-    }
-    else
-    {
-        initPopup(popup, program, "", "");
-    }
+    initPopup(popup, program, "", "");
 
     QSqlDatabase *db = QSqlDatabase::database();
     QButton *playButton;
 
-    if (playList.count())
+    if (curitem->programflags & FL_BOOKMARK)
     {
-        playButton = popup->addButton(tr("Play"), this, SLOT(doPlay()));
-        popup->addButton(tr("Shuffle Play"), this, SLOT(doPlayListRandom()));
-        popup->addButton(tr("Change Recording Group"), this,
-                     SLOT(showRecGroupChanger()));
+        playButton = popup->addButton(tr("Play from..."), this, SLOT(showPlayFromPopup()));
     }
     else
     {
-        if (curitem->programflags & FL_BOOKMARK)
-        {
-            playButton = popup->addButton(tr("Play from..."), this, SLOT(showPlayFromPopup()));
-        }
-        else
-        {
-            playButton = popup->addButton(tr("Play"), this, SLOT(doPlay()));
-        }
+        playButton = popup->addButton(tr("Play"), this, SLOT(doPlay()));
+    }
 
-        if (RemoteGetRecordingStatus(program, overrectime, underrectime) > 0)
-            popup->addButton(tr("Stop Recording"), this, SLOT(askStop()));
+    QString key;
+    key = curitem->chanid + "_" +
+         curitem->startts.toString(Qt::ISODate);
 
-        // Remove this check and the auto expire buttons if a third button is added to the StoragePopup screen
-        // Otherwise for non-max-episode schedules, the popup will only show one button
-        if (delitem && delitem->UsesMaxEpisodes(db))
-        {
-            popup->addButton(tr("Storage Options"), this, SLOT(showStoragePopup()));
-        } else {
-            if (delitem && delitem->GetAutoExpireFromRecorded(db))
-                popup->addButton(tr("Don't Auto Expire"), this, SLOT(noAutoExpire()));
-            else
-                popup->addButton(tr("Auto Expire"), this, SLOT(doAutoExpire()));
-        }
+    if (playList.grep(key).count())
+        popup->addButton(tr("Remove from Playlist"), this, SLOT(togglePlayListItem()));
+    else
+        popup->addButton(tr("Add to Playlist"), this, SLOT(togglePlayListItem()));
+
+    if (RemoteGetRecordingStatus(program, overrectime, underrectime) > 0)
+        popup->addButton(tr("Stop Recording"), this, SLOT(askStop()));
 
-        popup->addButton(tr("Recording Options"), this, SLOT(showRecordingPopup()));
-        popup->addButton(tr("Job Options"), this, SLOT(showJobPopup()));
+    // Remove this check and the auto expire buttons if a third button is added to the StoragePopup screen
+    // Otherwise for non-max-episode schedules, the popup will only show one button
+    if (delitem && delitem->UsesMaxEpisodes(db))
+    {
+        popup->addButton(tr("Storage Options"), this, SLOT(showStoragePopup()));
+    } else {
+        if (delitem && delitem->GetAutoExpireFromRecorded(db))
+            popup->addButton(tr("Don't Auto Expire"), this, SLOT(noAutoExpire()));
+        else
+            popup->addButton(tr("Auto Expire"), this, SLOT(doAutoExpire()));
     }
 
+    popup->addButton(tr("Recording Options"), this, SLOT(showRecordingPopup()));
+    popup->addButton(tr("Job Options"), this, SLOT(showJobPopup()));
+
     popup->addButton(tr("Delete"), this, SLOT(askDelete()));
 
     popup->ShowPopup(this, SLOT(doCancel()));
@@ -1976,6 +2034,14 @@
     setActiveWindow();
 }
 
+void PlaybackBox::doClearPlaylist(void)
+{
+    if (expectingPopup)
+        cancelPopup();
+
+    playList.clear();
+}
+
 void PlaybackBox::doPlay(void)
 {
     if (!expectingPopup)
@@ -1997,33 +2063,25 @@
     doPlay();
 }
 
-void PlaybackBox::doPlayListRandom(void)
+void PlaybackBox::doPlayList(void)
 {
     if (!expectingPopup)
         return;
 
-    if (playList.count())
-    {
-        QStringList randomList;
-        QStringList resList;
-        int i;
-        unsigned int items = playList.count();
+    cancelPopup();
 
-        while(randomList.count() != items)
-        {
-            i = (int)(1.0 * items * rand() / (RAND_MAX + 1.0));
+    playSelectedPlaylist(false);
+}
 
-            resList = randomList.grep(playList[i]);
-            if (resList.count())
-                continue;
 
-            randomList << playList[i];
-        }
+void PlaybackBox::doPlayListRandom(void)
+{
+    if (!expectingPopup)
+        return;
 
-        playList = randomList;
-    }
+    cancelPopup();
 
-    doPlay();
+    playSelectedPlaylist(true);
 }
 
 void PlaybackBox::doPreserveEpisode(void)
@@ -2191,6 +2249,33 @@
     timer->start(500);
 }
 
+void PlaybackBox::doPlaylistDelete(void)
+{
+    if (!expectingPopup)
+        return;
+
+    cancelPopup();
+
+    ProgramInfo *tmpItem;
+    QStringList::Iterator it;
+
+    for (it = playList.begin(); it != playList.end(); ++it )
+    {
+        tmpItem = findMatchingProg(*it);
+        if (tmpItem)
+        {
+            // Perform functions from doRemove here but update only once
+            // at the end to improve performance
+            RemoteDeleteRecording(tmpItem, false);
+            ScheduledRecording::signalChange(QSqlDatabase::database());
+        }
+    }
+
+    playList.clear();
+    connected = FillList();
+    update(fullRect);
+}
+
 void PlaybackBox::doDelete(void)
 {
     if (!expectingPopup)
@@ -2356,6 +2441,9 @@
 
 void PlaybackBox::togglePlayListItem(void)
 {
+    if (expectingPopup)
+        cancelPopup();
+
     if (!curitem)
         return;
 
@@ -2370,8 +2458,6 @@
             if (p)
                 togglePlayListItem(p);
         }
-
-        cursorRight();
     }
     else
     {
@@ -2448,7 +2534,6 @@
         {
             if (titleView) titleView = false;
             else titleView = true;
-            playList.clear();
             connected = FillList();
             skipUpdate = false;
             update(fullRect);
@@ -3016,6 +3101,17 @@
                 query.value(1).toString();
 }
 
+void PlaybackBox::doPlaylistChangeRecGroup(void)
+{
+    // This is needed to signal the RecGroup changer that we are taking
+    // action on the entire playlist.  Since the same function can be
+    // called with a playlist built but targeted against a single item
+    // checking the existance of a playlist is not enough
+    onPlaylist = true;
+    showRecGroupChanger();
+    onPlaylist = false;
+}
+
 void PlaybackBox::showRecGroupChanger(void)
 {
     if (!expectingPopup)
@@ -3106,11 +3202,7 @@
 
     QSqlDatabase *m_db = QSqlDatabase::database();
 
-    if (!playList.count())
-    {
-        delitem->ApplyRecordRecGroupChange(m_db, newRecGroup);
-    }
-    else
+    if (onPlaylist)
     {
         ProgramInfo *tmpItem;
         QStringList::Iterator it;
@@ -3121,6 +3213,9 @@
             if (tmpItem)
                 tmpItem->ApplyRecordRecGroupChange(m_db, newRecGroup);
         }
+        playList.clear();
+    } else {
+        delitem->ApplyRecordRecGroupChange(m_db, newRecGroup);
     }
     
     inTitle = gContext->GetNumSetting("PlaybackBoxStartInTitle", 0);
Index: mythtv/programs/mythfrontend/playbackbox.h
===================================================================
RCS file: /var/lib/mythcvs/mythtv/programs/mythfrontend/playbackbox.h,v
retrieving revision 1.62
diff -n -u -r1.62 playbackbox.h
--- mythtv/programs/mythfrontend/playbackbox.h	21 Jan 2005 07:12:48 -0000	1.62
+++ mythtv/programs/mythfrontend/playbackbox.h	28 Jan 2005 01:00:30 -0000
@@ -57,6 +57,7 @@
     void showRecordingPopup();
     void showJobPopup();
     void showStoragePopup();
+    void showPlaylistPopup();
 
     void doPlay();
     void doPlayFromBeg();
@@ -93,6 +94,12 @@
     void changeOldPasswordChanged(const QString &newText);
     void doBeginTranscoding();
     void doBeginFlagging();
+    void doClearPlaylist();
+    void doPlaylistDelete();
+    void doPlaylistChangeRecGroup();
+    void togglePlayListItem(void);
+    void playSelectedPlaylist(bool random);
+    void doPlayList(void);
   protected:
     void paintEvent(QPaintEvent *);
     void keyPressEvent(QKeyEvent *e);
@@ -110,7 +117,6 @@
     void expire(ProgramInfo *);
     void showActions(ProgramInfo *);
 
-    void togglePlayListItem(void);
     void togglePlayListItem(ProgramInfo *pginfo);
     void randomizePlayList(void);
 
@@ -137,6 +143,7 @@
     int progIndex;
     QStringList titleList;
     QStringList playList;
+    bool onPlaylist;
     QMap<QString, ProgramList> progLists;
 
     ProgramInfo *findMatchingProg(ProgramInfo *);


More information about the mythtv-dev mailing list