[vlc-commits] Qt: rework EPG

Francois Cartegnie git at videolan.org
Fri Dec 16 14:43:12 CET 2016


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Wed Dec 14 19:45:01 2016 +0100| [ab494fd208e74112324254a2f78970c81d7744db] | committer: Francois Cartegnie

Qt: rework EPG

Less loops and simplified structs/updates

Also now redisplays recorded epg.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=ab494fd208e74112324254a2f78970c81d7744db
---

 modules/gui/qt/Makefile.am                    |   2 +
 modules/gui/qt/components/epg/EPGChannels.cpp |  18 +-
 modules/gui/qt/components/epg/EPGChannels.hpp |   7 +-
 modules/gui/qt/components/epg/EPGItem.cpp     |  35 +--
 modules/gui/qt/components/epg/EPGItem.hpp     |  16 +-
 modules/gui/qt/components/epg/EPGProgram.cpp  | 135 ++++++++++++
 modules/gui/qt/components/epg/EPGProgram.hpp  |  65 ++++++
 modules/gui/qt/components/epg/EPGRuler.cpp    |  24 +-
 modules/gui/qt/components/epg/EPGRuler.hpp    |   3 +-
 modules/gui/qt/components/epg/EPGView.cpp     | 302 +++++++-------------------
 modules/gui/qt/components/epg/EPGView.hpp     |  32 ++-
 modules/gui/qt/components/epg/EPGWidget.cpp   |  28 +--
 12 files changed, 355 insertions(+), 312 deletions(-)

diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index 799b193..bf3d98b 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -83,6 +83,7 @@ libqt_plugin_la_SOURCES = \
 	components/controller_widget.cpp components/controller_widget.hpp \
 	components/epg/EPGChannels.cpp components/epg/EPGChannels.hpp \
 	components/epg/EPGItem.cpp components/epg/EPGItem.hpp \
+	components/epg/EPGProgram.cpp components/epg/EPGProgram.hpp \
 	components/epg/EPGRuler.cpp components/epg/EPGRuler.hpp \
 	components/epg/EPGView.cpp components/epg/EPGView.hpp \
 	components/epg/EPGWidget.cpp components/epg/EPGWidget.hpp \
@@ -180,6 +181,7 @@ nodist_libqt_plugin_la_SOURCES = \
 	components/controller.moc.cpp \
 	components/controller_widget.moc.cpp \
 	components/epg/EPGChannels.moc.cpp \
+	components/epg/EPGProgram.moc.cpp \
 	components/epg/EPGRuler.moc.cpp \
 	components/epg/EPGView.moc.cpp \
 	components/epg/EPGWidget.moc.cpp \
diff --git a/modules/gui/qt/components/epg/EPGChannels.cpp b/modules/gui/qt/components/epg/EPGChannels.cpp
index 1266a29..bb12729 100644
--- a/modules/gui/qt/components/epg/EPGChannels.cpp
+++ b/modules/gui/qt/components/epg/EPGChannels.cpp
@@ -25,11 +25,13 @@
 #include <vlc_epg.h>
 
 #include "EPGChannels.hpp"
+#include "EPGProgram.hpp"
 #include "EPGView.hpp"
 
 #include <QPainter>
 #include <QFont>
 #include <QPaintEvent>
+#include <QtAlgorithms>
 
 EPGChannels::EPGChannels( QWidget *parent, EPGView *m_epgView )
     : QWidget( parent ), m_epgView( m_epgView ), m_offset( 0 )
@@ -43,19 +45,20 @@ void EPGChannels::setOffset( int offset )
     update();
 }
 
-void EPGChannels::addChannel( QString channelName )
+void EPGChannels::addProgram( const EPGProgram *program )
 {
-    if ( !channelList.contains( channelName ) )
+    if ( !programsList.contains( program ) )
     {
-        channelList << channelName;
-        channelList.sort();
+        programsList << program;
+        qSort(programsList.begin(), programsList.end(), EPGProgram::lessThan);
         update();
     }
 }
 
-void EPGChannels::removeChannel( QString channelName )
+void EPGChannels::reset()
 {
-    if ( channelList.removeOne( channelName ) ) update();
+    programsList.clear();
+    update();
 }
 
 void EPGChannels::paintEvent( QPaintEvent *event )
@@ -68,8 +71,9 @@ void EPGChannels::paintEvent( QPaintEvent *event )
     p.drawLine( 0, 0, width() - 1, 0 );
 
     unsigned int i=0;
-    foreach( QString text, channelList )
+    foreach( const EPGProgram *program, programsList )
     {
+        QString text = program->getName();
         /* try to remove the " [Program xxx]" end */
         int i_idx_channel = text.lastIndexOf(" [");
         if (i_idx_channel > 0)
diff --git a/modules/gui/qt/components/epg/EPGChannels.hpp b/modules/gui/qt/components/epg/EPGChannels.hpp
index a0143d8..b4fee69 100644
--- a/modules/gui/qt/components/epg/EPGChannels.hpp
+++ b/modules/gui/qt/components/epg/EPGChannels.hpp
@@ -28,6 +28,7 @@
 #include <QWidget>
 
 class EPGView;
+class EPGProgram;
 
 class EPGChannels : public QWidget
 {
@@ -37,8 +38,8 @@ public:
 
 public slots:
     void setOffset( int offset );
-    void addChannel( QString );
-    void removeChannel( QString );
+    void addProgram( const EPGProgram * );
+    void reset();
 
 protected:
     void paintEvent( QPaintEvent *event ) Q_DECL_OVERRIDE;
@@ -46,7 +47,7 @@ protected:
 private:
     EPGView *m_epgView;
     int m_offset;
-    QStringList channelList;
+    QList<const EPGProgram *> programsList;
 };
 
 #endif // EPGCHANNELS_HPP
diff --git a/modules/gui/qt/components/epg/EPGItem.cpp b/modules/gui/qt/components/epg/EPGItem.cpp
index 3d83928..2ba01e0 100644
--- a/modules/gui/qt/components/epg/EPGItem.cpp
+++ b/modules/gui/qt/components/epg/EPGItem.cpp
@@ -35,11 +35,13 @@
 
 #include "qt.hpp"
 
-EPGItem::EPGItem( const vlc_epg_event_t *data, EPGView *view )
-    : m_view( view )
+EPGItem::EPGItem( const vlc_epg_event_t *data, EPGView *view, const EPGProgram *prog )
+    : QGraphicsItem()
 {
+    m_view = view;
+    program = prog;
+    m_id = data->i_id;
     setData( data );
-    m_current = false;
     m_boundingRect.setHeight( TRACKS_HEIGHT );
     setFlags( QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable);
     setAcceptHoverEvents( true );
@@ -67,8 +69,8 @@ void EPGItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *option,
 
     QLinearGradient gradient( mapped.topLeft(), mapped.bottomLeft() );
 
-    bool b_simultaneous = playsAt( m_view->baseTime() );
-    if ( m_current || b_simultaneous )
+    bool b_simultaneous = m_view->liveTime().isValid() && playsAt( m_view->liveTime() );
+    if ( program->getCurrent() == this || b_simultaneous )
         gradientColor.setRgb( 244, 125, 0 , b_simultaneous ? 192 : 255 );
     else
         gradientColor.setRgb( 201, 217, 242 );
@@ -139,15 +141,14 @@ QDateTime EPGItem::end() const
     return QDateTime( m_start ).addSecs( m_duration );
 }
 
-int EPGItem::duration() const
+uint32_t EPGItem::duration() const
 {
     return m_duration;
 }
 
-void EPGItem::setRow( unsigned int i_row_ )
+uint16_t EPGItem::eventID() const
 {
-    i_row = i_row_;
-    updatePos();
+    return m_id;
 }
 
 bool EPGItem::setData( const vlc_epg_event_t *data )
@@ -171,16 +172,12 @@ bool EPGItem::setData( const vlc_epg_event_t *data )
         setDuration( data->i_duration );
         setRating( data->i_rating );
         update();
+        updatePos();
         return true;
     }
     return false;
 }
 
-void EPGItem::setCurrent( bool b_current )
-{
-    m_current = b_current;
-}
-
 bool EPGItem::endsBefore( const QDateTime &ref ) const
 {
     return m_start.addSecs( m_duration ) < ref;
@@ -191,7 +188,7 @@ bool EPGItem::playsAt( const QDateTime & ref ) const
     return (m_start <= ref) && !endsBefore( ref );
 }
 
-void EPGItem::setDuration( int duration )
+void EPGItem::setDuration( uint32_t duration )
 {
     m_duration = duration;
     m_boundingRect.setWidth( duration );
@@ -215,8 +212,12 @@ QString EPGItem::description() const
 
 void EPGItem::updatePos()
 {
-    int x = m_view->startTime().secsTo( m_start );
-    setPos( x, i_row * TRACKS_HEIGHT );
+    QDateTime overallmin = m_view->startTime();
+    if( overallmin.isValid() )
+    {
+        int x = m_view->startTime().secsTo( m_start );
+        setPos( x, program->getPosition() * TRACKS_HEIGHT );
+    }
 }
 
 void EPGItem::hoverEnterEvent ( QGraphicsSceneHoverEvent * event )
diff --git a/modules/gui/qt/components/epg/EPGItem.hpp b/modules/gui/qt/components/epg/EPGItem.hpp
index 938ecdc..92d0c8c 100644
--- a/modules/gui/qt/components/epg/EPGItem.hpp
+++ b/modules/gui/qt/components/epg/EPGItem.hpp
@@ -33,11 +33,12 @@
 class QPainter;
 class QString;
 class EPGView;
+class EPGProgram;
 
 class EPGItem : public QGraphicsItem
 {
 public:
-    EPGItem( const vlc_epg_event_t *data, EPGView *view );
+    EPGItem( const vlc_epg_event_t *data, EPGView *view, const EPGProgram * );
 
     QRectF boundingRect() const Q_DECL_OVERRIDE;
     void paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0 ) Q_DECL_OVERRIDE;
@@ -45,14 +46,13 @@ public:
     const QDateTime& start() const;
     QDateTime end() const;
 
-    int duration() const;
+    uint32_t duration() const;
+    uint16_t eventID() const;
     const QString& name() const { return m_name; }
     QString description() const;
     int rating() const { return m_rating; }
     bool setData( const vlc_epg_event_t * );
-    void setRow( unsigned int );
-    void setCurrent( bool );
-    void setDuration( int duration );
+    void setDuration( uint32_t duration );
     void setRating( uint8_t i_rating );
     void updatePos();
     bool endsBefore( const QDateTime & ) const;
@@ -64,16 +64,16 @@ protected:
     void hoverLeaveEvent ( QGraphicsSceneHoverEvent * ) Q_DECL_OVERRIDE;
 
 private:
+    const EPGProgram *program;
     EPGView     *m_view;
     QRectF      m_boundingRect;
-    unsigned int i_row;
 
     QDateTime   m_start;
-    int         m_duration;
+    uint32_t    m_duration;
+    uint16_t    m_id;
     QString     m_name;
     QString     m_description;
     QString     m_shortDescription;
-    bool        m_current;
     uint8_t     m_rating;
 };
 
diff --git a/modules/gui/qt/components/epg/EPGProgram.cpp b/modules/gui/qt/components/epg/EPGProgram.cpp
new file mode 100644
index 0000000..3309cc0
--- /dev/null
+++ b/modules/gui/qt/components/epg/EPGProgram.cpp
@@ -0,0 +1,135 @@
+/*****************************************************************************
+ * EPGProgram.cpp:
+ ****************************************************************************
+ * Copyright © 2016 VideoLAN Authors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#include "EPGProgram.hpp"
+#include "EPGItem.hpp"
+#include "EPGView.hpp"
+
+#include <QtAlgorithms>
+
+EPGProgram::EPGProgram( EPGView *view_, const vlc_epg_t *p_epg ) : QObject( view_ )
+{
+    name = QString(p_epg->psz_name);
+    id = p_epg->i_id;
+    sourceid = p_epg->i_source_id;
+    view = view_;
+    pos = 0;
+    current = NULL;
+}
+
+EPGProgram::~EPGProgram()
+{
+    qDeleteAll(eventsbyid);
+    eventsbytime.clear();
+}
+
+bool EPGProgram::lessThan( const EPGProgram *a, const EPGProgram *b )
+{
+    return a->pos < b->pos;
+}
+
+size_t EPGProgram::getPosition() const
+{
+    return pos;
+}
+
+const EPGItem * EPGProgram::getCurrent() const
+{
+    return current;
+}
+
+const QString & EPGProgram::getName() const
+{
+    return name;
+}
+
+void EPGProgram::setPosition( size_t i )
+{
+    pos = i;
+}
+
+void EPGProgram::pruneEvents( const QDateTime &date )
+{
+    QMap<QDateTime, const EPGItem *>::iterator it = eventsbytime.begin();
+    for( ; it != eventsbytime.end(); )
+    {
+        const EPGItem *item = *it;
+        if( item->endsBefore( date ) ) /* Expired item ? */
+        {
+            EPGItem *modifiableitem = eventsbyid.take( item->eventID() );
+            view->scene()->removeItem( modifiableitem );
+            delete modifiableitem;
+            it = eventsbytime.erase( it );
+        }
+        else break;
+    }
+}
+
+void EPGProgram::updateEventPos()
+{
+    foreach( EPGItem *item, eventsbyid )
+        item->updatePos();
+}
+
+void EPGProgram::updateEvents( const vlc_epg_event_t * const * pp_events, size_t i_events,
+                               const vlc_epg_event_t *p_current, QDateTime *mindate )
+{
+    for( size_t i=0; i<i_events; i++ )
+    {
+        const vlc_epg_event_t *p_event = pp_events[i];
+        QDateTime eventStart = QDateTime::fromTime_t( p_event->i_start );
+        if( !mindate->isValid() || eventStart < *mindate )
+            *mindate = eventStart;
+
+        EPGItem *epgItem = NULL;
+        QHash<uint32_t, EPGItem *>::iterator it = eventsbyid.find( p_event->i_id );
+        if ( it != eventsbyid.end() )
+        {
+            epgItem = *it;
+
+            /* Update our existing programs */
+            if( eventStart != epgItem->start() )
+            {
+                eventsbytime.remove( epgItem->start() );
+                eventsbytime.insert( eventStart, epgItem );
+            }
+
+            epgItem->setData( p_event ); /* updates our entry */
+        }
+        else if( !eventsbytime.contains( eventStart ) /* !Inconsistency */ )
+        {
+            /* Insert a new program entry */
+            epgItem = new EPGItem( p_event, view, this );
+
+            /* Effectively insert our new program */
+            eventsbyid.insert( p_event->i_id, epgItem );
+            eventsbytime.insert( eventStart, epgItem );
+
+            view->scene()->addItem( epgItem );
+
+            /* First Insert, needs to focus by default then */
+            if( !view->hasFocus() )
+                view->focusItem( epgItem );
+        }
+
+        if( p_current == p_event )
+            current = epgItem;
+    }
+}
+
diff --git a/modules/gui/qt/components/epg/EPGProgram.hpp b/modules/gui/qt/components/epg/EPGProgram.hpp
new file mode 100644
index 0000000..9e7aa1d
--- /dev/null
+++ b/modules/gui/qt/components/epg/EPGProgram.hpp
@@ -0,0 +1,65 @@
+/*****************************************************************************
+ * EPGProgram.hpp:
+ ****************************************************************************
+ * Copyright © 2016 VideoLAN Authors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifndef EPGPROGRAM_HPP
+#define EPGPROGRAM_HPP
+
+#include "qt.hpp"
+
+#include <vlc_epg.h>
+#include <QObject>
+#include <QMap>
+#include <QHash>
+#include <QDateTime>
+
+class EPGView;
+class EPGItem;
+
+class EPGProgram : public QObject
+{
+    Q_OBJECT
+
+    public:
+        EPGProgram( EPGView *, const vlc_epg_t * );
+        virtual ~EPGProgram();
+
+        void pruneEvents( const QDateTime & );
+        void updateEvents( const vlc_epg_event_t * const *, size_t, const vlc_epg_event_t *,
+                           QDateTime * );
+        void updateEventPos();
+        size_t getPosition() const;
+        void setPosition( size_t );
+        const EPGItem * getCurrent() const;
+        const QString & getName() const;
+        static bool lessThan( const EPGProgram *, const EPGProgram * );
+
+        QHash<uint32_t, EPGItem *> eventsbyid;
+        QMap<QDateTime, const EPGItem *> eventsbytime;
+
+    private:
+        const EPGItem *current;
+        EPGView *view;
+        size_t pos;
+
+        QString name;
+        uint32_t id;
+        uint16_t sourceid;
+};
+
+#endif // EPGPROGRAM_HPP
diff --git a/modules/gui/qt/components/epg/EPGRuler.cpp b/modules/gui/qt/components/epg/EPGRuler.cpp
index bd7ccac..46a87cc 100644
--- a/modules/gui/qt/components/epg/EPGRuler.cpp
+++ b/modules/gui/qt/components/epg/EPGRuler.cpp
@@ -47,15 +47,17 @@ void EPGRuler::setScale( double scale )
     update();
 }
 
-void EPGRuler::setStartTime( const QDateTime& startTime )
+void EPGRuler::setRange( const QDateTime& startTime, const QDateTime& endTime )
 {
-    m_startTime = startTime;
-    update();
-}
-
-void EPGRuler::setDuration( int duration )
-{
-    m_duration = duration;
+    if( !startTime.isValid() || !endTime.isValid() )
+    {
+        m_startTime = QDateTime();
+    }
+    else
+    {
+        m_startTime = startTime;
+        m_duration = startTime.secsTo( endTime );
+    }
     update();
 }
 
@@ -73,6 +75,12 @@ void EPGRuler::paintEvent( QPaintEvent *event )
     const int spacing = m_scale * 3600;
     QPainter p( this );
 
+    if( !m_startTime.isValid() )
+    {
+        QWidget::paintEvent( event );
+        return;
+    }
+
     QDateTime localStartTime;
     localStartTime = m_startTime.addSecs( m_offset / m_scale );
 
diff --git a/modules/gui/qt/components/epg/EPGRuler.hpp b/modules/gui/qt/components/epg/EPGRuler.hpp
index ddd7873..1a8021b 100644
--- a/modules/gui/qt/components/epg/EPGRuler.hpp
+++ b/modules/gui/qt/components/epg/EPGRuler.hpp
@@ -39,8 +39,7 @@ public:
 
 public slots:
     void setScale( double scale );
-    void setStartTime( const QDateTime& startTime );
-    void setDuration( int duration );
+    void setRange( const QDateTime&, const QDateTime& );
     void setOffset( int offset );
 
 protected:
diff --git a/modules/gui/qt/components/epg/EPGView.cpp b/modules/gui/qt/components/epg/EPGView.cpp
index 5835e01..ea5b3ac 100644
--- a/modules/gui/qt/components/epg/EPGView.cpp
+++ b/modules/gui/qt/components/epg/EPGView.cpp
@@ -40,6 +40,12 @@ void EPGGraphicsScene::drawBackground( QPainter *painter, const QRectF &rect)
 {
     EPGView *epgView = qobject_cast<EPGView *>(parent());
 
+    if( !epgView->startTime().isValid() )
+    {
+        QGraphicsScene::drawBackground( painter, rect );
+        return;
+    }
+
     /* day change */
     QDateTime rectstarttime = epgView->startTime().addSecs( rect.left() );
     QDateTime nextdaylimit = QDateTime( rectstarttime.date() );
@@ -63,9 +69,12 @@ void EPGGraphicsScene::drawBackground( QPainter *painter, const QRectF &rect)
        painter->drawLine( QLineF( rect.left(), y, rect.right(), y ) );
 
     /* current hour line */
-    int x = epgView->startTime().secsTo( epgView->baseTime() );
-    painter->setPen( QPen( QColor( 255, 192, 192 ) ) );
-    painter->drawLine( QLineF( x, rect.top(), x, rect.bottom() ) );
+    if( epgView->liveTime().isValid() )
+    {
+        int x = epgView->startTime().secsTo( epgView->liveTime() );
+        painter->setPen( QPen( QColor( 255, 192, 192 ) ) );
+        painter->drawLine( QLineF( x, rect.top(), x, rect.bottom() ) );
+    }
 }
 
 EPGView::EPGView( QWidget *parent ) : QGraphicsView( parent )
@@ -74,7 +83,8 @@ EPGView::EPGView( QWidget *parent ) : QGraphicsView( parent )
     setFrameStyle( QFrame::Box );
     setAlignment( Qt::AlignLeft | Qt::AlignTop );
 
-    m_startTime = QDateTime::currentDateTime();
+    m_startTime = QDateTime();
+    m_maxTime = m_startTime;
 
     EPGGraphicsScene *EPGscene = new EPGGraphicsScene( this );
 
@@ -89,276 +99,114 @@ void EPGView::setScale( double scaleFactor )
     setMatrix( matrix );
 }
 
-void EPGView::updateStartTime()
-{
-    mutex.lock();
-    foreach( EPGEventByTimeQMap *epgItemByTime, epgitemsByChannel.values() )
-    {
-        foreach( EPGItem *epgItem, epgItemByTime->values() )
-        {
-            epgItem->updatePos();
-        }
-    }
-    mutex.unlock();
-}
-
-void EPGView::updateChannels()
-{
-    /* Make sure our items goes to the correct row */
-    unsigned int channelIndex = 0;
-    mutex.lock();
-    foreach( EPGEventByTimeQMap *epgItemByTime, epgitemsByChannel.values() )
-    {
-        foreach( EPGItem *epgItem, epgItemByTime->values() )
-            epgItem->setRow( channelIndex );
-        channelIndex++;
-    }
-    mutex.unlock();
-}
-
 const QDateTime& EPGView::startTime() const
 {
     return m_startTime;
 }
 
-const QDateTime& EPGView::baseTime() const
+QDateTime EPGView::liveTime() const
 {
-    return m_baseTime;
+    if( m_startTime.isValid() && m_maxTime.isValid() )
+    {
+        QDateTime now = QDateTime::currentDateTime();
+        if( now >= m_startTime && now <= m_maxTime )
+            return now;
+    }
+    return QDateTime();
 }
 
 bool EPGView::hasValidData() const
 {
-    return !epgitemsByChannel.isEmpty();
+    return !programs.isEmpty();
 }
 
-bool EPGView::addEPGEvents( vlc_epg_event_t **pp_events, size_t i_events,
-                            QString channelName, const vlc_epg_event_t *p_current )
+bool EPGView::updateEPG( const vlc_epg_t * const *pp_epg, size_t i_epg )
 {
-    /* Init our nested map if required */
-    EPGEventByTimeQMap *epgItemByTime;
-    EPGItem *epgItem;
-    bool b_refresh_channels = false;
-
-    if( i_events < 1 )
-        return false;
+    m_updtMinTime = QDateTime();
 
-    mutex.lock();
-    /* First check and create channel if missing */
-    if ( !epgitemsByChannel.contains( channelName ) )
+    for ( size_t i = 0; i < i_epg; ++i )
     {
-        epgItemByTime = new EPGEventByTimeQMap();
-        epgitemsByChannel.insert( channelName, epgItemByTime );
-        emit channelAdded( channelName );
-        b_refresh_channels = true;
-    } else {
-        epgItemByTime = epgitemsByChannel.value( channelName );
-    }
+        const vlc_epg_t *p_epg = pp_epg[i];
 
-    QDateTime rangeStart = QDateTime::fromTime_t( pp_events[0]->i_start );
-    QDateTime rangeEnd = QDateTime::fromTime_t( pp_events[i_events - 1]->i_start );
-    rangeEnd.addSecs( pp_events[i_events - 1]->i_duration );
+        EPGProgram *program;
 
-    EPGEventByTimeQMap::iterator itRangeBegin =
-            epgItemByTime->lowerBound( rangeStart );
-    EPGEventByTimeQMap::iterator itRangeEnd =
-            epgItemByTime->upperBound( rangeEnd );
-
-    EPGEventByTimeQMap::iterator it = itRangeBegin;
-    for( size_t i=0; i<i_events; i++ )
-    {
-        const vlc_epg_event_t *p_event = pp_events[i];
-
-        for( ; it != itRangeEnd; ++it )
+        QHash<uint16_t, EPGProgram*>::iterator it = programs.find( p_epg->i_source_id );
+        if( it != programs.end() )
         {
-            EPGItem *epgItem = *it;
-            QDateTime eventStart = QDateTime::fromTime_t( p_event->i_start );
-            if( epgItem->start() < eventStart )
-            {
-                if( it != itRangeBegin ||
-                    epgItem->start().addSecs( epgItem->duration() ) > eventStart )
-                    delete *it++;
-            }
-            else if( epgItem->start() > eventStart )
-            {
-                break;
-            }
+            program = *it;
         }
-    }
-
-    mutex.unlock();
-
-
-    bool b_added = false;
-    for( size_t i=0; i<i_events; i++ )
-    {
-        const vlc_epg_event_t *p_event = pp_events[i];
-
-        QDateTime eventStart = QDateTime::fromTime_t( p_event->i_start );
-        if ( eventStart.addSecs( p_event->i_duration ) < m_baseTime )
-            continue; /* EPG feed sent expired item */
-        if ( eventStart < m_startTime )
-        {
-            m_startTime = eventStart;
-            emit startTimeChanged( m_startTime );
-        }
-
-        mutex.lock();
-
-        if ( epgItemByTime->contains( eventStart ) )
+        else
         {
-            /* Update our existing programs */
-            epgItem = epgItemByTime->value( eventStart );
-            epgItem->setCurrent( ( p_event == p_current ) );
-            epgItem->setData( p_event ); /* updates our entry */
-        } else {
-            /* Insert a new program entry */
-            epgItem = new EPGItem( p_event, this );
-            /* Effectively insert our new program */
-            epgItem->setCurrent( ( p_event == p_current ) );
-            epgItemByTime->insert( eventStart, epgItem );
-            scene()->addItem( epgItem );
-            /* update only our row (without calling the updatechannels()) */
-            epgItem->setRow( epgitemsByChannel.keys().indexOf( channelName ) );
-
-            /* First Insert, needs to focus by default then */
-            if ( epgitemsByChannel.keys().count() == 1 &&
-                 epgItemByTime->count() == 1 )
-                focusItem( epgItem );
-            b_added = true;
+            program = new EPGProgram( this, p_epg );
+            program->setPosition( programs.count() );
+            programs.insert( p_epg->i_source_id, program );
+            emit programAdded( program );
         }
-
-        mutex.unlock();
+        program->updateEvents( p_epg->pp_event, p_epg->i_event, p_epg->p_current, &m_updtMinTime );
     }
 
+    if( !m_startTime.isValid() )
+        m_startTime = m_updtMinTime;
 
-    /* Update rows on each item */
-    if ( b_refresh_channels ) updateChannels();
-
-    return b_added;
-}
-
-void EPGView::removeEPGEvent( vlc_epg_event_t *eventdata, QString channelName )
-{
-    EPGEventByTimeQMap *epgItemByTime;
-    QDateTime eventStart = QDateTime::fromTime_t( eventdata->i_start );
-    EPGItem *epgItem;
-    bool b_update_channels = false;
-
-    mutex.lock();
-    if ( epgitemsByChannel.contains( channelName ) )
-    {
-        epgItemByTime = epgitemsByChannel.value( channelName );
-
-        if ( epgItemByTime->contains( eventStart ) )
-        { /* delete our EPGItem */
-            epgItem = epgItemByTime->value( eventStart );
-            epgItemByTime->remove( eventStart );
-            scene()->removeItem( epgItem );
-            delete epgItem;
-        }
-
-        if ( epgItemByTime->keys().isEmpty() )
-        { /* Now unused channel */
-            epgitemsByChannel.remove( channelName );
-            delete epgItemByTime;
-            emit channelRemoved( channelName );
-            b_update_channels = true;
-        }
-    }
-    mutex.unlock();
-
-    if ( b_update_channels ) updateChannels();
+    return true;
 }
 
 void EPGView::reset()
 {
     /* clean our items storage and remove them from the scene */
-    EPGEventByTimeQMap *epgItemByTime;
-    EPGItem *epgItem;
-    mutex.lock();
-    foreach( const QString &channelName, epgitemsByChannel.keys() )
-    {
-        epgItemByTime = epgitemsByChannel[ channelName ];
-        foreach( const QDateTime &key, epgItemByTime->keys() )
-        {
-            epgItem = epgItemByTime->value( key );
-            scene()->removeItem( epgItem );
-            epgItemByTime->remove( key );
-            delete epgItem;
-        }
-        epgitemsByChannel.remove( channelName );
-        delete epgItemByTime;
-        emit channelRemoved( channelName ); /* notify others */
-    }
-    mutex.unlock();
+    qDeleteAll(programs.values());
+    programs.clear();
+    m_startTime = m_maxTime = QDateTime();
 }
 
-void EPGView::cleanup()
+void EPGView::walkItems( bool b_cleanup )
 {
-    /* remove expired items and clear their current flag */
-    EPGEventByTimeQMap *epgItemByTime;
-    EPGItem *epgItem;
-    m_baseTime = QDateTime::currentDateTime();
-    QDateTime lowestTime = m_baseTime;
-    bool b_timechanged = false;
-    bool b_update_channels = false;
-
-    mutex.lock();
-    foreach( const QString &channelName, epgitemsByChannel.keys() )
+    m_updtMinTime = m_startTime;
+    QDateTime maxTime;
+    bool b_rangechanged = false;
+
+    foreach( EPGProgram *program, programs )
     {
-        epgItemByTime = epgitemsByChannel[ channelName ];
-        foreach( const QDateTime &key, epgItemByTime->keys() )
+        /* remove expired items and clear their current flag */
+        if( b_cleanup && m_updtMinTime.isValid() )
+            program->pruneEvents( m_updtMinTime );
+
+        if( !program->eventsbytime.isEmpty() )
         {
-            epgItem = epgItemByTime->value( key );
-            if ( epgItem->endsBefore( baseTime() ) ) /* Expired item ? */
+            const EPGItem *last = program->eventsbytime.last();
+            if( !maxTime.isValid() ||
+                 last->start().addSecs( last->duration() ) > maxTime )
             {
-                scene()->removeItem( epgItem );
-                epgItemByTime->remove( key );
-                delete epgItem;
-            } else {
-                epgItem->setCurrent( false ); /* if stream doesn't update */
-                if ( lowestTime > epgItem->start() )
-                {
-                    lowestTime = epgItem->start(); /* update our reference */
-                    b_timechanged = true;
-                }
+                maxTime = last->start().addSecs( last->duration() );
             }
         }
-
-        if ( epgItemByTime->keys().isEmpty() )
-        { /* Now unused channel */
-            epgitemsByChannel.remove( channelName );
-            delete epgItemByTime;
-            emit channelRemoved( channelName );
-            b_update_channels = true;
-        }
     }
-    mutex.unlock();
 
-    if ( b_timechanged )
+    if( m_startTime.isValid() && m_startTime != m_updtMinTime )
+        b_rangechanged = m_updtMinTime.isValid();
+
+    if( maxTime.isValid() && m_maxTime != maxTime )
+        b_rangechanged |= m_updtMinTime.isValid();
+
+    m_startTime = m_updtMinTime;
+    m_maxTime = maxTime;
+
+    if ( b_rangechanged )
     {
-        m_startTime = lowestTime;
-        emit startTimeChanged( m_startTime );
+        foreach( EPGProgram *program, programs )
+            program->updateEventPos();
+        emit rangeChanged( m_startTime, m_maxTime );
     }
-
-    if ( b_update_channels ) updateChannels();
 }
 
-EPGView::~EPGView()
+void EPGView::cleanup()
 {
-    reset();
+    walkItems( true );
 }
 
-void EPGView::updateDuration()
+EPGView::~EPGView()
 {
-    QDateTime maxItemTime;
-    mutex.lock();
-    foreach( EPGEventByTimeQMap *epgItemByTime, epgitemsByChannel.values() )
-        foreach( EPGItem *epgItem, epgItemByTime->values() )
-            if ( epgItem->end() > maxItemTime ) maxItemTime = epgItem->end();
-    mutex.unlock();
-    m_duration = m_startTime.secsTo( maxItemTime );
-    emit durationChanged( m_duration );
+    reset();
 }
 
 void EPGView::focusItem( EPGItem *epgItem )
diff --git a/modules/gui/qt/components/epg/EPGView.hpp b/modules/gui/qt/components/epg/EPGView.hpp
index c74413c..114e973 100644
--- a/modules/gui/qt/components/epg/EPGView.hpp
+++ b/modules/gui/qt/components/epg/EPGView.hpp
@@ -26,22 +26,20 @@
 
 #include "qt.hpp"
 
+#include "EPGProgram.hpp"
+
 #include <vlc_epg.h>
 
 #include <QGraphicsView>
 #include <QGraphicsScene>
 #include <QList>
-#include <QMap>
-#include <QMutex>
+#include <QHash>
 #include <QDateTime>
 
 class EPGItem;
 
 #define TRACKS_HEIGHT 60
 
-typedef QMap<QDateTime, EPGItem *> EPGEventByTimeQMap;
-typedef QMap<QString, EPGEventByTimeQMap* > EPGTimeMapByChannelQMap;
-
 class EPGGraphicsScene : public QGraphicsScene
 {
 Q_OBJECT
@@ -61,36 +59,32 @@ public:
 
     void            setScale( double scaleFactor );
 
-    void            updateStartTime();
     const QDateTime& startTime() const;
-    const QDateTime& baseTime() const;
+    QDateTime       liveTime() const;
 
-    bool            addEPGEvents( vlc_epg_event_t **, size_t, QString, const vlc_epg_event_t * );
-    void            removeEPGEvent( vlc_epg_event_t*, QString );
-    void            updateDuration();
+    bool            updateEPG( const vlc_epg_t * const *, size_t );
     void            reset();
     void            cleanup();
     bool            hasValidData() const;
 
 signals:
-    void            startTimeChanged( const QDateTime& startTime );
-    void            durationChanged( int seconds );
+    void            rangeChanged( const QDateTime&, const QDateTime& );
     void            itemFocused( EPGItem * );
-    void            channelAdded( QString );
-    void            channelRemoved( QString );
-protected:
+    void            programAdded( const EPGProgram * );
 
+protected:
+    void            walkItems( bool );
     QDateTime       m_startTime;
-    QDateTime       m_baseTime;
+    QDateTime       m_maxTime;
+    QDateTime       m_updtMinTime; /* >= startTime before pruning */
     int             m_scaleFactor;
     int             m_duration;
 
 public slots:
     void            focusItem( EPGItem * );
+
 private:
-    EPGTimeMapByChannelQMap epgitemsByChannel;
-    void updateChannels();
-    QMutex mutex;
+    QHash<uint16_t, EPGProgram*> programs;
 };
 
 #endif // EPGVIEW_H
diff --git a/modules/gui/qt/components/epg/EPGWidget.cpp b/modules/gui/qt/components/epg/EPGWidget.cpp
index ec113b4..bf9cb49 100644
--- a/modules/gui/qt/components/epg/EPGWidget.cpp
+++ b/modules/gui/qt/components/epg/EPGWidget.cpp
@@ -69,25 +69,22 @@ EPGWidget::EPGWidget( QWidget *parent ) : QWidget( parent )
     layout->addWidget( rootWidget );
     setLayout( layout );
 
-    CONNECT( m_epgView, startTimeChanged(QDateTime),
-             m_rulerWidget, setStartTime(QDateTime) );
-    CONNECT( m_epgView, durationChanged(int),
-             m_rulerWidget, setDuration(int) );
+    CONNECT( m_epgView, rangeChanged(const QDateTime &, const QDateTime &),
+             m_rulerWidget, setRange(const QDateTime &, const QDateTime &) );
+
     CONNECT( m_epgView->horizontalScrollBar(), valueChanged(int),
              m_rulerWidget, setOffset(int) );
     CONNECT( m_epgView->verticalScrollBar(), valueChanged(int),
              m_channelsWidget, setOffset(int) );
     connect( m_epgView, SIGNAL( itemFocused(EPGItem*)),
              this, SIGNAL(itemSelectionChanged(EPGItem*)) );
-    CONNECT( m_epgView, channelAdded(QString), m_channelsWidget, addChannel(QString) );
-    CONNECT( m_epgView, channelRemoved(QString), m_channelsWidget, removeChannel(QString) );
+    CONNECT( m_epgView, programAdded(const EPGProgram *), m_channelsWidget, addProgram(const EPGProgram *) );
 }
 
 void EPGWidget::reset()
 {
+    m_channelsWidget->reset();
     m_epgView->reset();
-    m_epgView->updateDuration();
-    m_epgView->updateStartTime();
 }
 
 void EPGWidget::setZoom( int level )
@@ -106,26 +103,15 @@ void EPGWidget::updateEPG( input_item_t *p_input_item )
     i_event_source_type = p_input_item->i_type;
     b_input_type_known = true;
 
-    m_epgView->cleanup(); /* expire items and flags */
     /* Fixme: input could have dissapeared */
     vlc_mutex_lock(  & p_input_item->lock );
-
-    for ( int i = 0; i < p_input_item->i_epg; ++i )
-    {
-        vlc_epg_t *p_epg = p_input_item->pp_epg[i];
-        /* Read current epg events from libvlc and try to insert them */
-        m_epgView->addEPGEvents( p_epg->pp_event, p_epg->i_event,
-                                 qfu( p_epg->psz_name ),
-                                 p_epg->p_current );
-    }
+    m_epgView->updateEPG( p_input_item->pp_epg, p_input_item->i_epg );
     vlc_mutex_unlock( & p_input_item->lock );
 
     /* toggle our widget view */
     rootWidget->setCurrentIndex(
             m_epgView->hasValidData() ? EPGVIEW_WIDGET : NOEPG_WIDGET );
 
-    // Update the global duration and start time.
-    m_epgView->updateDuration();
-    m_epgView->updateStartTime();
+    m_epgView->cleanup();
 }
 



More information about the vlc-commits mailing list