You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kaffeine/kaffeine/src/input/dvb/dvbpanel.cpp

2703 lines
68 KiB

/*
* dvbpanel.cpp
*
* Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr>
*
* 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 <sys/statvfs.h>
#include <tqlayout.h>
#include <tqfile.h>
#include <tqdir.h>
#include <tqstringlist.h>
#include <tqlabel.h>
#include <tqpixmap.h>
#include <tqtooltip.h>
#include <tqwhatsthis.h>
#include <tqapplication.h>
#include <tqpopupmenu.h>
#include <tqmap.h>
#include <kiconloader.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <kstandarddirs.h>
#include <kinputdialog.h>
#include <kicondialog.h>
#include <tdeaction.h>
#include <kprocess.h>
#include <tdefiledialog.h>
#include <ktrader.h>
#include <kxmlguifactory.h>
#include <tdeparts/componentfactory.h>
#include "kaffeinedvbplugin.h"
#include "dvbpanel.h"
#include "channeldesc.h"
#include "dvbstream.h"
#include "kevents.h"
#include "broadcasteditor.h"
#include "channeleditor.h"
#define CHANICONSIZE 28
#define MODE_FREE 0
#define MODE_LIVE 100
#define MODE_BROADCAST 200
#define MODE_RECORD 300
#define MODE_CANTDO 400
DIconViewItem::DIconViewItem( DvbPanel *pan, TQIconView *parent, const TQString &text, const TQPixmap &icon )
: TDEIconViewItem( parent, text, icon )
{
panel = pan;
}
void DIconViewItem::dropped( TQDropEvent *e, const TQValueList<TQIconDragItem> & )
{
TQString s;
if ( !dropEnabled() )
return;
if ( TQTextDrag::decode( e, s ) )
panel->moveChannel( text(), s );
}
DListView::DListView( TQWidget *parent ) : TDEListView( parent )
{
visibleItems = 0;
}
TQDragObject* DListView::dragObject()
{
if ( currentItem() )
return new TQTextDrag( currentItem()->text(1), this );
else
return 0;
}
DvbPanel::DvbPanel( TQWidget *parent, TQObject *objParent, const char *name ) : KaffeineInput(objParent,name)
{
browseDvbStream = -1;
plug = NULL;
isTuning = false;
timeShiftFileName = "";
timersDialog = 0;
currentCategory = "All";
channels.setAutoDelete( true );
timers.setAutoDelete( true );
dvb.setAutoDelete( true );
mainWidget = new TQVBox( parent );
mainWidget->setSizePolicy( TQSizePolicy (TQSizePolicy::Preferred, TQSizePolicy::Preferred) );
split = new TQSplitter( mainWidget );
split->setOpaqueResize( true );
pbox = new TQVBox( split );
iconView = new TDEIconView( pbox );
iconView->setVScrollBarMode( TQScrollView::AlwaysOff );
iconView->setHScrollBarMode( TQScrollView::AlwaysOff );
iconView->horizontalScrollBar()->setFixedHeight( 0 );
connect( iconView, TQT_SIGNAL(rightButtonPressed(TQIconViewItem*,const TQPoint&)), this, TQT_SLOT(catContextMenu(TQIconViewItem*,const TQPoint&)) );
connect( iconView, TQT_SIGNAL(clicked(TQIconViewItem*)), this, TQT_SLOT(catSelected(TQIconViewItem*)) );
iconView->setArrangement(TQIconView::TopToBottom);
iconView->setMargin(0);
iconView->setSpacing(0);
iconView->setItemsMovable(false);
iconView->setResizeMode(TQIconView::Adjust);
iconView->setSizePolicy( TQSizePolicy( TQSizePolicy::Preferred, TQSizePolicy::Minimum ) );
playerBox = new TQVBox( pbox );
playerBox->setMinimumWidth( 200 );
panel = new TQFrame( split );
panel->setLineWidth(1);
panel->setFrameStyle(TQFrame::Panel|TQFrame::Sunken);
split->moveToFirst( panel );
split->setResizeMode( panel, TQSplitter::KeepSize );
TQVBoxLayout *vb = new TQVBoxLayout( panel, 3, 3 );
channelsBtn = new TQToolButton( panel );
channelsBtn->setAutoRaise( true );
TQToolTip::add( channelsBtn, i18n("Channels"));
dateBtn = new TQToolButton( panel );
dateBtn->setAutoRaise( true );
TQToolTip::add( dateBtn, i18n("Timers"));
infoBtn = new TQToolButton( panel );
infoBtn->setAutoRaise( true );
TQToolTip::add( infoBtn, i18n("Electronic Program Guide"));
osdBtn = new TQToolButton( panel );
osdBtn->setAutoRaise( true );
TQToolTip::add( osdBtn, i18n("OSD"));
configBtn = new TQToolButton( panel );
configBtn->setAutoRaise( true );
TQToolTip::add( configBtn, i18n("DVB settings"));
recallBtn = new TQToolButton( panel );
recallBtn->setAutoRaise( true );
TQToolTip::add( recallBtn, i18n("Recall"));
TQHBoxLayout *h1 = new TQHBoxLayout();
h1->addItem( new TQSpacerItem( 1, 1, TQSizePolicy::Preferred, TQSizePolicy::Minimum ) );
h1->addWidget( channelsBtn );
h1->addWidget( dateBtn );
h1->addWidget( infoBtn );
h1->addWidget( osdBtn );
h1->addWidget( configBtn );
h1->addWidget( recallBtn );
h1->addItem( new TQSpacerItem( 1, 1, TQSizePolicy::Preferred, TQSizePolicy::Minimum ) );
vb->addLayout( h1 );
h1 = new TQHBoxLayout();
searchBtn = new TQToolButton( panel );
searchBtn->setAutoRaise( true );
TQToolTip::add( searchBtn, i18n("Search channel(s)"));
TQLabel* filterLabel = new TQLabel( i18n("Filter") + ":", panel );
searchLE = new KLineEdit( panel );
searchLE->setFocusPolicy( TQWidget::ClickFocus );
h1->addWidget( searchBtn );
h1->addWidget( filterLabel );
h1->addWidget( searchLE );
vb->addLayout( h1 );
channelsCb = new DListView( panel );
channelsCb->setHScrollBarMode( TQListView::AlwaysOff );
//channelsCb->setPaletteBackgroundColor( TQColor(255,255,200) );
connect( channelsCb, TQT_SIGNAL(itemRenamed(TQListViewItem*)), this, TQT_SLOT(channelNumberChanged(TQListViewItem*)) );
connect( channelsCb, TQT_SIGNAL(doubleClicked(TQListViewItem*)), this, TQT_SLOT(channelSelected(TQListViewItem*)) );
connect( channelsCb, TQT_SIGNAL(clicked(TQListViewItem*)), this, TQT_SLOT(channelClicked(TQListViewItem*)) );
connect( channelsCb, TQT_SIGNAL(contextMenuRequested(TQListViewItem*,const TQPoint&,int)), this, TQT_SLOT(channelPopup(TQListViewItem*,const TQPoint&,int)) );
channelsCb->setItemsRenameable( true );
channelsCb->addColumn( i18n("Number") );
channelsCb->addColumn( i18n("Name") );
channelsCb->addColumn( i18n("Source") );
channelsCb->setAllColumnsShowFocus( true );
channelsCb->setSizePolicy( TQSizePolicy (TQSizePolicy::Preferred, TQSizePolicy::MinimumExpanding) );
//channelsCb->setEnabled( false );
vb->addWidget( channelsCb );
h1 = new TQHBoxLayout();
recordBtn = new TQToolButton( panel );
TQToolTip::add( recordBtn, i18n("Instant Record") );
recordBtn->setToggleButton( true );
h1->addWidget( recordBtn );
broadcastBtn = new TQToolButton( panel );
TQToolTip::add( broadcastBtn, i18n("Broadcast") );
h1->addWidget( broadcastBtn );
vb->addLayout( h1 );
h1 = new TQHBoxLayout();
h1->addItem( new TQSpacerItem( 1, 1, TQSizePolicy::Preferred, TQSizePolicy::Minimum ) );
shiftLed = new KLed( panel );
shiftLed->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) );
shiftLed->setDarkFactor( 500 );
shiftLed->off();
TQToolTip::add( shiftLed, i18n("Time shifting") );
h1->addWidget( shiftLed );
h1->addItem( new TQSpacerItem( 1, 1, TQSizePolicy::Preferred, TQSizePolicy::Minimum ) );
recordLed = new KLed( panel );
recordLed->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) );
recordLed->setColor( TQColor( 255,0,0 ) );
recordLed->setDarkFactor( 500 );
recordLed->off();
TQToolTip::add( recordLed, i18n("Recording") );
h1->addWidget( recordLed );
h1->addItem( new TQSpacerItem( 1, 1, TQSizePolicy::Preferred, TQSizePolicy::Minimum ) );
broadcastLed = new KLed( panel );
broadcastLed->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) );
broadcastLed->setColor( TQColor( 255,128,0 ) );
broadcastLed->setDarkFactor( 500 );
broadcastLed->off();
TQToolTip::add( broadcastLed, i18n("Broadcasting") );
h1->addWidget( broadcastLed );
h1->addItem( new TQSpacerItem( 1, 1, TQSizePolicy::Preferred, TQSizePolicy::Minimum ) );
vb->addLayout( h1 );
TDEIconLoader *icon = new TDEIconLoader();
tvPix = icon->loadIcon( "kdvbtv", TDEIcon::Small );
tvcPix = icon->loadIcon( "kdvbtvc", TDEIcon::Small );
raPix = icon->loadIcon( "kdvbra", TDEIcon::Small );
racPix = icon->loadIcon( "kdvbrac", TDEIcon::Small );
TQIconSet iconset;
iconset.setPixmap( icon->loadIcon( "document-save", TDEIcon::Small ), TQIconSet::Small );
iconset.setPixmap( icon->loadIcon( "player_record", TDEIcon::Small), TQIconSet::Small, TQIconSet::Normal, TQIconSet::On );
recordBtn->setIconSet( iconset );
broadcastBtn->setIconSet( icon->loadIconSet("network_local", TDEIcon::Small) );
dateBtn->setIconSet( icon->loadIconSet("date", TDEIcon::Small) );
infoBtn->setIconSet( icon->loadIconSet("view_text", TDEIcon::Small) );
osdBtn->setIconSet( icon->loadIconSet("application-vnd.tde.info", TDEIcon::Small) );
channelsBtn->setIconSet( icon->loadIconSet("kdvbtv", TDEIcon::Small) );
configBtn->setIconSet( icon->loadIconSet("configure", TDEIcon::Small) );
recallBtn->setIconSet( icon->loadIconSet("reload", TDEIcon::Small) );
searchBtn->setIconSet( icon->loadIconSet("locationbar_erase", TDEIcon::Small) );
setXMLFile("kaffeinedvb.rc");
setupActions();
connect( this, TQT_SIGNAL(zap(ChannelDesc*)), TQT_SLOT(dvbZap(ChannelDesc*)) );
connect( configBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(showConfigDialog()));
connect( recallBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(recallZap()));
connect( recordBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(setRecord()) );
connect( broadcastBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(setBroadcast()) );
connect( infoBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(showEvents()) );
connect( channelsBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(scanner()) );
connect( dateBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(showTimers()) );
connect( osdBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(dvbOSD()));
connect( searchBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(resetSearch()) );
connect(searchLE, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(searchChannel(const TQString&)));
connect( &timersTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(checkTimers()) );
connect( &osdTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(resetOSD()) );
connect( &showOsdTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(dvbOSD()) );
connect( &tuningTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(setTuning()) );
connect( &stopTuningTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(setTuning()) );
connect( &diskTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(diskStatus()) );
setConfig();
updown = 1;
autocount = 0;
delete icon;
events.loadEpg();
}
void DvbPanel::togglePanel()
{
if ( panel->isHidden() )
panel->show();
else
panel->hide();
}
void DvbPanel::diskStatus()
{
double freemb;
struct statvfs buf;
if ( statvfs( dvbConfig->shiftDir.local8Bit(), &buf ) ) {
fprintf(stderr,"Couldn't get file system statistics\n");
return;
}
freemb = (double)(((double)(buf.f_bavail)*(double)(buf.f_bsize))/(1024.0*1024.0));
if ( freemb<300 )
emit showOSD( i18n("Warning: low disc space")+TQString(" (%1").arg((int)freemb)+i18n("MB")+")", 5000, 3 );
}
void DvbPanel::channelPopup( TQListViewItem *it, const TQPoint &pos, int col )
{
TQPoint p=pos;
if ( !it )
return;
int i=col, j;
TQImage img;
TQPixmap pix;
TQString name = it->text(1);
TQString s;
TQPopupMenu *pop = new TQPopupMenu();
pop->insertItem( i18n("Select icon..."), 1 );
pop->insertItem( i18n("Edit..."), 2 );
i = 0;
i = pop->exec( TQCursor::pos() );
switch ( i ) {
case 0 :
break;
case 1 :
s = KFileDialog::getOpenFileName( TQString(), "image/png image/jpeg image/gif image/x-bmp image/x-xpm", 0, i18n("Choose channel icon"));
if ( s.isEmpty() )
break;
img = TQImage( s );
if ( img.isNull() )
break;
if ( img.width()>img.height() )
img = img.smoothScale( CHANICONSIZE, img.height()*CHANICONSIZE/img.width() );
else
img = img.smoothScale( img.width()*CHANICONSIZE/img.height(), CHANICONSIZE );
pix.convertFromImage( img );
for ( j=0; j<(int)channels.count(); j++ ) {
if ( channels.at(j)->name==name ) {
channels.at(j)->pix = pix;
break;
}
}
pix.save( dvbConfig->dvbConfigIconsDir+name, "PNG" );
fillChannelList();
break;
case 2:
editChannel( name );
break;
}
delete pop;
}
bool DvbPanel::editChannel( TQString &name )
{
int j;
ChannelDesc *chan=0;
TQStringList list;
TQPixmap pix;
for ( j=0; j<(int)channels.count(); j++ ) {
chan = channels.at(j);
if ( chan->name==name ) {
j = -1;
list.append( chan->tp.source );
break;
}
}
if ( j==-1 ) {
ChannelEditor dlg( list, false, chan, &channels, mainWidget );
int ret = dlg.exec();
if ( ret==ChannelEditor::Accepted ) {
pix.load( dvbConfig->dvbConfigIconsDir+chan->name );
if ( !pix.isNull() )
chan->pix = pix;
else {
if ( chan->type==1 ) {
if ( chan->fta )
pix = tvcPix;
else
pix = tvPix;
}
else {
if ( chan->fta )
pix = racPix;
else
pix = raPix;
}
}
fillChannelList( chan );
return true;
}
}
return false;
}
void DvbPanel::getTargets( TQStringList &uiNames, TQStringList &iconNames, TQStringList &targetNames )
{
uiNames.append( i18n("Digital TV") );
iconNames.append( "tv" );
targetNames.append( "DVB" );
}
bool DvbPanel::execTarget( const TQString &target )
{
if ( target=="DVB" ) {
if ( !channelsCb->isEnabled() ) {
KMessageBox::information( mainWidget, i18n("Live digital TV only works with the xine engine.") );
return true;
}
emit showMe( this );
TQTimer::singleShot( 100, this, TQT_SLOT(playLastChannel()) );
return true;
}
return false;
}
void DvbPanel::setupActions()
{
new TDEAction(i18n("OSD Next Channel"), "go-next", CTRL+SHIFT+Key_W, this, TQT_SLOT(dvbOSDNext()), actionCollection(), "dvb_browse_next");
new TDEAction(i18n("OSD Previous Channel"), "go-previous", CTRL+SHIFT+Key_Q, this, TQT_SLOT(dvbOSDPrev()), actionCollection(),"dvb_browse_prev");
new TDEAction(i18n("OSD Zap"), "ok", CTRL+SHIFT+Key_E, this, TQT_SLOT(dvbOSDZap()), actionCollection(), "dvb_browse_zap");
new TDEAction(i18n("OSD Next Event"), "go-down", CTRL+SHIFT+Key_S, this, TQT_SLOT(dvbOSDAdvance()), actionCollection(), "dvb_browse_advance");
new TDEAction(i18n("OSD Previous Event"), "go-up", CTRL+SHIFT+Key_A, this, TQT_SLOT(dvbOSDRetreat()), actionCollection(), "dvb_browse_retreat");
new TDEAction(i18n("Instant Record"), "document-save", 0, this, TQT_SLOT(setRecord()), actionCollection(), "dvb_instant_record");
new TDEAction(i18n("Recall"), "reload", CTRL+SHIFT+Key_Z, this, TQT_SLOT(recallZap()), actionCollection(), "dvb_recall");
new TDEAction(i18n("Show OSD"), "application-vnd.tde.info", Key_O, this, TQT_SLOT(dvbOSD()), actionCollection(), "dvb_show_osd");
new TDEAction(i18n("EPG..."), "view_text", Key_G, this, TQT_SLOT(showEvents()), actionCollection(), "dvb_show_epg");
new TDEAction(i18n("Timers..."), "date", Key_T, this, TQT_SLOT(showTimers()), actionCollection(), "dvb_show_timers");
new TDEAction(i18n("Broadcasting..."), "network_local", Key_B, this, TQT_SLOT(setBroadcast()), actionCollection(), "dvb_show_broadcast");
new TDEAction(i18n("Channels..."), "kdvbtv", Key_C, this, TQT_SLOT(scanner()), actionCollection(), "dvb_channels");
new TDEAction(i18n("Configure DVB..."), "configure", CTRL|Key_C, this, TQT_SLOT(showConfigDialog()), actionCollection(), "dvb_config");
}
TQWidget *DvbPanel::wantPlayerWindow()
{
return playerBox;
}
TQWidget *DvbPanel::inputMainWidget()
{
return mainWidget;
}
void DvbPanel::searchChannel( const TQString &text )
{
int i, c=-1;
TQListViewItemIterator it( channelsCb );
if ( !it.current() )
return;
for ( i=0; i<channelsCb->columns(); i++ ) {
if ( channelsCb->columnText(i)==i18n("Name") ) {
c = i;
break;
}
}
if ( c==-1 )
return;
channelsCb->visibleItems = 0;
while ( it.current() ) {
if ( text.isEmpty() || it.current()->text( c ).contains( text, false ) ) {
it.current()->setVisible(true);
++channelsCb->visibleItems;
}
else {
it.current()->setVisible(false);
}
++it;
}
}
void DvbPanel::resetSearch()
{
searchLE->clear();
searchChannel( "" );
}
void DvbPanel::channelNumberChanged( TQListViewItem *it )
{
int i, j;
bool ok;
unsigned int oldNum=0;
unsigned int num = it->text(0).toUInt( &ok, 10 );
for ( i=0; i<(int)channels.count(); i++ ) {
if ( channels.at(i)->name==it->text(1) ) {
oldNum = channels.at(i)->num;
break;
}
}
if ( num && oldNum ) {
for ( j=0; j<(int)channels.count(); j++ ) {
if ( channels.at(j)->num==num ) {
channels.at(j)->num = oldNum;
channels.at(i)->num = num;
break;
}
}
}
if ((int)num > maxChannelNumber)
maxChannelNumber = num;
if ((int)num < minChannelNumber)
minChannelNumber = num;
fillChannelList();
}
void DvbPanel::catSelected( TQIconViewItem *it )
{
if ( !it ) return;
if ( it->text()==i18n("All") )
currentCategory = "All";
else if ( it->text()==i18n("TV") )
currentCategory = "TV";
else if ( it->text()==i18n("Radio") )
currentCategory = "Radio";
else
currentCategory = it->text();
fillChannelList();
}
void DvbPanel::catContextMenu( TQIconViewItem *it, const TQPoint &p )
{
bool ok;
TQString name, icon;
int i=0, ret;
TQPopupMenu *pop = new TQPopupMenu();
if ( !it ) {
pop->insertItem( i18n("New Category..."), 0 );
}
else {
pop->insertItem( i18n("Change Icon..."), 1 );
if ( it->text()!=i18n("All") && it->text()!=i18n("Radio") && it->text()!=i18n("TV") )
pop->insertItem( i18n("Delete Category..."), 2 );
}
i = pop->exec( p );
switch ( i ) {
case 0 :
name = KInputDialog::getText( i18n("New Category"), i18n("Enter a name for this category:"), TQString(), &ok);
for ( TQIconViewItem *qitem = iconView->firstItem(); qitem; qitem = qitem->nextItem() ) {
if ( qitem->text()==name )
ok = false;
}
if ( ok ) {
TDEIconViewItem* item = new DIconViewItem(this, iconView, name, TDEGlobal::iconLoader()->loadIcon("kaffeine", TDEIcon::NoGroup, TDEIcon::SizeSmallMedium));
item->setDropEnabled( true );
dvbConfig->addCategory( name, "kaffeine" );
}
break;
case 1 :
icon = TDEIconDialog::getIcon();
if ( !icon.isEmpty() ) {
it->setPixmap( TDEGlobal::iconLoader()->loadIcon(icon, TDEIcon::NoGroup, TDEIcon::SizeSmallMedium) );
dvbConfig->changeIconCategory( it->text(), icon );
}
break;
case 2 :
ret = KMessageBox::questionYesNo( mainWidget, i18n("Do you really want to delete this category?") );
if ( ret==KMessageBox::Yes ) {
dvbConfig->removeCategory( it->text() );
delete it;
currentCategory = "All";
fillChannelList();
}
break;
}
delete pop;
}
void DvbPanel::moveChannel( const TQString &cat, const TQString &name )
{
int i;
ChannelDesc *chan;
TQListViewItem *it;
for ( i=0; i<(int)channels.count(); i++ ) {
chan = channels.at(i);
if ( chan->name==name ) {
if ( cat==i18n("All") )
chan->category = "";
else
chan->category = cat;
it = channelsCb->currentItem();
if ( it && currentCategory!="All" && currentCategory!="TV" && currentCategory!="Radio" )
delete it;
break;
}
}
}
void DvbPanel::dumpEvents()
{
EventSource *esrc;
EventTsid *et;
EventSid *es;
TQPtrList<EventDesc> *esEvents;
EventDesc *desc;
int i, k, j, m, n;
TQString s;
TQFile f( TQDir::homeDirPath()+"/kaffeine_dvb_events.txt" );
if ( f.open(IO_WriteOnly|IO_Truncate) ) {
fprintf( stderr, "Creating events file.\n");
TQTextStream tt( &f );
tt << "Saved: "+TQDateTime::currentDateTime().toString( "dd-MM-yyyy hh:mm:ss" )+"\n";
k= 0;
for( i=0; i<events.getNSource(); i++ ) {
if ( !(esrc=events.getNEventSource( i )) )
continue;
tt << esrc->getSource()+TQString(" : %1 TS with events.\n").arg( esrc->getNTsid() );
for ( m=0; m<esrc->getNTsid(); m++ ) {
if ( !(et=esrc->getNEventTsid( m )) )
continue;
tt << TQString("TSID %1 : %2 services with events\n").arg( et->getTsid() ).arg( et->getNSid() );
for ( n=0; n<et->getNSid(); n++ ) {
if ( !(es=et->getNEventSid( n )) )
continue;
tt << TQString(" SID %1 : %2 events\n").arg( es->getSid() ).arg( es->getNDesc() );
k+= es->getNDesc();
}
}
}
tt << "Number of events : "+s.setNum( k )+"\n";
fprintf( stderr, "Number of events : %d\n", k );
tt << "-------------------------\n";
tt << "\n";
for( i=0; i<events.getNSource(); i++ ) {
if ( !(esrc=events.getNEventSource( i )) )
continue;
for ( m=0; m<esrc->getNTsid(); m++ ) {
if ( !(et=esrc->getNEventTsid( m )) )
continue;
for ( n=0; n<et->getNSid(); n++ ) {
if ( !(es=et->getNEventSid( n )) )
continue;
esEvents = es->getEvents();
es->lock();
for ( j=0; j<(int)esEvents->count(); j++ ) {
if ( !(desc=esEvents->at( j )) )
continue;
tt << "Source: "+desc->source+"\n";
tt << TQString("Network ID: %1\n").arg(desc->nid);
tt << TQString("Transport Stream ID: %1\n").arg(desc->tsid);
tt << TQString("Service ID: %1\n").arg(desc->sid);
tt << TQString("Event ID: %1\n").arg(desc->eid);
tt << "Title: "+desc->title+"\n";
tt << "Subtitle: "+desc->subtitle+"\n";
tt << desc->startDateTime.toString( "dd-MM-yyyy hh:mm:ss" )+"\n";
tt << desc->duration.toString( "hh:mm:ss" )+"\n";
s = "";
for ( k=0; k<(int)desc->shortEvents.count(); k++ ) {
s = s + desc->shortEvents.at(k)->name;
if (!desc->shortEvents.at(k)->name.isEmpty() && !desc->shortEvents.at(k)->text.isEmpty()) {
s = s + " : ";
s = s + desc->shortEvents.at(k)->text;
s = s+". ";
}
}
for ( k=0; k<(int)desc->extEvents.count(); k++ )
s = s+ *desc->extEvents.at(k);
tt << s+"\n";
tt << "\n";
}
es->unlock();
}
}
}
f.close();
}
else fprintf( stderr, "Can't create events file!\n");
}
void DvbPanel::channelClicked( TQListViewItem *it )
{
TQPtrListIterator<ChannelDesc> iter( channels );
ChannelDesc *itdesc, *desc=0;
DvbStream *d = 0;
if ( !it )
return;
iter.toFirst();
while ( (itdesc=iter.current())!=0 ) {
if ( itdesc->name==it->text(1) ) {
desc = itdesc;
break;
}
++iter;
}
if ( !desc )
return;
for (int j = 0; j < (int)dvb.count(); j ++) {
if (dvb.at(j)->canSource(desc)) {
d = dvb.at(j);
break;
}
}
osdMode = 0;
dvbOSD( *desc, d );
}
void DvbPanel::resetOSD()
{
osdMode = 0;
}
void DvbPanel::dvbOSD()
{
DvbStream *d = 0;
if (browseDvbStream != -1 && osdMode != 0) {
dvbOSDSkip(0);
return;
}
for (int i=0; i<(int)dvb.count(); i++ ) {
if ( dvb.at(i)->hasLive() ) {
d = dvb.at(i);
break;
}
}
if ( d )
dvbOSD( d->getLiveChannel(), d );
}
void DvbPanel::dvbOSDZap()
{
ChannelDesc *chan = 0;
if (browseDvbStream == -1)
return;
osdMode = 0;
for (int i=0; i<(int)channels.count(); i++) {
if ((int) channels.at(i)->num == browseDvbStream) {
chan = channels.at(i);
break;
}
}
if (!chan)
return;
dvbZap(chan);
}
void DvbPanel::dvbOSDNext()
{
browseDvbTimeShift = -1;
osdMode = 0;
dvbOSDSkip(1);
}
void DvbPanel::dvbOSDSkip(int skip, int timeShift /* = 0 */)
{
DvbStream *d = 0;
ChannelDesc *chan = 0;
int mychan = -1;
if (browseDvbStream == -1)
mychan = dvbConfig->lastChannel;
else
mychan = browseDvbStream + skip;
if (mychan < minChannelNumber)
mychan = maxChannelNumber;
else if (mychan > maxChannelNumber)
mychan = minChannelNumber;
for (int i = 0; i < (int)channels.count(); i ++) {
if ((int) channels.at(i)->num == mychan) {
chan = channels.at(i);
break;
}
}
if (!chan)
return;
for (int j = 0; j < (int)dvb.count(); j ++) {
if (dvb.at(j)->canSource(chan)) {
d = dvb.at(j);
break;
}
}
if (!d)
return;
browseDvbStream = chan->num;
dvbOSD(*chan, d, timeShift);
}
void DvbPanel::dvbOSDPrev()
{
browseDvbTimeShift = -1;
osdMode = 0;
dvbOSDSkip(-1);
}
void DvbPanel::dvbOSDHide()
{
browseDvbStream = -1;
browseDvbTimeShift = -1;
}
void DvbPanel::dvbOSDAdvance()
{
osdMode = 0;
dvbOSDSkip(0, 1);
}
void DvbPanel::dvbOSDRetreat()
{
osdMode = 0;
dvbOSDSkip(0, -1);
}
void DvbPanel::dvbOSD(ChannelDesc liveChannel, DvbStream *d, int timeShift /* = 0 */)
{
TQStringList list;
EventSource *esrc;
EventSid *es;
TQPtrList<EventDesc> *esEvents;
EventDesc *desc;
TQString s;
int i, j, k;
int first=0;
if ( !d || liveChannel.name.isEmpty() )
return;
if ( osdMode==2 ) {
osdTimer.stop();
osdMode = 0;
list.append( "STOP" );
emit showDvbOSD( s.setNum( liveChannel.num )+" - "+liveChannel.name, list );
return;
}
if ( osdMode==1 )
osdTimer.stop();
if ( osdMode==0 ) {
if ( d->liveIsRecording() )
list.append( "R" );
if ( d->timeShiftMode() )
list.append( "T" );
}
else
list.append( "E" );
int myshift = 0;
if (browseDvbTimeShift == -1)
myshift = 0;
else
myshift = browseDvbTimeShift + timeShift;
if (myshift < 0)
myshift = 0;
browseDvbTimeShift = myshift;
k = 0;
esrc = events.getEventSource( liveChannel.tp.source );
es = esrc->getEventSid( liveChannel.tp.nid, liveChannel.tp.tsid, liveChannel.sid );
if ( !es )
goto end;
es->lock();
esEvents = es->getEvents();
for ( j=myshift; j<(myshift+2); j++ ) {
desc = esEvents->at( j );
if ( !desc )
continue;
if ( !desc->title.isEmpty() ) {
s = desc->startDateTime.toString( "hh:mm" );
s = s+" - ";
s = s+desc->title;
if ( !osdMode && !first && !myshift ) {
TQDateTime dt = TQDateTime::currentDateTime();
int secs = desc->startDateTime.secsTo( dt );
i = TQTime().secsTo( desc->duration );
if ( i!=0 )
i = secs*100/i;
if ( i>100 )
i = 100;
list.append( TQString("BAR")+TQString().setNum( i ) );
++first;
}
list.append( s );
k++;
}
else if ( osdMode )
list.append( "" );
if ( osdMode==0 ) {
if ( k>1 )
break;
else
continue;
}
list.append( desc->subtitle );
s = "";
for ( i=0; i<(int)desc->shortEvents.count(); i++ ) {
s = s + desc->shortEvents.at(i)->name;
if (!desc->shortEvents.at(i)->name.isEmpty() && !desc->shortEvents.at(i)->text.isEmpty()) {
s+= " : ";
s+= desc->shortEvents.at(i)->text;
s+= ". ";
}
}
for ( i=0; i<(int)desc->extEvents.count(); i++ )
s+= *desc->extEvents.at(i);
list.append( s );
break;
}
es->unlock();
end:
if ( osdMode==0 )
osdTimer.start( 5000, true );
osdMode++;
emit showDvbOSD( s.setNum( liveChannel.num )+" - "+liveChannel.name, list );
}
void DvbPanel::enableLiveDvb( bool on )
{
channelsCb->setEnabled( on );
}
void DvbPanel::checkFirstRun()
{
if ( dvbConfig->firstRun() )
showConfigDialog();
}
void DvbPanel::setConfig()
{
int i;
int error = 0;
TDEIconViewItem* item = NULL;
DvbStream *d;
TQString s = locateLocal("appdata", "");
dvbConfig = new DVBconfig( s );
item = new DIconViewItem(this, iconView, i18n("All"), TDEGlobal::iconLoader()->loadIcon(dvbConfig->allIcon, TDEIcon::NoGroup, TDEIcon::SizeSmallMedium));
iconView->setFixedHeight( item->height()+iconView->horizontalScrollBar()->height() );
item->setDropEnabled( true );
item = new DIconViewItem(this, iconView, i18n("Radio"), TDEGlobal::iconLoader()->loadIcon(dvbConfig->radioIcon, TDEIcon::NoGroup, TDEIcon::SizeSmallMedium));
item->setDropEnabled( false );
item = new DIconViewItem(this, iconView, i18n("TV"), TDEGlobal::iconLoader()->loadIcon(dvbConfig->tvIcon, TDEIcon::NoGroup, TDEIcon::SizeSmallMedium));
item->setDropEnabled( false );
TDETrader::OfferList offers = TDETrader::self()->query("KaffeineDvbPlugin");
TDETrader::OfferList::Iterator it = offers.begin();
if ( it!=offers.end() ) {
KService::Ptr ptr = (*it);
plugName = ptr->desktopEntryName();
plug = KParts::ComponentFactory::createPartInstanceFromService<KaffeineDvbPlugin>(ptr, 0, ptr->name().ascii(), 0, 0, 0, &error);
if (error > 0) {
fprintf( stderr, "Loading of DVB plugin failed: %s\n", KLibLoader::self()->lastErrorMessage().ascii() );
plug = NULL;
}
else {
fprintf( stderr, "DVB plugin loaded\n.");
}
}
for ( i=0; i<(int)dvbConfig->categories.count(); i++ ) {
item = new DIconViewItem(this, iconView, dvbConfig->categories.at(i)->name, TDEGlobal::iconLoader()->loadIcon(dvbConfig->categories.at(i)->icon, TDEIcon::NoGroup, TDEIcon::SizeSmallMedium));
item->setDropEnabled( true );
}
for ( i=0; i<(int)dvbConfig->devList.count(); i++ ) {
d = new DvbStream( dvbConfig->devList.at(i), dvbConfig->defaultCharset, &events );
d->setPlug( plug );
dvb.append( d );
connect( d, TQT_SIGNAL(shifting(bool)), this, TQT_SLOT(setShiftLed(bool)) );
connect( d, TQT_SIGNAL(isBroadcasting(bool)), this, TQT_SLOT(setBroadcastLed(bool)) );
connect( d, TQT_SIGNAL(timerEnded(RecTimer*)), this, TQT_SLOT(killTimer(RecTimer*)) );
connect( d, TQT_SIGNAL(isRecording(bool)), this, TQT_SLOT(setRecordLed(bool)) );
connect( d, TQT_SIGNAL(playDvb()), this, TQT_SLOT(pipeOpened()) );
}
fifoName = TDEGlobal::dirs()->saveLocation("tmp")+".kaxtv.ts";
TQFile f( fifoName );
if ( f.exists() )
f.remove();
if ( (mkfifo( fifoName.ascii(), 0644 ))<0 ) {
perror( fifoName.latin1() );
fifoName = "";
}
fifoName1 = TDEGlobal::dirs()->saveLocation("tmp")+".kaxtv1.ts";
TQFile f1( fifoName1 );
if ( f1.exists() )
f1.remove();
if ( (mkfifo( fifoName1.ascii(), 0644 ))<0 ) {
perror( fifoName1.latin1() );
fifoName1 = "";
}
currentFifo = fifoName;
getTimerList();
timersTimer.start( 5000 );
getChannelList();
rtp = new Ts2Rtp();
rtp->setSocket( dvbConfig->broadcastAddress, dvbConfig->broadcastPort, dvbConfig->senderPort );
cleaner = new Cleaner( dvbConfig->shiftDir, dvbConfig->recordDir );
split->setSizes( dvbConfig->splitSizes );
recallChannel = dvbConfig->lastChannel;
}
void DvbPanel::showConfigDialog()
{
int i, ret;
loop:
if ( !dvbConfig->haveData() ) {
ret = KMessageBox::questionYesNo( mainWidget, i18n("<qt>Can't get DVB data from http://hftom.free.fr/kaxtv/dvbdata.tar.gz!<br>\
Check your internet connection, and say Yes to try again.<br>\
Or say No to cancel.<br>\
If you already have this archive, copy it to ~/.trinity/share/apps/kaffeine/dvbdata.tar.gz and say Yes.<br><br>Should I try again?</qt>") );
if ( ret==KMessageBox::Yes )
goto loop;
return;
}
for ( i=0; i<(int)dvb.count(); i++ )
dvb.at(i)->probeCam();
DvbConfigDialog dlg( this, dvbConfig, mainWidget, plug );
connect( dlg.dumpBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(dumpEvents()) );
ret = dlg.exec();
disconnect( dlg.dumpBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(dumpEvents()) );
if ( ret==DvbConfigDialog::Rejected )
return;
rtp->setSocket( dvbConfig->broadcastAddress, dvbConfig->broadcastPort, dvbConfig->senderPort );
cleaner->setPaths( dvbConfig->shiftDir, dvbConfig->recordDir );
fillChannelList();
}
void DvbPanel::camClicked( int devNum )
{
dvb.at(devNum)->showCamDialog();
}
TQPtrList<Transponder> DvbPanel::getSourcesStatus()
{
int i, j;
TQStringList list;
TQPtrList<Transponder> ss;
Transponder t;
for ( i=0; i<(int)dvb.count(); i++ ) {
if ( !dvb.at(i)->getPriority() ) // priority==0==don't use
continue;
list = dvb.at(i)->getSources();
for ( j=0; j<(int)list.count(); j++ ) {
if ( dvb.at(i)->hasRec() || dvb.at(i)->hasBroadcast() )
t = dvb.at(i)->getCurrentTransponder();
else {
t = Transponder();
t.source = list[j];
}
ss.append( new Transponder( t ) );
}
}
return ss;
}
void DvbPanel::fillChannelList( ChannelDesc *ch )
{
int i, j;
ChannelDesc *chan;
TDEListViewItem *it, *visible=0;
bool cont=false;
TQPtrList<Transponder> trans = getSourcesStatus();
trans.setAutoDelete( true );
searchLE->clear();
channelsCb->clear();
for ( i=0; i<(int)channels.count(); i++ ) {
chan = channels.at(i);
for ( j=0; j<(int)trans.count(); j++ ) {
cont = false;
if ( trans.at(j)->source==chan->tp.source ) {
if ( trans.at(j)->freq ) {
if ( chan->tp==*trans.at(j) ) break;
}
else
break;
}
cont = true;
}
if ( cont )
continue;
if ( currentCategory=="TV" ) {
if ( chan->type!=1 )
continue;
}
else if ( currentCategory=="Radio" ) {
if ( chan->type!=2 )
continue;
}
else if ( currentCategory!="All" && chan->category!=currentCategory )
continue;
it = new TDEListViewItem( channelsCb, TQString().sprintf("%05d", chan->num), chan->name, chan->tp.source );
if ( ch && ch==chan )
visible = it;
it->setDragEnabled( true );
chan->pix.load( dvbConfig->dvbConfigIconsDir+chan->name );
if ( !chan->pix.isNull() )
it->setPixmap( 1, chan->pix );
else {
if ( chan->type==1 ) {
if ( chan->fta )
it->setPixmap( 1, tvcPix );
else
it->setPixmap( 1, tvPix );
}
else {
if ( chan->fta )
it->setPixmap( 1, racPix );
else
it->setPixmap( 1, raPix );
}
}
}
channelsCb->visibleItems = channelsCb->childCount();
trans.clear();
if ( visible ) {
channelsCb->ensureItemVisible( visible );
channelsCb->setSelected( visible, true );
}
}
DvbStream* DvbPanel::getWorkingDvb( int mode, ChannelDesc *chan )
{
int i, ret;
TQValueList<int> working; // free=0, hasLive=100, hasBroadcast=200, hasRec=300, can'tDoChannel=400
for ( i=0; i<(int)dvb.count(); i++ )
working.append( 100-dvb.at(i)->getPriority() );
// fill in working status
for ( i=0; i<(int)dvb.count(); i++ ) {
if ( !dvb.at(i)->canSource( chan ) || working[i]==100 ) {
working[i] = MODE_CANTDO;
continue;
}
if ( dvb.at(i)->isTuned() ) {
if ( dvb.at(i)->getCurrentTransponder()==chan->tp ) {
return dvb.at(i); // use that one since it's already tuned on the good mplex
}
else if ( dvb.at(i)->hasRec() )
working[i] += MODE_RECORD;
else if ( dvb.at(i)->hasBroadcast() )
working[i] += MODE_BROADCAST;
else {
if ( mode==MODE_LIVE )
working[i] += MODE_FREE;
else
working[i] += MODE_LIVE;
}
}
else
working[i] += MODE_FREE;
}
ret = 0;
// search for least working card
for ( i=1; i<(int)working.count(); i++ ) {
if ( working[i]<working[0] ) {
working[0] = working[i];
ret = i;
}
}
if ( working[0]<mode )
return dvb.at(ret);
else
return 0;
}
void DvbPanel::setBroadcast()
{
int ret, i;
TQPtrList<ChannelDesc> list;
bool live=false;
DvbStream *d;
BroadcastEditor dlg( mainWidget, &channels, &list );
ret = dlg.exec();
if ( ret==BroadcastEditor::Rejected )
return;
for ( i=0; i<(int)dvb.count(); i++ ) {
if ( dvb.at(i)->hasBroadcast() )
dvb.at(i)->stopBroadcast();
}
if ( ! list.count() ) {
return;
}
d = getWorkingDvb( MODE_BROADCAST, list.at(0) );
if ( d )
ret = d->canStartBroadcast( live, list.at(0) );
else
ret = -1;
if ( ret==0 ) {
if ( live ) {
stopLive();
emit dvbStop();
}
if ( !d->startBroadcast( &list, rtp ) ) {
KMessageBox::information( mainWidget, i18n("Broadcasting failed.") );
}
}
else
KMessageBox::information( mainWidget, i18n("Can't start broadcasting.") );
}
void DvbPanel::checkTimers()
{
int i, j, ret;
bool live=false;
RecTimer *t;
ChannelDesc *chan;
TQDateTime cur=TQDateTime::currentDateTime();
DvbStream *d;
for ( i=0; i<(int)timers.count(); i++ ) {
t = timers.at(i);
if ( t->running )
continue;
if ( t->begin<=cur && cur<t->begin.addSecs(TQTime().secsTo(t->duration)) ) {
chan = 0;
for ( j=0; j<(int)channels.count(); j++ ) {
if ( channels.at(j)->name==t->channel ) {
chan = channels.at(j);
break;
}
}
if ( !chan )
continue;
d = getWorkingDvb( MODE_RECORD, chan );
live = false;
if ( d )
ret = d->canStartTimer( live, chan );
else
ret = -1;
if ( ret==0 ) {
if ( live ) {
stopLive();
emit dvbStop();
}
if ( d->startTimer( chan, dvbConfig->recordDir, dvbConfig->sizeFile, t, dvbConfig->filenameFormat ) ) {
TDEProcess proc;
proc << TQDir::homeDirPath()+"/bin/kaffeine_recording";
proc << "On";
proc.start( TDEProcess::DontCare );
t->running = 1;
if ( timersDialog )
emit timersChanged();
saveTimerList();
i--;
}
else
fprintf( stderr, "start timer failed!!!\n" );
}
else
fprintf( stderr, "Cant start timer !!!\n" );
}
else if ( t->mode ) {
if (t->begin.addSecs(t->duration.hour()*3600+t->duration.minute()*60+60)<cur) {
updateModeTimer( t );
if ( timersDialog )
emit timersChanged();
}
}
}
}
void DvbPanel::setRecord()
{
ChannelDesc curchan;
TQString s="";
int ret, i, r=0;
bool live=false;
RecTimer *t, *rt;
EventDesc *desc;
DvbStream *d=0;
for ( i=0; i<(int)dvb.count(); i++ ) {
if ( dvb.at(i)->hasLive() ) {
d = dvb.at(i);
curchan = d->getLiveChannel();
break;
}
}
if ( !d ) {
recordBtn->setOn( false );
showTimers();
return;
}
desc = events.getEventDesc( curchan.tp.source, curchan.tp.nid, curchan.tp.tsid, curchan.sid, 0 );
if ( desc )
s = desc->title;
if ( s.isEmpty() ) {
if ( !dvbConfig->filenameFormat.contains("%chan") )
s = curchan.name;
if ( !dvbConfig->filenameFormat.contains("%date") )
s+="_"+TQDateTime::currentDateTime().toString( "yyyyMMdd-hhmmss" );
}
rt = new RecTimer();
rt->name = s;
rt->channel = curchan.name;
rt->begin = TQDateTime::currentDateTime();
rt->duration = TQTime( 0,0,0).addSecs( dvbConfig->instantDuration*60 ) ;
rt->running = 1;
rt->mode = 0;
ret = d->canStartTimer( live, &curchan );
if ( ret==0 ) {
if ( d->startTimer( &curchan, dvbConfig->recordDir, dvbConfig->sizeFile, rt, dvbConfig->filenameFormat ) ) {
TDEProcess proc;
proc << TQDir::homeDirPath()+"/bin/kaffeine_recording";
proc << "On";
proc.start( TDEProcess::DontCare );
for ( i=0; i<(int)timers.count(); i++ ) {
t = timers.at(i);
if ( rt->begin>t->begin )
r=i+1;
}
timers.insert( r, rt );
if ( timersDialog )
emit timersChanged();
saveTimerList();
emit showOSD( i18n("Instant Record successfully started"), 5000, 3 );
}
else {
KMessageBox::information( mainWidget, i18n("Instant Recording failed to start.") );
fprintf( stderr, "DvbPanel::setRecord:start timer failed!\n" );
delete rt;
}
}
else {
delete rt;
for ( i=0; i<(int)timers.count(); i++ ) {
t = timers.at(i);
if ( d->liveIsRecording() && t->running && curchan.name == t->channel ) {
d->updateTimer( t, 0 );
emit showOSD( i18n("Recording successfully stopped"), 5000, 3 );
return;
}
}
showTimers();
}
}
void DvbPanel::setRecordLed( bool on )
{
int i;
bool rec=false;
if ( on ) {
recordLed->on();
fillChannelList();
}
else {
for ( i=0; i<(int)dvb.count(); i++ ) {
if ( dvb.at(i)->hasRec() ) {
rec = true;
break;
}
}
if ( !rec )
recordLed->off();
else
recordLed->on();
fillChannelList();
}
for ( i=0; i<(int)dvb.count(); i++ ) {
if ( dvb.at(i)->liveIsRecording() ) {
recordBtn->setOn( true );
return;
}
}
recordBtn->setOn( false );
}
void DvbPanel::setBroadcastLed( bool on )
{
int i;
bool broad=false;
if ( on ) {
broadcastLed->on();
fillChannelList();
}
else {
for ( i=0; i<(int)dvb.count(); i++ ) {
if ( dvb.at(i)->hasBroadcast() ) {
broad = true;
break;
}
}
if ( !broad )
broadcastLed->off();
else
broadcastLed->on();
fillChannelList();
}
}
void DvbPanel::killTimer( RecTimer *t )
{
int i;
for ( i=0; i<(int)timers.count(); i++ ) {
if ( timers.at(i)==t ) {
TDEProcess proc;
proc << TQDir::homeDirPath()+"/bin/kaffeine_recording";
if ( recordLed->state()==KLed::On )
proc << "On";
else
proc << "Off";
proc << TDEProcess::quote( t->fullPath );
proc.start( TDEProcess::DontCare );
if ( t->mode )
updateModeTimer( t );
else
timers.remove( t );
if ( timersDialog )
emit timersChanged();
return;
}
}
}
void DvbPanel::updateModeTimer( RecTimer *t )
{
int stop=0, r=0, i;
if ( t->mode==CronTimer::Daily )
t->begin = t->begin.addDays(1);
else if ( t->mode==CronTimer::Weekly )
t->begin = t->begin.addDays(7);
else if ( t->mode==CronTimer::Monthly )
t->begin = t->begin.addMonths(1);
else while ( !stop ) {
t->begin = t->begin.addDays(1);
if ( (t->begin.date().dayOfWeek()==1) && (t->mode&CronTimer::Monday) ) stop++;
else if ( (t->begin.date().dayOfWeek()==2) && (t->mode&CronTimer::Tuesday) ) stop++;
else if ( (t->begin.date().dayOfWeek()==3) && (t->mode&CronTimer::Wednesday) ) stop++;
else if ( (t->begin.date().dayOfWeek()==4) && (t->mode&CronTimer::Thursday) ) stop++;
else if ( (t->begin.date().dayOfWeek()==5) && (t->mode&CronTimer::Friday) ) stop++;
else if ( (t->begin.date().dayOfWeek()==6) && (t->mode&CronTimer::Saturday) ) stop++;
else if ( (t->begin.date().dayOfWeek()==7) && (t->mode&CronTimer::Sunday) ) stop++;
}
RecTimer *nt = new RecTimer();
nt->name = t->name;
nt->channel = t->channel;
nt->begin = t->begin;
nt->duration = t->duration;
nt->running = 0;
nt->mode = t->mode;
timers.remove( t );
for ( i=0; i<(int)timers.count(); i++ ) {
t = timers.at(i);
if ( nt->begin>t->begin )
r=i+1;
}
timers.insert( r, nt );
}
void DvbPanel::showTimers()
{
int i;
TQStringList list;
TQMap<TQString,TQString> map;
if ( channels.count()==0 ) {
KMessageBox::sorry( 0, i18n("You may want to define some channel first!") );
return;
}
for ( TQPtrListIterator<ChannelDesc> it(channels); it.current(); ++it )
map[it.current()->name] = it.current()->name;
TQMap<TQString,TQString>::Iterator it;
TQMap<TQString,TQString>::Iterator end(map.end());
for ( it = map.begin(); it != end; ++it )
list.append( it.data() );
timersDialog = new KRecord( list, &timers, mainWidget, dvbConfig->timerSize );
for ( i=0; i<(int)dvb.count(); i++ ) {
connect( timersDialog, TQT_SIGNAL(updateTimer(RecTimer*,int)), dvb.at(i), TQT_SLOT(updateTimer(RecTimer*,int)) );
}
connect( this, TQT_SIGNAL(timersChanged()), timersDialog, TQT_SLOT(refresh()) );
timersDialog->exec();
for ( i=0; i<(int)dvb.count(); i++ ) {
disconnect( timersDialog, TQT_SIGNAL(updateTimer(RecTimer*,int)), dvb.at(i), TQT_SLOT(updateTimer(RecTimer*,int)) );
}
disconnect( this, TQT_SIGNAL(timersChanged()), timersDialog, TQT_SLOT(refresh()) );
dvbConfig->timerSize = timersDialog->size();
delete timersDialog;
timersDialog = 0;
saveTimerList();
}
int DvbPanel::getSNR( int device )
{
if ( device<0 || device>=(int)dvb.count() )
return -1;
return dvb.at(device)->getSNR();
}
void DvbPanel::dvbNewTimer( TQString name, TQString channel, TQString datetime, TQString duration )
{
newTimer( channel, name, TQDateTime::fromString( datetime, TQt::ISODate ), TQTime::fromString( duration ), false );
}
void DvbPanel::newTimer( TQString channel, TQString name, TQDateTime begin, TQTime duration, bool warn )
{
int i, r=0;
RecTimer *t;
RecTimer *rt = new RecTimer();
rt->name = name.replace("/","_").replace(">","_").replace("<","_").replace(":","_").replace('"',"_").replace("\\","_").replace("|","_");
rt->channel = channel;
rt->begin = begin.addSecs( -(dvbConfig->beginMargin*60) );
rt->duration = duration.addSecs( (dvbConfig->beginMargin+dvbConfig->endMargin)*60 ) ;
rt->running = 0;
rt->mode = 0;
for ( i=0; i<(int)timers.count(); i++ ) {
t = timers.at(i);
if ( rt->begin>t->begin )
r=i+1;
}
timers.insert( r, rt );
if ( warn )
KMessageBox::information( 0, i18n("Timer successfully created.") );
}
void DvbPanel::scanner()
{
int ret;
loop:
if ( !dvbConfig->haveData() ) {
ret = KMessageBox::questionYesNo( mainWidget, i18n("<qt>Can't get DVB data from http://hftom.free.fr/kaxtv/dvbdata.tar.gz!<br>\
Check your internet connection, and say Yes to try again.<br>\
Or say No to cancel.<br>\
If you already have this archive, copy it to ~/.trinity/share/apps/kaffeine/dvbdata.tar.gz and say Yes.<br><br>Should I try again?</qt>") );
if ( ret==KMessageBox::Yes )
goto loop;
return;
}
if ( !dvbConfig->haveData() )
return;
ScanDialog dlg( &dvb, &channels, dvbConfig->scanSize, dvbConfig->dvbConfigDir, dvbConfig->defaultCharset );
dlg.exec();
dvbConfig->scanSize = dlg.size();
fillChannelList();
saveChannelList();
}
void DvbPanel::showEvents()
{
events.doClean( false );
KEvents dlg( &channels, &dvb, &events, mainWidget, dvbConfig->epgSize );
connect( &dlg, TQT_SIGNAL(addTimer(TQString,TQString,TQDateTime,TQTime)), this, TQT_SLOT(newTimer(TQString,TQString,TQDateTime,TQTime)) );
connect( &dlg, TQT_SIGNAL(zapTo(const TQString &)), this, TQT_SLOT(channelSelected(const TQString &)) );
dlg.exec();
dvbConfig->epgSize = dlg.size();
disconnect( &dlg, TQT_SIGNAL(addTimer(TQString,TQString,TQDateTime,TQTime)), this, TQT_SLOT(newTimer(TQString,TQString,TQDateTime,TQTime)) );
disconnect( &dlg, TQT_SIGNAL(zapTo(const TQString &)), this, TQT_SLOT(channelSelected(const TQString &)) );
events.doClean( true );
}
void DvbPanel::setShiftLed( bool on )
{
if ( on ) {
shiftLed->on();
diskTimer.start( 300000 );
}
else {
shiftLed->off();
diskTimer.stop();
}
}
void DvbPanel::channelSelected( const TQString &name )
{
TQPtrListIterator<ChannelDesc> iter( channels );
ChannelDesc *itdesc;
iter.toFirst();
while ( (itdesc=iter.current())!=0 ) {
if ( itdesc->name==name ) {
dvbZap( itdesc );
break;
}
++iter;
}
}
void DvbPanel::channelSelected( TQListViewItem *it )
{
TQPtrListIterator<ChannelDesc> iter( channels );
ChannelDesc *itdesc;
if ( !it )
return;
iter.toFirst();
while ( (itdesc=iter.current())!=0 ) {
if ( itdesc->name==it->text(1) ) {
dvbZap( itdesc );
break;
}
++iter;
}
}
bool DvbPanel::nextTrack( MRL& )
{
next();
return false;
}
bool DvbPanel::previousTrack( MRL& )
{
previous();
return false;
}
bool DvbPanel::currentTrack( MRL& )
{
playLastChannel();
return false;
}
bool DvbPanel::trackNumber( int num, MRL& )
{
playNumChannel( num );
return false;
}
void DvbPanel::recallZap()
{
emit showMe( this );
playNumChannel( recallChannel );
}
void DvbPanel::playNumChannel( int num )
{
int j;
bool ok=false;
if ( !channelsCb->isEnabled() )
return;
for ( j=0; j<(int)channels.count(); j++ ) {
if ( (int)channels.at(j)->num==num ) {
ok = true;
break;
}
}
if ( ok )
dvbZap( channels.at( j ) );
}
bool DvbPanel::playbackFinished( MRL& )
{
return false;
}
void DvbPanel::playLastChannel()
{
/*int ret, i, j;
TQPtrList<ChannelDesc> list;
bool live=false, ok=false;
DvbStream *d;
for ( i=0; i<(int)dvb.count(); i++ ) {
if ( dvb.at(i)->hasBroadcast() )
dvb.at(i)->stopBroadcast();
}
++dvbConfig->lastChannel;
if ( dvbConfig->lastChannel>channels.count() )
dvbConfig->lastChannel = 1;
for ( j=0; j<(int)channels.count(); j++ ) {
if ( (int)channels.at(j)->num==dvbConfig->lastChannel ) {
ok = true;
list.append( channels.at(j) );
break;
}
}
if ( ! list.count() ) {
TQTimer::singleShot( 2000, this, TQT_SLOT(playLastChannel()) );
return;
}
d = getWorkingDvb( MODE_BROADCAST, list.at(0) );
if ( d )
ret = d->canStartBroadcast( live, list.at(0) );
else
ret = -1;
if ( ret==0 ) {
if ( live ) {
stopLive();
emit dvbStop();
}
if ( !d->startBroadcast( &list, rtp ) ) {
fprintf( stderr, "Broadcasting failed.\n" );
}
else {
fprintf( stderr, "Tuning to: %s / autocount: %lu\n", channels.at(j)->name.ascii(), autocount );
++autocount;
}
}
else
fprintf( stderr, "Can't start broadcasting.\n");
TQTimer::singleShot( 2000, this, TQT_SLOT(playLastChannel()) );
return;*/
int j;
bool ok=false;
if ( !channelsCb->isEnabled() )
return;
for ( j=0; j<(int)channels.count(); j++ ) {
if ( (int)channels.at(j)->num==dvbConfig->lastChannel ) {
ok = true;
break;
}
}
if ( !ok )
return;
dvbZap( channels.at(j) );
}
void DvbPanel::next()
{
if ( !channelsCb->isEnabled() )
return;
TQListViewItem* nextItem;
TQListViewItem* playingItem = channelsCb->findItem( TQString().sprintf("%05d", dvbConfig->lastChannel), 0 );
if ( !playingItem == 0 ) // yes, it's in the current category
{
if ( playingItem == channelsCb->lastItem() )
nextItem = channelsCb->firstChild(); // wrap around
else
nextItem = playingItem->itemBelow();
}
else // not in current category, user has switched category, use first in current cat
nextItem = channelsCb->firstChild();
channelsCb->setSelected( nextItem, true );
channelSelected( nextItem );
}
void DvbPanel::previous()
{
if ( !channelsCb->isEnabled() )
return;
TQListViewItem* prevItem;
TQListViewItem* playingItem = channelsCb->findItem( TQString().sprintf("%05d", dvbConfig->lastChannel), 0 );
if ( !playingItem == 0 ) // yes, it's in the current category
{
if ( playingItem == channelsCb->firstChild() )
prevItem = channelsCb->lastItem(); // wrap around
else
prevItem = playingItem->itemAbove();
}
else // not in current category, user has switched category, use first in current cat
prevItem = channelsCb->firstChild();
channelsCb->setSelected( prevItem, true );
channelSelected( prevItem );
}
void DvbPanel::dvbZap( ChannelDesc *chan )
{
int i;
DvbStream *d;
if ( currentFifo.isEmpty() || isTuning )
return;
isTuning = true;
emit setTimeShiftFilename( "" );
d = getWorkingDvb( MODE_LIVE, chan );
for ( i=0; i<(int)dvb.count(); i++ ) {
if ( dvb.at(i)->hasLive() ) {
dvb.at(i)->preStopLive();
emit dvbPause( false );
dvb.at(i)->stopLive( chan );
break;
}
}
finalZap( d, chan );
}
void DvbPanel::pipeOpened()
{
tuningTimer.start( 1000, true );
}
void DvbPanel::setTuning()
{
tuningTimer.stop();
stopTuningTimer.stop();
isTuning = false;
}
void DvbPanel::finalZap( DvbStream *d, ChannelDesc *chan )
{
TQString s, t;
int i;
emit setCurrentPlugin( this );
fprintf( stderr, "Tuning to: %s / autocount: %lu\n", chan->name.latin1(), autocount );
TQTime tm;
tm.start();
if ( !d ) {
emit dvbStop();
isTuning = false;
return;
}
int ret = d->goLive( chan, currentFifo, dvbConfig->ringBufSize );
switch ( ret ) {
case DvbStream::ErrIsRecording :
emit showOSD( i18n("Still recording."), 5000, 3 );
break;
case DvbStream::ErrIsBroadcasting :
emit showOSD( i18n("Still broadcasting."), 5000, 3 );
break;
case DvbStream::ErrCantTune :
emit showOSD( i18n("Can't tune dvb!"), 5000, 3 );
break;
case DvbStream::ErrCantSetPids :
emit showOSD( i18n("Can't set pid(s)"), 5000, 3 );
break;
case DvbStream::ErrCamUsed :
emit showOSD( i18n("No CAM free"), 5000, 3 );
break;
}
fprintf( stderr, "Tuning delay: %d ms\n", tm.elapsed() );
osdMode = 0;
if ( ret<1 ) {
emit dvbOpen( currentFifo, s.setNum( chan->num)+" - "+chan->name, chan->vpid );
showOsdTimer.start( 2000, true );
++autocount;
stopTuningTimer.start( 5000, true );
if ( currentFifo==fifoName ) {
if ( !fifoName1.isEmpty() )
currentFifo = fifoName1;
}
else {
if ( !fifoName.isEmpty() )
currentFifo = fifoName;
}
if ( channelsCb->visibleItems<5 ) {
resetSearch();
}
if ( d->liveIsRecording() )
recordBtn->setOn( true );
else
recordBtn->setOn( false );
}
else {
recordBtn->setOn( false );
isTuning = false;
emit dvbStop();
}
if ( dvbConfig->lastChannel!=(int)chan->num ) {
recallChannel = dvbConfig->lastChannel;
dvbConfig->lastChannel = chan->num;
}
//TQTimer::singleShot( 3000, this, TQT_SLOT(playLastChannel()) );
}
void DvbPanel::pauseLiveTV()
{
int i;
DvbStream *d=0;
for ( i=0; i<(int)dvb.count(); i++ ) {
if ( dvb.at(i)->hasLive() ) {
d = dvb.at(i);
break;
}
}
if ( !d )
return;
timeShiftFileName = dvbConfig->shiftDir+"DVBLive-"+TQDateTime::currentDateTime().toString("yyyyMMddThhmmss")+".m2t";
if ( d->doPause( timeShiftFileName ) )
emit setTimeShiftFilename( timeShiftFileName );
}
bool DvbPanel::timeShiftMode()
{
int i;
for ( i=0; i<(int)dvb.count(); i++ ) {
if ( dvb.at(i)->hasLive() ) {
return dvb.at(i)->timeShiftMode();
break;
}
}
return false;
}
void DvbPanel::stopLive()
{
int i;
ChannelDesc chan;
for ( i=0; i<(int)dvb.count(); i++ ) {
if ( dvb.at(i)->hasLive() ) {
recallChannel = dvb.at(i)->getLiveChannel().num;
dvb.at(i)->preStopLive();
dvb.at(i)->stopLive( &chan );
break;
}
}
recordBtn->setOn( false );
emit setTimeShiftFilename( "" );
}
// TV | vpid(stream_type) | apid1(lang)(ac3),apid2, | ttpid | sid | tsid | type(S,C,T)source | freq | sr | pol | fecH | inv | mod | fecL | bw | trans | guard | hier | number / subpid1(type)(pageid)(ancid)(lang),subpid2..., | category | nid |
bool DvbPanel::getChannelList()
{
bool ret=false;
TQString s, c, t, u, type;
int pos, tpos;
ChannelDesc *chan;
TQString src="";
int ns;
TDEListViewItem *it;
TQPixmap pix;
maxChannelNumber = 0;
minChannelNumber = -1;
int sort = dvbConfig->readDvbChanOrder();
if ( sort ) {
int column = sort&1;
int order = sort>>1;
switch (order){
case 1:
channelsCb->setSorting ( column, FALSE );
break;
case 0:
channelsCb->setSorting ( column, TRUE );
break;
}
}
TQFile f( locateLocal("appdata", "channels.dvb" ) );
if ( f.open(IO_ReadOnly) ) {
TQTextStream tt( &f );
while ( !tt.eof() ) {
s = tt.readLine();
if ( s.startsWith("#") ) {
if ( s.contains("KaxTV") )
break;
continue;
}
chan = new ChannelDesc();
pos = s.find("|");
c = s.left( pos );
if ( c=="TV" || c=="TVC" )
chan->type=1;
else
chan->type=2;
if ( c=="TVC" || c=="RAC" )
chan->fta=1;
s = s.right( s.length()-pos-1 );
pos = s.find("|");
chan->name = s.left( pos );
s = s.right( s.length()-pos-1 );
pos = s.find("|");
c = s.left( pos );
s = s.right( s.length()-pos-1 );
tpos = c.find("(");
if ( tpos>0 )
chan->vpid = c.left(tpos).toUShort();
else
chan->vpid = c.toUShort();
if( tpos>0 ) {
t = c.right( c.length()-tpos-1);
t.remove(")");
chan->vType = t.toUShort();
}
else
chan->vType = 2;
if ( !chan->vpid )
chan->vType = 0;
pos = s.find("|");
c = s.left( pos );
s = s.right( s.length()-pos-1 );
while ( (pos=c.find(","))!=-1 ) {
t = c.left(pos);
chan->napid++;
if ( t.contains("(ac3)") ) {
chan->apid[chan->napid-1].ac3=1;
t.remove("(ac3)");
}
if( (tpos=t.find("("))!=-1 ) {
t.remove(")");
chan->apid[chan->napid-1].lang=t.right( t.length()-tpos-1 );
t = t.left( tpos );
}
chan->apid[chan->napid-1].pid=t.toUShort();
c = c.right( c.length()-pos-1 );
}
pos = s.find("|");
chan->ttpid = s.left(pos).toUShort();
s = s.right( s.length()-pos-1 );
pos = s.find("|");
chan->sid = s.left(pos).toUShort();
s = s.right( s.length()-pos-1 );
pos = s.find("|");
chan->tp.tsid = s.left(pos).toUShort();
s = s.right( s.length()-pos-1 );
pos = s.find("|");
c = s.left(pos);
if ( c.startsWith("T") ) {
chan->tp.type=FE_OFDM;
chan->tp.source = "Terrestrial";
}
else if ( c.startsWith("C") ) {
chan->tp.type=FE_QAM;
chan->tp.source = "Cable";
}
else if ( c.startsWith("S") ) {
chan->tp.type=FE_QPSK;
c.remove( 0, 1 );
chan->tp.source = c;
}
else {
chan->tp.type=FE_ATSC;
chan->tp.source = "Atsc";
}
s = s.right( s.length()-pos-1 );
pos = s.find("|");
chan->tp.freq = s.left(pos).toULong();
s = s.right( s.length()-pos-1 );
pos = s.find("|");
chan->tp.sr = s.left(pos).toULong();
s = s.right( s.length()-pos-1 );
pos = s.find("|");
c = s.left( pos );
chan->tp.pol = c[0].latin1();
s = s.right( s.length()-pos-1 );
pos = s.find("|");
switch ( s.left(pos).toInt() ) {
case 0 : chan->tp.coderateH = FEC_NONE; break;
case 12 : chan->tp.coderateH = FEC_1_2; break;
case 23 : chan->tp.coderateH = FEC_2_3; break;
case 34 : chan->tp.coderateH = FEC_3_4; break;
case 45 : chan->tp.coderateH = FEC_4_5; break;
case 56 : chan->tp.coderateH = FEC_5_6; break;
case 67 : chan->tp.coderateH = FEC_6_7; break;
case 78 : chan->tp.coderateH = FEC_7_8; break;
case 89 : chan->tp.coderateH = FEC_8_9; break;
case 35 : chan->tp.coderateH = FEC_3_5; break;
case 910 : chan->tp.coderateH = FEC_9_10; break;
case -1 : chan->tp.coderateH = FEC_AUTO;
}
s = s.right( s.length()-pos-1 );
pos = s.find("|");
switch ( s.left(pos).toInt() ) {
case 0 : chan->tp.inversion = INVERSION_OFF; break;
case 1 : chan->tp.inversion = INVERSION_ON; break;
case -1 : chan->tp.inversion = INVERSION_AUTO;
}
s = s.right( s.length()-pos-1 );
pos = s.find("|");
switch ( s.left(pos).toInt() ) {
case 8 : chan->tp.modulation = QPSK; break;
case 16 : chan->tp.modulation = QAM_16; break;
case 32 : chan->tp.modulation = QAM_32; break;
case 64 : chan->tp.modulation = QAM_64; break;
case 128 : chan->tp.modulation = QAM_128; break;
case 256 : chan->tp.modulation = QAM_256; break;
case 108 : chan->tp.modulation = VSB_8; break;
case 116 : chan->tp.modulation = VSB_16; break;
case 1000 : chan->tp.modulation = PSK_8; break;
case 1001 : chan->tp.modulation = APSK_16; break;
case 1003 : chan->tp.modulation = DQPSK; break;
case -1 : chan->tp.modulation = QAM_AUTO;
}
s = s.right( s.length()-pos-1 );
pos = s.find("|");
switch ( s.left(pos).toInt() ) {
case 0 : chan->tp.coderateL = FEC_NONE; break;
case 12 : chan->tp.coderateL = FEC_1_2; break;
case 23 : chan->tp.coderateL = FEC_2_3; break;
case 34 : chan->tp.coderateL = FEC_3_4; break;
case 45 : chan->tp.coderateL = FEC_4_5; break;
case 56 : chan->tp.coderateL = FEC_5_6; break;
case 67 : chan->tp.coderateL = FEC_6_7; break;
case 78 : chan->tp.coderateL = FEC_7_8; break;
case 89 : chan->tp.coderateL = FEC_8_9; break;
case 35 : chan->tp.coderateH = FEC_3_5; break;
case 910 : chan->tp.coderateH = FEC_9_10; break;
case -1 : chan->tp.coderateL = FEC_AUTO;
}
s = s.right( s.length()-pos-1 );
pos = s.find("|");
switch ( s.left(pos).toInt() ) {
case 8 : chan->tp.bandwidth = BANDWIDTH_8_MHZ; break;
case 7 : chan->tp.bandwidth = BANDWIDTH_7_MHZ; break;
case 6 : chan->tp.bandwidth = BANDWIDTH_6_MHZ; break;
case -1 : chan->tp.bandwidth = BANDWIDTH_AUTO;
}
s = s.right( s.length()-pos-1 );
pos = s.find("|");
switch ( s.left(pos).toInt() ) {
case 2 : chan->tp.transmission = TRANSMISSION_MODE_2K; break;
case 8 : chan->tp.transmission = TRANSMISSION_MODE_8K; break;
case -1 : chan->tp.transmission = TRANSMISSION_MODE_AUTO;
}
s = s.right( s.length()-pos-1 );
pos = s.find("|");
switch ( s.left(pos).toInt() ) {
case 32 : chan->tp.guard = GUARD_INTERVAL_1_32; break;
case 16 : chan->tp.guard = GUARD_INTERVAL_1_16; break;
case 8 : chan->tp.guard = GUARD_INTERVAL_1_8; break;
case 4 : chan->tp.guard = GUARD_INTERVAL_1_4; break;
case -1 : chan->tp.guard = GUARD_INTERVAL_AUTO;
}
s = s.right( s.length()-pos-1 );
pos = s.find("|");
switch ( s.left(pos).toInt() ) {
case 0 : chan->tp.hierarchy = HIERARCHY_NONE; break;
case 1 : chan->tp.hierarchy = HIERARCHY_1; break;
case 2 : chan->tp.hierarchy = HIERARCHY_2; break;
case 4 : chan->tp.hierarchy = HIERARCHY_4; break;
case -1 : chan->tp.hierarchy = HIERARCHY_AUTO;
}
s = s.right( s.length()-pos-1 );
pos = s.find("|");
chan->num = s.left(pos).toUInt();
s = s.right( s.length()-pos-1 );
pos = s.find("|");
c = s.left( pos );
s = s.right( s.length()-pos-1 );
while ( (pos=c.find(","))!=-1 ) {
t = c.left(pos);
tpos=t.find("(");
ns = (int)chan->nsubpid;
chan->subpid[ns].pid = t.left(tpos).toUShort();
t = t.right( t.length()-tpos-1 );
tpos=t.find(")");
chan->subpid[ns].type = t.left(tpos).toUShort();
t = t.right( t.length()-tpos-2 );
tpos=t.find(")");
chan->subpid[ns].page = t.left(tpos).toUShort();
t = t.right( t.length()-tpos-2 );
tpos=t.find(")");
chan->subpid[ns].id = t.left(tpos).toUShort();
t = t.right( t.length()-tpos-2 );
tpos=t.find(")");
chan->subpid[ns].lang = t.left(tpos);
c = c.right( c.length()-pos-1 );
chan->nsubpid++;
}
pos = s.find("|");
chan->category = s.left( pos );
s = s.right( s.length()-pos-1 );
pos = s.find("|");
chan->tp.nid = s.left(pos).toUShort();
s = s.right( s.length()-pos-1 );
pos = s.find("|");
switch ( s.left(pos).toInt() ) {
case 20 : chan->tp.rolloff = ROLLOFF_20; break;
case 25 : chan->tp.rolloff = ROLLOFF_25; break;
case 35 : chan->tp.rolloff = ROLLOFF_35; break;
case -1 : chan->tp.rolloff = ROLLOFF_AUTO;
}
s = s.right( s.length()-pos-1 );
pos = s.find("|");
chan->tp.S2 = s.left(pos).toInt();
if ( chan->tp.source.isEmpty() ) {
delete chan;
continue;
}
chan->pix.load( dvbConfig->dvbConfigIconsDir+chan->name );
it = new TDEListViewItem( channelsCb, TQString().sprintf("%05d", chan->num), chan->name, chan->tp.source );
it->setDragEnabled( true );
if ( !chan->pix.isNull() )
it->setPixmap( 1, chan->pix );
else {
if ( chan->type==1 ) {
if ( chan->fta )
it->setPixmap( 1, tvcPix );
else
it->setPixmap( 1, tvPix );
}
else {
if ( chan->fta )
it->setPixmap( 1, racPix );
else
it->setPixmap( 1, raPix );
}
}
channels.append( chan );
if ( chan->num<=0 )
chan->num = channels.count();
if ( (int)chan->num > maxChannelNumber )
maxChannelNumber = chan->num;
if ( minChannelNumber == -1 || (int)chan->num < minChannelNumber )
minChannelNumber = chan->num;
}
ret = true;
f.close();
}
return ret;
}
bool DvbPanel::saveChannelList()
{
bool ret=false;
int i, k;
TQString s;
ChannelDesc *chan=0;
TQFile f( locateLocal("appdata", "channels.dvb" ) );
if ( f.open(IO_WriteOnly|IO_Truncate) ) {
TQTextStream tt( &f );
tt<<"#Generated by Kaffeine 0.5\n";
for( i=0; i<(int)channels.count(); i++ ) {
chan = channels.at(i);
if ( chan->type==1 ) {
if ( chan->fta )
tt<<"TVC|";
else
tt<<"TV|";
}
else {
if ( chan->fta )
tt<<"RAC|";
else
tt<<"RA|";
}
tt<< chan->name+"|";
tt<< s.setNum(chan->vpid);
if ( chan->vType ) {
tt<< "(";
tt<< s.setNum(chan->vType);
tt<< ")";
}
tt<< "|";
for ( k=0; k<chan->napid; k++ ) {
tt<< s.setNum(chan->apid[k].pid);
if ( !chan->apid[k].lang.isEmpty() )
tt<< "("+chan->apid[k].lang+")";
if ( chan->apid[k].ac3 )
tt<< "(ac3)";
tt<< ",";
}
tt<< "|";
tt<< s.setNum(chan->ttpid)+"|";
tt<< s.setNum(chan->sid)+"|";
tt<< s.setNum(chan->tp.tsid)+"|";
switch ( chan->tp.type ) {
case FE_QPSK : tt<< "S"; tt<< chan->tp.source; break;
case FE_QAM : tt<< "Cable"; break;
case FE_OFDM : tt<< "Terrestrial"; break;
case FE_ATSC : tt<< "Atsc"; break;
}
tt<< "|";
tt<< s.setNum(chan->tp.freq)+"|";
tt<< s.setNum(chan->tp.sr)+"|";
if ( chan->tp.pol=='h' )
tt<< "h|";
else
tt<< "v|";
switch ( chan->tp.coderateH ) {
case FEC_NONE : tt<< "0|"; break;
case FEC_1_2 : tt<< "12|"; break;
case FEC_2_3 : tt<< "23|"; break;
case FEC_3_4 : tt<< "34|"; break;
case FEC_4_5 : tt<< "45|"; break;
case FEC_5_6 : tt<< "56|"; break;
case FEC_6_7 : tt<< "67|"; break;
case FEC_7_8 : tt<< "78|"; break;
case FEC_8_9 : tt<< "89|"; break;
case FEC_3_5 : tt<< "35|"; break;
case FEC_9_10 : tt<< "910|"; break;
case FEC_AUTO : tt<< "-1|";
}
switch ( chan->tp.inversion ) {
case INVERSION_OFF : tt<< "0|"; break;
case INVERSION_ON : tt<< "1|"; break;
case INVERSION_AUTO : tt<< "-1|";
}
switch ( chan->tp.modulation ) {
case QPSK : tt<< "8|"; break;
case QAM_16 : tt<< "16|"; break;
case QAM_32 : tt<< "32|"; break;
case QAM_64 : tt<< "64|"; break;
case QAM_128 : tt<< "128|"; break;
case QAM_256 : tt<< "256|"; break;
case VSB_8 : tt<< "108|"; break;
case VSB_16 : tt<< "116|"; break;
case PSK_8 : tt<< "1000|"; break;
case APSK_16 : tt<< "1001|"; break;
case DQPSK : tt<< "1003|"; break;
case QAM_AUTO : tt<< "-1|";
}
switch ( chan->tp.coderateL ) {
case FEC_NONE : tt<< "0|"; break;
case FEC_1_2 : tt<< "12|"; break;
case FEC_2_3 : tt<< "23|"; break;
case FEC_3_4 : tt<< "34|"; break;
case FEC_4_5 : tt<< "45|"; break;
case FEC_5_6 : tt<< "56|"; break;
case FEC_6_7 : tt<< "67|"; break;
case FEC_7_8 : tt<< "78|"; break;
case FEC_8_9 : tt<< "89|"; break;
case FEC_3_5 : tt<< "35|"; break;
case FEC_9_10 : tt<< "910|"; break;
case FEC_AUTO : tt<< "-1|";
}
switch ( chan->tp.bandwidth ) {
case BANDWIDTH_8_MHZ : tt<< "8|"; break;
case BANDWIDTH_7_MHZ : tt<< "7|"; break;
case BANDWIDTH_6_MHZ : tt<< "6|"; break;
case BANDWIDTH_AUTO : tt<< "-1|";
}
switch ( chan->tp.transmission ) {
case TRANSMISSION_MODE_8K : tt<< "8|"; break;
case TRANSMISSION_MODE_2K : tt<< "2|"; break;
case TRANSMISSION_MODE_AUTO : tt<< "-1|";
}
switch ( chan->tp.guard ) {
case GUARD_INTERVAL_1_32 : tt<< "32|"; break;
case GUARD_INTERVAL_1_16 : tt<< "16|"; break;
case GUARD_INTERVAL_1_8 : tt<< "8|"; break;
case GUARD_INTERVAL_1_4 : tt<< "4|"; break;
case GUARD_INTERVAL_AUTO : tt<< "-1|";
}
switch ( chan->tp.hierarchy ) {
case HIERARCHY_NONE : tt<< "0|"; break;
case HIERARCHY_1 : tt<< "1|"; break;
case HIERARCHY_2 : tt<< "2|"; break;
case HIERARCHY_4 : tt<< "4|"; break;
case HIERARCHY_AUTO : tt<< "-1|";
}
tt<< s.setNum(chan->num)+"|";
for ( k=0; k<chan->nsubpid; k++ ) {
tt<< s.setNum(chan->subpid[k].pid);
tt<< "("+s.setNum(chan->subpid[k].type)+")";
tt<< "("+s.setNum(chan->subpid[k].page)+")";
tt<< "("+s.setNum(chan->subpid[k].id)+")";
tt<< "("+chan->subpid[k].lang+")";
tt<< ",";
}
tt<< "|";
tt<< chan->category+"|";
tt<< s.setNum(chan->tp.nid)+"|";
switch ( chan->tp.rolloff ) {
case ROLLOFF_20 : tt<< "20|"; break;
case ROLLOFF_25 : tt<< "25|"; break;
case ROLLOFF_35 : tt<< "35|"; break;
case ROLLOFF_AUTO : tt<< "-1|";
}
tt<< s.setNum(chan->tp.S2)+"|";
tt<< "\n";
}
ret = true;
f.close();
}
return ret;
}
bool DvbPanel::getTimerList()
{
bool ret=false;
TQString s;
int pos;
RecTimer *t;
TQFile f( locateLocal("appdata", "timers.dvb" ) );
if ( f.open(IO_ReadOnly) ) {
TQTextStream tt( &f );
while ( !tt.eof() ) {
s = tt.readLine();
if ( s.startsWith("#") )
continue;
t = new RecTimer();
pos = s.find("|");
t->name = s.left( pos );
s = s.right( s.length()-pos-1 );
pos = s.find("|");
t->channel = s.left( pos );
s = s.right( s.length()-pos-1 );
pos = s.find("|");
t->begin = TQDateTime::fromString( s.left( pos ), TQt::ISODate );
s = s.right( s.length()-pos-1 );
pos = s.find("|");
t->duration = TQTime::fromString( s.left( pos ) );
s = s.right( s.length()-pos-1 );
pos = s.find("|");
//t->filetype = s.left( pos ).toInt();
t->mode = 0;
s = s.right( s.length()-pos-1 );
pos = s.find("|");
t->mode = s.left( pos ).toInt();
t->running = 0;
timers.append( t );
}
ret = true;
f.close();
}
return ret;
}
bool DvbPanel::saveTimerList()
{
bool ret=false;
int i;
TQString s;
RecTimer *t;
TQFile f( locateLocal("appdata", "timers.dvb" ) );
if ( f.open(IO_WriteOnly|IO_Truncate) ) {
TQTextStream tt( &f );
tt<<"#Generated by Kaffeine 0.5\n";
for( i=0; i<(int)timers.count(); i++ ) {
t = timers.at(i);
if ( t->running && !t->mode )
continue;
tt<< t->name+"|";
tt<< t->channel+"|";
tt<< t->begin.toString("yyyy-MM-ddThh:mm:ss")+"|";
tt<< t->duration.toString()+"|";
tt<< s.setNum(0/*t->filetype*/)+"|";
tt<< s.setNum(t->mode)+"|";
tt<< "\n";
}
ret = true;
f.close();
}
return ret;
}
bool DvbPanel::close()
{
int ret=0, i;
bool rec = false;
for ( i=0; i<(int)dvb.count(); i++ ) {
if ( dvb.at(i)->hasRec() ) {
rec = true;
break;
}
}
if ( rec ) {
ret = KMessageBox::questionYesNo( 0, i18n("Kaffeine is still recording. Do you really want to quit?") );
if ( ret!=KMessageBox::Yes )
return false;
}
else if ( timers.count() ) {
ret = KMessageBox::questionYesNo( 0, i18n("Kaffeine has queued timers. Do you really want to quit?") );
if ( ret!=KMessageBox::Yes )
return false;
}
emit dvbStop();
stopLive();
return true;
}
void DvbPanel::saveConfig()
{
saveTimerList();
saveChannelList();
dvbConfig->splitSizes = split->sizes();
dvbConfig->saveDvbChanOrder( channelsCb->sortOrder(), channelsCb->sortColumn() );
dvbConfig->saveConfig();
//delete dvbConfig;
}
DvbPanel::~DvbPanel()
{
dvb.clear();
delete rtp;
delete cleaner;
if ( plug ) {
KService::Ptr service = KService::serviceByDesktopName( plugName );
KLibLoader::self()->unloadLibrary( service->library().ascii() );
}
events.saveEpg();
}
#include "dvbpanel.moc"