summaryrefslogtreecommitdiffstats
path: root/tderesources/tvanytime/kcal_resourcetvanytime.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tderesources/tvanytime/kcal_resourcetvanytime.cpp')
-rw-r--r--tderesources/tvanytime/kcal_resourcetvanytime.cpp489
1 files changed, 489 insertions, 0 deletions
diff --git a/tderesources/tvanytime/kcal_resourcetvanytime.cpp b/tderesources/tvanytime/kcal_resourcetvanytime.cpp
new file mode 100644
index 000000000..9de4b0d1d
--- /dev/null
+++ b/tderesources/tvanytime/kcal_resourcetvanytime.cpp
@@ -0,0 +1,489 @@
+/*
+ This file is part of tdepim.
+
+ Copyright (c) 2005 Will Stephenson <[email protected]>
+
+ 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, 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 <libtdepim/kpimprefs.h>
+
+#include <tqapplication.h>
+#include <tqdom.h>
+#include <tqdatetime.h>
+#include <tqptrlist.h>
+#include <tqregexp.h>
+#include <tqstringlist.h>
+#include <tqtimer.h>
+
+#include <kabc/locknull.h>
+#include <karchive.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <tderesources/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 TDEConfig *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, TQT_SIGNAL( timeout() ),
+ this, TQT_SLOT( slotEmitResourceChanged() ) );
+}
+
+TVAnytimePrefsBase *ResourceTVAnytime::prefs()
+{
+ return mPrefs;
+}
+
+void ResourceTVAnytime::readConfig( const TDEConfig *config )
+{
+ kdDebug() << "KCal::ResourceTVAnytime::readConfig()" << endl;
+
+ mPrefs->readConfig();
+
+ ResourceCached::readConfig( config );
+
+ TQStringList defaultActive;
+ defaultActive << "BBCOne" << "BBCTwo" << "BBCThree" << "BBCROne" << "BBCRTwo" << "BBCRThree" << "BBCRFour";
+ mActiveServices = config->readListEntry( "ActiveServices", defaultActive );
+
+}
+
+void ResourceTVAnytime::writeConfig( TDEConfig *config )
+{
+ kdDebug() << "KCal::ResourceTVAnytime::writeConfig()" << endl;
+
+ ResourceCalendar::writeConfig( config );
+
+ mPrefs->writeConfig();
+
+ ResourceCached::writeConfig( config );
+ TQStringList 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 = TDEIO::file_copy( url, destination, -1, true );
+ connect( mDownloadJob, TQT_SIGNAL( result( TDEIO::Job * ) ),
+ TQT_SLOT( slotJobResult( TDEIO::Job * ) ) );
+
+ mProgress = KPIM::ProgressManager::instance()->createProgressItem(
+ KPIM::ProgressManager::getUniqueID(), i18n("Downloading program schedule") );
+
+ connect( mProgress,
+ TQT_SIGNAL( progressItemCanceled( KPIM::ProgressItem * ) ),
+ TQT_SLOT( cancelLoad() ) );
+
+ return true;
+}
+
+void ResourceTVAnytime::slotJobResult( TDEIO::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;
+}
+
+TQDomDocument ResourceTVAnytime::archiveFileXml( const TQString & name )
+{
+ TQDomDocument 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()
+{
+ TQString uncompress = "application/x-gzip";
+ mScheduleArchive = new KTar( mDestination->name(), uncompress );
+ mScheduleArchive->open( IO_ReadOnly );
+
+ TQDomDocument 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
+ TQString serviceId = "BBCOne";
+ Service s = mServiceMap[ serviceId ];
+ if ( s.active() )
+ readService( serviceId );
+#endif
+
+ mScheduleArchive->close();
+ return true;
+}
+
+bool ResourceTVAnytime::readServiceInformation( const TQDomDocument & serviceInfo )
+{
+ kdDebug() << k_funcinfo << endl;
+ TQDomElement docElem = serviceInfo.documentElement();
+
+ TQDomNode n = docElem.firstChild();
+ while( !n.isNull() ) {
+ TQDomElement e = n.toElement(); // try to convert the node to an element.
+ if( !e.isNull() && e.tagName() == "ProgramDescription" ) {
+ TQDomNode n2 = e.firstChild();
+ TQDomElement e2 = n2.toElement();
+ if( !e2.isNull() && e2.tagName() == "ServiceInformationTable" ) {
+ TQDomNode n3 = e2.firstChild();
+ while ( !n3.isNull() ) {
+ Service s;
+ TQDomElement 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 TQString & serviceId )
+{
+ kdDebug() << k_funcinfo << endl;
+ // open programme information table
+ Service service = mServiceMap[ serviceId ];
+
+ TQStringList entries = mScheduleArchive->directory()->entries();
+ TQRegExp re( "^(\\d{8})" + serviceId );
+ TQStringList dates;
+ TQString todaysDate = TQDate::currentDate().toString( "yyyyMMdd" );
+ for( TQStringList::Iterator it = entries.begin(); it != entries.end(); ++it )
+ {
+ if ( re.search( *it ) != -1 ) // this entry belongs to the requested service
+ {
+ TQString entry = re.cap( 1 );
+ // handle this date according to user preferences
+ TQDate entryDate( entry.left( 4 ).toInt(), entry.mid( 4, 2 ).toInt(), entry.right( 2 ).toInt() );
+ if ( entryDate < TQDate::currentDate() || ( entryDate > TQDate::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( TQStringList::Iterator it = dates.begin(); it != dates.end(); ++it )
+ {
+ ProgramInformationMap progInfoMap = service.programmeInformation();
+ TQString programInfoFileName = TQString( *it + serviceId + "_pi.xml" );
+ TQDomDocument programInfo = archiveFileXml( programInfoFileName );
+ if ( !programInfo.isNull() ) {
+ TQDomElement docElem = programInfo.documentElement();
+ TQDomNode n = docElem.firstChild();
+ while( !n.isNull() ) {
+ TQDomElement e = n.toElement(); // try to convert the node to an element.
+ if( !e.isNull() && e.tagName() == "ProgramDescription" ) {
+ TQDomNode n2 = e.firstChild();
+ TQDomElement e2 = n2.toElement();
+ if( !e2.isNull() && e2.tagName() == "ProgramInformationTable" ) {
+ TQDomNode n3 = e2.firstChild();
+ while ( !n3.isNull() ) {
+ TQDomElement 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
+
+ TQString programLocationFileName = TQString( *it + serviceId + "_pl.xml" );
+ TQDomDocument programLocation = archiveFileXml( programLocationFileName );
+ if ( !programLocation.isNull() ) {
+ TQDomElement docElem = programLocation.documentElement();
+ TQDomNode n = docElem.firstChild();
+ while( !n.isNull() ) {
+ TQDomElement e = n.toElement(); // try to convert the node to an element.
+ if( !e.isNull() && e.tagName() == "ProgramDescription" ) {
+ TQDomNode n2 = e.firstChild();
+ TQDomElement e2 = n2.toElement();
+ if( !e2.isNull() && e2.tagName() == "ProgramLocationTable" ) {
+ TQDomNode n3 = e2.firstChild();
+ TQDomElement e3 = n3.toElement();
+ if( !e3.isNull() && e3.tagName() == "Schedule" ) {
+ TQString foundServiceId = e3.attribute( "serviceIDRef" );
+ if ( serviceId == foundServiceId ) {
+ TQDomNode n4 = e3.firstChild();
+ while ( !n4.isNull() ) {
+ TQDomElement 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;
+}
+
+TQStringList ResourceTVAnytime::subresources() const
+{
+ //const_cast<ResourceTVAnytime*>( this )->doLoad();
+ return mServiceMap.keys();
+}
+
+const TQString
+ResourceTVAnytime::labelForSubresource( const TQString& subresource ) const
+{
+ Service s = mServiceMap[ subresource ];
+ return s.name();
+}
+
+TQString ResourceTVAnytime::subresourceIdentifier( Incidence *incidence )
+{
+ return incidence->customProperty( "TVANYWHERE", "SERVICEID" );
+}
+
+bool ResourceTVAnytime::subresourceActive( const TQString & subresource ) const
+{
+ Service s = mServiceMap[ subresource ];
+ return s.active();
+}
+
+void ResourceTVAnytime::setSubresourceActive( const TQString & 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"