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.
tdetoys/kweather/weatherlib.cpp

414 lines
11 KiB

/***************************************************************************
weatherlib.cpp - description
-------------------
begin : Wed Jul 5 2000
copyright : (C) 2000 by Ian Reinhart Geiser
email : geiseri@msoe.edu
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <tqfile.h>
#include <tqdatetime.h>
#include <tqtextstream.h>
#include <tdeglobal.h>
#include <tdelocale.h>
#include <kdebug.h>
#include <math.h>
#include <krfcdate.h>
#include <tdeio/job.h>
#include <kurl.h>
#include <knotifyclient.h>
#include <tdetempfile.h>
#include <unistd.h>
#include <tdeapplication.h>
#include <kpassivepopup.h>
#include <tdeconfig.h>
#include "metar_parser.h"
#include "stationdatabase.h"
#include "sun.h"
#include "weatherlib.h"
#include "weather_icon.h"
#include "weatherlib.moc"
class WeatherLib::Data
{
public:
Data();
~Data(){ if ( target ) delete target; }
void clear();
/** The current weather state outside */
struct WeatherInfo wi;
TQDateTime age;
KTempFile *target;
bool downloading;
bool updated;
TDEIO::Job *job;
};
WeatherLib::Data::Data()
: target( 0 ), job( 0 )
{
clear();
}
void WeatherLib::Data::clear()
{
age = TQDateTime::currentDateTime();
downloading = false;
updated = false;
job = 0;
if ( target )
{
delete target;
target = 0;
}
}
WeatherLib::WeatherLib(StationDatabase *stationDB, TQObject *parent, const char *name)
: TQObject (parent, name)
{
TDEGlobal::locale()->insertCatalogue("kweather");
m_StationDb = stationDB;
data.setAutoDelete( true );
// Initialize correct icon setting
TDEConfig *conf = new TDEConfig("weather_panelappletrc");
conf->setGroup("General Options");
WeatherIconPrivate::instance()->useIconTheme(conf->readBoolEntry("use_icon_theme", true));
delete conf;
}
WeatherLib::~WeatherLib()
{
}
void WeatherLib::slotCopyDone(TDEIO::Job* job)
{
kdDebug(12006) << "Copy done..." << endl;
if( job->error())
{
kdDebug(12006) << "Error code: " << job->error() << endl;
//job->showErrorDialog(0L);
if ((job->error() == TDEIO::ERR_COULD_NOT_CONNECT || job->error() == TDEIO::ERR_UNKNOWN_HOST)
&& !hostDown)
{
hostDown= true;
// no need to show a passive popup here, as below all stations will show "dunno" icon
}
}
// Find the job
TQDictIterator<Data> it( data );
Data *d = 0L;
for( ; it.current(); ++it )
{
kdDebug(12006) << "Searching for job..." << endl;
if(it.current()->job == job)
{
d = it.current();
d->downloading = false;
if( !job->error() )
{
kdDebug( 12006) << "Reading: " << d->target->name() << endl;
TQFile file( d->target->name() );
file.open( IO_ReadOnly );
TQTextStream *t = new TQTextStream( &file );
//TQTextStream *t = d->target->textStream();
if( t )
{
TQString s = TQString();
while ( !t->eof() )
{
s += " " + t->readLine();
}
if ( !s.isEmpty() )
{
kdDebug( 12006 ) << "Parse: " << s << endl;
MetarParser parser(m_StationDb, TDEGlobal::locale()->measureSystem());
d->wi = parser.processData(d->wi.reportLocation, s);
d->age = TQDateTime::currentDateTime().addSecs(1800);
emit fileUpdate(d->wi.reportLocation);
d->updated = true;
}
else
{
// File error
kdDebug( 12006 ) << "File empty error..." << endl;
KPassivePopup::message( i18n("KWeather Error!"),
i18n("The temp file %1 was empty.").arg(d->target->name()), 0L,"error" );
d->updated = false;
}
}
else
{
// File error
kdDebug( 12006 ) << "File read error..." << endl;
KPassivePopup::message( i18n("KWeather Error!"),
i18n("Could not read the temp file %1.").arg(d->target->name()), 0L,"error" );
d->updated = false;
}
delete d->target;
d->target = 0L;
d->job = 0L;
}
else if( job->error() == TDEIO::ERR_DOES_NOT_EXIST)
{
data.remove(d->wi.reportLocation);
kdDebug( 12006 ) << "Bad station data so i am going to remove it" << endl;
KPassivePopup::message( i18n("KWeather Error!"),
i18n("The requested station does not exist."), 0L,"error" );
}
else if(job->error() == TDEIO::ERR_COULD_NOT_CONNECT ||
job->error() == TDEIO::ERR_UNKNOWN_HOST)
{
kdDebug( 12006 ) << "Offline now..." << endl;
d->clear();
d->wi.theWeather = "dunno";
TQString offlineStr = i18n("The network is currently offline...");
if (!d->wi.qsCurrentList.contains(offlineStr)) {
d->wi.qsCurrentList.append(offlineStr);
d->wi.qsCurrentList.append(i18n("Please update later."));
}
emit fileUpdate(d->wi.reportLocation);
}
else
{
kdDebug( 12006 ) << "Duh?..." << endl;
}
}
}
}
void WeatherLib::getData(Data *d, bool force /* try even if host was down last time*/)
{
if(!d->downloading && (force || !hostDown) )
{
d->downloading = true;
d->updated = false;
TQString u = "http://tgftp.nws.noaa.gov/data/observations/metar/stations/";
u += d->wi.reportLocation.upper().stripWhiteSpace();
u += ".TXT";
d->target = new KTempFile(TQString(), "-weather");
d->target->setAutoDelete(true);
d->target->file();
KURL url(u);
KURL local(d->target->name());
d->job = TDEIO::file_copy( url, local, -1, true, false, false);
d->job->addMetaData("cache", "reload"); // Make sure to get fresh info
connect( d->job, TQ_SIGNAL( result( TDEIO::Job *)),
TQ_SLOT(slotCopyDone(TDEIO::Job *)));
kdDebug( 12006 ) << "Copying " << url.prettyURL() << " to "
<< local.prettyURL() << endl;
emit fileUpdating(d->wi.reportLocation);
}
}
WeatherLib::Data* WeatherLib::findData(const TQString &stationID)
{
Data *d = data[stationID];
if (!d)
{
d = new Data();
d->wi.reportLocation = stationID;
d->wi.theWeather = "dunno";
d->wi.qsCurrentList.append( i18n( "Retrieving weather data..." ) );
data.insert(stationID, d);
getData(d);
}
return d;
}
TQString WeatherLib::temperature(const TQString &stationID){
Data *d = findData(stationID);
return d->wi.qsTemperature;
}
TQString WeatherLib::pressure(const TQString &stationID){
Data *d = findData(stationID);
return d->wi.qsPressure;
}
TQString WeatherLib::wind(const TQString &stationID){
Data *d = findData(stationID);
return (d->wi.qsWindSpeed + " " + d->wi.qsWindDirection);
}
/** */
TQString WeatherLib::dewPoint(const TQString &stationID){
Data *d = findData(stationID);
return d->wi.qsDewPoint;
}
TQString WeatherLib::relHumidity(const TQString &stationID){
Data *d = findData(stationID);
return d->wi.qsRelHumidity;
}
TQString WeatherLib::heatIndex(const TQString &stationID){
Data *d = findData(stationID);
return d->wi.qsHeatIndex;
}
TQString WeatherLib::windChill(const TQString &stationID){
Data *d = findData(stationID);
return d->wi.qsWindChill;
}
TQString WeatherLib::iconName(const TQString &stationID, uint iconSize) {
TQString result = TQString::null;
if (!stationID.isEmpty()) {
WeatherIcon *wi = weatherIcon(stationID);
result = wi->name(iconSize);
delete wi;
}
if (result.isEmpty())
result = WeatherIcon::unknown(iconSize).name;
return result;
}
TQString WeatherLib::iconName(const TQString &stationID) {
return iconName(stationID, IconSize(TDEIcon::Panel));
}
TQString WeatherLib::iconPath(const TQString &stationID, uint iconSize) {
TQString result = TQString::null;
if (!stationID.isEmpty()) {
WeatherIcon *wi = weatherIcon(stationID);
result = wi->path(iconSize);
delete wi;
}
if (result.isEmpty())
result = WeatherIcon::unknown(iconSize).path;
return result;
}
/** Returns a WeatherIcon object for the current weather conditions */
WeatherIcon* WeatherLib::weatherIcon(const TQString &stationID) {
Data *d = findData(stationID);
if (d->wi.theWeather == "dunno")
{
return new WeatherIcon();
}
int condition = d->wi.wiCondition;
int strength = d->wi.wiStrength;
bool night = d->wi.wiNight;
WeatherIcon* wi;
if (d->wi.wiStrength != 0) // Ranged condition
wi = new WeatherIcon(condition, night, strength);
else // Simple condition
wi = new WeatherIcon(condition, night);
return wi;
}
TQString WeatherLib::date(const TQString &stationID){
Data *d = findData(stationID);
if (d->wi.qsDate.isValid()) {
TQDateTime gmtDateTime(d->wi.qsDate, d->wi.qsTime);
TQDateTime localDateTime = gmtDateTime.addSecs(KRFCDate::localUTCOffset() * 60);
return TDEGlobal::locale()->formatDateTime(localDateTime, false, false);
}
return TQString::null;
}
/** Returns the current cover */
TQStringList WeatherLib::cover(const TQString &stationID){
Data *d = findData(stationID);
return d->wi.qsCoverList;
}
/** return the visibility */
TQString WeatherLib::visibility(const TQString &stationID){
Data *d = findData(stationID);
return d->wi.qsVisibility;
}
/** return the weather text */
TQStringList WeatherLib::weather(const TQString &stationID){
Data *d = findData(stationID);
return d->wi.qsCurrentList;
}
bool WeatherLib::stationNeedsMaintenance(const TQString &stationID)
{
Data *d = findData(stationID);
return d->wi.stationNeedsMaintenance;
}
bool WeatherLib::weatherDataAvailable(const TQString &stationID)
{
Data *d = findData(stationID);
return !(d->wi.theWeather == "dunno");
}
void WeatherLib::update(const TQString &stationID)
{
// Only grab new data if its more than 50 minutes old
Data *d = findData(stationID);
TQDateTime timeout = TQDateTime::currentDateTime();
kdDebug (12006) << "Current Time: " << TDEGlobal::locale()->formatDateTime(timeout, false, false) <<
" Update at: " << TDEGlobal::locale()->formatDateTime(d->age, false, false) << endl;
if( timeout >= d->age || !d->updated)
getData(d, true /* try even if host was down last time */);
else
emit fileUpdate(d->wi.reportLocation);
}
TQStringList WeatherLib::stations()
{
TQStringList l;
TQDictIterator<Data> it( data );
for( ; it.current(); ++it )
l += it.currentKey();
return l;
}
void WeatherLib::forceUpdate(const TQString &stationID)
{
hostDown = false; // we want to show error message if host is still down
Data *d = findData(stationID);
getData( d );
}
void WeatherLib::remove(const TQString &stationID)
{
data.remove(stationID);
emit stationRemoved(stationID);
}