Index: weatherengine.cpp =================================================================== --- weatherengine.cpp (revision 724674) +++ weatherengine.cpp (working copy) @@ -21,7 +21,6 @@ #include #include #include -#include #include "ions/ion.h" class WeatherEngine::Private @@ -29,10 +28,26 @@ public: Private() {} ~Private() { - m_ions.clear(); + qDeleteAll(m_ions); } - QTimer *m_timer; + IonInterface* ionForSource(const QString& name) + { + int offset = name.indexOf(':'); + + if (offset < 1) { + return 0; + } + + QString ionName = name.left(offset); + + if (!this->m_ions.contains(ionName)) { + return 0; + } + + return this->m_ions[ionName]; + } + IonInterface::IonDict m_ions; KDateTime m_localTime; }; @@ -51,7 +66,6 @@ // Loads an Ion plugin given a plugin name found via KService. IonInterface* WeatherEngine::loadIon(const KService::Ptr& service) { - IonInterface *ion = 0; QString plugName = service->property("X-IonName").toString(); IonInterface::IonDict::const_iterator it = d->m_ions.find(plugName); @@ -135,7 +149,6 @@ return; } ion->connectSource(source, this); - ion->fetch(); } void WeatherEngine::removeIonSource(const QString& source) @@ -167,11 +180,6 @@ foreach(KService::Ptr service, knownIons()) { loadIon(service); } - - // Setup a master time to ping each Ion for new data. - d->m_timer = new QTimer(this); - d->m_timer->setSingleShot(false); - connect(d->m_timer, SIGNAL(timeout()), this, SLOT(updateData())); } // dtor @@ -182,31 +190,42 @@ } // Setup each Ion for the first time -bool WeatherEngine::sourceRequested(const QString &name) +bool WeatherEngine::sourceRequested(const QString &source) { - // Pass values to set when getting data from the ion. - foreach(IonInterface *ion, d->m_ions) { - // Before we use the timer, get the data. - ion->setSource(name); - kDebug() << "sourceRequested()"; + IonInterface *ion = d->ionForSource(source); + + if (!ion) { + kDebug() << "BAD ION!!!!!!!!!!"; + return false; } - /* FIXME: Make the timer value configurable in 30 minute intervals via Applet */ - if (!d->m_timer->isActive()) - d->m_timer->start(50000); + // Pass values to set when getting data from the ion. - updateData(); + QStringList tokens = source.split(':'); + if (tokens.size() < 1) { + kDebug() << "Invalid string :-("; + return false; + } + + kDebug() << "Source requested: " << tokens[1]; + ion->connectSource(tokens[1], this); + kDebug() << "sourceRequested()"; return true; } // SLOT: update the Applet with new data from all ions loaded. -void WeatherEngine::updateData() +bool WeatherEngine::updateSource(const QString& source) { - foreach(IonInterface *ion, d->m_ions) { - ion->fetch(); - ion->updateData(); + IonInterface *ion = d->ionForSource(source); + + kDebug() << "*********** TIMEOUT ********** Get new push of data!"; + if (!ion) { + return false; } + + ion->updateSource(source); + return true; } #include "weatherengine.moc" Index: ions/ion_envcan.cpp =================================================================== --- ions/ion_envcan.cpp (revision 724674) +++ ions/ion_envcan.cpp (working copy) @@ -104,10 +104,11 @@ } // Get a specific Ion's data -void EnvCanadaIon::fetch() +bool EnvCanadaIon::updateIonSource(const QString& source) { - // Go read the city's XML file - getXMLData(); + kDebug() << "Getting WEATHER FOR ==========> " << source; + getXMLData(source); + return true; } // Parses city list and gets the correct city based on ID number @@ -126,27 +127,21 @@ } // Gets specific city XML data -void EnvCanadaIon::getXMLData() +void EnvCanadaIon::getXMLData(const QString& source) { KUrl url; - foreach(QString key, this->ionSourceDict()) { - if (!validLocation(key)) { - continue; - } else { - url = "http://dd.weatheroffice.ec.gc.ca/EC_sites/xml/" + d->m_place[key].territoryName + "/" + d->m_place[key].cityCode + "_e.xml"; - } + url = "http://dd.weatheroffice.ec.gc.ca/EC_sites/xml/" + d->m_place[source].territoryName + "/" + d->m_place[source].cityCode + "_e.xml"; - //kDebug() << "URL Location: " << url.url(); + kDebug() << "URL Location: " << url.url(); - d->m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo); - d->m_jobXml.insert(d->m_job, new QXmlStreamReader); - d->m_jobList.insert(d->m_job, key); + d->m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo); + d->m_jobXml.insert(d->m_job, new QXmlStreamReader); + d->m_jobList.insert(d->m_job, source); - if (d->m_job) { - connect(d->m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this, - SLOT(slotDataArrived(KIO::Job *, const QByteArray &))); - connect(d->m_job, SIGNAL(result(KJob *)), this, SLOT(slotJobFinished(KJob *))); - } + if (d->m_job) { + connect(d->m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this, + SLOT(slotDataArrived(KIO::Job *, const QByteArray &))); + connect(d->m_job, SIGNAL(result(KJob *)), this, SLOT(slotJobFinished(KJob *))); } } @@ -186,9 +181,7 @@ { Q_UNUSED(job) readXMLSetup(); - - // Do the XML fetching for the correct city. - getXMLData(); + this->setInitialized(true); } // Parse the city list and store into a QMap @@ -261,11 +254,11 @@ } // Parse Weather data main loop, from here we have to decend into each tag pair -bool EnvCanadaIon::readXMLData(QString key, QXmlStreamReader& xml) +bool EnvCanadaIon::readXMLData(const QString& source, QXmlStreamReader& xml) { WeatherData data; data.comforttemp = "N/A"; - data.shortTerritoryName = d->m_place[key].territoryName; + data.shortTerritoryName = d->m_place[source].territoryName; while (!xml.atEnd()) { xml.readNext(); @@ -282,8 +275,8 @@ } } - d->m_weatherData[key] = data; - updateData(); + d->m_weatherData[source] = data; + updateWeather(source); return !xml.error(); } @@ -853,135 +846,124 @@ } } -void EnvCanadaIon::updateData() +void EnvCanadaIon::updateWeather(const QString& source) { - QVector sources; QMap dataFields; QStringList fieldList; QVector forecastList; int i = 0; - sources = this->ionSourceDict(); - foreach(QString keyname, sources) { - // Does this place exist? - if (!this->validLocation(keyname)) { - kDebug() << "EnvCanadaIon::updateData() " << keyname << " is not a valid location"; - //setData(keyname, "Invalid Place", "Invalid location"); - continue; - } - setData(keyname, "Country", this->country(keyname)); - setData(keyname, "Place", QString("%1, %2").arg(this->city(keyname)).arg(this->territory(keyname))); - setData(keyname, "Region", this->region(keyname)); - setData(keyname, "Airport Code", this->station(keyname)); + setData(source, "Country", this->country(source)); + setData(source, "Place", QString("%1, %2").arg(this->city(source)).arg(this->territory(source))); + setData(source, "Region", this->region(source)); + setData(source, "Airport Code", this->station(source)); - // Real weather - Current conditions - setData(keyname, "Observations At", this->observationTime(keyname)); - setData(keyname, "Current Conditions", this->condition(keyname)); - dataFields = this->temperature(keyname); - setData(keyname, "Temperature", dataFields["temperature"]); + // Real weather - Current conditions + setData(source, "Observations At", this->observationTime(source)); + setData(source, "Current Conditions", this->condition(source)); + dataFields = this->temperature(source); + setData(source, "Temperature", dataFields["temperature"]); - // Do we have a comfort temperature? if so display it - if (dataFields["comfortTemperature"] != "N/A" && !dataFields["comfortTemperature"].isEmpty()) { - if (dataFields["comfortTemperature"].toFloat() <= 0 || (dataFields["comfortTemperature"].toFloat() <= 32 && !d->m_useMetric)) { - setData(keyname, "Windchill", QString("%1%2").arg(dataFields["comfortTemperature"]).arg(QChar(176))); - } else { - setData(keyname, "Humidex", QString("%1%2").arg(dataFields["comfortTemperature"]).arg(QChar(176))); - } + // Do we have a comfort temperature? if so display it + if (dataFields["comfortTemperature"] != "N/A" && !dataFields["comfortTemperature"].isEmpty()) { + if (dataFields["comfortTemperature"].toFloat() <= 0 || (dataFields["comfortTemperature"].toFloat() <= 32 && !d->m_useMetric)) { + setData(source, "Windchill", QString("%1%2").arg(dataFields["comfortTemperature"]).arg(QChar(176))); + } else { + setData(source, "Humidex", QString("%1%2").arg(dataFields["comfortTemperature"]).arg(QChar(176))); } + } - setData(keyname, "Dewpoint", this->dewpoint(keyname)); - dataFields = this->pressure(keyname); - setData(keyname, "Pressure", dataFields["pressure"]); - setData(keyname, "Pressure Tendency", dataFields["pressureTendency"]); - setData(keyname, "Visibility", this->visibility(keyname)); - setData(keyname, "Humidity", this->humidity(keyname)); - dataFields = this->wind(keyname); - setData(keyname, "Wind Speed", dataFields["windSpeed"]); - setData(keyname, "Wind Speed Unit", dataFields["windUnit"]); - setData(keyname, "Wind Gust", dataFields["windGust"]); - setData(keyname, "Wind Gust Unit", dataFields["windGustUnit"]); - setData(keyname, "Wind Direction", dataFields["windDirection"]); + setData(source, "Dewpoint", this->dewpoint(source)); + dataFields = this->pressure(source); + setData(source, "Pressure", dataFields["pressure"]); + setData(source, "Pressure Tendency", dataFields["pressureTendency"]); + setData(source, "Visibility", this->visibility(source)); + setData(source, "Humidity", this->humidity(source)); + dataFields = this->wind(source); + setData(source, "Wind Speed", dataFields["windSpeed"]); + setData(source, "Wind Speed Unit", dataFields["windUnit"]); + setData(source, "Wind Gust", dataFields["windGust"]); + setData(source, "Wind Gust Unit", dataFields["windGustUnit"]); + setData(source, "Wind Direction", dataFields["windDirection"]); - dataFields = this->regionalTemperatures(keyname); - setData(keyname, "Normal High", dataFields["normalHigh"]); - setData(keyname, "Normal Low", dataFields["normalLow"]); + dataFields = this->regionalTemperatures(source); + setData(source, "Normal High", dataFields["normalHigh"]); + setData(source, "Normal Low", dataFields["normalLow"]); - // Check if UV index is available for the location - dataFields = this->uvIndex(keyname); - if (!dataFields["uvRating"].isEmpty()) { - setData(keyname, "UV Rating", dataFields["uvRating"]); - setData(keyname, "UV Index", dataFields["uvIndex"]); - } + // Check if UV index is available for the location + dataFields = this->uvIndex(source); + if (!dataFields["uvRating"].isEmpty()) { + setData(source, "UV Rating", dataFields["uvRating"]); + setData(source, "UV Index", dataFields["uvIndex"]); + } - dataFields = this->warnings(keyname); - // Check if we have warnings or watches - if (!dataFields["watch"].isEmpty()) { - fieldList = dataFields["watch"].split('|'); - setData(keyname, "Watch Priority", fieldList[0]); - setData(keyname, "Watch Description", fieldList[1]); - setData(keyname, "Watch Info", fieldList[2]); - setData(keyname, "Watch Timestamp", fieldList[3]); - } - if (!dataFields["warning"].isEmpty()) { - fieldList = dataFields["warning"].split('|'); - setData(keyname, "Warning Priority", fieldList[0]); - setData(keyname, "Warning Description", fieldList[1]); - setData(keyname, "Warning Info", fieldList[2]); - setData(keyname, "Warning Timestamp", fieldList[3]); - } + dataFields = this->warnings(source); + // Check if we have warnings or watches + if (!dataFields["watch"].isEmpty()) { + fieldList = dataFields["watch"].split('|'); + setData(source, "Watch Priority", fieldList[0]); + setData(source, "Watch Description", fieldList[1]); + setData(source, "Watch Info", fieldList[2]); + setData(source, "Watch Timestamp", fieldList[3]); + } + if (!dataFields["warning"].isEmpty()) { + fieldList = dataFields["warning"].split('|'); + setData(source, "Warning Priority", fieldList[0]); + setData(source, "Warning Description", fieldList[1]); + setData(source, "Warning Info", fieldList[2]); + setData(source, "Warning Timestamp", fieldList[3]); + } - forecastList = this->forecasts(keyname); - foreach(QString forecastItem, forecastList) { - fieldList = forecastItem.split('|'); + forecastList = this->forecasts(source); + foreach(QString forecastItem, forecastList) { + fieldList = forecastItem.split('|'); - if (d->m_useMetric) { - setData(keyname, QString("Short Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5") \ - .arg(fieldList[0]).arg(fieldList[1]).arg(fieldList[3]).arg(fieldList[4]).arg(fieldList[5])); + if (d->m_useMetric) { + setData(source, QString("Short Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5") \ + .arg(fieldList[0]).arg(fieldList[1]).arg(fieldList[3]).arg(fieldList[4]).arg(fieldList[5])); - setData(keyname, QString("Long Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5|%6|%7|%8") \ - .arg(fieldList[0]).arg(fieldList[2]).arg(fieldList[3]).arg(fieldList[4]).arg(fieldList[6]) \ - .arg(fieldList[7]).arg(fieldList[8]).arg(fieldList[9])); - } else { - setData(keyname, QString("Short Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5") \ - .arg(fieldList[0]).arg(fieldList[1]).arg(fieldList[3] == "N/A" ? "N/A" : \ - QString::number(d->m_formula.celsiusToF(fieldList[3].toFloat()), 'd', 0)) \ - .arg(fieldList[4] == "N/A" ? "N/A" : QString::number(d->m_formula.celsiusToF(fieldList[4].toFloat()),'d',0)).arg(fieldList[5])); + setData(source, QString("Long Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5|%6|%7|%8") \ + .arg(fieldList[0]).arg(fieldList[2]).arg(fieldList[3]).arg(fieldList[4]).arg(fieldList[6]) \ + .arg(fieldList[7]).arg(fieldList[8]).arg(fieldList[9])); + } else { + setData(source, QString("Short Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5") \ + .arg(fieldList[0]).arg(fieldList[1]).arg(fieldList[3] == "N/A" ? "N/A" : \ + QString::number(d->m_formula.celsiusToF(fieldList[3].toFloat()), 'd', 0)) \ + .arg(fieldList[4] == "N/A" ? "N/A" : QString::number(d->m_formula.celsiusToF(fieldList[4].toFloat()),'d',0)).arg(fieldList[5])); - setData(keyname, QString("Long Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5|%6|%7|%8") \ - .arg(fieldList[0]).arg(fieldList[2]).arg(fieldList[3] == "N/A" ? "N/A" : \ - QString::number(d->m_formula.celsiusToF(fieldList[3].toFloat()),'d', 0)) \ - .arg(fieldList[4] == "N/A" ? "N/A" : QString::number(d->m_formula.celsiusToF(fieldList[4].toFloat()),'d',0)).arg(fieldList[6]).arg(fieldList[7]) \ - .arg(fieldList[8]).arg(fieldList[9])); + setData(source, QString("Long Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5|%6|%7|%8") \ + .arg(fieldList[0]).arg(fieldList[2]).arg(fieldList[3] == "N/A" ? "N/A" : \ + QString::number(d->m_formula.celsiusToF(fieldList[3].toFloat()),'d', 0)) \ + .arg(fieldList[4] == "N/A" ? "N/A" : QString::number(d->m_formula.celsiusToF(fieldList[4].toFloat()),'d',0)).arg(fieldList[6]).arg(fieldList[7]) \ + .arg(fieldList[8]).arg(fieldList[9])); } i++; } - dataFields = this->yesterdayWeather(keyname); - setData(keyname, "Yesterday High", dataFields["prevHigh"]); - setData(keyname, "Yesterday Low", dataFields["prevLow"]); - setData(keyname, "Yesterday Precip Total", dataFields["prevPrecip"]); - setData(keyname, "Yesterday Precip Unit", dataFields["prevPrecipUnit"]); + dataFields = this->yesterdayWeather(source); + setData(source, "Yesterday High", dataFields["prevHigh"]); + setData(source, "Yesterday Low", dataFields["prevLow"]); + setData(source, "Yesterday Precip Total", dataFields["prevPrecip"]); + setData(source, "Yesterday Precip Unit", dataFields["prevPrecipUnit"]); - dataFields = this->sunriseSet(keyname); - setData(keyname, "Sunrise At", dataFields["sunrise"]); - setData(keyname, "Sunset At", dataFields["sunset"]); + dataFields = this->sunriseSet(source); + setData(source, "Sunrise At", dataFields["sunrise"]); + setData(source, "Sunset At", dataFields["sunset"]); - dataFields = this->moonriseSet(keyname); - setData(keyname, "Moonrise At", dataFields["moonrise"]); - setData(keyname, "Moonset At", dataFields["moonset"]); + dataFields = this->moonriseSet(source); + setData(source, "Moonrise At", dataFields["moonrise"]); + setData(source, "Moonset At", dataFields["moonset"]); - dataFields = this->weatherRecords(keyname); - setData(keyname, "Record High Temperature", dataFields["recordHigh"]); - setData(keyname, "Record Low Temperature", dataFields["recordLow"]); - setData(keyname, "Record Rainfall", dataFields["recordRain"]); - setData(keyname, "Record Rainfall Unit", dataFields["recordRainUnit"]); - setData(keyname, "Record Snowfall", dataFields["recordSnow"]); - setData(keyname, "Record Snowfall Unit", dataFields["recordSnowUnit"]); + dataFields = this->weatherRecords(source); + setData(source, "Record High Temperature", dataFields["recordHigh"]); + setData(source, "Record Low Temperature", dataFields["recordLow"]); + setData(source, "Record Rainfall", dataFields["recordRain"]); + setData(source, "Record Rainfall Unit", dataFields["recordRainUnit"]); + setData(source, "Record Snowfall", dataFields["recordSnow"]); + setData(source, "Record Snowfall Unit", dataFields["recordSnowUnit"]); - setData(keyname, "Credit", "Environment Canada"); - i = 0; - } + setData(source, "Credit", "Environment Canada"); } QString EnvCanadaIon::country(QString key) Index: ions/ion_envcan.h =================================================================== --- ions/ion_envcan.h (revision 724674) +++ ions/ion_envcan.h (working copy) @@ -129,9 +129,9 @@ EnvCanadaIon(QObject *parent, const QVariantList &args); ~EnvCanadaIon(); void init(); // Setup the city location, fetching the correct URL name. - void fetch(); // Get the City XML data. - void updateData(void); // Sync data source with Applet + bool updateIonSource(const QString& source); // Sync data source with Applet void option(int option, QVariant value); + void updateWeather(const QString& source); protected slots: void setup_slotDataArrived(KIO::Job *, const QByteArray &); @@ -173,8 +173,8 @@ bool readXMLSetup(); // Load and parse the specific place(s) - void getXMLData(); - bool readXMLData(QString key, QXmlStreamReader& xml); + void getXMLData(const QString& source); + bool readXMLData(const QString& source, QXmlStreamReader& xml); // Check if place specified is valid or not bool validLocation(QString key); Index: ions/ion.cpp =================================================================== --- ions/ion.cpp (revision 724674) +++ ions/ion.cpp (working copy) @@ -24,12 +24,14 @@ { public: Private(IonInterface *i) - : ion(i) {} + : ion(i), + initialized(false) + {} int ref; IonInterface *ion; bool valid; - QVector ionSource; // Array of this ions sources + bool initialized; }; IonInterface::IonInterface(QObject *parent) @@ -62,29 +64,35 @@ return d->valid; } -// Set the Ions datasource name listing. Used by weather dataengine -void IonInterface::setSource(QString key) +bool IonInterface::sourceRequested(const QString &source) { - if (!d->ionSource.contains(key)) { - d->ionSource.append(key); + setData(source, Plasma::DataEngine::Data()); + + if (d->initialized) { + this->updateSource(source); } + + return true; } -// Return an array of sources from a Ion -QVector IonInterface::ionSourceDict() const +bool IonInterface::updateSource(const QString& source) { - return d->ionSource; + kDebug() << "SOURCE IS = " << source; + if (d->initialized) { + this->updateIonSource(source); + return true; + } + + return false; } -// Deletes a datasource from the ion -void IonInterface::removeSource(QString key) +void IonInterface::setInitialized(bool initialized) { - QVector::iterator it; - for (it = d->ionSource.begin(); it != d->ionSource.end(); ++it) { - if (*it == key) { - kDebug() << "Going to remove: " << *it; - d->ionSource.erase(it); - break; - } - } + d->initialized = initialized; + + if (d->initialized) { + foreach (const QString &source, sources()) { + updateSource(source); + } + } } Index: ions/ion.h =================================================================== --- ions/ion.h (revision 724674) +++ ions/ion.h (working copy) @@ -51,16 +51,12 @@ * For example fetching the list of available cities or weather data sources should be fetched here. */ virtual void init(void) = 0; - /** - * Reimplement to do the fetching of weather data. - * This is being called just before calling updateData() - */ - virtual void fetch(void) = 0; /** * Increment ion counter. This is used to watch if the ion is being used. */ void ref(); + /** * Decrement ion counter. */ @@ -71,42 +67,42 @@ * @return true if the ion is being used, false otherwise */ bool isUsed() const; - + /** * Returns whether the ion is valid. Not used for now. * @return true if the ion is valid. */ bool isValid() const; + enum ionOptions { UNITS, TIMEFORMAT, WINDFORMAT }; /** - * Reimplement this to set the data to the engine by using setData() calls. - * You may have to force to call this method inside your ion everytime new data has been arrived from the fetching job. + * Reimplement to set the wanted options for the ion such as unit and time, and wind speed formats. */ - virtual void updateData(void) = 0; + virtual void option(int option, QVariant value) = 0; - /** - * Returns the source array. - * @return Returns the array of source the ion has. - */ - QVector ionSourceDict() const; - /** - * Set the datasource name to the array of sources - * @param key The name of the datasource - */ - void setSource(QString key); +public slots: + bool updateSource(const QString& source); +protected: /** - * Remove a datasource entry from the array - * @param key The name of the datasource - */ - void removeSource(QString key); + * Call this method to flush waiting source requests that may be pending + * initialization + * + * @arg initialized whether or not the ion is currently ready to fetch data + */ + void setInitialized(bool initialized); - enum ionOptions { UNITS, TIMEFORMAT, WINDFORMAT }; /** - * Reimplement to set the wanted options for the ion such as unit and time, and wind speed formats. - */ - virtual void option(int option, QVariant value) = 0; + * reimplemented from DataEngine + */ + bool sourceRequested(const QString &name); + /** + * Reimplement to fetch the data from the ion + * + */ + virtual bool updateIonSource(const QString &name) = 0; + private: class Private; Private* const d; Index: weatherengine.h =================================================================== --- weatherengine.h (revision 724674) +++ weatherengine.h (working copy) @@ -48,16 +48,16 @@ protected: // dataEngine method - We use it to communicate to the Ion plugins to set the data sources - bool sourceRequested(const QString &); + bool sourceRequested(const QString &source); protected slots: // SLOT: trigger to indicate new data is available from an Ion. There are two modes. // When using a timer no ion is specified, otherwise when loading an ion an ion is // specified. - void updateData(); void updated(const QString& source, Plasma::DataEngine::Data data); void newIonSource(const QString& source); void removeIonSource(const QString& source); + bool updateSource(const QString& source); private: class Private;