summaryrefslogtreecommitdiffstats
path: root/kresources/tvanytime/kcal_resourcetvanytime.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kresources/tvanytime/kcal_resourcetvanytime.cpp')
-rw-r--r--kresources/tvanytime/kcal_resourcetvanytime.cpp489
1 files changed, 489 insertions, 0 deletions
diff --git a/kresources/tvanytime/kcal_resourcetvanytime.cpp b/kresources/tvanytime/kcal_resourcetvanytime.cpp
new file mode 100644
index 000000000..6904d76a7
--- /dev/null
+++ b/kresources/tvanytime/kcal_resourcetvanytime.cpp
@@ -0,0 +1,489 @@
+/*
+ This file is part of kdepim.
+
+ Copyright (c) 2005 Will Stephenson <wstephenson@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include "kcal_resourcetvanytime.h"
+
+#include "kcal_tvanytimeprefsbase.h"
+#include "kcal_resourcetvanytimeconfig.h"
+
+#include <libkcal/icalformat.h>
+#include <libkcal/calendarlocal.h>
+#include <libkcal/confirmsavedialog.h>
+
+#include <libkdepim/kpimprefs.h>
+
+#include <qapplication.h>
+#include <qdom.h>
+#include <qdatetime.h>
+#include <qptrlist.h>
+#include <qregexp.h>
+#include <qstringlist.h>
+#include <qtimer.h>
+
+#include <kabc/locknull.h>
+#include <karchive.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kresources/configwidget.h>
+#include <kstandarddirs.h>
+#include <kstringhandler.h>
+#include <ktempfile.h>
+#include <ktar.h>
+#include <kurl.h>
+
+using namespace KCal;
+
+ResourceTVAnytime::ResourceTVAnytime()
+ : ResourceCached( 0 ), mLock( true )
+{
+ init();
+
+ mPrefs->addGroupPrefix( identifier() );
+}
+
+ResourceTVAnytime::ResourceTVAnytime( const KConfig *config )
+ : ResourceCached( config ), mLock( true )
+{
+ init();
+
+ mPrefs->addGroupPrefix( identifier() );
+
+ if ( config ) readConfig( config );
+}
+
+ResourceTVAnytime::~ResourceTVAnytime()
+{
+ disableChangeNotification();
+
+ delete mPrefs;
+ mPrefs = 0;
+}
+
+void ResourceTVAnytime::init()
+{
+ mDownloadJob = 0;
+ mProgress = 0;
+ mDestination = 0;
+
+ mIsShowingError = false;
+
+ mPrefs = new TVAnytimePrefsBase();
+
+ setType( "tvanytime" );
+
+ enableChangeNotification();
+
+ //setReadOnly( true );
+
+ connect( &mResourceChangedTimer, SIGNAL( timeout() ),
+ this, SLOT( slotEmitResourceChanged() ) );
+}
+
+TVAnytimePrefsBase *ResourceTVAnytime::prefs()
+{
+ return mPrefs;
+}
+
+void ResourceTVAnytime::readConfig( const KConfig *config )
+{
+ kdDebug() << "KCal::ResourceTVAnytime::readConfig()" << endl;
+
+ mPrefs->readConfig();
+
+ ResourceCached::readConfig( config );
+
+ QStringList defaultActive;
+ defaultActive << "BBCOne" << "BBCTwo" << "BBCThree" << "BBCROne" << "BBCRTwo" << "BBCRThree" << "BBCRFour";
+ mActiveServices = config->readListEntry( "ActiveServices", defaultActive );
+
+}
+
+void ResourceTVAnytime::writeConfig( KConfig *config )
+{
+ kdDebug() << "KCal::ResourceTVAnytime::writeConfig()" << endl;
+
+ ResourceCalendar::writeConfig( config );
+
+ mPrefs->writeConfig();
+
+ ResourceCached::writeConfig( config );
+ QStringList activeServices;
+ ServiceMap::ConstIterator it;
+ for ( it = mServiceMap.begin(); it != mServiceMap.end(); ++it )
+ if ( it.data().active() )
+ activeServices.append( it.key() );
+ config->writeEntry( "ActiveServices", activeServices );
+}
+
+bool ResourceTVAnytime::doOpen()
+{
+ return true;
+}
+
+void ResourceTVAnytime::doClose()
+{
+ ResourceCached::doClose();
+}
+
+bool ResourceTVAnytime::doLoad()
+{
+ kdDebug() << "ResourceTVAnytime::load()" << endl;
+
+ if ( mIsShowingError ) {
+ kdDebug() << "Still showing error" << endl;
+ return true;
+ }
+
+ if ( mDownloadJob ) {
+ kdWarning() << "Download still in progress" << endl;
+ return false;
+ }
+
+ mUidMap.clear();
+ mCalendar.close();
+
+ disableChangeNotification();
+ // FIXME - reenable cache
+ loadCache(); // TODO: default loadCache() won't set up the subresources...
+ enableChangeNotification();
+
+ emit resourceChanged( this );
+
+ clearChanges();
+
+ mDestination = new KTempFile;
+ KURL url( prefs()->url() );
+
+ KURL destination = KURL( mDestination->name() );
+
+ kdDebug(5850) << " SOURCE: " << url.url() << endl;
+ kdDebug(5850) << " DESTINATION: " << destination.url() << endl;
+
+ // TODO: find out if the file to download is fresh. if not, just work with the cache.
+ mDownloadJob = KIO::file_copy( url, destination, -1, true );
+ connect( mDownloadJob, SIGNAL( result( KIO::Job * ) ),
+ SLOT( slotJobResult( KIO::Job * ) ) );
+
+ mProgress = KPIM::ProgressManager::instance()->createProgressItem(
+ KPIM::ProgressManager::getUniqueID(), i18n("Downloading program schedule") );
+
+ connect( mProgress,
+ SIGNAL( progressItemCanceled( KPIM::ProgressItem * ) ),
+ SLOT( cancelLoad() ) );
+
+ return true;
+}
+
+void ResourceTVAnytime::slotJobResult( KIO::Job *job )
+{
+ kdDebug() << "ResourceTVAnytime::slotJobResult(): " << endl;
+
+ if ( job->error() ) {
+ mIsShowingError = true;
+ loadError( job->errorString() );
+ mIsShowingError = false;
+ delete mDestination;
+ mDestination = 0;
+ } else {
+ disableChangeNotification();
+
+ clearCache();
+
+ // FIXME: This does not take into account the time zone!
+
+ readSchedule();
+
+ // FIXME - reenable cache
+ saveCache();
+ enableChangeNotification();
+
+ clearChanges();
+
+ emit resourceChanged( this );
+ emit resourceLoaded( this );
+ }
+
+ mDownloadJob = 0;
+ if ( mProgress ) mProgress->setComplete();
+ mProgress = 0;
+ delete mDestination;
+ mDestination = 0;
+}
+
+QDomDocument ResourceTVAnytime::archiveFileXml( const QString & name )
+{
+ QDomDocument result;
+ const KArchiveDirectory *dir = mScheduleArchive->directory();
+ const KArchiveEntry * entry = dir->entry( name );
+ if ( entry && entry->isFile() )
+ {
+ const KArchiveFile * file = static_cast<const KArchiveFile *>( entry );
+ result.setContent( file->data() );
+ }
+ return result;
+}
+
+bool ResourceTVAnytime::readSchedule()
+{
+ QString uncompress = "application/x-gzip";
+ mScheduleArchive = new KTar( mDestination->name(), uncompress );
+ mScheduleArchive->open( IO_ReadOnly );
+
+ QDomDocument serviceInfo = archiveFileXml( "ServiceInformation.xml" );
+ if ( !serviceInfo.isNull() )
+ readServiceInformation( serviceInfo );
+
+
+ ServiceMap::Iterator it;
+ // for each date in the tarball/or user preference:
+#if 1
+ for ( it = mServiceMap.begin(); it != mServiceMap.end(); ++it )
+ {
+ if ( (it.data().active() ) )
+ readService( it.key() );
+ }
+#else
+ QString serviceId = "BBCOne";
+ Service s = mServiceMap[ serviceId ];
+ if ( s.active() )
+ readService( serviceId );
+#endif
+
+ mScheduleArchive->close();
+ return true;
+}
+
+bool ResourceTVAnytime::readServiceInformation( const QDomDocument & serviceInfo )
+{
+ kdDebug() << k_funcinfo << endl;
+ QDomElement docElem = serviceInfo.documentElement();
+
+ QDomNode n = docElem.firstChild();
+ while( !n.isNull() ) {
+ QDomElement e = n.toElement(); // try to convert the node to an element.
+ if( !e.isNull() && e.tagName() == "ProgramDescription" ) {
+ QDomNode n2 = e.firstChild();
+ QDomElement e2 = n2.toElement();
+ if( !e2.isNull() && e2.tagName() == "ServiceInformationTable" ) {
+ QDomNode n3 = e2.firstChild();
+ while ( !n3.isNull() ) {
+ Service s;
+ QDomElement e3 = n3.toElement();
+ if (s.loadXML( e3 ) ) {
+ s.setActive( mActiveServices.contains( s.id() ) );
+ bool newService = !mServiceMap.contains( s.id() );
+ if ( newService )
+ {
+ mServiceMap.insert( s.id(), s );
+ emit signalSubresourceAdded( this, "Calendar", s.id(), s.name() );
+ }
+ }
+ else
+ kdDebug() << " couldn't find ServiceInformation: " << e3.tagName() << endl;
+ n3 = n3.nextSibling();
+ }
+ }
+ else
+ kdDebug() << " couldn't find ServiceInformationTable: " << e2.tagName() << endl;
+ }
+ else
+ kdDebug() << " couldn't find ProgramDescription: " << e.tagName() << endl;
+ n = n.nextSibling();
+ }
+ return true;
+}
+
+bool ResourceTVAnytime::readService( const QString & serviceId )
+{
+ kdDebug() << k_funcinfo << endl;
+ // open programme information table
+ Service service = mServiceMap[ serviceId ];
+
+ QStringList entries = mScheduleArchive->directory()->entries();
+ QRegExp re( "^(\\d{8})" + serviceId );
+ QStringList dates;
+ QString todaysDate = QDate::currentDate().toString( "yyyyMMdd" );
+ for( QStringList::Iterator it = entries.begin(); it != entries.end(); ++it )
+ {
+ if ( re.search( *it ) != -1 ) // this entry belongs to the requested service
+ {
+ QString entry = re.cap( 1 );
+ // handle this date according to user preferences
+ QDate entryDate( entry.left( 4 ).toInt(), entry.mid( 4, 2 ).toInt(), entry.right( 2 ).toInt() );
+ if ( entryDate < QDate::currentDate() || ( entryDate > QDate::currentDate().addDays( prefs()->days() - 1 ) ) )
+ continue;
+
+ if ( !dates.contains( re.cap( 1 ) ) )
+ dates.append( re.cap( 1 ) );
+ }
+ }
+
+ kdDebug() << "reading schedule for " << serviceId << " on " << dates << endl;
+
+ for( QStringList::Iterator it = dates.begin(); it != dates.end(); ++it )
+ {
+ ProgramInformationMap progInfoMap = service.programmeInformation();
+ QString programInfoFileName = QString( *it + serviceId + "_pi.xml" );
+ QDomDocument programInfo = archiveFileXml( programInfoFileName );
+ if ( !programInfo.isNull() ) {
+ QDomElement docElem = programInfo.documentElement();
+ QDomNode n = docElem.firstChild();
+ while( !n.isNull() ) {
+ QDomElement e = n.toElement(); // try to convert the node to an element.
+ if( !e.isNull() && e.tagName() == "ProgramDescription" ) {
+ QDomNode n2 = e.firstChild();
+ QDomElement e2 = n2.toElement();
+ if( !e2.isNull() && e2.tagName() == "ProgramInformationTable" ) {
+ QDomNode n3 = e2.firstChild();
+ while ( !n3.isNull() ) {
+ QDomElement e3 = n3.toElement();
+ ProgramInformation pi;
+ if ( pi.loadXML( e3 ) ) {
+ //kdDebug() << "Found programme: " << pi.id() << "," << pi.title() << "," << pi.synopsis() << endl;
+ progInfoMap.insert( pi.id(), pi );
+ }
+ n3 = n3.nextSibling();
+ }
+ }
+ }
+ n = n.nextSibling();
+ }
+ service.setProgramInformation( progInfoMap );
+ }
+ else
+ kdDebug() << "Service file: " << programInfoFileName << " not found in archive" << endl;
+ // open programme location table, iterate and create incidences
+
+ QString programLocationFileName = QString( *it + serviceId + "_pl.xml" );
+ QDomDocument programLocation = archiveFileXml( programLocationFileName );
+ if ( !programLocation.isNull() ) {
+ QDomElement docElem = programLocation.documentElement();
+ QDomNode n = docElem.firstChild();
+ while( !n.isNull() ) {
+ QDomElement e = n.toElement(); // try to convert the node to an element.
+ if( !e.isNull() && e.tagName() == "ProgramDescription" ) {
+ QDomNode n2 = e.firstChild();
+ QDomElement e2 = n2.toElement();
+ if( !e2.isNull() && e2.tagName() == "ProgramLocationTable" ) {
+ QDomNode n3 = e2.firstChild();
+ QDomElement e3 = n3.toElement();
+ if( !e3.isNull() && e3.tagName() == "Schedule" ) {
+ QString foundServiceId = e3.attribute( "serviceIDRef" );
+ if ( serviceId == foundServiceId ) {
+ QDomNode n4 = e3.firstChild();
+ while ( !n4.isNull() ) {
+ QDomElement e4 = n4.toElement();
+ ScheduleEvent se;
+ if ( se.loadXML( e4 ) ) {
+ ProgramInformation pi = progInfoMap[ se.crid() ];
+ //kdDebug() << "programme incidence: " << se.crid() << "," << se.startTime() << "," << se.duration() << "," << pi.title() << "," << pi.synopsis() << endl;
+ KCal::Event *event = new KCal::Event();
+ event->setFloats( false );
+ event->setSummary( pi.title() );
+ event->setDescription( pi.synopsis() );
+ event->setDtStart( KPimPrefs::localTimeToUtc( se.startTime(), "Europe/London" ) );
+ event->setDuration( se.duration() );
+ event->setLocation( service.name() );
+ event->setCategories( pi.genres() );
+ event->setUid( se.programUrl() );
+ event->setCustomProperty( "TVANYWHERE", "SERVICEID", serviceId );
+ // store the reverse mapping from event to service, for subresources
+ mUidMap.insert( event->uid(), serviceId );
+ event->setReadOnly( true );
+
+ addIncidence( event );
+ }
+ n4 = n4.nextSibling();
+ }
+ }
+ else
+ kdDebug() << " file contains schedule for another service!" << endl;
+ }
+ }
+ }
+ n = n.nextSibling();
+ }
+ }
+ else
+ kdDebug() << "Program location file: " << programLocationFileName << " not found in archive" << endl;
+ }
+ return true;
+}
+
+QStringList ResourceTVAnytime::subresources() const
+{
+ //const_cast<ResourceTVAnytime*>( this )->doLoad();
+ return mServiceMap.keys();
+}
+
+const QString
+ResourceTVAnytime::labelForSubresource( const QString& subresource ) const
+{
+ Service s = mServiceMap[ subresource ];
+ return s.name();
+}
+
+QString ResourceTVAnytime::subresourceIdentifier( Incidence *incidence )
+{
+ return incidence->customProperty( "TVANYWHERE", "SERVICEID" );
+}
+
+bool ResourceTVAnytime::subresourceActive( const QString & subresource ) const
+{
+ Service s = mServiceMap[ subresource ];
+ return s.active();
+}
+
+void ResourceTVAnytime::setSubresourceActive( const QString & subresource, bool active )
+{
+ if ( mServiceMap.contains( subresource ) )
+ {
+ Service s = mServiceMap[ subresource ];
+ if ( s.active() != active )
+ {
+ s.setActive( active );
+ mServiceMap.insert( subresource, s );
+ doLoad();
+ mResourceChangedTimer.changeInterval( 150 );
+ }
+ }
+}
+
+KABC::Lock *ResourceTVAnytime::lock()
+{
+ return &mLock;
+}
+
+void ResourceTVAnytime::cancelLoad()
+{
+ if ( mDownloadJob ) mDownloadJob->kill();
+ mDownloadJob = 0;
+ if ( mProgress ) mProgress->setComplete();
+ mProgress = 0;
+}
+
+void ResourceTVAnytime::slotEmitResourceChanged()
+{
+ emit resourceChanged( this );
+ mResourceChangedTimer.stop();
+}
+
+#include "kcal_resourcetvanytime.moc"