Commit 900dfeda authored by Francois Cartegnie's avatar Francois Cartegnie

Qt: EPG: rework

- Change data structures to deduplicate data.
Using the right structures, most data is available in dictionaries keys
and items. (epgevent now unused)
- Use signals and slots to manage QMap indexed channels
(widget storage were required for channel list et number)
- Removes EPGEvent memory leak on focus notification
parent 51a887bb
...@@ -39,6 +39,21 @@ void EPGChannels::setOffset( int offset ) ...@@ -39,6 +39,21 @@ void EPGChannels::setOffset( int offset )
update(); update();
} }
void EPGChannels::addChannel( QString channelName )
{
if ( !channelList.contains( channelName ) )
{
channelList << channelName;
channelList.sort();
update();
}
}
void EPGChannels::removeChannel( QString channelName )
{
if ( channelList.removeOne( channelName ) ) update();
}
void EPGChannels::paintEvent( QPaintEvent *event ) void EPGChannels::paintEvent( QPaintEvent *event )
{ {
Q_UNUSED( event ); Q_UNUSED( event );
...@@ -48,17 +63,15 @@ void EPGChannels::paintEvent( QPaintEvent *event ) ...@@ -48,17 +63,15 @@ void EPGChannels::paintEvent( QPaintEvent *event )
/* Draw the top and the bottom lines. */ /* Draw the top and the bottom lines. */
p.drawLine( 0, 0, width() - 1, 0 ); p.drawLine( 0, 0, width() - 1, 0 );
QList<QString> channels = m_epgView->getChannelList(); unsigned int i=0;
foreach( QString text, channelList )
for( int i = 0; i < channels.count(); ++i )
{ {
QString text( channels[i] );
/* try to remove the " [Program xxx]" end */ /* try to remove the " [Program xxx]" end */
int i_idx_channel = text.lastIndexOf(" [Program "); int i_idx_channel = text.lastIndexOf(" [Program ");
if (i_idx_channel > 0) if (i_idx_channel > 0)
text = text.left( i_idx_channel ); text = text.left( i_idx_channel );
p.drawText( 0, - m_offset + ( i + 0.5 ) * TRACKS_HEIGHT - 4, p.drawText( 0, - m_offset + ( i++ + 0.5 ) * TRACKS_HEIGHT - 4,
width(), 20, Qt::AlignLeft, text ); width(), 20, Qt::AlignLeft, text );
int i_width = fontMetrics().width( text ); int i_width = fontMetrics().width( text );
......
...@@ -32,10 +32,11 @@ class EPGChannels : public QWidget ...@@ -32,10 +32,11 @@ class EPGChannels : public QWidget
Q_OBJECT Q_OBJECT
public: public:
EPGChannels( QWidget *parent, EPGView *m_epgView ); EPGChannels( QWidget *parent, EPGView *m_epgView );
virtual ~EPGChannels() { }
public slots: public slots:
void setOffset( int offset ); void setOffset( int offset );
void addChannel( QString );
void removeChannel( QString );
protected: protected:
virtual void paintEvent( QPaintEvent *event ); virtual void paintEvent( QPaintEvent *event );
...@@ -43,6 +44,7 @@ protected: ...@@ -43,6 +44,7 @@ protected:
private: private:
EPGView *m_epgView; EPGView *m_epgView;
int m_offset; int m_offset;
QStringList channelList;
}; };
#endif // EPGCHANNELS_HPP #endif // EPGCHANNELS_HPP
...@@ -34,13 +34,14 @@ ...@@ -34,13 +34,14 @@
#include "EPGItem.hpp" #include "EPGItem.hpp"
#include "EPGView.hpp" #include "EPGView.hpp"
#include "EPGEvent.hpp"
EPGItem::EPGItem( EPGView *view ) #include "qt4.hpp"
EPGItem::EPGItem( vlc_epg_event_t *data, EPGView *view )
: m_view( view ) : m_view( view )
{ {
setData( data );
m_current = false; m_current = false;
m_simultaneous = false;
m_boundingRect.setHeight( TRACKS_HEIGHT ); m_boundingRect.setHeight( TRACKS_HEIGHT );
setFlags( QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable); setFlags( QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable);
setAcceptHoverEvents( true ); setAcceptHoverEvents( true );
...@@ -68,8 +69,9 @@ void EPGItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, ...@@ -68,8 +69,9 @@ void EPGItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *option,
QLinearGradient gradient( mapped.topLeft(), mapped.bottomLeft() ); QLinearGradient gradient( mapped.topLeft(), mapped.bottomLeft() );
if ( m_current || m_simultaneous ) bool b_simultaneous = playsAt( m_view->baseTime() );
gradientColor.setRgb( 244, 125, 0 , m_simultaneous ? 192 : 255 ); if ( m_current || b_simultaneous )
gradientColor.setRgb( 244, 125, 0 , b_simultaneous ? 192 : 255 );
else else
gradientColor.setRgb( 201, 217, 242 ); gradientColor.setRgb( 201, 217, 242 );
...@@ -111,7 +113,7 @@ void EPGItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, ...@@ -111,7 +113,7 @@ void EPGItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *option,
/* Draw the hours. */ /* Draw the hours. */
painter->drawText( mapped, Qt::AlignTop | Qt::AlignLeft, painter->drawText( mapped, Qt::AlignTop | Qt::AlignLeft,
fm.elidedText( m_start.toString( "hh:mm" ) + " - " + fm.elidedText( start().toString( "hh:mm" ) + " - " +
m_end.toString( "hh:mm" ), m_end.toString( "hh:mm" ),
Qt::ElideRight, mapped.width() ) ); Qt::ElideRight, mapped.width() ) );
} }
...@@ -121,47 +123,69 @@ const QDateTime& EPGItem::start() const ...@@ -121,47 +123,69 @@ const QDateTime& EPGItem::start() const
return m_start; return m_start;
} }
int EPGItem::duration() const QDateTime EPGItem::end()
{ {
return m_duration; return QDateTime( m_start ).addSecs( m_duration );
} }
int EPGItem::getChannelNb() const int EPGItem::duration() const
{ {
return m_channelNb; return m_duration;
} }
void EPGItem::setChannelNb( int channelNb ) void EPGItem::setRow( unsigned int i_row_ )
{ {
//qDebug() << "Channel" << channelNb; i_row = i_row_;
m_channelNb = channelNb;
updatePos(); updatePos();
} }
void EPGItem::setData( EPGEvent *event ) void EPGItem::setData( vlc_epg_event_t *data )
{ {
m_start = event->start; m_start = QDateTime::fromTime_t( data->i_start );
m_name = event->name; m_name = qfu( data->psz_name );
m_description = event->description; setToolTip( qfu( data->psz_name ) );
m_shortDescription = event->shortDescription; m_description = qfu( data->psz_description );
m_current = event->current; m_shortDescription = qfu( data->psz_short_description );
m_simultaneous = event->simultaneous; setDuration( data->i_duration );
setDuration( event->duration );
updatePos();
setToolTip( m_name );
update(); update();
} }
void EPGItem::setCurrent( bool b_current )
{
m_current = b_current;
}
bool EPGItem::endsBefore( const QDateTime &ref ) const
{
return m_start.addSecs( m_duration ) < ref;
}
bool EPGItem::playsAt( const QDateTime & ref ) const
{
return (m_start <= ref) && !endsBefore( ref );
}
void EPGItem::setDuration( int duration ) void EPGItem::setDuration( int duration )
{ {
m_duration = duration; m_duration = duration;
m_boundingRect.setWidth( duration ); m_boundingRect.setWidth( duration );
} }
QString EPGItem::description()
{
if( m_description.isEmpty() )
return m_shortDescription;
QString text( m_description );
if( !m_shortDescription.isEmpty() )
text += QString(" - ") += m_shortDescription;
return text;
}
void EPGItem::updatePos() void EPGItem::updatePos()
{ {
int x = m_view->startTime().secsTo( m_start ); int x = m_view->startTime().secsTo( m_start );
setPos( x, m_channelNb * TRACKS_HEIGHT ); setPos( x, i_row * TRACKS_HEIGHT );
} }
void EPGItem::hoverEnterEvent ( QGraphicsSceneHoverEvent * event ) void EPGItem::hoverEnterEvent ( QGraphicsSceneHoverEvent * event )
...@@ -172,11 +196,7 @@ void EPGItem::hoverEnterEvent ( QGraphicsSceneHoverEvent * event ) ...@@ -172,11 +196,7 @@ void EPGItem::hoverEnterEvent ( QGraphicsSceneHoverEvent * event )
void EPGItem::focusInEvent( QFocusEvent * event ) void EPGItem::focusInEvent( QFocusEvent * event )
{ {
EPGEvent *evEPG = new EPGEvent( m_name ); event->accept();
evEPG->description = m_description; m_view->focusItem( this );
evEPG->shortDescription = m_shortDescription;
evEPG->start = m_start;
evEPG->duration = m_duration;
m_view->eventFocused( evEPG );
update(); update();
} }
...@@ -24,33 +24,37 @@ ...@@ -24,33 +24,37 @@
#ifndef EPGITEM_H #ifndef EPGITEM_H
#define EPGITEM_H #define EPGITEM_H
#include <vlc_common.h>
#include <vlc_epg.h>
#include <QGraphicsItem> #include <QGraphicsItem>
#include <QDateTime>
class QPainter; class QPainter;
class QString; class QString;
class QDateTime;
class EPGView; class EPGView;
class EPGEvent;
class EPGItem : public QGraphicsItem class EPGItem : public QGraphicsItem
{ {
public: public:
EPGItem( EPGView *view ); EPGItem( vlc_epg_event_t *data, EPGView *view );
virtual ~EPGItem() { }
virtual QRectF boundingRect() const; virtual QRectF boundingRect() const;
virtual void paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0 ); virtual void paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0 );
const QDateTime& start() const; const QDateTime& start() const;
QDateTime end();
int duration() const; int duration() const;
int getChannelNb() const; const QString& name() { return m_name; };
QString description();
void setData( EPGEvent * ); void setData( vlc_epg_event_t * );
void setChannelNb( int channelNb ); void setRow( unsigned int );
void setCurrent( bool );
void setDuration( int duration ); void setDuration( int duration );
void updatePos(); void updatePos();
bool endsBefore( const QDateTime & ) const;
bool playsAt( const QDateTime & ) const;
protected: protected:
virtual void focusInEvent( QFocusEvent * event ); virtual void focusInEvent( QFocusEvent * event );
...@@ -59,16 +63,14 @@ protected: ...@@ -59,16 +63,14 @@ protected:
private: private:
EPGView *m_view; EPGView *m_view;
QRectF m_boundingRect; QRectF m_boundingRect;
int m_channelNb; unsigned int i_row;
/*FIXME: Bad object design. We shouldn't need to clone this EPGEvent data */
QDateTime m_start; QDateTime m_start;
int m_duration; int m_duration;
QString m_name; QString m_name;
QString m_description; QString m_description;
QString m_shortDescription; QString m_shortDescription;
bool m_current; bool m_current;
bool m_simultaneous;
}; };
#endif // EPGITEM_H #endif // EPGITEM_H
...@@ -54,31 +54,29 @@ void EPGView::setScale( double scaleFactor ) ...@@ -54,31 +54,29 @@ void EPGView::setScale( double scaleFactor )
void EPGView::updateStartTime() void EPGView::updateStartTime()
{ {
QList<QGraphicsItem*> itemList = items(); mutex.lock();
foreach( EPGEventByTimeQMap *epgItemByTime, epgitemsByChannel.values() )
/* Set the new start time. */
for ( int i = 0; i < itemList.count(); ++i )
{ {
EPGItem* item = qgraphicsitem_cast<EPGItem*>( itemList.at( i ) ); foreach( EPGItem *epgItem, epgItemByTime->values() )
if ( !item ) {
continue; epgItem->updatePos();
if( i == 0 ) }
m_startTime = item->start();
if ( item->start() < m_startTime )
m_startTime = item->start();
} }
mutex.unlock();
}
/* Update the position of all items. */ void EPGView::updateChannels()
for ( int i = 0; i < itemList.count(); ++i ) {
/* Make sure our items goes to the correct row */
unsigned int channelIndex = 0;
mutex.lock();
foreach( EPGEventByTimeQMap *epgItemByTime, epgitemsByChannel.values() )
{ {
EPGItem* item = qgraphicsitem_cast<EPGItem*>( itemList.at( i ) ); foreach( EPGItem *epgItem, epgItemByTime->values() )
if ( !item ) epgItem->setRow( channelIndex );
continue; channelIndex++;
item->updatePos();
} }
mutex.unlock();
// Our start time may have changed.
emit startTimeChanged( m_startTime );
} }
const QDateTime& EPGView::startTime() const QDateTime& EPGView::startTime()
...@@ -86,62 +84,172 @@ const QDateTime& EPGView::startTime() ...@@ -86,62 +84,172 @@ const QDateTime& EPGView::startTime()
return m_startTime; return m_startTime;
} }
void EPGView::addEvent( EPGEvent* event ) const QDateTime& EPGView::baseTime()
{ {
if ( !m_channels.contains( event->channelName ) ) return m_baseTime;
m_channels.append( event->channelName ); }
bool EPGView::addEPGEvent( vlc_epg_event_t *data, QString channelName, bool b_current )
{
/* Init our nested map if required */
EPGEventByTimeQMap *epgItemByTime;
EPGItem *epgItem;
bool b_refresh_channels = false;
QDateTime eventStart = QDateTime::fromTime_t( data->i_start );
if ( eventStart < m_startTime )
{
m_startTime = eventStart;
emit startTimeChanged( m_startTime );
}
mutex.lock();
if ( !epgitemsByChannel.contains( channelName ) )
{
epgItemByTime = new EPGEventByTimeQMap();
epgitemsByChannel.insert( channelName, epgItemByTime );
emit channelAdded( channelName );
b_refresh_channels = true;
} else {
epgItemByTime = epgitemsByChannel.value( channelName );
}
EPGItem* item = new EPGItem( this ); if ( epgItemByTime->contains( eventStart ) )
item->setData( event ); {
item->setChannelNb( m_channels.indexOf( event->channelName ) ); /* Update our existing programs */
item->setDuration( event->duration ); epgItem = epgItemByTime->value( eventStart );
epgItem->setData( data ); /* updates our entry */
epgItem->setCurrent( b_current );
mutex.unlock();
return false;
} else {
/* Insert a new program entry */
epgItem = new EPGItem( data, this );
/* Effectively insert our new program */
epgItem->setCurrent( b_current );
epgItemByTime->insert( eventStart, epgItem );
scene()->addItem( epgItem );
/* update only our row (without calling the updatechannels()) */
epgItem->setRow( epgitemsByChannel.keys().indexOf( channelName ) );
}
mutex.unlock();
event->item = item; /* Update rows on each item */
if ( b_refresh_channels ) updateChannels();
scene()->addItem( item ); return true;
} }
void EPGView::delEvent( EPGEvent* event ) void EPGView::removeEPGEvent( vlc_epg_event_t *data, QString channelName )
{ {
if( event->item == NULL ) EPGEventByTimeQMap *epgItemByTime;
return; QDateTime eventStart = QDateTime::fromTime_t( data->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;
}
int channelNb = event->item->getChannelNb(); if ( epgItemByTime->keys().empty() )
{ /* Now unused channel */
epgitemsByChannel.remove( channelName );
delete epgItemByTime;
emit channelRemoved( channelName );
b_update_channels = true;
}
}
mutex.unlock();
// Remove the item. if ( b_update_channels ) updateChannels();
scene()->removeItem( event->item ); }
event->item = NULL;
// Look if the channel is still used by other events. void EPGView::reset()
QList<QGraphicsItem*> itemList = items(); {
bool b_used = false; /* clean our items storage and remove them from the scene */
for( int i = 0; i < itemList.count(); ++i ) EPGEventByTimeQMap *epgItemByTime;
EPGItem *epgItem;
mutex.lock();
foreach( const QString &channelName, epgitemsByChannel.keys() )
{ {
EPGItem* item = qgraphicsitem_cast<EPGItem*>( itemList.at( i ) ); epgItemByTime = epgitemsByChannel[ channelName ];
if ( !item ) foreach( const QDateTime &key, epgItemByTime->keys() )
continue;
if( item->getChannelNb() == channelNb )
{ {
b_used = true; epgItem = epgItemByTime->value( key );
break; scene()->removeItem( epgItem );
epgItemByTime->remove( key );
delete epgItem;
} }
epgitemsByChannel.remove( channelName );
delete epgItemByTime;
emit channelRemoved( channelName ); /* notify others */
} }
mutex.unlock();
}
void EPGView::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;
// If the channel is no more used, then we remove it from the list mutex.lock();
// and decrease the channel number of the concerned items. foreach( const QString &channelName, epgitemsByChannel.keys() )
if( !b_used )
{ {
m_channels.removeAt( channelNb ); epgItemByTime = epgitemsByChannel[ channelName ];
for( int i = 0; i < itemList.count(); ++i ) foreach( const QDateTime &key, epgItemByTime->keys() )
{ {
EPGItem* item = qgraphicsitem_cast<EPGItem*>( itemList.at( i ) ); epgItem = epgItemByTime->value( key );
if ( !item ) if ( epgItem->endsBefore( baseTime() ) ) /* Expired item ? */
continue; {
int itemChannelNb = item->getChannelNb(); scene()->removeItem( epgItem );
if( itemChannelNb > channelNb ) epgItemByTime->remove( key );
item->setChannelNb( itemChannelNb - 1 ); delete epgItem;
} else {
epgItem->setCurrent( false ); /* if stream doesn't update */
if ( lowestTime > epgItem->start() )
{
lowestTime = epgItem->start(); /* update our reference */
b_timechanged = true;
}
}
}
if ( epgItemByTime->keys().empty() )
{ /* Now unused channel */
epgitemsByChannel.remove( channelName );
delete epgItemByTime;
emit channelRemoved( channelName );
b_update_channels = true;
} }
} }
mutex.unlock();
if ( b_timechanged )
{
m_startTime = lowestTime;
emit startTimeChanged( m_startTime );
}
if ( b_update_channels ) updateChannels();
}
EPGView::~EPGView()
{
reset();
} }
void EPGView::updateDuration() void EPGView::updateDuration()
...@@ -149,6 +257,7 @@ void EPGView::updateDuration() ...@@ -149,6 +257,7 @@ void EPGView::updateDuration()
QDateTime lastItem; QDateTime lastItem;
QList<QGraphicsItem*> list = items(); QList<QGraphicsItem*> list = items();
mutex.lock();
for ( int i = 0; i < list.count(); ++i ) for ( int i = 0; i < list.count(); ++i )
{ {
EPGItem* item = qgraphicsitem_cast<EPGItem*>( list.at( i ) ); EPGItem* item = qgraphicsitem_cast<EPGItem*>( list.at( i ) );
...@@ -158,16 +267,12 @@ void EPGView::updateDuration() ...@@ -158,16 +267,12 @@ void EPGView::updateDuration()
if ( itemEnd > lastItem ) if ( itemEnd > lastItem )
lastItem = itemEnd; lastItem = itemEnd;
} }
mutex.unlock();
m_duration = m_startTime.secsTo( lastItem ); m_duration = m_startTime.secsTo( lastItem );
emit durationChanged( m_duration ); emit durationChanged( m_duration );
} }
QList<QString> EPGView::getChannelList() void EPGView::focusItem( EPGItem *epgItem )
{
return m_channels;
}
void EPGView::eventFocused( EPGEvent *ev )
{ {
emit eventFocusedChanged( ev ); emit itemFocused( epgItem );
} }
...@@ -24,45 +24,58 @@ ...@@ -24,45 +24,58 @@
#ifndef EPGVIEW_H #ifndef EPGVIEW_H
#define EPGVIEW_H #define EPGVIEW_H
#include "EPGEvent.hpp" #include "EPGItem.hpp"
#include <QGraphicsView> #include <QGraphicsView>
#include <QList> #include <QList>
#include <QMap>
#include <QMutex>
#include <QDateTime>
#define TRACKS_HEIGHT 60 #define TRACKS_HEIGHT 60
class QDateTime; typedef QMap<QDateTime, EPGItem *> EPGEventByTimeQMap;
typedef QMap<QString, EPGEventByTimeQMap* > EPGTimeMapByChannelQMap;
class EPGView : public QGraphicsView class EPGView : public QGraphicsView
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit EPGView( QWidget *parent = 0 ); explicit EPGView( QWidget *parent = 0 );
~EPGView();
void setScale( double scaleFactor ); void setScale( double scaleFactor );
void updateStartTime(); void updateStartTime();
const QDateTime& startTime(); const QDateTime& startTime();
const QDateTime& baseTime();
void addEvent( EPGEvent* event ); bool addEPGEvent( vlc_epg_event_t*, QString, bool );
void delEvent( EPGEvent* event ); void removeEPGEvent( vlc_epg_event_t*, QString );
void updateDuration(); void updateDuration();
void reset();
QList<QString> getChannelList(); void cleanup();
signals: signals:
void startTimeChanged( const QDateTime& startTime ); void startTimeChanged( const QDateTime& startTime );
void durationChanged( int seconds ); void durationChanged( int seconds );
void eventFocusedChanged( EPGEvent * ); void itemFocused( EPGItem * );
void channelAdded( QString );
void channelRemoved( QString );
protected: protected:
QList<QString> m_channels;
QDateTime m_startTime; QDateTime m_startTime;
QDateTime m_baseTime;
int m_scaleFactor; int m_scaleFactor;
int m_duration; int m_duration;
public slots: public slots:
void eventFocused( EPGEvent * ); void focusItem( EPGItem * );
private:
EPGTimeMapByChannelQMap epgitemsByChannel;
void updateChannels();
QMutex mutex;
}; };
#endif // EPGVIEW_H #endif // EPGVIEW_H
...@@ -26,11 +26,9 @@ ...@@ -26,11 +26,9 @@
#endif #endif
#include "EPGWidget.hpp" #include "EPGWidget.hpp"
#include "EPGItem.hpp"
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QScrollBar> #include <QScrollBar>
#include <QDebug>
#include <QLabel> #include <QLabel>
#include <QStringList> #include <QStringList>
#include "qt4.hpp" #include "qt4.hpp"
...@@ -41,7 +39,6 @@ EPGWidget::EPGWidget( QWidget *parent ) : QWidget( parent ) ...@@ -41,7 +39,6 @@ EPGWidget::EPGWidget( QWidget *parent ) : QWidget( parent )
m_rulerWidget = new EPGRuler( this ); m_rulerWidget = new EPGRuler( this );
m_epgView = new EPGView( this ); m_epgView = new EPGView( this );
m_channelsWidget = new EPGChannels( this, m_epgView ); m_channelsWidget = new EPGChannels( this, m_epgView );
timeReference = QDateTime::currentDateTime().addDays( 1 );
m_channelsWidget->setMinimumWidth( 100 ); m_channelsWidget->setMinimumWidth( 100 );
...@@ -63,29 +60,17 @@ EPGWidget::EPGWidget( QWidget *parent ) : QWidget( parent ) ...@@ -63,29 +60,17 @@ EPGWidget::EPGWidget( QWidget *parent ) : QWidget( parent )
m_rulerWidget, SLOT( setOffset(int) ) ); m_rulerWidget, SLOT( setOffset(int) ) );
connect( m_epgView->verticalScrollBar(), SIGNAL( valueChanged(int) ), connect( m_epgView->verticalScrollBar(), SIGNAL( valueChanged(int) ),
m_channelsWidget, SLOT( setOffset(int) ) ); m_channelsWidget, SLOT( setOffset(int) ) );
connect( m_epgView, SIGNAL( eventFocusedChanged(EPGEvent*)), connect( m_epgView, SIGNAL( itemFocused(EPGItem*)),
this, SIGNAL(itemSelectionChanged(EPGEvent*)) ); this, SIGNAL(itemSelectionChanged(EPGItem*)) );
} CONNECT( m_epgView, channelAdded(QString), m_channelsWidget, addChannel(QString) );
CONNECT( m_epgView, channelRemoved(QString), m_channelsWidget, removeChannel(QString) );
EPGWidget::~EPGWidget()
{
foreach( const QString &str, m_events.uniqueKeys() )
foreach( EPGEvent *item, m_events.values( str ) )
delete item;
} }
void EPGWidget::reset() void EPGWidget::reset()
{ {
foreach( const QString &str, m_events.uniqueKeys() ) m_epgView->reset();
foreach( EPGEvent *item, m_events.values( str ) )
{
m_epgView->delEvent( item );
m_events.remove( str, item );
delete item;
}
m_epgView->updateDuration(); m_epgView->updateDuration();
m_epgView->updateStartTime(); m_epgView->updateStartTime();
m_channelsWidget->update();
} }
void EPGWidget::setZoom( int level ) void EPGWidget::setZoom( int level )
...@@ -97,106 +82,27 @@ void EPGWidget::setZoom( int level ) ...@@ -97,106 +82,27 @@ void EPGWidget::setZoom( int level )
void EPGWidget::updateEPG( vlc_epg_t **pp_epg, int i_epg, uint8_t i_input_type ) void EPGWidget::updateEPG( vlc_epg_t **pp_epg, int i_epg, uint8_t i_input_type )
{ {
QStringList channelsList;
EPGEvent* epgEvent;
/* if we have epg time available take new minimum time */
if ( i_epg > 0 && pp_epg[0]->i_event > 0 )
timeReference = QDateTime::fromTime_t( pp_epg[0]->pp_event[0]->i_start );
/* flush our EPG data if input type has changed */ /* flush our EPG data if input type has changed */
if ( b_input_type_known && i_input_type != i_event_source_type ) reset(); if ( b_input_type_known && i_input_type != i_event_source_type ) m_epgView->reset();
i_event_source_type = i_input_type; i_event_source_type = i_input_type;
b_input_type_known = true; b_input_type_known = true;
/* flag all entries as non updated */ m_epgView->cleanup(); /* expire items and flags */
foreach( const QString &str, m_events.uniqueKeys() )
foreach( epgEvent, m_events.values( str ) )
{
epgEvent->updated = false;
epgEvent->current = false;
}
for ( int i = 0; i < i_epg; ++i ) for ( int i = 0; i < i_epg; ++i )
{ {
vlc_epg_t *p_epg = pp_epg[i]; vlc_epg_t *p_epg = pp_epg[i];
QString channelName = qfu( p_epg->psz_name );
channelsList.append( channelName );
/* Read current epg events from libvlc and try to insert them */ /* Read current epg events from libvlc and try to insert them */
for ( int j = 0; j < p_epg->i_event; ++j ) for ( int j = 0; j < p_epg->i_event; ++j )
{ {
vlc_epg_event_t *p_event = p_epg->pp_event[j]; vlc_epg_event_t *p_event = p_epg->pp_event[j];
QString eventName = qfu( p_event->psz_name ); m_epgView->addEPGEvent( p_event, qfu( p_epg->psz_name ),
QDateTime eventStart = QDateTime::fromTime_t( p_event->i_start ); ( p_epg->p_current == p_event ) );
/* ensure we display ongoing item */
if ( eventStart < timeReference ) timeReference = eventStart;
/* FIXME: EPGView timechanged signal is duplicate */
QList<EPGEvent*> events = m_events.values( channelName );
epgEvent = new EPGEvent( eventName );
epgEvent->description = qfu( p_event->psz_description );
epgEvent->shortDescription = qfu( p_event->psz_short_description );
epgEvent->start = eventStart;
epgEvent->duration = p_event->i_duration;
epgEvent->channelName = channelName;
epgEvent->current = ( p_epg->p_current == p_event ) ? true : false;
bool alreadyIn = false;
for ( int k = 0; k < events.count(); ++k )
{
if ( *events.at( k ) == *epgEvent )
{
alreadyIn = true;
events.at( k )->updated = true;
break;
}
}
if ( !alreadyIn )
{
m_events.insert( channelName, epgEvent );
m_epgView->addEvent( epgEvent );
}
else /* the new epgEvent is unused */
delete epgEvent;
}
}
/* Remove old (not in current epg list) items for current tuned channels */
/* and try to keep previously tuned in channels data */
QMultiMap<QString, EPGEvent*>::iterator i = m_events.begin();
while ( i != m_events.end() )
{
epgEvent = i.value();
if ( channelsList.contains( epgEvent->channelName ) && !epgEvent->updated )
{
m_epgView->delEvent( epgEvent );
delete epgEvent;
i = m_events.erase( i );
}
else
{/* If it's known but not in current libvlc data, try to expire it */
if ( epgEvent->ends_before( timeReference ) )
{
m_epgView->delEvent( epgEvent );
delete epgEvent;
i = m_events.erase( i );
}
else
{
++i;
epgEvent->simultaneous = ( !epgEvent->current
&& epgEvent->plays_at( QDateTime::currentDateTime() ) );
epgEvent->item->setData( epgEvent ); /* update data */
}
} }
} }
// Update the global duration and start time. // Update the global duration and start time.
m_epgView->updateDuration(); m_epgView->updateDuration();
m_epgView->updateStartTime(); m_epgView->updateStartTime();
// Udate the channel list.
m_channelsWidget->update();
} }
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#define EPGWIDGET_H #define EPGWIDGET_H
#include "EPGView.hpp" #include "EPGView.hpp"
#include "EPGEvent.hpp" #include "EPGItem.hpp"
#include "EPGRuler.hpp" #include "EPGRuler.hpp"
#include "EPGChannels.hpp" #include "EPGChannels.hpp"
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
#include <vlc_epg.h> #include <vlc_epg.h>
#include <QWidget> #include <QWidget>
#include <QMultiMap>
class QDateTime; class QDateTime;
...@@ -42,7 +41,6 @@ class EPGWidget : public QWidget ...@@ -42,7 +41,6 @@ class EPGWidget : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit EPGWidget( QWidget* parent = 0 ); explicit EPGWidget( QWidget* parent = 0 );
~EPGWidget();
void reset(); void reset();
public slots: public slots:
...@@ -54,13 +52,11 @@ private: ...@@ -54,13 +52,11 @@ private:
EPGView* m_epgView; EPGView* m_epgView;
EPGChannels *m_channelsWidget; EPGChannels *m_channelsWidget;
QMultiMap<QString, EPGEvent*> m_events;
uint8_t i_event_source_type; uint8_t i_event_source_type;
bool b_input_type_known; bool b_input_type_known;
QDateTime timeReference;
signals: signals:
void itemSelectionChanged( EPGEvent * ); void itemSelectionChanged( EPGItem * );
}; };
#endif // EPGWIDGET_H #endif // EPGWIDGET_H
...@@ -72,7 +72,7 @@ EpgDialog::EpgDialog( intf_thread_t *_p_intf ): QVLCFrame( _p_intf ) ...@@ -72,7 +72,7 @@ EpgDialog::EpgDialog( intf_thread_t *_p_intf ): QVLCFrame( _p_intf )
layout->addWidget( epg, 10 ); layout->addWidget( epg, 10 );
layout->addWidget( descBox ); layout->addWidget( descBox );
CONNECT( epg, itemSelectionChanged( EPGEvent *), this, showEvent( EPGEvent *) ); CONNECT( epg, itemSelectionChanged( EPGItem *), this, showEvent( EPGItem *) );
CONNECT( THEMIM->getIM(), epgChanged(), this, updateInfos() ); CONNECT( THEMIM->getIM(), epgChanged(), this, updateInfos() );
CONNECT( THEMIM, inputChanged( input_thread_t * ), this, updateInfos() ); CONNECT( THEMIM, inputChanged( input_thread_t * ), this, updateInfos() );
...@@ -103,26 +103,17 @@ EpgDialog::~EpgDialog() ...@@ -103,26 +103,17 @@ EpgDialog::~EpgDialog()
writeSettings( "EPGDialog" ); writeSettings( "EPGDialog" );
} }
void EpgDialog::showEvent( EPGEvent *event ) void EpgDialog::showEvent( EPGItem *epgItem )
{ {
if( !event ) return; if( !epgItem ) return;
QString titleDescription, textDescription; QDateTime end = epgItem->start().addSecs( epgItem->duration() );
if( event->description.isEmpty() ) title->setText( QString("%1 - %2 : %3")
textDescription = event->shortDescription; .arg( epgItem->start().toString( "hh:mm" ) )
else .arg( end.toString( "hh:mm" ) )
{ .arg( epgItem->name() )
textDescription = event->description; );
if( !event->shortDescription.isEmpty() ) description->setText( epgItem->description() );
titleDescription = " - " + event->shortDescription;
}
QDateTime end = event->start.addSecs( event->duration );
title->setText( event->start.toString( "hh:mm" ) + " - "
+ end.toString( "hh:mm" ) + " : "
+ event->name + titleDescription );
description->setText( textDescription );
} }
void EpgDialog::updateInfos() void EpgDialog::updateInfos()
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
class QLabel; class QLabel;
class QTextEdit; class QTextEdit;
class QTimer; class QTimer;
class EPGEvent; class EPGItem;
class EPGWidget; class EPGWidget;
class EpgDialog : public QVLCFrame, public Singleton<EpgDialog> class EpgDialog : public QVLCFrame, public Singleton<EpgDialog>
...@@ -48,7 +48,7 @@ private: ...@@ -48,7 +48,7 @@ private:
friend class Singleton<EpgDialog>; friend class Singleton<EpgDialog>;
private slots: private slots:
void showEvent( EPGEvent * ); void showEvent( EPGItem * );
void updateInfos(); void updateInfos();
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment