Ticket #8757: 8757-v1.patch

File 8757-v1.patch, 63.8 KB (added by danielk, 16 years ago)

Initial patch

  • libs/libmythtv/libmythtv.pro

     
    255255    HEADERS += tv_play_win.h            deletemap.h
    256256    HEADERS += mythcommflagplayer.h     commbreakmap.h
    257257    HEADERS += BDRingBuffer.h           mythbdplayer.h
    258     HEADERS += mythiowrapper.h
     258    HEADERS += mythiowrapper.h          tvbrowsehelper.h
    259259    SOURCES += tv_play.cpp              mythplayer.cpp
    260260    SOURCES += mythdvdplayer.cpp        audioplayer.cpp
    261261    SOURCES += DVDRingBuffer.cpp        playercontext.cpp
    262262    SOURCES += tv_play_win.cpp          deletemap.cpp
    263263    SOURCES += mythcommflagplayer.cpp   commbreakmap.cpp
    264264    SOURCES += BDRingBuffer.cpp         mythbdplayer.cpp
    265     SOURCES += mythiowrapper.cpp
     265    SOURCES += mythiowrapper.cpp        tvbrowsehelper.cpp
    266266
    267267    # Text subtitle parser
    268268    HEADERS += textsubtitleparser.h     xine_demux_sputext.h
  • libs/libmythtv/tv_play.h

     
    5858class TV;
    5959class OSDListTreeItemEnteredEvent;
    6060class OSDListTreeItemSelectedEvent;
     61class TVBrowseHelper;
    6162struct osdInfo;
    6263
    6364typedef QMap<QString,InfoMap>    DDValueMap;
     
    7879//            -> timerIdLock
    7980//            -> mainLoopCondLock
    8081//            -> stateChangeCondLock
    81 //            -> browseLock
     82//            -> channelGroupLock
    8283//
    8384// When holding one of these locks, you may lock any lock of  the locks to
    8485// the right of the current lock, but may not lock any lock to the left of
     
    169170    friend class PlaybackBox;
    170171    friend class GuideGrid;
    171172    friend class TvPlayWindow;
     173    friend class TVBrowseHelper;
    172174
    173175    Q_OBJECT
    174176  public:
     
    192194    void ProcessKeypress(PlayerContext*, QKeyEvent *e);
    193195    void ProcessNetworkControlCommand(PlayerContext *, const QString &command);
    194196    void customEvent(QEvent *e);
     197    bool event(QEvent *e);
    195198    bool HandleTrackAction(PlayerContext*, const QString &action);
    196199
    197200    // LiveTV commands
     
    263266                            const QStringList &actions,
    264267                            bool isDVD, bool isDVDStillFrame);
    265268
    266     void GetNextProgram(RemoteEncoder *enc,
    267                         BrowseDirection direction, InfoMap &infoMap) const;
    268     void GetNextProgram(BrowseDirection direction, InfoMap &infoMap) const;
    269 
    270269    // static functions
    271270    static void InitKeys(void);
    272271    static void ResetKeys(void);
     
    285284    void HandleUDPNotifyEvent(void);
    286285
    287286    // Channel Groups
    288     void SaveChannelGroup(void);
    289287    void UpdateChannelList(int groupID);
    290288
    291289  public slots:
     
    515513
    516514    void ToggleAutoExpire(PlayerContext*);
    517515
    518     void BrowseStart(PlayerContext*);
    519     void BrowseEnd(PlayerContext*, bool change_channel);
    520     void BrowseDispInfo(PlayerContext*, BrowseDirection direction);
    521     void BrowseChannel(PlayerContext*, const QString &channum);
    522516    bool BrowseHandleAction(PlayerContext*, const QStringList &actions);
    523     uint BrowseAllGetChanId(const QString &chan) const;
    524517
    525518    void ToggleRecord(PlayerContext*);
    526519
     
    652645    // Configuration variables from database
    653646    QString baseFilters;
    654647    QString db_channel_format;
    655     QString db_time_format;
    656     QString db_short_date_format;
    657648    uint    db_idle_timeout;
    658649    uint    db_udpnotify_port;
    659     uint    db_browse_max_forward;
    660650    int     db_playback_exit_prompt;
    661651    uint    db_autoexpire_default;
    662652    bool    db_auto_set_watched;
     
    670660    bool    db_use_fixed_size;
    671661    bool    db_browse_always;
    672662    bool    db_browse_all_tuners;
    673     DBChanList db_browse_all_channels;
     663    bool    db_use_channel_groups;
     664    bool    db_remember_last_channel_group;
     665    ChannelGroupList db_channel_groups;
    674666
    675667    bool    arrowAccel;
    676668
     
    763755    QDateTime lastLockSeenTime;
    764756
    765757    // Channel browsing state variables
    766     bool       browsemode;
    767     QString    browsechannum;
    768     uint       browsechanid;
    769     QString    browsestarttime;
    770     mutable QMutex browseLock; // protects db_browse_all_channels
     758    TVBrowseHelper *browsehelper;
    771759
    772760    // Program Info for currently playing video
    773761    // (or next video if InChangeState() is true)
     
    834822#endif // PLAY_FROM_RECORDER
    835823
    836824    // Channel group stuff
    837     int channel_group_id;
    838     uint browse_changrp;
    839     ChannelGroupList m_changrplist;
    840     DBChanList m_channellist;
     825    mutable QMutex channelGroupLock;
     826    int            channelGroupId;
     827    DBChanList     channelGroupChannelList;
    841828
    842829    // Network Control stuff
    843830    MythDeque<QString> networkControlCommands;
  • libs/libmythtv/tvbrowsehelper.h

     
     1// -*- Mode: c++ -*-
     2
     3#ifndef _TV_BROWSE_HELPER_H_
     4#define _TV_BROWSE_HELPER_H_
     5
     6#include <QWaitCondition>
     7#include <QThread>
     8#include <QString>
     9
     10#include "dbchannelinfo.h" // for DBChanList
     11#include "programtypes.h"  // for InfoMap
     12#include "tv.h"            // for BrowseDirection
     13
     14class PlayerContext;
     15class RemoteEncoder;
     16class TV;
     17
     18class BrowseInfo
     19{
     20  public:
     21    BrowseInfo(BrowseDirection dir) :
     22        m_dir(dir), m_chanid(0)
     23    {
     24    }
     25    BrowseInfo(BrowseDirection dir,
     26               const QString &channum,
     27               uint           chanid,
     28               const QString &starttime) :
     29        m_dir(dir),  m_channum(channum),
     30        m_chanid(0), m_starttime(starttime)
     31    {
     32    }
     33
     34    BrowseDirection m_dir;
     35    QString         m_channum;
     36    uint            m_chanid;
     37    QString         m_starttime;
     38};
     39
     40
     41class TVBrowseHelper : public QThread
     42{
     43  public:
     44    TVBrowseHelper(TV      *tv,
     45                   QString  time_format,
     46                   QString  short_date_format,
     47                   uint     browse_max_forward,
     48                   bool     browse_all_tuners,
     49                   bool     use_channel_groups,
     50                   QString  db_channel_ordering);
     51
     52    virtual ~TVBrowseHelper()
     53    {
     54        Stop();
     55        Wait();
     56    }
     57
     58    virtual void deleteLater()
     59    {
     60        Stop();
     61        QThread::deleteLater();
     62    }
     63
     64    void Stop()
     65    {
     66        QMutexLocker locker(&m_lock);
     67        m_list.clear();
     68        m_run = false;
     69        m_wait.wakeAll();
     70    }
     71
     72    void Wait() { QThread::wait(); }
     73
     74    bool BrowseStart(PlayerContext *ctx, bool skip_browse = false);
     75    void BrowseEnd(PlayerContext *ctx, bool change_channel);
     76    void BrowseDispInfo(PlayerContext *ctx, BrowseInfo &bi);
     77
     78    void BrowseDispInfo(PlayerContext *ctx, BrowseDirection direction)
     79    {
     80        BrowseInfo bi(direction);
     81        if (BROWSE_SAME != direction)
     82            BrowseDispInfo(ctx, bi);
     83    }
     84
     85    void BrowseChannel(PlayerContext *ctx, const QString &channum)
     86    {
     87        BrowseInfo bi(BROWSE_SAME, channum, 0, "");
     88        BrowseDispInfo(ctx, bi);
     89    }
     90
     91    BrowseInfo GetBrowsedInfo(void) const;
     92    bool IsBrowsing(void) const;
     93    uint BrowseAllGetChanId(const QString &channum) const;
     94
     95  protected:
     96    void GetNextProgram(BrowseDirection direction, InfoMap &infoMap) const;
     97    void GetNextProgramDB(BrowseDirection direction, InfoMap &infoMap) const;
     98
     99    virtual void run();
     100
     101    TV               *m_tv;
     102    DBChanList        db_browse_all_channels;
     103    QString           db_time_format;
     104    QString           db_short_date_format;
     105    uint              db_browse_max_forward;
     106    bool              db_browse_all_tuners;
     107    bool              db_use_channel_groups;
     108
     109    mutable QMutex    m_lock; // protects variables below
     110    PlayerContext    *m_ctx;
     111    QString           m_channum;
     112    uint              m_chanid;
     113    QString           m_starttime;
     114    bool              m_run;
     115    QWaitCondition    m_wait;
     116    QList<BrowseInfo> m_list;
     117};
     118
     119#endif // _TV_BROWSE_HELPER_H_
  • libs/libmythtv/tvbrowsehelper.cpp

     
     1#include "mythcorecontext.h"
     2
     3#include <QCoreApplication>
     4
     5#include "tvbrowsehelper.h"
     6#include "playercontext.h"
     7#include "remoteencoder.h"
     8#include "recordinginfo.h"
     9#include "tv_play.h"
     10
     11#define GetPlayer(X,Y) GetPlayerHaveLock(X, Y, __FILE__ , __LINE__)
     12#define GetOSDLock(X) GetOSDL(X, __FILE__, __LINE__)
     13
     14static void format_time(int seconds, QString &tMin, QString &tHrsMin)
     15{
     16    int minutes     = seconds / 60;
     17    int hours       = minutes / 60;
     18    int min         = minutes % 60;
     19
     20    tMin = TV::tr("%n minute(s)", "", minutes);
     21    tHrsMin.sprintf("%d:%02d", hours, min);
     22}
     23
     24TVBrowseHelper::TVBrowseHelper(
     25    TV      *tv,
     26    QString  time_format,
     27    QString  short_date_format,
     28    uint     browse_max_forward,
     29    bool     browse_all_tuners,
     30    bool     use_channel_groups,
     31    QString  db_channel_ordering) :
     32    m_tv(tv),
     33    db_time_format(time_format),
     34    db_short_date_format(short_date_format),
     35    db_browse_max_forward(browse_max_forward),
     36    db_browse_all_tuners(browse_all_tuners),
     37    db_use_channel_groups(use_channel_groups),
     38    m_ctx(NULL),
     39    m_chanid(0),
     40    m_run(true)
     41{
     42    if (db_browse_all_tuners)
     43    {
     44        db_browse_all_channels = ChannelUtil::GetChannels(
     45            0, true, "channum, callsign");
     46        ChannelUtil::SortChannels(
     47            db_browse_all_channels, db_channel_ordering, true);
     48    }
     49
     50    start();
     51}
     52
     53
     54/// \brief Begins channel browsing.
     55/// \note This may only be called from the UI thread.
     56bool TVBrowseHelper::BrowseStart(PlayerContext *ctx, bool skip_browse)
     57{
     58    VERBOSE(VB_IMPORTANT, "BrowseStart()");
     59
     60    if (!gCoreContext->IsUIThread())
     61        return false;
     62
     63    QMutexLocker locker(&m_lock);
     64
     65    if (m_ctx)
     66        return m_ctx == ctx;
     67
     68    if (ctx->paused)
     69        return false;
     70
     71    m_tv->ClearOSD(ctx);
     72
     73    ctx->LockPlayingInfo(__FILE__, __LINE__);
     74    if (ctx->playingInfo)
     75    {
     76        m_ctx = ctx;
     77        BrowseInfo bi(BROWSE_SAME,
     78                      ctx->playingInfo->GetChanNum(),
     79                      ctx->playingInfo->GetChanID(),
     80                      ctx->playingInfo->GetScheduledStartTime(ISODate));
     81        ctx->UnlockPlayingInfo(__FILE__, __LINE__);
     82
     83        if (!skip_browse)
     84        {
     85            locker.unlock();
     86            BrowseDispInfo(ctx, bi);
     87        }
     88        return true;
     89    }
     90    else
     91    {
     92        ctx->UnlockPlayingInfo(__FILE__, __LINE__);
     93        return false;
     94    }
     95}
     96
     97/** \brief Ends channel browsing.
     98 *         Changing the channel if change_channel is true.
     99 *  \note This may only be called from the UI thread.
     100 *  \param ctx PlayerContext to end browsing on
     101 *  \param change_channel iff true we call ChangeChannel()
     102 */
     103void TVBrowseHelper::BrowseEnd(PlayerContext *ctx, bool change_channel)
     104{
     105    VERBOSE(VB_IMPORTANT, "BrowseEnd()");
     106
     107    if (!gCoreContext->IsUIThread())
     108        return;
     109
     110    QMutexLocker locker(&m_lock);
     111
     112    if (ctx && m_ctx != ctx)
     113        return;
     114
     115    if (!m_ctx)
     116        return;
     117
     118    {
     119        QMutexLocker locker(&m_tv->timerIdLock);
     120        if (m_tv->browseTimerId)
     121        {
     122            m_tv->KillTimer(m_tv->browseTimerId);
     123            m_tv->browseTimerId = 0;
     124        }
     125    }
     126
     127    {
     128        QMutexLocker locker(&m_lock);
     129        m_list.clear();
     130        m_wait.wakeAll();
     131    }
     132
     133    OSD *osd = m_tv->GetOSDLock(ctx);
     134    if (osd)
     135        osd->HideWindow("browse_info");
     136    m_tv->ReturnOSDLock(ctx, osd);
     137
     138    if (change_channel)
     139        m_tv->ChangeChannel(ctx, 0, m_channum);
     140
     141    m_ctx = NULL;
     142}
     143
     144void TVBrowseHelper::BrowseDispInfo(PlayerContext *ctx, BrowseInfo &bi)
     145{
     146    VERBOSE(VB_IMPORTANT, "BrowseDispInfo()");
     147
     148    if (!gCoreContext->IsUIThread())
     149        return;
     150
     151    if (!BrowseStart(ctx, true))
     152        return;
     153
     154    {
     155        QMutexLocker locker(&m_tv->timerIdLock);
     156        if (m_tv->browseTimerId)
     157        {
     158            m_tv->KillTimer(m_tv->browseTimerId);
     159            m_tv->browseTimerId =
     160                m_tv->StartTimer(TV::kBrowseTimeout, __LINE__);
     161        }
     162    }
     163
     164    QMutexLocker locker(&m_lock);
     165    if (BROWSE_SAME == bi.m_dir)
     166        m_list.clear();
     167    m_list.push_back(bi);
     168    m_wait.wakeAll();
     169}
     170
     171BrowseInfo TVBrowseHelper::GetBrowsedInfo(void) const
     172{
     173    QMutexLocker locker(&m_lock);
     174    BrowseInfo bi(BROWSE_SAME);
     175    if (m_ctx != NULL)
     176    {
     177        bi.m_channum   = m_channum;
     178        bi.m_chanid    = m_chanid;
     179        bi.m_starttime = m_starttime;
     180    }
     181    return bi;
     182}
     183
     184/**
     185 *  \note This may only be called from the UI thread.
     186 */
     187bool TVBrowseHelper::IsBrowsing(void) const
     188{
     189    if (!gCoreContext->IsUIThread())
     190        return true;
     191
     192    return m_ctx != NULL;
     193}
     194
     195/// Returns chanid of random channel with with matching channum
     196uint TVBrowseHelper::BrowseAllGetChanId(const QString &channum) const
     197{
     198    DBChanList::const_iterator it = db_browse_all_channels.begin();
     199    for (; it != db_browse_all_channels.end(); ++it)
     200    {
     201        if ((*it).channum == channum)
     202            return (*it).chanid;
     203    }
     204    return 0;
     205}
     206
     207/**
     208 *  \brief Fetches information on the desired program from the backend.
     209 *  \param enc RemoteEncoder to query, if null query the actx->recorder.
     210 *  \param direction BrowseDirection to get information on.
     211 *  \param infoMap InfoMap to fill in with returned data
     212 */
     213void TVBrowseHelper::GetNextProgram(
     214    BrowseDirection direction, InfoMap &infoMap) const
     215{
     216    if (!m_ctx->recorder)
     217        return;
     218
     219    QString title, subtitle, desc, category, endtime, callsign, iconpath;
     220    QDateTime begts, endts;
     221
     222    QString starttime = infoMap["dbstarttime"];
     223    QString chanid    = infoMap["chanid"];
     224    QString channum   = infoMap["channum"];
     225    QString seriesid  = infoMap["seriesid"];
     226    QString programid = infoMap["programid"];
     227
     228    m_ctx->recorder->GetNextProgram(
     229        direction,
     230        title,     subtitle,  desc,      category,
     231        starttime, endtime,   callsign,  iconpath,
     232        channum,   chanid,    seriesid,  programid);
     233
     234    if (!starttime.isEmpty())
     235        begts = QDateTime::fromString(starttime, Qt::ISODate);
     236    else
     237        begts = QDateTime::fromString(infoMap["dbstarttime"], Qt::ISODate);
     238
     239    infoMap["starttime"] = begts.toString(db_time_format);
     240    infoMap["startdate"] = begts.toString(db_short_date_format);
     241
     242    infoMap["endtime"] = infoMap["enddate"] = "";
     243    if (!endtime.isEmpty())
     244    {
     245        endts = QDateTime::fromString(endtime, Qt::ISODate);
     246        infoMap["endtime"] = endts.toString(db_time_format);
     247        infoMap["enddate"] = endts.toString(db_short_date_format);
     248    }
     249
     250    infoMap["lenmins"] = tr("%n minute(s)", "", 0);
     251    infoMap["lentime"] = "0:00";
     252    if (begts.isValid() && endts.isValid())
     253    {
     254        QString lenM, lenHM;
     255        format_time(begts.secsTo(endts), lenM, lenHM);
     256        infoMap["lenmins"] = lenM;
     257        infoMap["lentime"] = lenHM;
     258    }
     259
     260    infoMap["dbstarttime"] = starttime;
     261    infoMap["dbendtime"]   = endtime;
     262    infoMap["title"]       = title;
     263    infoMap["subtitle"]    = subtitle;
     264    infoMap["description"] = desc;
     265    infoMap["category"]    = category;
     266    infoMap["callsign"]    = callsign;
     267    infoMap["channum"]     = channum;
     268    infoMap["chanid"]      = chanid;
     269    infoMap["iconpath"]    = iconpath;
     270    infoMap["seriesid"]    = seriesid;
     271    infoMap["programid"]   = programid;
     272}
     273
     274void TVBrowseHelper::GetNextProgramDB(
     275    BrowseDirection direction, InfoMap &infoMap) const
     276{
     277    uint chanid = infoMap["chanid"].toUInt();
     278    if (!chanid)
     279        chanid = BrowseAllGetChanId(infoMap["channum"]);
     280
     281    int chandir = -1;
     282    switch (direction)
     283    {
     284        case BROWSE_UP:       chandir = CHANNEL_DIRECTION_UP;       break;
     285        case BROWSE_DOWN:     chandir = CHANNEL_DIRECTION_DOWN;     break;
     286        case BROWSE_FAVORITE: chandir = CHANNEL_DIRECTION_FAVORITE; break;
     287    }
     288    if (direction != BROWSE_INVALID)
     289    {
     290        chanid = ChannelUtil::GetNextChannel(
     291            db_browse_all_channels, chanid, 0, chandir);
     292    }
     293
     294    infoMap["chanid"] = QString::number(chanid);
     295
     296    DBChanList::const_iterator it = db_browse_all_channels.begin();
     297    for (; it != db_browse_all_channels.end(); ++it)
     298    {
     299        if ((*it).chanid == chanid)
     300        {
     301            QString tmp = (*it).channum;
     302            tmp.detach();
     303            infoMap["channum"] = tmp;
     304            break;
     305        }
     306    }
     307
     308    QDateTime nowtime = QDateTime::currentDateTime();
     309    QDateTime latesttime = nowtime.addSecs(6*60*60);
     310    QDateTime browsetime = QDateTime::fromString(
     311        infoMap["dbstarttime"], Qt::ISODate);
     312
     313    MSqlBindings bindings;
     314    bindings[":CHANID"] = chanid;
     315    bindings[":NOWTS"] = nowtime.toString("yyyy-MM-ddThh:mm:ss");
     316    bindings[":LATESTTS"] = latesttime.toString("yyyy-MM-ddThh:mm:ss");
     317    bindings[":BROWSETS"] = browsetime.toString("yyyy-MM-ddThh:mm:ss");
     318    bindings[":BROWSETS2"] = browsetime.toString("yyyy-MM-ddThh:mm:ss");
     319
     320    QString querystr = " WHERE program.chanid = :CHANID ";
     321    switch (direction)
     322    {
     323        case BROWSE_LEFT:
     324            querystr += " AND program.endtime <= :BROWSETS "
     325                " AND program.endtime > :NOWTS ";
     326            break;
     327
     328        case BROWSE_RIGHT:
     329            querystr += " AND program.starttime > :BROWSETS "
     330                " AND program.starttime < :LATESTTS ";
     331            break;
     332
     333        default:
     334            querystr += " AND program.starttime <= :BROWSETS "
     335                " AND program.endtime > :BROWSETS2 ";
     336    };
     337
     338    ProgramList progList;
     339    ProgramList dummySched;
     340    LoadFromProgram(progList, querystr, bindings, dummySched, false);
     341
     342    if (progList.empty())
     343    {
     344        infoMap["dbstarttime"] = "";
     345        return;
     346    }
     347
     348    const ProgramInfo *prog = (direction == BROWSE_LEFT) ?
     349        progList[progList.size() - 1] : progList[0];
     350
     351    infoMap["dbstarttime"] = prog->GetScheduledStartTime(ISODate);
     352}
     353
     354void TVBrowseHelper::run()
     355{
     356    QMutexLocker locker(&m_lock);
     357    while (true)
     358    {
     359        while (m_list.empty() && m_run)
     360            m_wait.wait(&m_lock);
     361
     362        if (!m_run)
     363            break;
     364
     365        BrowseInfo bi = m_list.front();
     366        m_list.pop_front();
     367
     368        PlayerContext *ctx = m_ctx;
     369
     370        if (BROWSE_SAME == bi.m_dir)
     371        {
     372            m_channum   = bi.m_channum;
     373            m_chanid    = bi.m_chanid;
     374            m_starttime = bi.m_starttime;
     375        }
     376
     377        BrowseDirection direction = bi.m_dir;
     378
     379        QDateTime lasttime = QDateTime::fromString(
     380            m_starttime, Qt::ISODate);
     381        QDateTime curtime  = QDateTime::currentDateTime();
     382        if (lasttime < curtime)
     383            m_starttime = curtime.toString(Qt::ISODate);
     384
     385        QDateTime maxtime  = curtime.addSecs(db_browse_max_forward);
     386        if ((lasttime > maxtime) && (direction == BROWSE_RIGHT))
     387            continue;
     388
     389        m_lock.unlock();
     390
     391        // if browsing channel groups is enabled or
     392        // direction if BROWSE_FAVORITES
     393        // Then pick the next channel in the channel group list to browse
     394        // If channel group is ALL CHANNELS (-1), then bypass picking from
     395        // the channel group list
     396        if ((db_use_channel_groups || (direction == BROWSE_FAVORITE)) &&
     397            (direction != BROWSE_RIGHT) && (direction != BROWSE_LEFT) &&
     398            (direction != BROWSE_SAME))
     399        {
     400            m_tv->channelGroupLock.lock();
     401            if (m_tv->channelGroupId > -1)
     402            {
     403                int dir = direction;
     404                if ((direction == BROWSE_UP) || (direction == BROWSE_FAVORITE))
     405                    dir = CHANNEL_DIRECTION_UP;
     406                else if (direction == BROWSE_DOWN)
     407                    dir = CHANNEL_DIRECTION_DOWN;
     408
     409                uint chanid = ChannelUtil::GetNextChannel(
     410                    m_tv->channelGroupChannelList, m_chanid, 0, dir);
     411                direction = BROWSE_SAME;
     412
     413                m_tv->channelGroupLock.unlock();
     414
     415                m_lock.lock();
     416                m_chanid  = chanid;
     417                m_channum = QString::null;
     418                m_lock.unlock();
     419            }
     420            else
     421                m_tv->channelGroupLock.unlock();
     422        }
     423
     424        if (direction == BROWSE_FAVORITE)
     425            direction = BROWSE_UP;
     426
     427        InfoMap infoMap;
     428        infoMap["dbstarttime"] = m_starttime;
     429        infoMap["channum"]     = m_channum;
     430        infoMap["chanid"]      = QString::number(m_chanid);
     431
     432        m_tv->GetPlayerReadLock(0,__FILE__,__LINE__);
     433        bool still_there = false;
     434        for (uint i = 0; i < m_tv->player.size() && !still_there; i++)
     435            still_there |= (ctx == m_tv->player[0]);
     436        if (still_there)
     437        {
     438            if (!db_browse_all_tuners)
     439            {
     440                GetNextProgram(direction, infoMap);
     441            }
     442            else
     443            {
     444                GetNextProgramDB(direction, infoMap);
     445                while (!m_tv->IsTunable(ctx, infoMap["chanid"].toUInt()) &&
     446                       (infoMap["channum"] != m_channum))
     447                {
     448                    GetNextProgramDB(direction, infoMap);
     449                }
     450            }
     451        }
     452        m_tv->ReturnPlayerLock(ctx);
     453
     454        m_lock.lock();
     455        if (!m_ctx && !still_there)
     456            continue;
     457
     458        VERBOSE(VB_IMPORTANT, QString("browsechanid: %1 -> %2")
     459                .arg(m_chanid).arg(infoMap["chanid"].toUInt()));
     460
     461        m_channum = infoMap["channum"];
     462        m_chanid  = infoMap["chanid"].toUInt();
     463
     464        if (((direction == BROWSE_LEFT) || (direction == BROWSE_RIGHT)) &&
     465            !infoMap["dbstarttime"].isEmpty())
     466        {
     467            m_starttime = infoMap["dbstarttime"];
     468        }
     469
     470        if (!m_list.empty())
     471        {
     472            // send partial info to UI for appearance of responsiveness
     473            QCoreApplication::postEvent(
     474                this, new UpdateBrowseInfoEvent(infoMap));
     475            continue;
     476        }
     477        m_lock.unlock();
     478
     479        // pull in additional data from the DB...
     480        QDateTime startts = QDateTime::fromString(
     481            m_starttime, Qt::ISODate);
     482        RecordingInfo recinfo(m_chanid, startts, false);
     483        recinfo.ToMap(infoMap);
     484        infoMap["iconpath"] = ChannelUtil::GetIcon(recinfo.GetChanID());
     485
     486        m_lock.lock();
     487        if (m_ctx)
     488        {
     489            QCoreApplication::postEvent(
     490                this, new UpdateBrowseInfoEvent(infoMap));
     491        }
     492    }
     493}
  • libs/libmythtv/tv_play.cpp

     
    5858#include "videometadatautil.h"
    5959#include "mythdialogbox.h"
    6060#include "mythdirs.h"
     61#include "tvbrowsehelper.h"
    6162
    6263#if ! HAVE_ROUND
    6364#define round(x) ((int) ((x) + 0.5))
     
    421422    bool allowrerecord = tv->getAllowRerecord();
    422423    bool deleterecording = tv->requestDelete;
    423424
    424     tv->SaveChannelGroup();
    425 
    426425    delete tv;
    427426
    428427    if (curProgram)
     
    857856    : // Configuration variables from database
    858857      baseFilters(""),
    859858      db_channel_format("<num> <sign>"),
    860       db_time_format("h:mm AP"), db_short_date_format("M/d"),
    861859      db_idle_timeout(0),           db_udpnotify_port(0),
    862       db_browse_max_forward(14400),
    863860      db_playback_exit_prompt(0),   db_autoexpire_default(0),
    864861      db_auto_set_watched(false),   db_end_of_rec_exit_prompt(false),
    865862      db_jump_prefer_osd(true),     db_use_gui_size_for_tv(false),
     
    867864      db_run_jobs_on_remote(false), db_continue_embedded(false),
    868865      db_use_fixed_size(true),      db_browse_always(false),
    869866      db_browse_all_tuners(false),
     867      db_use_channel_groups(false), db_remember_last_channel_group(false),
    870868
    871869      arrowAccel(false),
    872870      tryUnflaggedSkip(false),
     
    902900      // Channel changing state variables
    903901      queuedChanNum(""),
    904902      lockTimerOn(false),
    905       // channel browsing state variables
    906       browsemode(false),
    907       browsechannum(""), browsechanid(0), browsestarttime(""),
     903      // channel browsing
     904      browsehelper(NULL),
    908905      // Program Info for currently playing video
    909906      lastProgram(NULL),
    910907      inPlaylist(false), underNetworkControl(false),
     
    992989    kv["FFRewReposTime"]           = "100";
    993990    kv["FFRewReverse"]             = "1";
    994991
    995     kv["ChannelGroupDefault"]      = "-1";
    996992    kv["BrowseChannelGroup"]       = "0";
     993    kv["ChannelGroupDefault"]      = "-1";
     994    kv["ChannelGroupRememberLast"] = "0";
     995
    997996    kv["VbiFormat"]                = "";
    998997    kv["DecodeVBIFormat"]          = "";
    999998
     
    10031002
    10041003    MythDB::getMythDB()->GetSettings(kv);
    10051004
     1005    QString db_time_format;
     1006    QString db_short_date_format;
     1007    QString db_channel_ordering;
     1008    uint    db_browse_max_forward;
     1009
    10061010    // convert from minutes to ms.
    10071011    db_idle_timeout        = kv["LiveTVIdleTimeout"].toInt() * 60 * 1000;
    10081012    db_udpnotify_port      = kv["UDPNotifyPort"].toInt();
     
    10201024    db_use_fixed_size      = kv["UseFixedWindowSize"].toInt();
    10211025    db_browse_always       = kv["PersistentBrowseMode"].toInt();
    10221026    db_browse_all_tuners   = kv["BrowseAllTuners"].toInt();
    1023     QString channelOrdering= kv["ChannelOrdering"];
     1027    db_channel_ordering    = kv["ChannelOrdering"];
    10241028    baseFilters           += kv["CustomFilters"];
    10251029    db_channel_format      = kv["ChannelFormat"];
    10261030    db_time_format         = kv["TimeFormat"];
    10271031    db_short_date_format   = kv["ShortDateFormat"];
    10281032    arrowAccel             = kv["UseArrowAccels"].toInt();
    10291033    tryUnflaggedSkip       = kv["TryUnflaggedSkip"].toInt();
    1030     channel_group_id       = kv["ChannelGroupDefault"].toInt();
    1031     browse_changrp         = kv["BrowseChannelGroup"].toInt();
    10321034    smartForward           = kv["SmartForward"].toInt();
    10331035    ff_rew_repos           = kv["FFRewReposTime"].toFloat() * 0.01f;
    10341036    ff_rew_reverse         = kv["FFRewReverse"].toInt();
    1035     channel_group_id       = kv["ChannelGroupDefault"].toInt();
    1036     browse_changrp         = kv["BrowseChannelGroup"].toInt();
     1037
     1038    db_use_channel_groups  = kv["BrowseChannelGroup"].toInt();
     1039    db_remember_last_channel_group = kv["ChannelGroupRememberLast"].toInt();
     1040    channelGroupId         = kv["ChannelGroupDefault"].toInt();
     1041
    10371042    QString beVBI          = kv["VbiFormat"];
    10381043    QString feVBI          = kv["DecodeVBIFormat"];
    10391044
     1045    if (db_use_channel_groups)
     1046    {
     1047        db_channel_groups  = ChannelGroup::GetChannelGroups();
     1048        if (channelGroupId > -1)
     1049        {
     1050            channelGroupChannelList = ChannelUtil::GetChannels(
     1051                0, true, "channum, callsign", channelGroupId);
     1052            ChannelUtil::SortChannels(
     1053                channelGroupChannelList, "channum", true);
     1054        }
     1055    }
     1056
    10401057    for (uint i = 0; i < sizeof(ff_rew_def)/sizeof(ff_rew_def[0]); i++)
    10411058        ff_rew_speeds.push_back(kv[QString("FFRewSpeed%1").arg(i)].toInt());
    10421059
    10431060    // process it..
     1061    browsehelper = new TVBrowseHelper(
     1062        this,
     1063        db_time_format,          db_short_date_format,
     1064        db_browse_max_forward,   db_browse_all_tuners,
     1065        db_use_channel_groups,   db_channel_ordering);
    10441066
    1045     if (db_browse_all_tuners)
    1046     {
    1047         QMutexLocker locker(&browseLock);
    1048         db_browse_all_channels = ChannelUtil::GetChannels(
    1049             0, true, "channum, callsign");
    1050         ChannelUtil::SortChannels(
    1051             db_browse_all_channels, channelOrdering, true);
    1052     }
    1053 
    10541067    vbimode = VBIMode::Parse(!feVBI.isEmpty() ? feVBI : beVBI);
    10551068
    1056     if (browse_changrp && (channel_group_id > -1))
    1057     {
    1058         m_channellist = ChannelUtil::GetChannels(
    1059             0, true, "channum, callsign", channel_group_id);
    1060         ChannelUtil::SortChannels(m_channellist, "channum", true);
    1061     }
    1062 
    1063     m_changrplist  = ChannelGroup::GetChannelGroups();
    1064 
    10651069    gCoreContext->addListener(this);
    10661070
    10671071    QMutexLocker lock(&initFromDBLock);
     
    11891193{
    11901194    VERBOSE(VB_PLAYBACK, "TV::~TV() -- begin");
    11911195
     1196    if (browsehelper)
     1197        browsehelper->Stop();
     1198
    11921199    if (udpnotify)
    11931200    {
    11941201        udpnotify->deleteLater();
     
    12431250        }
    12441251    }
    12451252
     1253    if (browsehelper)
     1254    {
     1255        delete browsehelper;
     1256        browsehelper = NULL;
     1257    }
     1258
    12461259    PlayerContext *mctx = GetPlayerWriteLock(0, __FILE__, __LINE__);
    12471260    while (!player.empty())
    12481261    {
     
    12571270}
    12581271
    12591272/**
    1260  * \brief save channel group setting to database
    1261  */
    1262 void TV::SaveChannelGroup(void)
    1263 {
    1264     int remember_last_changrp = gCoreContext->GetNumSetting("ChannelGroupRememberLast", 0);
    1265 
    1266     if (remember_last_changrp)
    1267        gCoreContext->SaveSetting("ChannelGroupDefault", channel_group_id);
    1268 }
    1269 
    1270 /**
    12711273 * \brief update the channel list with channels from the selected channel group
    12721274 */
    12731275void TV::UpdateChannelList(int groupID)
    12741276{
    1275     if (groupID == channel_group_id)
     1277    if (!db_use_channel_groups)
    12761278        return;
    12771279
    1278     channel_group_id = groupID;
     1280    QMutexLocker locker(&channelGroupLock);
     1281    if (groupID == channelGroupId)
     1282        return;
    12791283
    1280     if (browse_changrp)
     1284    DBChanList list;
     1285    if (groupID != -1)
    12811286    {
    1282         m_channellist = ChannelUtil::GetChannels(0, true, "channum, callsign", channel_group_id);
    1283         ChannelUtil::SortChannels(m_channellist, "channum", true);
     1287        list = ChannelUtil::GetChannels(
     1288            0, true, "channum, callsign", groupID);
     1289        ChannelUtil::SortChannels(list, "channum", true);
    12841290    }
     1291
     1292    channelGroupId = groupID;
     1293    channelGroupChannelList = list;
     1294
     1295    if (db_remember_last_channel_group)
     1296        gCoreContext->SaveSetting("ChannelGroupDefault", channelGroupId);
    12851297}
    12861298
    12871299/**
     
    15951607        OSD *osd = GetOSDLock(ctx);
    15961608        if (osd)
    15971609        {
    1598             BrowseEnd(ctx, false);
     1610            browsehelper->BrowseEnd(ctx, false);
    15991611            timeuntil = QDateTime::currentDateTime().secsTo((*it).expiry) * 1000;
    16001612            osd->DialogShow(OSD_DLG_ASKALLOW, message, timeuntil);
    16011613            osd->DialogAddButton(record_watch, "DIALOG_ASKALLOW_WATCH_0",
     
    16711683        OSD *osd = GetOSDLock(ctx);
    16721684        if (osd && conflict_count > 1)
    16731685        {
    1674             BrowseEnd(ctx, false);
     1686            browsehelper->BrowseEnd(ctx, false);
    16751687            osd->DialogShow(OSD_DLG_ASKALLOW, message, timeuntil);
    16761688            osd->DialogAddButton(let_recordm, "DIALOG_ASKALLOW_EXIT_0",
    16771689                                 false, true);
     
    16801692        }
    16811693        else if (osd)
    16821694        {
    1683             BrowseEnd(ctx, false);
     1695            browsehelper->BrowseEnd(ctx, false);
    16841696            osd->DialogShow(OSD_DLG_ASKALLOW, message, timeuntil);
    16851697            osd->DialogAddButton(let_record1, "DIALOG_ASKALLOW_EXIT_0",
    16861698                                 false, !has_rec);
     
    28572869    if (timer_id == browseTimerId)
    28582870    {
    28592871        PlayerContext *actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
    2860         BrowseEnd(actx, false);
     2872        browsehelper->BrowseEnd(actx, false);
    28612873        ReturnPlayerLock(actx);
    28622874        handled = true;
    28632875    }
     
    33333345    ReturnPlayerLock(actx);
    33343346}
    33353347
     3348/// This selectively blocks KeyPress and Resize events
    33363349bool TV::eventFilter(QObject *o, QEvent *e)
    33373350{
    3338     const MythMainWindow *mainWindow = GetMythMainWindow();
    3339     if (mainWindow == o)
     3351    // We want to intercept all resize events sent to the main window
     3352    if ((e->type() == QEvent::Resize))
     3353        return (GetMythMainWindow()!=o)?false:event(e);
     3354
     3355    // We want to intercept all KeyPress events unless ignoreKeyPresses is set
     3356    if (QEvent::KeyPress == e->type())
     3357        return ignoreKeyPresses?false:event(e);
     3358
     3359    return QThread::eventFilter(o,e);
     3360}
     3361
     3362/// This handles all standard events
     3363bool TV::event(QEvent *e)
     3364{
     3365    if (QEvent::Resize == e->type())
    33403366    {
    3341         if (e->type() == QEvent::Resize)
    3342         {
    3343             PlayerContext *mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
    3344             mctx->LockDeletePlayer(__FILE__, __LINE__);
    3345             if (mctx->player)
    3346                 mctx->player->WindowResized(((const QResizeEvent*) e)->size());
    3347             mctx->UnlockDeletePlayer(__FILE__, __LINE__);
    3348             ReturnPlayerLock(mctx);
    3349         }
     3367        PlayerContext *mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
     3368        mctx->LockDeletePlayer(__FILE__, __LINE__);
     3369        if (mctx->player)
     3370            mctx->player->WindowResized(((const QResizeEvent*) e)->size());
     3371        mctx->UnlockDeletePlayer(__FILE__, __LINE__);
     3372        ReturnPlayerLock(mctx);
     3373        return true;
    33503374    }
    33513375
    3352     if (e->type() == MythEvent::MythEventMessage)
     3376    if (QEvent::KeyPress == e->type())
    33533377    {
    3354         customEvent(e);
     3378        QKeyEvent *k = new QKeyEvent(*(QKeyEvent *)e);
     3379        QMutexLocker locker(&timerIdLock);
     3380        keyList.enqueue(k);
     3381        if (!keyListTimerId)
     3382            keyListTimerId = StartTimer(1, __LINE__);
    33553383        return true;
    33563384    }
    33573385
    33583386    switch (e->type())
    33593387    {
    3360         case QEvent::KeyPress:
    3361         {
    3362             // we ignore keypresses if the epg is running for example
    3363             if (!ignoreKeyPresses)
    3364             {
    3365                 QKeyEvent *k = new QKeyEvent(*(QKeyEvent *)e);
    3366                 QMutexLocker locker(&timerIdLock);
    3367                 keyList.enqueue(k);
    3368                 if (!keyListTimerId)
    3369                     keyListTimerId = StartTimer(1, __LINE__);
    3370 
    3371                 return true;
    3372              }
    3373              else
    3374              {
    3375                 return false;
    3376              }
    3377         }
    3378 
    33793388        case QEvent::Paint:
    33803389        case QEvent::UpdateRequest:
    33813390        case QEvent::Enter:
    3382         {
    33833391            DrawUnusedRects();
    3384             return false;
    3385         }
    3386 
     3392            return true;
    33873393        default:
    3388             return false;
     3394            break;
    33893395    }
     3396
     3397    return QThread::event(e);
    33903398}
    33913399
    33923400bool TV::HandleTrackAction(PlayerContext *ctx, const QString &action)
     
    34053413        handled = true;
    34063414        ctx->player->ToggleCaptions(kTrackTypeTextSubtitle);
    34073415    }
    3408     else if (action == "TOGGLECC" && !browsemode)
     3416    else if (action == "TOGGLECC" && !browsehelper->IsBrowsing())
    34093417    {
    34103418        handled = true;
    34113419        if (ccInputMode)
     
    35343542        bool pause = has_action("PAUSE",  actions);
    35353543        bool play  = has_action("PLAY",   actions);
    35363544
    3537         if ((!esc || browsemode) && !pause && !play)
     3545        if ((!esc || browsehelper->IsBrowsing()) && !pause && !play)
    35383546            return;
    35393547    }
    35403548
     
    36943702
    36953703bool TV::BrowseHandleAction(PlayerContext *ctx, const QStringList &actions)
    36963704{
    3697     if (!browsemode)
     3705    if (!browsehelper->IsBrowsing())
    36983706        return false;
    36993707
    37003708    bool handled = true;
    37013709
    37023710    if (has_action("UP", actions) || has_action("CHANNELUP", actions))
    3703         BrowseDispInfo(ctx, BROWSE_UP);
     3711        browsehelper->BrowseDispInfo(ctx, BROWSE_UP);
    37043712    else if (has_action("DOWN", actions) || has_action("CHANNELDOWN", actions))
    3705         BrowseDispInfo(ctx, BROWSE_DOWN);
     3713        browsehelper->BrowseDispInfo(ctx, BROWSE_DOWN);
    37063714    else if (has_action("LEFT", actions))
    3707         BrowseDispInfo(ctx, BROWSE_LEFT);
     3715        browsehelper->BrowseDispInfo(ctx, BROWSE_LEFT);
    37083716    else if (has_action("RIGHT", actions))
    3709         BrowseDispInfo(ctx, BROWSE_RIGHT);
     3717        browsehelper->BrowseDispInfo(ctx, BROWSE_RIGHT);
    37103718    else if (has_action("NEXTFAV", actions))
    3711         BrowseDispInfo(ctx, BROWSE_FAVORITE);
     3719        browsehelper->BrowseDispInfo(ctx, BROWSE_FAVORITE);
    37123720    else if (has_action("SELECT", actions))
    37133721    {
    3714         BrowseEnd(ctx, true);
     3722        browsehelper->BrowseEnd(ctx, true);
    37153723    }
    37163724    else if (has_action("CLEAROSD",     actions) ||
    37173725             has_action("ESCAPE",       actions) ||
    37183726             has_action("BACK",         actions) ||
    37193727             has_action("TOGGLEBROWSE", actions))
    37203728    {
    3721         BrowseEnd(ctx, false);
     3729        browsehelper->BrowseEnd(ctx, false);
    37223730    }
    37233731    else if (has_action("TOGGLERECORD", actions))
    37243732        ToggleRecord(ctx);
     
    43094317    else if (has_action("TOGGLEBROWSE", actions))
    43104318    {
    43114319        if (islivetv)
    4312             BrowseStart(ctx);
     4320            browsehelper->BrowseStart(ctx);
    43134321        else if (!isDVD)
    43144322            ShowOSDMenu(ctx);
    43154323        else
     
    44084416        if (islivetv)
    44094417        {
    44104418            if (db_browse_always)
    4411                 BrowseDispInfo(ctx, BROWSE_UP);
     4419                browsehelper->BrowseDispInfo(ctx, BROWSE_UP);
    44124420            else
    44134421                ChangeChannel(ctx, CHANNEL_DIRECTION_UP);
    44144422        }
     
    44244432        if (islivetv)
    44254433        {
    44264434            if (db_browse_always)
    4427                 BrowseDispInfo(ctx, BROWSE_DOWN);
     4435                browsehelper->BrowseDispInfo(ctx, BROWSE_DOWN);
    44284436            else
    44294437                ChangeChannel(ctx, CHANNEL_DIRECTION_DOWN);
    44304438        }
     
    47014709                vol = ctx->player->AdjustVolume(vol);
    47024710                ctx->UnlockDeletePlayer(__FILE__, __LINE__);
    47034711
    4704                 if (!browsemode && !editmode)
     4712                if (!browsehelper->IsBrowsing() && !editmode)
    47054713                {
    47064714                    UpdateOSDStatus(ctx, tr("Adjust Volume"), tr("Volume"),
    47074715                                    QString::number(vol),
     
    66006608    // in browse mode because in browse mode space/enter exit browse
    66016609    // mode and change to the currently browsed channel.
    66026610    if (StateIsLiveTV(GetState(ctx)) && !ccInputMode && !asInputMode &&
    6603         browsemode)
     6611        browsehelper->IsBrowsing())
    66046612    {
    66056613        commitSmart = ProcessSmartChannel(ctx, inputStr);
    66066614    }
     
    67266734    {
    67276735        QString channum = GetQueuedChanNum();
    67286736        QString chaninput = GetQueuedInput();
    6729         if (browsemode)
     6737        if (browsehelper->IsBrowsing())
    67306738        {
    67316739            commited = true;
    67326740            if (channum.isEmpty())
     6741                channum = browsehelper->GetBrowsedInfo().m_channum;
     6742
     6743            if ((ctx->recorder && ctx->recorder->CheckChannel(channum)) ||
     6744                (db_browse_all_tuners &&
     6745                 browsehelper->BrowseAllGetChanId(channum)))
    67336746            {
    6734                 channum = browsechannum;
    6735                 channum.detach();
     6747                browsehelper->BrowseChannel(ctx, channum);
    67366748            }
    6737             BrowseChannel(ctx, channum);
    67386749            HideOSDWindow(ctx, "osd_input");
    67396750        }
    67406751        else if (GetQueuedChanID() || !channum.isEmpty())
     
    67506761
    67516762void TV::ChangeChannel(PlayerContext *ctx, int direction)
    67526763{
    6753     if ((browse_changrp || (direction == CHANNEL_DIRECTION_FAVORITE)) &&
    6754         (channel_group_id > -1))
     6764    if (db_use_channel_groups || (direction == CHANNEL_DIRECTION_FAVORITE))
    67556765    {
    6756        uint    chanid;
     6766        QMutexLocker locker(&channelGroupLock);
     6767        if (channelGroupId > -1)
     6768        {
     6769            locker.unlock();
     6770            ctx->LockPlayingInfo(__FILE__, __LINE__);
     6771            if (!ctx->playingInfo)
     6772            {
     6773                VERBOSE(VB_IMPORTANT,
     6774                        LOC_ERR + "ChangeChannel(): "
     6775                        "no active ctx playingInfo.");
     6776                ctx->UnlockPlayingInfo(__FILE__, __LINE__);
     6777                ReturnPlayerLock(ctx);
     6778                return;
     6779            }
     6780            // Collect channel info
     6781            const ProgramInfo pginfo(*ctx->playingInfo);
     6782            uint old_chanid = pginfo.GetChanID();
     6783            ctx->UnlockPlayingInfo(__FILE__, __LINE__);
    67576784
    6758        ctx->LockPlayingInfo(__FILE__, __LINE__);
    6759        if (!ctx->playingInfo)
    6760        {
    6761            VERBOSE(VB_IMPORTANT,
    6762                    LOC_ERR + "ChangeChannel(): no active ctx playingInfo.");
    6763            ctx->UnlockPlayingInfo(__FILE__, __LINE__);
    6764            ReturnPlayerLock(ctx);
    6765            return;
    6766        }
    6767 
    6768        // Collect channel info
    6769        const ProgramInfo pginfo(*ctx->playingInfo);
    6770        uint    old_chanid  = pginfo.GetChanID();
    6771        ctx->UnlockPlayingInfo(__FILE__, __LINE__);
    6772 
    6773        chanid = ChannelUtil::GetNextChannel(m_channellist, old_chanid, 0, direction);
    6774 
    6775        ChangeChannel(ctx, chanid, "");
    6776        return;
     6785            locker.relock();
     6786            if (channelGroupId > -1)
     6787            {
     6788                uint chanid = ChannelUtil::GetNextChannel(
     6789                    channelGroupChannelList, old_chanid, 0, direction);
     6790                if (chanid)
     6791                    ChangeChannel(ctx, chanid, "");
     6792                return;
     6793            }
     6794        }
    67776795    }
    6778     else if (direction == CHANNEL_DIRECTION_FAVORITE)
     6796
     6797    if (direction == CHANNEL_DIRECTION_FAVORITE)
    67796798        direction = CHANNEL_DIRECTION_UP;
    67806799
    67816800    QString oldinputname = ctx->recorder->GetInput();
     
    70137032    }
    70147033    ReturnOSDLock(ctx, osd);
    70157034
    7016     if (browsemode)
    7017     {
    7018         QMutexLocker locker(&timerIdLock);
    7019         if (browseTimerId)
    7020         {
    7021             KillTimer(browseTimerId);
    7022             browseTimerId = 0;
    7023         }
    7024         browsemode = false;
    7025     }
     7035    if (browsehelper->IsBrowsing())
     7036        browsehelper->BrowseEnd(NULL, false);
    70267037
    70277038    return res;
    70287039}
     
    71897200void TV::UpdateOSDSignal(const PlayerContext *ctx, const QStringList &strlist)
    71907201{
    71917202    OSD *osd = GetOSDLock(ctx);
    7192     if (!osd || browsemode || !queuedChanNum.isEmpty())
     7203    if (!osd || browsehelper->IsBrowsing() || !queuedChanNum.isEmpty())
    71937204    {
    71947205        if (&ctx->lastSignalMsg != &strlist)
    71957206        {
     
    74937504}
    74947505
    74957506
    7496 /**
    7497  *  \brief Fetches information on the desired program from the backend.
    7498  *  \param enc RemoteEncoder to query, if null query the actx->recorder.
    7499  *  \param direction BrowseDirection to get information on.
    7500  *  \param infoMap InfoMap to fill in with returned data
    7501  */
    7502 void TV::GetNextProgram(RemoteEncoder *enc, BrowseDirection direction,
    7503                         InfoMap &infoMap) const
    7504 {
    7505     QString title, subtitle, desc, category, endtime, callsign, iconpath;
    7506     QDateTime begts, endts;
    7507 
    7508     QString starttime = infoMap["dbstarttime"];
    7509     QString chanid    = infoMap["chanid"];
    7510     QString channum   = infoMap["channum"];
    7511     QString seriesid  = infoMap["seriesid"];
    7512     QString programid = infoMap["programid"];
    7513 
    7514     const PlayerContext *actx = NULL;
    7515     if (!enc)
    7516     {
    7517         actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
    7518         enc  = actx->recorder;
    7519     }
    7520 
    7521     enc->GetNextProgram(direction,
    7522                         title,     subtitle,  desc,      category,
    7523                         starttime, endtime,   callsign,  iconpath,
    7524                         channum,   chanid,    seriesid,  programid);
    7525 
    7526     if (actx)
    7527     {
    7528         enc = NULL; // once we've returned the lock, using enc is unsafe
    7529         ReturnPlayerLock(actx);
    7530     }
    7531 
    7532     if (!starttime.isEmpty())
    7533         begts = QDateTime::fromString(starttime, Qt::ISODate);
    7534     else
    7535         begts = QDateTime::fromString(infoMap["dbstarttime"], Qt::ISODate);
    7536 
    7537     infoMap["starttime"] = begts.toString(db_time_format);
    7538     infoMap["startdate"] = begts.toString(db_short_date_format);
    7539 
    7540     infoMap["endtime"] = infoMap["enddate"] = "";
    7541     if (!endtime.isEmpty())
    7542     {
    7543         endts = QDateTime::fromString(endtime, Qt::ISODate);
    7544         infoMap["endtime"] = endts.toString(db_time_format);
    7545         infoMap["enddate"] = endts.toString(db_short_date_format);
    7546     }
    7547 
    7548     infoMap["lenmins"] = tr("%n minute(s)", "", 0);
    7549     infoMap["lentime"] = "0:00";
    7550     if (begts.isValid() && endts.isValid())
    7551     {
    7552         QString lenM, lenHM;
    7553         format_time(begts.secsTo(endts), lenM, lenHM);
    7554         infoMap["lenmins"] = lenM;
    7555         infoMap["lentime"] = lenHM;
    7556     }
    7557 
    7558     infoMap["dbstarttime"] = starttime;
    7559     infoMap["dbendtime"]   = endtime;
    7560     infoMap["title"]       = title;
    7561     infoMap["subtitle"]    = subtitle;
    7562     infoMap["description"] = desc;
    7563     infoMap["category"]    = category;
    7564     infoMap["callsign"]    = callsign;
    7565     infoMap["channum"]     = channum;
    7566     infoMap["chanid"]      = chanid;
    7567     infoMap["iconpath"]    = iconpath;
    7568     infoMap["seriesid"]    = seriesid;
    7569     infoMap["programid"]   = programid;
    7570 }
    7571 
    7572 void TV::GetNextProgram(BrowseDirection direction, InfoMap &infoMap) const
    7573 {
    7574     uint chanid = infoMap["chanid"].toUInt();
    7575     if (!chanid)
    7576         chanid = BrowseAllGetChanId(infoMap["channum"]);
    7577 
    7578     int chandir = -1;
    7579     switch (direction)
    7580     {
    7581         case BROWSE_UP:       chandir = CHANNEL_DIRECTION_UP;       break;
    7582         case BROWSE_DOWN:     chandir = CHANNEL_DIRECTION_DOWN;     break;
    7583         case BROWSE_FAVORITE: chandir = CHANNEL_DIRECTION_FAVORITE; break;
    7584     }
    7585     if (direction != BROWSE_INVALID)
    7586     {
    7587         QMutexLocker locker(&browseLock);
    7588         chanid = ChannelUtil::GetNextChannel(
    7589             db_browse_all_channels, chanid, 0, chandir);
    7590     }
    7591 
    7592     infoMap["chanid"] = QString::number(chanid);
    7593 
    7594     {
    7595         QMutexLocker locker(&browseLock);
    7596         DBChanList::const_iterator it = db_browse_all_channels.begin();
    7597         for (; it != db_browse_all_channels.end(); ++it)
    7598         {
    7599             if ((*it).chanid == chanid)
    7600             {
    7601                 QString tmp = (*it).channum;
    7602                 tmp.detach();
    7603                 infoMap["channum"] = tmp;
    7604                 break;
    7605             }
    7606         }
    7607     }
    7608 
    7609     QDateTime nowtime = QDateTime::currentDateTime();
    7610     QDateTime latesttime = nowtime.addSecs(6*60*60);
    7611     QDateTime browsetime = QDateTime::fromString(
    7612         infoMap["dbstarttime"], Qt::ISODate);
    7613 
    7614     MSqlBindings bindings;
    7615     bindings[":CHANID"] = chanid;
    7616     bindings[":NOWTS"] = nowtime.toString("yyyy-MM-ddThh:mm:ss");
    7617     bindings[":LATESTTS"] = latesttime.toString("yyyy-MM-ddThh:mm:ss");
    7618     bindings[":BROWSETS"] = browsetime.toString("yyyy-MM-ddThh:mm:ss");
    7619     bindings[":BROWSETS2"] = browsetime.toString("yyyy-MM-ddThh:mm:ss");
    7620 
    7621     QString querystr = " WHERE program.chanid = :CHANID ";
    7622     switch (direction)
    7623     {
    7624         case BROWSE_LEFT:
    7625             querystr += " AND program.endtime <= :BROWSETS "
    7626                 " AND program.endtime > :NOWTS ";
    7627             break;
    7628 
    7629         case BROWSE_RIGHT:
    7630             querystr += " AND program.starttime > :BROWSETS "
    7631                 " AND program.starttime < :LATESTTS ";
    7632             break;
    7633 
    7634         default:
    7635             querystr += " AND program.starttime <= :BROWSETS "
    7636                 " AND program.endtime > :BROWSETS2 ";
    7637     };
    7638 
    7639     ProgramList progList;
    7640     ProgramList dummySched;
    7641     LoadFromProgram(progList, querystr, bindings, dummySched, false);
    7642 
    7643     if (progList.empty())
    7644     {
    7645         infoMap["dbstarttime"] = "";
    7646         return;
    7647     }
    7648 
    7649     const ProgramInfo *prog = (direction == BROWSE_LEFT) ?
    7650         progList[progList.size() - 1] : progList[0];
    7651 
    7652     infoMap["dbstarttime"] = prog->GetScheduledStartTime(ISODate);
    7653 }
    7654 
    76557507bool TV::IsTunable(const PlayerContext *ctx, uint chanid, bool use_cache)
    76567508{
    76577509    VERBOSE(VB_PLAYBACK, QString("IsTunable(%1)").arg(chanid));
     
    78717723    const ProgramInfo pginfo(*actx->playingInfo);
    78727724    uint    chanid  = pginfo.GetChanID();
    78737725    QString channum = pginfo.GetChanNum();
    7874     int changrpid   = channel_group_id;
    78757726    actx->UnlockPlayingInfo(__FILE__, __LINE__);
    78767727
    78777728    ClearOSD(actx);
     
    79287779    {
    79297780        case kScheduleProgramGuide:
    79307781        {
     7782            channelGroupLock.lock();
     7783            int changrpid = channelGroupId;
     7784            channelGroupLock.unlock();
     7785
    79317786            isEmbedded = (isLiveTV && !pause_active && allowEmbedding);
    7932             RunProgramGuidePtr(chanid, channum, this, isEmbedded, true, changrpid);
     7787            RunProgramGuidePtr(chanid, channum, this,
     7788                               isEmbedded, true, changrpid);
    79337789            ignoreKeyPresses = true;
    79347790            break;
    79357791        }
     
    79927848    uint curvol = ctx->player->AdjustVolume((up) ? +2 : -2);
    79937849    ctx->UnlockDeletePlayer(__FILE__, __LINE__);
    79947850
    7995     if (!browsemode)
     7851    if (!browsehelper->IsBrowsing())
    79967852    {
    79977853        UpdateOSDStatus(ctx, tr("Adjust Volume"), tr("Volume"),
    79987854                        QString::number(curvol),
     
    80507906        ctx->UnlockDeletePlayer(__FILE__, __LINE__);
    80517907    }
    80527908
    8053     if (!browsemode)
     7909    if (!browsehelper->IsBrowsing())
    80547910    {
    80557911        if (!allowEdit)
    80567912        {
     
    80807936    else
    80817937        text = tr("Upmixer Off");
    80827938
    8083     if (!browsemode)
     7939    if (!browsehelper->IsBrowsing())
    80847940        SetOSDMessage(ctx, text);
    80857941}
    80867942
     
    81207976    }
    81217977    ctx->UnlockDeletePlayer(__FILE__, __LINE__);
    81227978
    8123     if (!browsemode)
     7979    if (!browsehelper->IsBrowsing())
    81247980    {
    81257981        QString text;
    81267982        int val = (int)newval;
     
    81998055
    82008056    text = tr("Sleep ") + " " + sleep_times[sleep_index].dispString;
    82018057
    8202     if (!browsemode)
     8058    if (!browsehelper->IsBrowsing())
    82038059        SetOSDMessage(ctx, text);
    82048060}
    82058061
     
    83768232    ctx->UnlockDeletePlayer(__FILE__, __LINE__);
    83778233}
    83788234
     8235/// This handles all custom events
    83798236void TV::customEvent(QEvent *e)
    83808237{
     8238    if (e->type() == MythEvent::kUpdateBrowseInfoEventType)
     8239    {
     8240        UpdateBrowseInfoEvent *b = (UpdateBrowseInfoEvent*)e;
     8241        PlayerContext *mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
     8242        OSD *osd = GetOSDLock(mctx);
     8243        if (osd)
     8244        {
     8245            osd->SetText("browse_info", b->im, kOSDTimeout_None);
     8246            osd->SetExpiry("browse_info", kOSDTimeout_None);
     8247        }
     8248        ReturnOSDLock(mctx, osd);
     8249        ReturnPlayerLock(mctx);
     8250        return;
     8251    }
     8252
    83818253    if (e->type() == DialogCompletionEvent::kEventType)
    83828254    {
    83838255        DialogCompletionEvent *dce = (DialogCompletionEvent *)e;
     
    87728644    }
    87738645}
    87748646
    8775 /** \fn TV::BrowseStart(PlayerContext*)
    8776  *  \brief Begins channel browsing.
    8777  */
    8778 void TV::BrowseStart(PlayerContext *ctx)
    8779 {
    8780     VERBOSE(VB_IMPORTANT, "BrowseStart()");
    8781 
    8782     if (ctx->paused)
    8783         return;
    8784 
    8785     OSD *osd = GetOSDLock(ctx);
    8786     if (osd && osd->IsWindowVisible("browse_info"))
    8787     {
    8788         ReturnOSDLock(ctx, osd);
    8789         return;
    8790     }
    8791     ReturnOSDLock(ctx, osd);
    8792 
    8793     ClearOSD(ctx);
    8794 
    8795     ctx->LockPlayingInfo(__FILE__, __LINE__);
    8796     if (ctx->playingInfo)
    8797     {
    8798         browsemode      = true;
    8799         browsechannum   = ctx->playingInfo->GetChanNum();
    8800         browsechannum.detach();
    8801         browsechanid    = ctx->playingInfo->GetChanID();
    8802         browsestarttime = ctx->playingInfo->GetScheduledStartTime(ISODate);
    8803         ctx->UnlockPlayingInfo(__FILE__, __LINE__);
    8804 
    8805         BrowseDispInfo(ctx, BROWSE_SAME);
    8806 
    8807         QMutexLocker locker(&timerIdLock);
    8808         if (browseTimerId)
    8809             KillTimer(browseTimerId);
    8810         browseTimerId = StartTimer(kBrowseTimeout, __LINE__);
    8811     }
    8812     else
    8813     {
    8814         ctx->UnlockPlayingInfo(__FILE__, __LINE__);
    8815     }
    8816 }
    8817 
    8818 /** \fn TV::BrowseEnd(PlayerContext*, bool)
    8819  *  \brief Ends channel browsing. Changing the channel if change is true.
    8820  *  \param change_channel iff true we call ChangeChannel()
    8821  */
    8822 void TV::BrowseEnd(PlayerContext *ctx, bool change_channel)
    8823 {
    8824     VERBOSE(VB_IMPORTANT, "BrowseEnd()");
    8825     {
    8826         QMutexLocker locker(&timerIdLock);
    8827         if (browseTimerId)
    8828         {
    8829             KillTimer(browseTimerId);
    8830             browseTimerId = 0;
    8831         }
    8832     }
    8833 
    8834     if (!browsemode)
    8835         return;
    8836 
    8837     HideOSDWindow(ctx, "browse_info");
    8838 
    8839     if (change_channel)
    8840         ChangeChannel(ctx, 0, browsechannum);
    8841 
    8842     browsemode = false;
    8843 }
    8844 
    8845 /** \brief Fetches browse info from backend and sends it to the OSD.
    8846  *  \param direction BrowseDirection to get information on.
    8847  */
    8848 void TV::BrowseDispInfo(PlayerContext *ctx, BrowseDirection direction)
    8849 {
    8850     VERBOSE(VB_IMPORTANT, "BrowseDispInfo()");
    8851 
    8852     if (!browsemode)
    8853         BrowseStart(ctx);
    8854 
    8855     // if browsing channel groups is enabled or direction if BROWSE_FAVORITES
    8856     // Then pick the next channel in the channel group list to browse
    8857     // If channel group is ALL CHANNELS (-1), then bypass picking from
    8858     // the channel group list
    8859     if ((browse_changrp || (direction == BROWSE_FAVORITE)) &&
    8860         (channel_group_id > -1) && (direction != BROWSE_SAME) &&
    8861         (direction != BROWSE_RIGHT) && (direction != BROWSE_LEFT))
    8862     {
    8863         uint chanid;
    8864         int  dir;
    8865 
    8866         if ( (direction == BROWSE_UP) || (direction == BROWSE_FAVORITE) )
    8867             dir = CHANNEL_DIRECTION_UP;
    8868         else if (direction == BROWSE_DOWN)
    8869             dir = CHANNEL_DIRECTION_DOWN;
    8870         else // this should never happen, but just in case
    8871             dir = direction;
    8872 
    8873         chanid = ChannelUtil::GetNextChannel(
    8874             m_channellist, browsechanid, 0, dir);
    8875         VERBOSE(VB_IMPORTANT, QString("Get channel: %1").arg(chanid));
    8876         browsechanid  = chanid;
    8877         browsechannum = QString::null;
    8878         direction     = BROWSE_SAME;
    8879     }
    8880     else if ((channel_group_id == -1) && (direction == BROWSE_FAVORITE))
    8881         direction = BROWSE_UP;
    8882 
    8883     OSD *osd = GetOSDLock(ctx);
    8884     if (ctx->paused || !osd)
    8885     {
    8886         ReturnOSDLock(ctx, osd);
    8887         return;
    8888     }
    8889 
    8890     {
    8891         QMutexLocker locker(&timerIdLock);
    8892         if (browseTimerId)
    8893             KillTimer(browseTimerId);
    8894         browseTimerId = StartTimer(kBrowseTimeout, __LINE__);
    8895     }
    8896 
    8897     QDateTime lasttime = QDateTime::fromString(browsestarttime, Qt::ISODate);
    8898     QDateTime curtime  = QDateTime::currentDateTime();
    8899     if (lasttime < curtime)
    8900         browsestarttime = curtime.toString(Qt::ISODate);
    8901 
    8902     QDateTime maxtime  = curtime.addSecs(db_browse_max_forward);
    8903     if ((lasttime > maxtime) && (direction == BROWSE_RIGHT))
    8904     {
    8905         ReturnOSDLock(ctx, osd);
    8906         return;
    8907     }
    8908 
    8909     InfoMap infoMap;
    8910     infoMap["dbstarttime"] = browsestarttime;
    8911     infoMap["channum"]     = browsechannum;
    8912     infoMap["chanid"]      = QString::number(browsechanid);
    8913 
    8914     if (ctx->recorder && !db_browse_all_tuners)
    8915     {
    8916         GetNextProgram(ctx->recorder, direction, infoMap);
    8917     }
    8918     else
    8919     {
    8920         GetNextProgram(direction, infoMap);
    8921         while (!IsTunable(ctx, infoMap["chanid"].toUInt()) &&
    8922                (infoMap["channum"] != browsechannum))
    8923         {
    8924             GetNextProgram(direction, infoMap);
    8925         }
    8926     }
    8927 
    8928     VERBOSE(VB_IMPORTANT, QString("browsechanid: %1 -> %2")
    8929             .arg(browsechanid).arg(infoMap["chanid"].toUInt()));
    8930 
    8931     browsechannum = infoMap["channum"];
    8932     browsechanid  = infoMap["chanid"].toUInt();
    8933 
    8934     if (((direction == BROWSE_LEFT) || (direction == BROWSE_RIGHT)) &&
    8935         !infoMap["dbstarttime"].isEmpty())
    8936     {
    8937         browsestarttime = infoMap["dbstarttime"];
    8938     }
    8939 
    8940     // pull in additional data from the DB...
    8941     QDateTime startts = QDateTime::fromString(browsestarttime, Qt::ISODate);
    8942     RecordingInfo recinfo(browsechanid, startts, false);
    8943     recinfo.ToMap(infoMap);
    8944     infoMap["iconpath"] = ChannelUtil::GetIcon(recinfo.GetChanID());
    8945 
    8946     osd->SetText("browse_info", infoMap, kOSDTimeout_None);
    8947     osd->SetExpiry("browse_info", kOSDTimeout_None);
    8948     ReturnOSDLock(ctx, osd);
    8949 }
    8950 
    8951 uint TV::BrowseAllGetChanId(const QString &chan) const
    8952 {
    8953     QMutexLocker locker(&browseLock);
    8954     DBChanList::const_iterator it = db_browse_all_channels.begin();
    8955     for (; it != db_browse_all_channels.end(); ++it)
    8956     {
    8957         if ((*it).channum == chan)
    8958             return (*it).chanid;
    8959     }
    8960     return 0;
    8961 }
    8962 
    89638647void TV::ToggleRecord(PlayerContext *ctx)
    89648648{
    8965     if (browsemode)
     8649    BrowseInfo bi = browsehelper->GetBrowsedInfo();
     8650    if (bi.m_chanid)
    89668651    {
    89678652        InfoMap infoMap;
    89688653        QDateTime startts = QDateTime::fromString(
    8969             browsestarttime, Qt::ISODate);
     8654            bi.m_starttime, Qt::ISODate);
    89708655
    89718656        RecordingInfo::LoadStatus status;
    8972         RecordingInfo recinfo(browsechanid, startts, false, 0, &status);
     8657        RecordingInfo recinfo(bi.m_chanid, startts, false, 0, &status);
    89738658        if (RecordingInfo::kFoundProgram == status)
    89748659            recinfo.ToggleRecord();
    89758660        recinfo.ToMap(infoMap);
     
    90408725    SetOSDMessage(ctx, msg);
    90418726}
    90428727
    9043 void TV::BrowseChannel(PlayerContext *ctx, const QString &chan)
    9044 {
    9045     if (!ctx->recorder || !ctx->recorder->CheckChannel(chan))
    9046     {
    9047         if (!db_browse_all_tuners || !BrowseAllGetChanId(chan))
    9048             return;
    9049     }
    9050 
    9051     browsechannum = chan;
    9052     browsechannum.detach();
    9053     browsechanid = 0;
    9054     BrowseDispInfo(ctx, BROWSE_SAME);
    9055 }
    9056 
    90578728void TV::HandleOSDClosed(int osdType)
    90588729{
    90598730    switch (osdType)
     
    99889659    }
    99899660    else if (action == "GUIDE")
    99909661        EditSchedule(actx, kScheduleProgramGuide);
    9991     else if (action.left(10) == "CHANGROUP_")
     9662    else if (action.left(10) == "CHANGROUP_" && db_use_channel_groups)
    99929663    {
    99939664        if (action == "CHANGROUP_ALL_CHANNELS")
    9994             channel_group_id = -1;
     9665        {
     9666            UpdateChannelList(-1);
     9667        }
    99959668        else
    99969669        {
    99979670            action.remove("CHANGROUP_");
    99989671
    9999             channel_group_id = action.toInt();
     9672            UpdateChannelList(action.toInt());
    100009673
    10001             if (browse_changrp)
     9674            QMutexLocker locker(&channelGroupLock);
     9675            const DBChanList &list = channelGroupChannelList;
     9676
     9677            // make sure the current channel is from the selected group
     9678            // or tune to the first in the group
     9679            if (actx->tvchain)
    100029680            {
    10003                 m_channellist = ChannelUtil::GetChannels(0, true, "channum, callsign", channel_group_id);
    10004                 ChannelUtil::SortChannels(m_channellist, "channum", true);
     9681                QString cur_channum = actx->tvchain->GetChannelName(-1);
     9682                QString new_channum = cur_channum;
    100059683
    10006                 // make sure the current channel is from the selected group
    10007                 // or tune to the first in the group
    10008                 if (actx->tvchain)
     9684                DBChanList::const_iterator it = list.begin();
     9685                for (; it != list.end(); ++it)
    100099686                {
    10010                     QString cur_channum = actx->tvchain->GetChannelName(-1);
    10011                     QString new_channum = cur_channum;
    10012 
    10013                     DBChanList::const_iterator it = m_channellist.begin();
    10014                     for (; it != m_channellist.end(); ++it)
     9687                    if ((*it).channum == cur_channum)
    100159688                    {
    10016                         if ((*it).channum == cur_channum)
    10017                         {
    10018                             break;
    10019                         }
     9689                        break;
    100209690                    }
     9691                }
    100219692
    10022                     if (it == m_channellist.end())
    10023                     {
    10024                         // current channel not found so switch to the
    10025                         // first channel in the group
    10026                         it = m_channellist.begin();
    10027                         if (it != m_channellist.end())
    10028                             new_channum = (*it).channum;
    10029                     }
     9693                if (it == list.end())
     9694                {
     9695                    // current channel not found so switch to the
     9696                    // first channel in the group
     9697                    it = list.begin();
     9698                    if (it != list.end())
     9699                        new_channum = (*it).channum;
     9700                }
    100309701
    10031                     VERBOSE(VB_IMPORTANT, LOC + QString("Channel Group: '%1'->'%2'")
    10032                             .arg(cur_channum).arg(new_channum));
     9702                VERBOSE(VB_IMPORTANT, LOC +
     9703                        QString("Channel Group: '%1'->'%2'")
     9704                        .arg(cur_channum).arg(new_channum));
    100339705
    10034                     // Only change channel if new channel != current channel
    10035                     if (cur_channum != new_channum && !new_channum.isEmpty())
    10036                     {
    10037                         QMutexLocker locker(&timerIdLock);
    10038                         queuedInput   = new_channum; queuedInput.detach();
    10039                         queuedChanNum = new_channum; queuedChanNum.detach();
    10040                         queuedChanID  = 0;
    10041                         if (!queueInputTimerId)
    10042                             queueInputTimerId = StartTimer(10, __LINE__);
    10043                     }
    10044 
    10045                     // Turn off OSD Channel Num so the channel changes right away
    10046                     HideOSDWindow(actx, "osd_input");
     9706                // Only change channel if new channel != current channel
     9707                if (cur_channum != new_channum && !new_channum.isEmpty())
     9708                {
     9709                    QMutexLocker locker(&timerIdLock);
     9710                    queuedInput   = new_channum; queuedInput.detach();
     9711                    queuedChanNum = new_channum; queuedChanNum.detach();
     9712                    queuedChanID  = 0;
     9713                    if (!queueInputTimerId)
     9714                        queueInputTimerId = StartTimer(10, __LINE__);
    100479715                }
     9716
     9717                // Turn off OSD Channel Num so the channel
     9718                // changes right away
     9719                HideOSDWindow(actx, "osd_input");
    100489720            }
    100499721        }
    100509722    }
     
    100669738    else if (StateIsLiveTV(GetState(actx)))
    100679739    {
    100689740        if (action == "TOGGLEBROWSE")
    10069             BrowseStart(actx);
     9741            browsehelper->BrowseStart(actx);
    100709742        else if (action == "PREVCHAN")
    100719743            PopPreviousChannel(actx, true);
    100729744        else if (action.left(14) == "SWITCHTOINPUT_")
     
    1093010602        osd->DialogAddButton(tr("Sleep"),
    1093110603                             "DIALOG_MENU_SLEEP_0", true,
    1093210604                              selected == "SLEEP");
    10933         if (browse_changrp)
     10605        if (db_use_channel_groups)
    1093410606        {
    1093510607            osd->DialogAddButton(tr("Channel Groups"),
    1093610608                                 "DIALOG_MENU_CHANNELGROUP_0",
     
    1097210644        currenttext = tr("Channel Groups");
    1097310645        osd->DialogAddButton(tr("All Channels"), "CHANGROUP_ALL_CHANNELS");
    1097410646        ChannelGroupList::const_iterator it;
    10975         for (it = m_changrplist.begin(); it != m_changrplist.end(); ++it)
     10647        for (it = db_channel_groups.begin();
     10648             it != db_channel_groups.end(); ++it)
     10649        {
     10650            QMutexLocker locker(&channelGroupLock);
    1097610651            osd->DialogAddButton(it->name,
    1097710652                                 QString("CHANGROUP_%1").arg(it->grpid),
    10978                                  false, (int)(it->grpid) == channel_group_id);
     10653                                 false, (int)(it->grpid) == channelGroupId);
     10654        }
    1097910655    }
    1098010656    else if (category == "PIP" && (allowPIP || allowPBP))
    1098110657    {
  • libs/libmyth/programinfo.cpp

     
    39713971QStringList ProgramInfo::LoadFromScheduler(
    39723972    const QString &tmptable, int recordid)
    39733973{
     3974    assert(!gCoreContext->IsUIThread());
     3975
    39743976    QStringList slist;
    39753977    if (gCoreContext->IsBackend())
    39763978    {
  • libs/libmythdb/mythevent.h

     
    11#ifndef MYTHEVENT_H_
    22#define MYTHEVENT_H_
    33
    4 #include <QString>
    54#include <QStringList>
    65#include <QEvent>
     6#include <QHash>
     7
    78#include "mythexp.h"
    89
    910/** \class MythEvent
     
    5859    static Type kPopDisableDrawingEventType;
    5960    static Type kLockInputDevicesEventType;
    6061    static Type kUnlockInputDevicesEventType;
     62    static Type kUpdateBrowseInfoEventType;
    6163
    6264  private:
    6365    QString message;
     
    7880    int keycode;
    7981};
    8082
     83class MPUBLIC UpdateBrowseInfoEvent : public QEvent
     84{
     85  public:
     86    UpdateBrowseInfoEvent(const QHash<QString,QString> &infoMap) :
     87        QEvent(MythEvent::kUpdateBrowseInfoEventType), im(infoMap) {}
     88    QHash<QString,QString> im;
     89};
     90
    8191#endif /* MYTHEVENT_H */
  • libs/libmythdb/mythevent.cpp

     
    1818    (QEvent::Type) QEvent::registerEventType();
    1919QEvent::Type MythEvent::kUnlockInputDevicesEventType =
    2020    (QEvent::Type) QEvent::registerEventType();
     21QEvent::Type MythEvent::kUpdateBrowseInfoEventType =
     22    (QEvent::Type) QEvent::registerEventType();
    2123QEvent::Type ExternalKeycodeEvent::kEventType =
    2224    (QEvent::Type) QEvent::registerEventType();