~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to plasma/generic/dataengines/weather/ions/envcan/ion_envcan.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *   Copyright (C) 2007-2009 by Shawn Starr <shawn.starr@rogers.com>       *
 
3
 *                                                                         *
 
4
 *   This program is free software; you can redistribute it and/or modify  *
 
5
 *   it under the terms of the GNU General Public License as published by  *
 
6
 *   the Free Software Foundation; either version 2 of the License, or     *
 
7
 *   (at your option) any later version.                                   *
 
8
 *                                                                         *
 
9
 *   This program is distributed in the hope that it will be useful,       *
 
10
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 
11
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 
12
 *   GNU General Public License for more details.                          *
 
13
 *                                                                         *
 
14
 *   You should have received a copy of the GNU General Public License     *
 
15
 *   along with this program; if not, write to the                         *
 
16
 *   Free Software Foundation, Inc.,                                       *
 
17
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
 
18
 ***************************************************************************/
 
19
 
 
20
/* Ion for Environment Canada XML data */
 
21
 
 
22
#include "ion_envcan.h"
 
23
 
 
24
#include <KIO/Job>
 
25
#include <KUnitConversion/Converter>
 
26
#include <Solid/Networking>
 
27
#include <Plasma/DataContainer>
 
28
 
 
29
 
 
30
// ctor, dtor
 
31
EnvCanadaIon::EnvCanadaIon(QObject *parent, const QVariantList &args)
 
32
        : IonInterface(parent, args)
 
33
{
 
34
}
 
35
 
 
36
void EnvCanadaIon::deleteForecasts()
 
37
{
 
38
    QMutableHashIterator<QString, WeatherData> it(m_weatherData);
 
39
    while (it.hasNext()) {
 
40
        it.next();
 
41
        WeatherData &item = it.value();
 
42
        qDeleteAll(item.warnings);
 
43
        item.warnings.clear();
 
44
 
 
45
        qDeleteAll(item.watches);
 
46
        item.watches.clear();
 
47
 
 
48
        qDeleteAll(item.forecasts);
 
49
        item.forecasts.clear();
 
50
    }
 
51
}
 
52
 
 
53
void EnvCanadaIon::reset()
 
54
{
 
55
    deleteForecasts();
 
56
    emitWhenSetup = true;
 
57
    m_sourcesToReset = sources();
 
58
    getXMLSetup();
 
59
}
 
60
 
 
61
EnvCanadaIon::~EnvCanadaIon()
 
62
{
 
63
    // Destroy each watch/warning stored in a QVector
 
64
    deleteForecasts();
 
65
}
 
66
 
 
67
// Get the master list of locations to be parsed
 
68
void EnvCanadaIon::init()
 
69
{
 
70
    // Get the real city XML URL so we can parse this
 
71
    getXMLSetup();
 
72
    m_timeEngine = dataEngine("time");
 
73
}
 
74
 
 
75
QMap<QString, IonInterface::ConditionIcons> EnvCanadaIon::setupConditionIconMappings(void) const
 
76
{
 
77
    QMap<QString, ConditionIcons> conditionList;
 
78
 
 
79
    // Explicit periods
 
80
    conditionList["mainly sunny"] = FewCloudsDay;
 
81
    conditionList["mainly clear"] = FewCloudsNight;
 
82
    conditionList["sunny"] = ClearDay;
 
83
    conditionList["clear"] = ClearNight;
 
84
 
 
85
    // Available conditions
 
86
    conditionList["blowing snow"] = Snow;
 
87
    conditionList["cloudy"] = Overcast;
 
88
    conditionList["distant precipitation"] = LightRain;
 
89
    conditionList["drifting snow"] = Flurries;
 
90
    conditionList["drizzle"] = LightRain;
 
91
    conditionList["dust"] = NotAvailable;
 
92
    conditionList["dust devils"] = NotAvailable;
 
93
    conditionList["fog"] = Mist;
 
94
    conditionList["fog bank near station"] = Mist;
 
95
    conditionList["fog depositing ice"] = Mist;
 
96
    conditionList["fog patches"] = Mist;
 
97
    conditionList["freezing drizzle"] = FreezingDrizzle;
 
98
    conditionList["freezing rain"] = FreezingRain;
 
99
    conditionList["funnel cloud"] = NotAvailable;
 
100
    conditionList["hail"] = Hail;
 
101
    conditionList["haze"] = Haze;
 
102
    conditionList["heavy blowing snow"] = Snow;
 
103
    conditionList["heavy drifting snow"] = Snow;
 
104
    conditionList["heavy drizzle"] = LightRain;
 
105
    conditionList["heavy hail"] = Hail;
 
106
    conditionList["heavy mixed rain and drizzle"] = LightRain;
 
107
    conditionList["heavy mixed rain and snow shower"] = RainSnow;
 
108
    conditionList["heavy rain"] = Rain;
 
109
    conditionList["heavy rain and snow"] = RainSnow;
 
110
    conditionList["heavy rainshower"] = Rain;
 
111
    conditionList["heavy snow"] = Snow;
 
112
    conditionList["heavy snow pellets"] = Snow;
 
113
    conditionList["heavy snowshower"] = Snow;
 
114
    conditionList["heavy thunderstorm with hail"] = Thunderstorm;
 
115
    conditionList["heavy thunderstorm with rain"] = Thunderstorm;
 
116
    conditionList["ice crystals"] = Flurries;
 
117
    conditionList["ice pellets"] = Hail;
 
118
    conditionList["increasing cloud"] = Overcast;
 
119
    conditionList["light drizzle"] = LightRain;
 
120
    conditionList["light freezing drizzle"] = FreezingRain;
 
121
    conditionList["light freezing rain"] = FreezingRain;
 
122
    conditionList["light rain"] = LightRain;
 
123
    conditionList["light rainshower"] = LightRain;
 
124
    conditionList["light snow"] = LightSnow;
 
125
    conditionList["light snow pellets"] = LightSnow;
 
126
    conditionList["light snowshower"] = Flurries;
 
127
    conditionList["lightning visible"] = Thunderstorm;
 
128
    conditionList["mist"] = Mist;
 
129
    conditionList["mixed rain and drizzle"] = LightRain;
 
130
    conditionList["mixed rain and snow shower"] = RainSnow;
 
131
    conditionList["not reported"] = NotAvailable;
 
132
    conditionList["rain"] = Rain;
 
133
    conditionList["rain and snow"] = RainSnow;
 
134
    conditionList["rainshower"] = LightRain;
 
135
    conditionList["recent drizzle"] = LightRain;
 
136
    conditionList["recent dust or sand storm"] = NotAvailable;
 
137
    conditionList["recent fog"] = Mist;
 
138
    conditionList["recent freezing precipitation"] = FreezingDrizzle;
 
139
    conditionList["recent hail"] = Hail;
 
140
    conditionList["recent rain"] = Rain;
 
141
    conditionList["recent rain and snow"] = RainSnow;
 
142
    conditionList["recent rainshower"] = Rain;
 
143
    conditionList["recent snow"] = Snow;
 
144
    conditionList["recent snowshower"] = Flurries;
 
145
    conditionList["recent thunderstorm"] = Thunderstorm;
 
146
    conditionList["recent thunderstorm with hail"] = Thunderstorm;
 
147
    conditionList["recent thunderstorm with heavy hail"] = Thunderstorm;
 
148
    conditionList["recent thunderstorm with heavy rain"] = Thunderstorm;
 
149
    conditionList["recent thunderstorm with rain"] = Thunderstorm;
 
150
    conditionList["sand or dust storm"] = NotAvailable;
 
151
    conditionList["severe sand or dust storm"] = NotAvailable;
 
152
    conditionList["shallow fog"] = Mist;
 
153
    conditionList["smoke"] = NotAvailable;
 
154
    conditionList["snow"] = Snow;
 
155
    conditionList["snow crystals"] = Flurries;
 
156
    conditionList["snow grains"] = Flurries;
 
157
    conditionList["squalls"] = Snow;
 
158
    conditionList["thunderstorm with hail"] = Thunderstorm;
 
159
    conditionList["thunderstorm with rain"] = Thunderstorm;
 
160
    conditionList["thunderstorm with sand or dust storm"] = Thunderstorm;
 
161
    conditionList["thunderstorm without precipitation"] = Thunderstorm;
 
162
    conditionList["tornado"] = NotAvailable;
 
163
    return conditionList;
 
164
}
 
165
 
 
166
 
 
167
QMap<QString, IonInterface::ConditionIcons> EnvCanadaIon::setupForecastIconMappings(void) const
 
168
{
 
169
    QMap<QString, ConditionIcons> forecastList;
 
170
 
 
171
    // Abbreviated forecast descriptions
 
172
    forecastList["a few flurries"] = Flurries;
 
173
    forecastList["a few flurries mixed with ice pellets"] = RainSnow;
 
174
    forecastList["a few flurries or rain showers"] = RainSnow;
 
175
    forecastList["a few flurries or thundershowers"] = RainSnow;
 
176
    forecastList["a few rain showers or flurries"] = RainSnow;
 
177
    forecastList["a few rain showers or wet flurries"] = RainSnow;
 
178
    forecastList["a few showers"] = LightRain;
 
179
    forecastList["a few showers or drizzle"] = LightRain;
 
180
    forecastList["a few showers or thundershowers"] = Thunderstorm;
 
181
    forecastList["a few showers or thunderstorms"] = Thunderstorm;
 
182
    forecastList["a few thundershowers"] = Thunderstorm;
 
183
    forecastList["a few thunderstorms"] = Thunderstorm;
 
184
    forecastList["a few wet flurries"] = RainSnow;
 
185
    forecastList["a few wet flurries or rain showers"] = RainSnow;
 
186
    forecastList["a mix of sun and cloud"] = PartlyCloudyDay;
 
187
    forecastList["cloudy with sunny periods"] = PartlyCloudyDay;
 
188
    forecastList["sunny"] = ClearDay;
 
189
    forecastList["blizzard"] = Snow;
 
190
    forecastList["clear"] = ClearNight;
 
191
    forecastList["cloudy"] = Overcast;
 
192
    forecastList["drizzle"] = LightRain;
 
193
    forecastList["drizzle mixed with freezing drizzle"] = FreezingDrizzle;
 
194
    forecastList["drizzle mixed with rain"] = LightRain;
 
195
    forecastList["drizzle or freezing drizzle"] = LightRain;
 
196
    forecastList["drizzle or rain"] = LightRain;
 
197
    forecastList["flurries"] = Flurries;
 
198
    forecastList["flurries at times heavy"] = Flurries;
 
199
    forecastList["flurries at times heavy or rain snowers"] = RainSnow;
 
200
    forecastList["flurries mixed with ice pellets"] = FreezingRain;
 
201
    forecastList["flurries or ice pellets"] = FreezingRain;
 
202
    forecastList["flurries or rain showers"] = RainSnow;
 
203
    forecastList["flurries or thundershowers"] = Flurries;
 
204
    forecastList["fog"] = Mist;
 
205
    forecastList["fog developing"] = Mist;
 
206
    forecastList["fog dissipating"] = Mist;
 
207
    forecastList["fog patches"] = Mist;
 
208
    forecastList["freezing drizzle"] = FreezingDrizzle;
 
209
    forecastList["freezing rain"] = FreezingRain;
 
210
    forecastList["freezing rain mixed with rain"] = FreezingRain;
 
211
    forecastList["freezing rain mixed with snow"] = FreezingRain;
 
212
    forecastList["freezing rain or ice pellets"] = FreezingRain;
 
213
    forecastList["freezing rain or rain"] = FreezingRain;
 
214
    forecastList["freezing rain or snow"] = FreezingRain;
 
215
    forecastList["ice fog"] = Mist;
 
216
    forecastList["ice fog developing"] = Mist;
 
217
    forecastList["ice fog dissipating"] = Mist;
 
218
    forecastList["ice pellet"] = Hail;
 
219
    forecastList["ice pellet mixed with freezing rain"] = Hail;
 
220
    forecastList["ice pellet mixed with snow"] = Hail;
 
221
    forecastList["ice pellet or snow"] = RainSnow;
 
222
    forecastList["light snow"] = LightSnow;
 
223
    forecastList["light snow and blizzard"] = LightSnow;
 
224
    forecastList["light snow and blizzard and blowing snow"] = Snow;
 
225
    forecastList["light snow and blowing snow"] = LightSnow;
 
226
    forecastList["light snow mixed with freezing drizzle"] = FreezingDrizzle;
 
227
    forecastList["light snow mixed with freezing rain"] = FreezingRain;
 
228
    forecastList["light snow or ice pellets"] = LightSnow;
 
229
    forecastList["light snow or rain"] = RainSnow;
 
230
    forecastList["light wet snow"] = RainSnow;
 
231
    forecastList["light wet snow or rain"] = RainSnow;
 
232
    forecastList["local snow squalls"] = Snow;
 
233
    forecastList["near blizzard"] = Snow;
 
234
    forecastList["overcast"] = Overcast;
 
235
    forecastList["increasing cloudiness"] = Overcast;
 
236
    forecastList["increasing clouds"] = Overcast;
 
237
    forecastList["periods of drizzle"] = LightRain;
 
238
    forecastList["periods of drizzle mixed with freezing drizzle"] = FreezingDrizzle;
 
239
    forecastList["periods of drizzle mixed with rain"] = LightRain;
 
240
    forecastList["periods of drizzle or freezing drizzle"] = FreezingDrizzle;
 
241
    forecastList["periods of drizzle or rain"] = LightRain;
 
242
    forecastList["periods of freezing drizzle"] = FreezingDrizzle;
 
243
    forecastList["periods of freezing drizzle or drizzle"] = FreezingDrizzle;
 
244
    forecastList["periods of freezing drizzle or rain"] = FreezingDrizzle;
 
245
    forecastList["periods of freezing rain"] = FreezingRain;
 
246
    forecastList["periods of freezing rain mixed with ice pellets"] = FreezingRain;
 
247
    forecastList["periods of freezing rain mixed with rain"] = FreezingRain;
 
248
    forecastList["periods of freezing rain mixed with snow"] = FreezingRain;
 
249
    forecastList["periods of freezing rain mixed with freezing drizzle"] = FreezingRain;
 
250
    forecastList["periods of freezing rain or ice pellets"] = FreezingRain;
 
251
    forecastList["periods of freezing rain or rain"] = FreezingRain;
 
252
    forecastList["periods of freezing rain or snow"] = FreezingRain;
 
253
    forecastList["periods of ice pellet"] = Hail;
 
254
    forecastList["periods of ice pellet mixed with freezing rain"] = Hail;
 
255
    forecastList["periods of ice pellet mixed with snow"] = Hail;
 
256
    forecastList["periods of ice pellet or freezing rain"] = Hail;
 
257
    forecastList["periods of ice pellet or snow"] = Hail;
 
258
    forecastList["periods of light snow"] = LightSnow;
 
259
    forecastList["periods of light snow and blizzard"] = Snow;
 
260
    forecastList["periods of light snow and blizzard and blowing snow"] = Snow;
 
261
    forecastList["periods of light snow and blowing snow"] = LightSnow;
 
262
    forecastList["periods of light snow mixed with freezing drizzle"] = RainSnow;
 
263
    forecastList["periods of light snow mixed with freezing rain"] = RainSnow;
 
264
    forecastList["periods of light snow mixed with ice pelletS"] = LightSnow;
 
265
    forecastList["periods of light snow mixed with rain"] = RainSnow;
 
266
    forecastList["periods of light snow or freezing drizzle"] = RainSnow;
 
267
    forecastList["periods of light snow or freezing rain"] = RainSnow;
 
268
    forecastList["periods of light snow or ice pellets"] = LightSnow;
 
269
    forecastList["periods of light snow or rain"] = RainSnow;
 
270
    forecastList["periods of light wet snow"] = LightSnow;
 
271
    forecastList["periods of light wet snow mixed with rain"] = RainSnow;
 
272
    forecastList["periods of light wet snow or rain"] = RainSnow;
 
273
    forecastList["periods of rain"] = Rain;
 
274
    forecastList["periods of rain mixed with freezing rain"] = Rain;
 
275
    forecastList["periods of rain mixed with snow"] = RainSnow;
 
276
    forecastList["periods of rain or drizzle"] = Rain;
 
277
    forecastList["periods of rain or freezing rain"] = Rain;
 
278
    forecastList["periods of rain or thundershowers"] = Showers;
 
279
    forecastList["periods of rain or thunderstorms"] = Thunderstorm;
 
280
    forecastList["periods of rain or snow"] = RainSnow;
 
281
    forecastList["periods of snow"] = Snow;
 
282
    forecastList["periods of snow and blizzard"] = Snow;
 
283
    forecastList["periods of snow and blizzard and blowing snow"] = Snow;
 
284
    forecastList["periods of snow and blowing snow"] = Snow;
 
285
    forecastList["periods of snow mixed with freezing drizzle"] = RainSnow;
 
286
    forecastList["periods of snow mixed with freezing rain"] = RainSnow;
 
287
    forecastList["periods of snow mixed with ice pellets"] = Snow;
 
288
    forecastList["periods of snow mixed with rain"] = RainSnow;
 
289
    forecastList["periods of snow or freezing drizzle"] = RainSnow;
 
290
    forecastList["periods of snow or freezing rain"] = RainSnow;
 
291
    forecastList["periods of snow or ice pellets"] = Snow;
 
292
    forecastList["periods of snow or rain"] = RainSnow;
 
293
    forecastList["periods of rain or snow"] = RainSnow;
 
294
    forecastList["periods of wet snow"] = Snow;
 
295
    forecastList["periods of wet snow mixed with rain"] = RainSnow;
 
296
    forecastList["periods of wet snow or rain"] = RainSnow;
 
297
    forecastList["rain"] = Rain;
 
298
    forecastList["rain at times heavy"] = Rain;
 
299
    forecastList["rain at times heavy mixed with freezing rain"] = FreezingRain;
 
300
    forecastList["rain at times heavy mixed with snow"] = RainSnow;
 
301
    forecastList["rain at times heavy or drizzle"] = Rain;
 
302
    forecastList["rain at times heavy or freezing rain"] = Rain;
 
303
    forecastList["rain at times heavy or snow"] = RainSnow;
 
304
    forecastList["rain at times heavy or thundershowers"] = Showers;
 
305
    forecastList["rain at times heavy or thunderstorms"] = Thunderstorm;
 
306
    forecastList["rain mixed with freezing rain"] = FreezingRain;
 
307
    forecastList["rain mixed with snow"] = RainSnow;
 
308
    forecastList["rain or drizzle"] = Rain;
 
309
    forecastList["rain or freezing rain"] = Rain;
 
310
    forecastList["rain or snow"] = RainSnow;
 
311
    forecastList["rain or thundershowers"] = Showers;
 
312
    forecastList["rain or thunderstorms"] = Thunderstorm;
 
313
    forecastList["rain showers or flurries"] = RainSnow;
 
314
    forecastList["rain showers or wet flurries"] = RainSnow;
 
315
    forecastList["showers"] = Showers;
 
316
    forecastList["showers at times heavy"] = Showers;
 
317
    forecastList["showers at times heavy or thundershowers"] = Showers;
 
318
    forecastList["showers at times heavy or thunderstorms"] = Thunderstorm;
 
319
    forecastList["showers or drizzle"] = Showers;
 
320
    forecastList["showers or thundershowers"] = Thunderstorm;
 
321
    forecastList["showers or thunderstorms"] = Thunderstorm;
 
322
    forecastList["smoke"] = NotAvailable;
 
323
    forecastList["snow"] = Snow;
 
324
    forecastList["snow and blizzard"] = Snow;
 
325
    forecastList["snow and blizzard and blowing snow"] = Snow;
 
326
    forecastList["snow and blowing snow"] = Snow;
 
327
    forecastList["snow at times heavy"] = Snow;
 
328
    forecastList["snow at times heavy and blizzard"] = Snow;
 
329
    forecastList["snow at times heavy and blowing snow"] = Snow;
 
330
    forecastList["snow at times heavy mixed with freezing drizzle"] = RainSnow;
 
331
    forecastList["snow at times heavy mixed with freezing rain"] = RainSnow;
 
332
    forecastList["snow at times heavy mixed with ice pellets"] = Snow;
 
333
    forecastList["snow at times heavy mixed with rain"] = RainSnow;
 
334
    forecastList["snow at times heavy or freezing rain"] = RainSnow;
 
335
    forecastList["snow at times heavy or ice pellets"] = Snow;
 
336
    forecastList["snow at times heavy or rain"] = RainSnow;
 
337
    forecastList["snow mixed with freezing drizzle"] = RainSnow;
 
338
    forecastList["snow mixed with freezing rain"] = RainSnow;
 
339
    forecastList["snow mixed with ice pellets"] = Snow;
 
340
    forecastList["snow mixed with rain"] = RainSnow;
 
341
    forecastList["snow or freezing drizzle"] = RainSnow;
 
342
    forecastList["snow or freezing rain"] = RainSnow;
 
343
    forecastList["snow or ice pellets"] = Snow;
 
344
    forecastList["snow or rain"] = RainSnow;
 
345
    forecastList["snow squalls"] = Snow;
 
346
    forecastList["sunny"] = ClearDay;
 
347
    forecastList["sunny with cloudy periods"] = PartlyCloudyDay;
 
348
    forecastList["thunderstorms"] = Thunderstorm;
 
349
    forecastList["thunderstorms and possible hail"] = Thunderstorm;
 
350
    forecastList["wet flurries"] = Flurries;
 
351
    forecastList["wet flurries at times heavy"] = Flurries;
 
352
    forecastList["wet flurries at times heavy or rain snowers"] = RainSnow;
 
353
    forecastList["wet flurries or rain showers"] = RainSnow;
 
354
    forecastList["wet snow"] = Snow;
 
355
    forecastList["wet snow at times heavy"] = Snow;
 
356
    forecastList["wet snow at times heavy mixed with rain"] = RainSnow;
 
357
    forecastList["wet snow mixed with rain"] = RainSnow;
 
358
    forecastList["wet snow or rain"] = RainSnow;
 
359
    forecastList["windy"] = NotAvailable;
 
360
 
 
361
    forecastList["chance of drizzle mixed with freezing drizzle"] = LightRain;
 
362
    forecastList["chance of flurries mixed with ice pellets"] = Flurries;
 
363
    forecastList["chance of flurries or ice pellets"] = Flurries;
 
364
    forecastList["chance of flurries or rain showers"] = RainSnow;
 
365
    forecastList["chance of flurries or thundershowers"] = RainSnow;
 
366
    forecastList["chance of freezing drizzle"] = FreezingDrizzle;
 
367
    forecastList["chance of freezing rain"] = FreezingRain;
 
368
    forecastList["chance of freezing rain mixed with snow"] = RainSnow;
 
369
    forecastList["chance of freezing rain or rain"] = FreezingRain;
 
370
    forecastList["chance of freezing rain or snow"] = RainSnow;
 
371
    forecastList["chance of light snow and blowing snow"] = LightSnow;
 
372
    forecastList["chance of light snow mixed with freezing drizzle"] = LightSnow;
 
373
    forecastList["chance of light snow mixed with ice pellets"] = LightSnow;
 
374
    forecastList["chance of light snow mixed with rain"] = RainSnow;
 
375
    forecastList["chance of light snow or freezing rain"] = RainSnow;
 
376
    forecastList["chance of light snow or ice pellets"] = LightSnow;
 
377
    forecastList["chance of light snow or rain"] = RainSnow;
 
378
    forecastList["chance of light wet snow"] = Snow;
 
379
    forecastList["chance of rain"] = Rain;
 
380
    forecastList["chance of rain at times heavy"] = Rain;
 
381
    forecastList["chance of rain mixed with snow"] = RainSnow;
 
382
    forecastList["chance of rain or drizzle"] = Rain;
 
383
    forecastList["chance of rain or freezing rain"] = Rain;
 
384
    forecastList["chance of rain or snow"] = RainSnow;
 
385
    forecastList["chance of rain showers or flurries"] = RainSnow;
 
386
    forecastList["chance of rain showers or wet flurries"] = RainSnow;
 
387
    forecastList["chance of severe thunderstorms"] = Thunderstorm;
 
388
    forecastList["chance of showers at times heavy"] = Rain;
 
389
    forecastList["chance of showers at times heavy or thundershowers"] = Thunderstorm;
 
390
    forecastList["chance of showers at times heavy or thunderstorms"] = Thunderstorm;
 
391
    forecastList["chance of showers or thundershowers"] = Thunderstorm;
 
392
    forecastList["chance of showers or thunderstorms"] = Thunderstorm;
 
393
    forecastList["chance of snow"] = Snow;
 
394
    forecastList["chance of snow and blizzard"] = Snow;
 
395
    forecastList["chance of snow mixed with freezing drizzle"] = Snow;
 
396
    forecastList["chance of snow mixed with freezing rain"] = RainSnow;
 
397
    forecastList["chance of snow mixed with rain"] = RainSnow;
 
398
    forecastList["chance of snow or rain"] = RainSnow;
 
399
    forecastList["chance of snow squalls"] = Snow;
 
400
    forecastList["chance of thundershowers"] = Showers;
 
401
    forecastList["chance of thunderstorms"] = Thunderstorm;
 
402
    forecastList["chance of thunderstorms and possible hail"] = Thunderstorm;
 
403
    forecastList["chance of wet flurries"] = Flurries;
 
404
    forecastList["chance of wet flurries at times heavy"] = Flurries;
 
405
    forecastList["chance of wet flurries or rain showers"] = RainSnow;
 
406
    forecastList["chance of wet snow"] = Snow;
 
407
    forecastList["chance of wet snow mixed with rain"] = RainSnow;
 
408
    forecastList["chance of wet snow or rain"] = RainSnow;
 
409
 
 
410
    return forecastList;
 
411
}
 
412
 
 
413
QMap<QString, IonInterface::ConditionIcons> const& EnvCanadaIon::conditionIcons(void) const
 
414
{
 
415
    static QMap<QString, ConditionIcons> const condval = setupConditionIconMappings();
 
416
    return condval;
 
417
}
 
418
 
 
419
QMap<QString, IonInterface::ConditionIcons> const& EnvCanadaIon::forecastIcons(void) const
 
420
{
 
421
    static QMap<QString, ConditionIcons> const foreval = setupForecastIconMappings();
 
422
    return foreval;
 
423
}
 
424
 
 
425
QStringList EnvCanadaIon::validate(const QString& source) const
 
426
{
 
427
    QStringList placeList;
 
428
    QString sourceNormalized = source.toUpper();
 
429
    QHash<QString, EnvCanadaIon::XMLMapInfo>::const_iterator it = m_places.constBegin();
 
430
    while (it != m_places.constEnd()) {
 
431
        if (it.key().toUpper().contains(sourceNormalized)) {
 
432
            placeList.append(QString("place|").append(it.key()));
 
433
        }
 
434
        ++it;
 
435
    }
 
436
 
 
437
    // Check if placeList is empty if so, return nothing.
 
438
    if (placeList.isEmpty()) {
 
439
        return QStringList();
 
440
    }
 
441
    placeList.sort();
 
442
    return placeList;
 
443
}
 
444
 
 
445
// Get a specific Ion's data
 
446
bool EnvCanadaIon::updateIonSource(const QString& source)
 
447
{
 
448
    //kDebug() << "updateIonSource()" << source;
 
449
 
 
450
    // We expect the applet to send the source in the following tokenization:
 
451
    // ionname|validate|place_name - Triggers validation of place
 
452
    // ionname|weather|place_name - Triggers receiving weather of place
 
453
 
 
454
    QStringList sourceAction = source.split('|');
 
455
 
 
456
    // Guard: if the size of array is not 2 then we have bad data, return an error
 
457
    if (sourceAction.size() < 2) {
 
458
        setData(source, "validate", "envcan|malformed");
 
459
        return true;
 
460
    }
 
461
 
 
462
    if (sourceAction[1] == "validate" && sourceAction.size() > 2) {
 
463
        QStringList result = validate(sourceAction[2]);
 
464
 
 
465
        if (result.size() == 1) {
 
466
            setData(source, "validate", QString("envcan|valid|single|").append(result.join("|")));
 
467
            return true;
 
468
        } else if (result.size() > 1) {
 
469
            setData(source, "validate", QString("envcan|valid|multiple|").append(result.join("|")));
 
470
            return true;
 
471
        } else if (result.size() == 0) {
 
472
            setData(source, "validate", QString("envcan|invalid|single|").append(sourceAction[2]));
 
473
            return true;
 
474
        }
 
475
 
 
476
    } else if (sourceAction[1] == "weather" && sourceAction.size() > 2) {
 
477
        getXMLData(source);
 
478
        return true;
 
479
    } else {
 
480
        setData(source, "validate", "envcan|malformed");
 
481
        return true;
 
482
    }
 
483
    return false;
 
484
}
 
485
 
 
486
// Parses city list and gets the correct city based on ID number
 
487
void EnvCanadaIon::getXMLSetup()
 
488
{
 
489
    //kDebug() << "getXMLSetup()";
 
490
 
 
491
    // If network is down, we need to spin and wait
 
492
 
 
493
    KIO::TransferJob *job = KIO::get(KUrl("http://dd.weatheroffice.ec.gc.ca/citypage_weather/xml/siteList.xml"), KIO::NoReload, KIO::HideProgressInfo);
 
494
 
 
495
    m_xmlSetup.clear();
 
496
    connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
 
497
            SLOT(setup_slotDataArrived(KIO::Job *, const QByteArray &)));
 
498
    connect(job, SIGNAL(result(KJob *)), this, SLOT(setup_slotJobFinished(KJob *)));
 
499
}
 
500
 
 
501
// Gets specific city XML data
 
502
void EnvCanadaIon::getXMLData(const QString& source)
 
503
{
 
504
    foreach (const QString &fetching, m_jobList) {
 
505
        if (fetching == source) {
 
506
            // already getting this source and awaiting the data
 
507
            return;
 
508
        }
 
509
    }
 
510
 
 
511
    //kDebug() << source;
 
512
 
 
513
    // Demunge source name for key only.
 
514
    QString dataKey = source;
 
515
    dataKey.remove("envcan|weather|");
 
516
 
 
517
    KUrl url = QString("http://dd.weatheroffice.ec.gc.ca/citypage_weather/xml/" + m_places[dataKey].territoryName + "/" + m_places[dataKey].cityCode + "_e.xml");
 
518
    //url="file:///home/spstarr/Desktop/s0000649_e.xml";
 
519
    //kDebug() << "Will Try URL: " << url;
 
520
 
 
521
    if (m_places[dataKey].territoryName.isEmpty() && m_places[dataKey].cityCode.isEmpty()) {
 
522
        setData(source, "validate", QString("envcan|malformed"));
 
523
        return;
 
524
    }
 
525
 
 
526
    KIO::TransferJob* const newJob  = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo);
 
527
 
 
528
    m_jobXml.insert(newJob, new QXmlStreamReader);
 
529
    m_jobList.insert(newJob, source);
 
530
 
 
531
    connect(newJob, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
 
532
            SLOT(slotDataArrived(KIO::Job *, const QByteArray &)));
 
533
    connect(newJob, SIGNAL(result(KJob *)), this, SLOT(slotJobFinished(KJob *)));
 
534
}
 
535
 
 
536
void EnvCanadaIon::setup_slotDataArrived(KIO::Job *job, const QByteArray &data)
 
537
{
 
538
    Q_UNUSED(job)
 
539
 
 
540
    if (data.isEmpty()) {
 
541
        //kDebug() << "done!";
 
542
        return;
 
543
    }
 
544
 
 
545
    // Send to xml.
 
546
    //kDebug() << data;
 
547
    m_xmlSetup.addData(data);
 
548
}
 
549
 
 
550
void EnvCanadaIon::slotDataArrived(KIO::Job *job, const QByteArray &data)
 
551
{
 
552
 
 
553
    if (data.isEmpty() || !m_jobXml.contains(job)) {
 
554
        return;
 
555
    }
 
556
 
 
557
    // Send to xml.
 
558
    m_jobXml[job]->addData(data);
 
559
}
 
560
 
 
561
void EnvCanadaIon::slotJobFinished(KJob *job)
 
562
{
 
563
    // Dual use method, if we're fetching location data to parse we need to do this first
 
564
    const QString source = m_jobList.value(job);
 
565
    //kDebug() << source << m_sourcesToReset.contains(source);
 
566
    setData(source, Data());
 
567
    QXmlStreamReader *reader = m_jobXml.value(job);
 
568
    if (reader) {
 
569
        readXMLData(m_jobList[job], *reader);
 
570
    }
 
571
 
 
572
    m_jobList.remove(job);
 
573
    delete m_jobXml[job];
 
574
    m_jobXml.remove(job);
 
575
 
 
576
    if (m_sourcesToReset.contains(source)) {
 
577
        m_sourcesToReset.removeAll(source);
 
578
 
 
579
        // so the weather engine updates it's data
 
580
        forceImmediateUpdateOfAllVisualizations();
 
581
 
 
582
        // update the clients of our engine
 
583
        emit forceUpdate(this, source);
 
584
    }
 
585
}
 
586
 
 
587
void EnvCanadaIon::setup_slotJobFinished(KJob *job)
 
588
{
 
589
    Q_UNUSED(job)
 
590
    const bool success = readXMLSetup();
 
591
    m_xmlSetup.clear();
 
592
    //kDebug() << success << m_sourcesToReset;
 
593
    setInitialized(success);
 
594
}
 
595
 
 
596
// Parse the city list and store into a QMap
 
597
bool EnvCanadaIon::readXMLSetup()
 
598
{
 
599
    bool success = false;
 
600
    QString territory;
 
601
    QString code;
 
602
    QString cityName;
 
603
 
 
604
    //kDebug() << "readXMLSetup()";
 
605
 
 
606
    while (!m_xmlSetup.atEnd()) {
 
607
        m_xmlSetup.readNext();
 
608
 
 
609
        if (m_xmlSetup.isStartElement()) {
 
610
 
 
611
            // XML ID code to match filename
 
612
            if (m_xmlSetup.name() == "site") {
 
613
                code = m_xmlSetup.attributes().value("code").toString();
 
614
            }
 
615
 
 
616
            if (m_xmlSetup.name() == "nameEn") {
 
617
                cityName = m_xmlSetup.readElementText(); // Name of cities
 
618
            }
 
619
 
 
620
            if (m_xmlSetup.name() == "provinceCode") {
 
621
                territory = m_xmlSetup.readElementText(); // Provinces/Territory list
 
622
            }
 
623
        }
 
624
 
 
625
        if (m_xmlSetup.isEndElement() && m_xmlSetup.name() == "site") {
 
626
            EnvCanadaIon::XMLMapInfo info;
 
627
            QString tmp = cityName + ", " + territory; // Build the key name.
 
628
 
 
629
            // Set the mappings
 
630
            info.cityCode = code;
 
631
            info.territoryName = territory;
 
632
            info.cityName = cityName;
 
633
 
 
634
            // Set the string list, we will use for the applet to display the available cities.
 
635
            m_places[tmp] = info;
 
636
            success = true;
 
637
        }
 
638
 
 
639
    }
 
640
 
 
641
    return (success && !m_xmlSetup.error());
 
642
}
 
643
 
 
644
void EnvCanadaIon::parseWeatherSite(WeatherData& data, QXmlStreamReader& xml)
 
645
{
 
646
    while (!xml.atEnd()) {
 
647
        xml.readNext();
 
648
 
 
649
        if (xml.isStartElement()) {
 
650
            if (xml.name() == "license") {
 
651
                xml.readElementText();
 
652
            } else if (xml.name() == "location") {
 
653
                parseLocations(data, xml);
 
654
            } else if (xml.name() == "warnings") {
 
655
                // Cleanup warning list on update
 
656
                data.warnings.clear();
 
657
                data.watches.clear();
 
658
                parseWarnings(data, xml);
 
659
            } else if (xml.name() == "currentConditions") {
 
660
                parseConditions(data, xml);
 
661
            } else if (xml.name() == "forecastGroup") {
 
662
                // Clean up forecast list on update
 
663
                data.forecasts.clear();
 
664
                parseWeatherForecast(data, xml);
 
665
            } else if (xml.name() == "yesterdayConditions") {
 
666
                parseYesterdayWeather(data, xml);
 
667
            } else if (xml.name() == "riseSet") {
 
668
                parseAstronomicals(data, xml);
 
669
            } else if (xml.name() == "almanac") {
 
670
                parseWeatherRecords(data, xml);
 
671
            } else {
 
672
                parseUnknownElement(xml);
 
673
            }
 
674
        }
 
675
    }
 
676
}
 
677
 
 
678
// Parse Weather data main loop, from here we have to decend into each tag pair
 
679
bool EnvCanadaIon::readXMLData(const QString& source, QXmlStreamReader& xml)
 
680
{
 
681
    WeatherData data;
 
682
    data.comforttemp = i18n("N/A");
 
683
    data.recordHigh = 0.0;
 
684
    data.recordLow = 0.0;
 
685
 
 
686
    //kDebug() << "readXMLData()";
 
687
 
 
688
    QString dataKey = source;
 
689
    dataKey.remove("envcan|weather|");
 
690
    data.shortTerritoryName = m_places[dataKey].territoryName;
 
691
    while (!xml.atEnd()) {
 
692
        xml.readNext();
 
693
 
 
694
        if (xml.isEndElement()) {
 
695
            break;
 
696
        }
 
697
 
 
698
        if (xml.isStartElement()) {
 
699
            if (xml.name() == "siteData") {
 
700
                parseWeatherSite(data, xml);
 
701
            } else {
 
702
                parseUnknownElement(xml);
 
703
            }
 
704
        }
 
705
    }
 
706
 
 
707
    m_weatherData[source] = data;
 
708
    updateWeather(source);
 
709
    return !xml.error();
 
710
}
 
711
 
 
712
void EnvCanadaIon::parseDateTime(WeatherData& data, QXmlStreamReader& xml, WeatherData::WeatherEvent *event)
 
713
{
 
714
 
 
715
    Q_ASSERT(xml.isStartElement() && xml.name() == "dateTime");
 
716
 
 
717
    // What kind of date info is this?
 
718
    QString dateType = xml.attributes().value("name").toString();
 
719
    QString dateZone = xml.attributes().value("zone").toString();
 
720
 
 
721
    QString selectTimeStamp;
 
722
 
 
723
    while (!xml.atEnd()) {
 
724
        xml.readNext();
 
725
 
 
726
        if (xml.isEndElement()) {
 
727
            break;
 
728
        }
 
729
 
 
730
        if (xml.isStartElement()) {
 
731
            if (dateType == "xmlCreation") {
 
732
                return;
 
733
            }
 
734
            if (dateZone == "UTC") {
 
735
                return;
 
736
            }
 
737
            if (xml.name() == "year") {
 
738
                xml.readElementText();
 
739
            } else if (xml.name() == "month") {
 
740
                xml.readElementText();
 
741
            } else if (xml.name() == "day") {
 
742
                xml.readElementText();
 
743
            } else if (xml.name() == "hour")
 
744
                xml.readElementText();
 
745
            else if (xml.name() == "minute")
 
746
                xml.readElementText();
 
747
            else if (xml.name() == "timeStamp")
 
748
                selectTimeStamp = xml.readElementText();
 
749
            else if (xml.name() == "textSummary") {
 
750
                if (dateType == "eventIssue") {
 
751
                    if (event) {
 
752
                        event->timestamp = xml.readElementText();
 
753
                    }
 
754
                } else if (dateType == "observation") {
 
755
                    xml.readElementText();
 
756
                    m_dateFormat = QDateTime::fromString(selectTimeStamp, "yyyyMMddHHmmss");
 
757
                    data.obsTimestamp = m_dateFormat.toString("dd.MM.yyyy @ hh:mm");
 
758
                    data.iconPeriodHour = m_dateFormat.toString("hh").toInt();
 
759
                    data.iconPeriodMinute = m_dateFormat.toString("mm").toInt();
 
760
                } else if (dateType == "forecastIssue") {
 
761
                    data.forecastTimestamp = xml.readElementText();
 
762
                } else if (dateType == "sunrise") {
 
763
                    data.sunriseTimestamp = xml.readElementText();
 
764
                } else if (dateType == "sunset") {
 
765
                    data.sunsetTimestamp = xml.readElementText();
 
766
                } else if (dateType == "moonrise") {
 
767
                    data.moonriseTimestamp = xml.readElementText();
 
768
                } else if (dateType == "moonset") {
 
769
                    data.moonsetTimestamp = xml.readElementText();
 
770
                }
 
771
            }
 
772
        }
 
773
    }
 
774
}
 
775
 
 
776
void EnvCanadaIon::parseLocations(WeatherData& data, QXmlStreamReader& xml)
 
777
{
 
778
    Q_ASSERT(xml.isStartElement() && xml.name() == "location");
 
779
 
 
780
    while (!xml.atEnd()) {
 
781
        xml.readNext();
 
782
 
 
783
        if (xml.isEndElement()) {
 
784
            break;
 
785
        }
 
786
 
 
787
        if (xml.isStartElement()) {
 
788
            if (xml.name() == "country") {
 
789
                data.countryName = xml.readElementText();
 
790
            } else if (xml.name() == "province" || xml.name() == "territory") {
 
791
                data.longTerritoryName = xml.readElementText();
 
792
            } else if (xml.name() == "name") {
 
793
                data.cityName = xml.readElementText();
 
794
            } else if (xml.name() == "region") {
 
795
                data.regionName = xml.readElementText();
 
796
            } else {
 
797
                parseUnknownElement(xml);
 
798
            }
 
799
        }
 
800
    }
 
801
}
 
802
 
 
803
void EnvCanadaIon::parseWindInfo(WeatherData& data, QXmlStreamReader& xml)
 
804
{
 
805
    Q_ASSERT(xml.isStartElement() && xml.name() == "wind");
 
806
 
 
807
    while (!xml.atEnd()) {
 
808
        xml.readNext();
 
809
 
 
810
        if (xml.isEndElement()) {
 
811
            break;
 
812
        }
 
813
 
 
814
        if (xml.isStartElement()) {
 
815
            if (xml.name() == "speed") {
 
816
                data.windSpeed = xml.readElementText();
 
817
            } else if (xml.name() == "gust") {
 
818
                data.windGust = xml.readElementText();
 
819
            } else if (xml.name() == "direction") {
 
820
                data.windDirection = xml.readElementText();
 
821
            } else if (xml.name() == "bearing") {
 
822
                data.windDegrees = xml.attributes().value("degrees").toString();
 
823
            } else {
 
824
                parseUnknownElement(xml);
 
825
            }
 
826
        }
 
827
    }
 
828
}
 
829
 
 
830
void EnvCanadaIon::parseConditions(WeatherData& data, QXmlStreamReader& xml)
 
831
{
 
832
 
 
833
    Q_ASSERT(xml.isStartElement() && xml.name() == "currentConditions");
 
834
    data.temperature = i18n("N/A");
 
835
    data.dewpoint = i18n("N/A");
 
836
    data.condition = i18n("N/A");
 
837
    data.comforttemp = i18n("N/A");
 
838
    data.stationID = i18n("N/A");
 
839
    data.stationLat = i18n("N/A");
 
840
    data.stationLon = i18n("N/A");
 
841
    data.pressure = 0.0;
 
842
    data.pressureTendency = i18n("N/A");
 
843
    data.visibility = 0;
 
844
    data.humidity = i18n("N/A");
 
845
    data.windSpeed = i18n("N/A");
 
846
    data.windGust = i18n("N/A");
 
847
 
 
848
    while (!xml.atEnd()) {
 
849
        xml.readNext();
 
850
 
 
851
        if (xml.isEndElement() && xml.name() == "currentConditions")
 
852
            break;
 
853
 
 
854
        if (xml.isStartElement()) {
 
855
            if (xml.name() == "station") {
 
856
                data.stationID = xml.attributes().value("code").toString();
 
857
                data.stationLat = xml.attributes().value("lat").toString();
 
858
                data.stationLon = xml.attributes().value("lon").toString();
 
859
            } else if (xml.name() == "dateTime") {
 
860
                parseDateTime(data, xml);
 
861
            } else if (xml.name() == "condition") {
 
862
                data.condition = xml.readElementText();
 
863
            } else if (xml.name() == "temperature") {
 
864
                data.temperature = xml.readElementText();
 
865
            } else if (xml.name() == "dewpoint") {
 
866
                data.dewpoint = xml.readElementText();
 
867
            } else if (xml.name() == "humidex" || xml.name() == "windChill") {
 
868
                data.comforttemp = xml.readElementText();
 
869
            } else if (xml.name() == "pressure") {
 
870
                data.pressureTendency = xml.attributes().value("tendency").toString();
 
871
                if (data.pressureTendency.isEmpty()) {
 
872
                    data.pressureTendency = "steady";
 
873
                }
 
874
                data.pressure = xml.readElementText().toFloat();
 
875
            } else if (xml.name() == "visibility") {
 
876
                data.visibility = xml.readElementText().toFloat();
 
877
            } else if (xml.name() == "relativeHumidity") {
 
878
                data.humidity = xml.readElementText();
 
879
            } else if (xml.name() == "wind") {
 
880
                parseWindInfo(data, xml);
 
881
            }
 
882
            //} else {
 
883
            //    parseUnknownElement(xml);
 
884
            //}
 
885
        }
 
886
    }
 
887
    if (data.temperature.isEmpty())  {
 
888
        data.temperature = i18n("N/A");
 
889
    }
 
890
}
 
891
 
 
892
void EnvCanadaIon::parseWarnings(WeatherData &data, QXmlStreamReader& xml)
 
893
{
 
894
    WeatherData::WeatherEvent *watch = new WeatherData::WeatherEvent;
 
895
    WeatherData::WeatherEvent *warning = new WeatherData::WeatherEvent;
 
896
 
 
897
    Q_ASSERT(xml.isStartElement() && xml.name() == "warnings");
 
898
    QString eventURL = xml.attributes().value("url").toString();
 
899
    int flag = 0;
 
900
 
 
901
    while (!xml.atEnd()) {
 
902
        xml.readNext();
 
903
 
 
904
        if (xml.isEndElement() && xml.name() == "warnings") {
 
905
            break;
 
906
        }
 
907
 
 
908
        if (xml.isStartElement()) {
 
909
            if (xml.name() == "dateTime") {
 
910
                if (flag == 1) {
 
911
                    parseDateTime(data, xml, watch);
 
912
                }
 
913
                if (flag == 2) {
 
914
                    parseDateTime(data, xml, warning);
 
915
                }
 
916
 
 
917
                if (!warning->timestamp.isEmpty() && !warning->url.isEmpty())  {
 
918
                    data.warnings.append(warning);
 
919
                    warning = new WeatherData::WeatherEvent;
 
920
                }
 
921
                if (!watch->timestamp.isEmpty() && !watch->url.isEmpty()) {
 
922
                    data.watches.append(watch);
 
923
                    watch = new WeatherData::WeatherEvent;
 
924
                }
 
925
 
 
926
            } else if (xml.name() == "event") {
 
927
                // Append new event to list.
 
928
                QString eventType = xml.attributes().value("type").toString();
 
929
                if (eventType == "watch") {
 
930
                    watch->url = eventURL;
 
931
                    watch->type = eventType;
 
932
                    watch->priority = xml.attributes().value("priority").toString();
 
933
                    watch->description = xml.attributes().value("description").toString();
 
934
                    flag = 1;
 
935
                }
 
936
 
 
937
                if (eventType == "warning") {
 
938
                    warning->url = eventURL;
 
939
                    warning->type = eventType;
 
940
                    warning->priority = xml.attributes().value("priority").toString();
 
941
                    warning->description = xml.attributes().value("description").toString();
 
942
                    flag = 2;
 
943
                }
 
944
            } else {
 
945
                if (xml.name() != "dateTime") {
 
946
                    parseUnknownElement(xml);
 
947
                }
 
948
            }
 
949
        }
 
950
    }
 
951
    delete watch;
 
952
    delete warning;
 
953
}
 
954
 
 
955
 
 
956
void EnvCanadaIon::parseWeatherForecast(WeatherData& data, QXmlStreamReader& xml)
 
957
{
 
958
    WeatherData::ForecastInfo* forecast = new WeatherData::ForecastInfo;
 
959
    Q_ASSERT(xml.isStartElement() && xml.name() == "forecastGroup");
 
960
 
 
961
    while (!xml.atEnd()) {
 
962
        xml.readNext();
 
963
 
 
964
        if (xml.isEndElement() && xml.name() == "forecastGroup") {
 
965
            break;
 
966
        }
 
967
 
 
968
        if (xml.isStartElement()) {
 
969
            if (xml.name() == "dateTime") {
 
970
                parseDateTime(data, xml);
 
971
            } else if (xml.name() == "regionalNormals") {
 
972
                parseRegionalNormals(data, xml);
 
973
            } else if (xml.name() == "forecast") {
 
974
                parseForecast(data, xml, forecast);
 
975
                forecast = new WeatherData::ForecastInfo;
 
976
            } else {
 
977
                parseUnknownElement(xml);
 
978
            }
 
979
        }
 
980
    }
 
981
    delete forecast;
 
982
}
 
983
 
 
984
void EnvCanadaIon::parseRegionalNormals(WeatherData& data, QXmlStreamReader& xml)
 
985
{
 
986
    Q_ASSERT(xml.isStartElement() && xml.name() == "regionalNormals");
 
987
 
 
988
    while (!xml.atEnd()) {
 
989
        xml.readNext();
 
990
 
 
991
        if (xml.isEndElement()) {
 
992
            break;
 
993
        }
 
994
 
 
995
        if (xml.isStartElement()) {
 
996
            if (xml.name() == "textSummary") {
 
997
                xml.readElementText();
 
998
            } else if (xml.name() == "temperature" && xml.attributes().value("class") == "high") {
 
999
                data.normalHigh = xml.readElementText();
 
1000
            } else if (xml.name() == "temperature" && xml.attributes().value("class") == "low") {
 
1001
                data.normalLow = xml.readElementText();
 
1002
            }
 
1003
        }
 
1004
    }
 
1005
}
 
1006
 
 
1007
void EnvCanadaIon::parseForecast(WeatherData& data, QXmlStreamReader& xml, WeatherData::ForecastInfo *forecast)
 
1008
{
 
1009
 
 
1010
    Q_ASSERT(xml.isStartElement() && xml.name() == "forecast");
 
1011
 
 
1012
    while (!xml.atEnd()) {
 
1013
        xml.readNext();
 
1014
 
 
1015
        if (xml.isEndElement() && xml.name() == "forecast") {
 
1016
            data.forecasts.append(forecast);
 
1017
            break;
 
1018
        }
 
1019
 
 
1020
        if (xml.isStartElement()) {
 
1021
            if (xml.name() == "period") {
 
1022
                forecast->forecastPeriod = xml.attributes().value("textForecastName").toString();
 
1023
            } else if (xml.name() == "textSummary") {
 
1024
                forecast->forecastSummary = xml.readElementText();
 
1025
            } else if (xml.name() == "abbreviatedForecast") {
 
1026
                parseShortForecast(forecast, xml);
 
1027
            } else if (xml.name() == "temperatures") {
 
1028
                parseForecastTemperatures(forecast, xml);
 
1029
            } else if (xml.name() == "winds") {
 
1030
                parseWindForecast(forecast, xml);
 
1031
            } else if (xml.name() == "precipitation") {
 
1032
                parsePrecipitationForecast(forecast, xml);
 
1033
            } else if (xml.name() == "uv") {
 
1034
                data.UVRating = xml.attributes().value("category").toString();
 
1035
                parseUVIndex(data, xml);
 
1036
                // else if (xml.name() == "frost") { FIXME: Wait until winter to see what this looks like.
 
1037
                //  parseFrost(xml, forecast);
 
1038
            } else {
 
1039
                if (xml.name() != "forecast") {
 
1040
                    parseUnknownElement(xml);
 
1041
                }
 
1042
            }
 
1043
        }
 
1044
    }
 
1045
}
 
1046
 
 
1047
void EnvCanadaIon::parseShortForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
 
1048
{
 
1049
    Q_ASSERT(xml.isStartElement() && xml.name() == "abbreviatedForecast");
 
1050
 
 
1051
    QString shortText;
 
1052
 
 
1053
    while (!xml.atEnd()) {
 
1054
        xml.readNext();
 
1055
 
 
1056
        if (xml.isEndElement() && xml.name() == "abbreviatedForecast") {
 
1057
            break;
 
1058
        }
 
1059
 
 
1060
        if (xml.isStartElement()) {
 
1061
            if (xml.name() == "pop") {
 
1062
                forecast->popPrecent = xml.readElementText();
 
1063
            }
 
1064
            if (xml.name() == "textSummary") {
 
1065
                shortText = xml.readElementText();
 
1066
                QMap<QString, ConditionIcons> forecastList;
 
1067
                forecastList = forecastIcons();
 
1068
                if ((forecast->forecastPeriod == "tonight") || (forecast->forecastPeriod.contains("night"))) {
 
1069
                    forecastList["a few clouds"] = FewCloudsNight;
 
1070
                    forecastList["cloudy periods"] = PartlyCloudyNight;
 
1071
                    forecastList["chance of drizzle mixed with rain"] = ChanceShowersNight;
 
1072
                    forecastList["chance of drizzle"] = ChanceShowersNight;
 
1073
                    forecastList["chance of drizzle or rain"] = ChanceShowersNight;
 
1074
                    forecastList["chance of flurries"] = ChanceSnowNight;
 
1075
                    forecastList["chance of light snow"] = ChanceSnowNight;
 
1076
                    forecastList["chance of flurries at times heavy"] = ChanceSnowNight;
 
1077
                    forecastList["chance of showers or drizzle"] = ChanceShowersNight;
 
1078
                    forecastList["chance of showers"] = ChanceShowersNight;
 
1079
                    forecastList["clearing"] = ClearNight;
 
1080
                } else {
 
1081
                    forecastList["a few clouds"] = FewCloudsDay;
 
1082
                    forecastList["cloudy periods"] = PartlyCloudyDay;
 
1083
                    forecastList["chance of drizzle mixed with rain"] = ChanceShowersDay;
 
1084
                    forecastList["chance of drizzle"] = ChanceShowersDay;
 
1085
                    forecastList["chance of drizzle or rain"] = ChanceShowersDay;
 
1086
                    forecastList["chance of flurries"] = ChanceSnowDay;
 
1087
                    forecastList["chance of light snow"] = ChanceSnowDay;
 
1088
                    forecastList["chance of flurries at times heavy"] = ChanceSnowDay;
 
1089
                    forecastList["chance of showers or drizzle"] = ChanceShowersDay;
 
1090
                    forecastList["chance of showers"] = ChanceShowersDay;
 
1091
                    forecastList["clearing"] = ClearDay;
 
1092
                }
 
1093
                forecast->shortForecast = shortText;
 
1094
                forecast->iconName = getWeatherIcon(forecastList, shortText.toLower());
 
1095
            }
 
1096
        }
 
1097
    }
 
1098
}
 
1099
 
 
1100
void EnvCanadaIon::parseUVIndex(WeatherData& data, QXmlStreamReader& xml)
 
1101
{
 
1102
    Q_ASSERT(xml.isStartElement() && xml.name() == "uv");
 
1103
 
 
1104
    while (!xml.atEnd()) {
 
1105
        xml.readNext();
 
1106
 
 
1107
        if (xml.isEndElement() && xml.name() == "uv") {
 
1108
            break;
 
1109
        }
 
1110
 
 
1111
        if (xml.isStartElement()) {
 
1112
            if (xml.name() == "index") {
 
1113
                data.UVIndex = xml.readElementText();
 
1114
            }
 
1115
            if (xml.name() == "textSummary") {
 
1116
                xml.readElementText();
 
1117
            }
 
1118
        }
 
1119
    }
 
1120
}
 
1121
 
 
1122
void EnvCanadaIon::parseForecastTemperatures(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
 
1123
{
 
1124
    Q_ASSERT(xml.isStartElement() && xml.name() == "temperatures");
 
1125
 
 
1126
    while (!xml.atEnd()) {
 
1127
        xml.readNext();
 
1128
 
 
1129
        if (xml.isEndElement() && xml.name() == "temperatures") {
 
1130
            break;
 
1131
        }
 
1132
 
 
1133
        if (xml.isStartElement()) {
 
1134
            if (xml.name() == "temperature" && xml.attributes().value("class") == "low") {
 
1135
                forecast->forecastTempLow = xml.readElementText();
 
1136
            } else if (xml.name() == "temperature" && xml.attributes().value("class") == "high") {
 
1137
                forecast->forecastTempHigh = xml.readElementText();
 
1138
            } else if (xml.name() == "textSummary") {
 
1139
                xml.readElementText();
 
1140
            }
 
1141
        }
 
1142
    }
 
1143
}
 
1144
 
 
1145
void EnvCanadaIon::parsePrecipitationForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
 
1146
{
 
1147
    Q_ASSERT(xml.isStartElement() && xml.name() == "precipitation");
 
1148
 
 
1149
    while (!xml.atEnd()) {
 
1150
        xml.readNext();
 
1151
 
 
1152
        if (xml.isEndElement() && xml.name() == "precipitation") {
 
1153
            break;
 
1154
        }
 
1155
 
 
1156
        if (xml.isStartElement()) {
 
1157
            if (xml.name() == "textSummary") {
 
1158
                forecast->precipForecast = xml.readElementText();
 
1159
            } else if (xml.name() == "precipType") {
 
1160
                forecast->precipType = xml.readElementText();
 
1161
            } else if (xml.name() == "accumulation") {
 
1162
                parsePrecipTotals(forecast, xml);
 
1163
            }
 
1164
        }
 
1165
    }
 
1166
}
 
1167
 
 
1168
void EnvCanadaIon::parsePrecipTotals(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
 
1169
{
 
1170
    Q_ASSERT(xml.isStartElement() && xml.name() == "accumulation");
 
1171
 
 
1172
    while (!xml.atEnd()) {
 
1173
        xml.readNext();
 
1174
 
 
1175
        if (xml.isEndElement() && xml.name() == "accumulation") {
 
1176
            break;
 
1177
        }
 
1178
 
 
1179
        if (xml.name() == "name") {
 
1180
            xml.readElementText();
 
1181
        } else if (xml.name() == "amount") {
 
1182
            forecast->precipTotalExpected = xml.readElementText();
 
1183
        }
 
1184
    }
 
1185
}
 
1186
 
 
1187
void EnvCanadaIon::parseWindForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
 
1188
{
 
1189
    Q_ASSERT(xml.isStartElement() && xml.name() == "winds");
 
1190
 
 
1191
    while (!xml.atEnd()) {
 
1192
        xml.readNext();
 
1193
 
 
1194
        if (xml.isEndElement() && xml.name() == "winds") {
 
1195
            break;
 
1196
        }
 
1197
 
 
1198
        if (xml.isStartElement()) {
 
1199
            if (xml.name() == "textSummary") {
 
1200
                forecast->windForecast = xml.readElementText();
 
1201
            } else {
 
1202
                if (xml.name() != "winds") {
 
1203
                    parseUnknownElement(xml);
 
1204
                }
 
1205
            }
 
1206
        }
 
1207
    }
 
1208
}
 
1209
 
 
1210
void EnvCanadaIon::parseYesterdayWeather(WeatherData& data, QXmlStreamReader& xml)
 
1211
{
 
1212
    Q_ASSERT(xml.isStartElement() && xml.name() == "yesterdayConditions");
 
1213
 
 
1214
    while (!xml.atEnd()) {
 
1215
        xml.readNext();
 
1216
 
 
1217
        if (xml.isEndElement()) {
 
1218
            break;
 
1219
        }
 
1220
 
 
1221
        if (xml.isStartElement()) {
 
1222
            if (xml.name() == "temperature" && xml.attributes().value("class") == "high") {
 
1223
                data.prevHigh = xml.readElementText();
 
1224
            } else if (xml.name() == "temperature" && xml.attributes().value("class") == "low") {
 
1225
                data.prevLow = xml.readElementText();
 
1226
            } else if (xml.name() == "precip") {
 
1227
                data.prevPrecipType = xml.attributes().value("units").toString();
 
1228
                if (data.prevPrecipType.isEmpty()) {
 
1229
                    data.prevPrecipType = QString::number(KUnitConversion::NoUnit);
 
1230
                }
 
1231
                data.prevPrecipTotal = xml.readElementText();
 
1232
            }
 
1233
        }
 
1234
    }
 
1235
}
 
1236
 
 
1237
void EnvCanadaIon::parseWeatherRecords(WeatherData& data, QXmlStreamReader& xml)
 
1238
{
 
1239
    Q_ASSERT(xml.isStartElement() && xml.name() == "almanac");
 
1240
 
 
1241
    while (!xml.atEnd()) {
 
1242
        xml.readNext();
 
1243
 
 
1244
        if (xml.isEndElement() && xml.name() == "almanac") {
 
1245
            break;
 
1246
        }
 
1247
 
 
1248
        if (xml.isStartElement()) {
 
1249
            if (xml.name() == "temperature" && xml.attributes().value("class") == "extremeMax") {
 
1250
                data.recordHigh = xml.readElementText().toFloat();
 
1251
            } else if (xml.name() == "temperature" && xml.attributes().value("class") == "extremeMin") {
 
1252
                data.recordLow = xml.readElementText().toFloat();
 
1253
            } else if (xml.name() == "precipitation" && xml.attributes().value("class") == "extremeRainfall") {
 
1254
                data.recordRain = xml.readElementText().toFloat();
 
1255
            } else if (xml.name() == "precipitation" && xml.attributes().value("class") == "extremeSnowfall") {
 
1256
                data.recordSnow = xml.readElementText().toFloat();
 
1257
            }
 
1258
        }
 
1259
    }
 
1260
}
 
1261
 
 
1262
void EnvCanadaIon::parseAstronomicals(WeatherData& data, QXmlStreamReader& xml)
 
1263
{
 
1264
    Q_ASSERT(xml.isStartElement() && xml.name() == "riseSet");
 
1265
 
 
1266
    while (!xml.atEnd()) {
 
1267
        xml.readNext();
 
1268
 
 
1269
        if (xml.isEndElement() && xml.name() == "riseSet") {
 
1270
            break;
 
1271
        }
 
1272
 
 
1273
        if (xml.isStartElement()) {
 
1274
            if (xml.name() == "disclaimer") {
 
1275
                xml.readElementText();
 
1276
            } else if (xml.name() == "dateTime") {
 
1277
                parseDateTime(data, xml);
 
1278
            }
 
1279
        }
 
1280
    }
 
1281
}
 
1282
 
 
1283
// handle when no XML tag is found
 
1284
void EnvCanadaIon::parseUnknownElement(QXmlStreamReader& xml) const
 
1285
{
 
1286
 
 
1287
    while (!xml.atEnd()) {
 
1288
        xml.readNext();
 
1289
 
 
1290
        if (xml.isEndElement()) {
 
1291
            break;
 
1292
        }
 
1293
 
 
1294
        if (xml.isStartElement()) {
 
1295
            parseUnknownElement(xml);
 
1296
        }
 
1297
    }
 
1298
}
 
1299
 
 
1300
void EnvCanadaIon::updateWeather(const QString& source)
 
1301
{
 
1302
    //kDebug() << "updateWeather()";
 
1303
 
 
1304
    QMap<QString, QString> dataFields;
 
1305
    Plasma::DataEngine::Data data;
 
1306
    QStringList fieldList;
 
1307
    QVector<QString> forecastList;
 
1308
    int i = 0;
 
1309
 
 
1310
    data.insert("Country", country(source));
 
1311
    data.insert("Place", QString("%1, %2").arg(city(source)).arg(territory(source)));
 
1312
    data.insert("Region", region(source));
 
1313
    data.insert("Station", station(source));
 
1314
 
 
1315
    data.insert("Latitude", latitude(source));
 
1316
    data.insert("Longitude", longitude(source));
 
1317
 
 
1318
    // Real weather - Current conditions
 
1319
    data.insert("Observation Period", observationTime(source));
 
1320
    data.insert("Current Conditions", i18nc("weather condition", condition(source).toUtf8()));
 
1321
    //kDebug() << "i18n condition string: " << qPrintable(condition(source));
 
1322
 
 
1323
    // Tell applet which icon to use for conditions and provide mapping for condition type to the icons to display
 
1324
    QMap<QString, ConditionIcons> conditionList;
 
1325
    conditionList = conditionIcons();
 
1326
 
 
1327
    const double lati = latitude(source).replace(QRegExp("[^0-9.]"), NULL).toDouble();
 
1328
    const double longi = longitude(source).replace(QRegExp("[^0-9.]"), NULL).toDouble();
 
1329
    const Plasma::DataEngine::Data timeData = m_timeEngine->query(
 
1330
            QString("Local|Solar|Latitude=%1|Longitude=%2")
 
1331
                .arg(lati).arg(-1 * longi));
 
1332
 
 
1333
    if (timeData["Corrected Elevation"].toDouble() < 0.0) {
 
1334
        conditionList["decreasing cloud"] = FewCloudsNight;
 
1335
        conditionList["mostly cloudy"] = PartlyCloudyNight;
 
1336
        conditionList["partly cloudy"] = PartlyCloudyNight;
 
1337
        conditionList["fair"] = FewCloudsNight;
 
1338
        //kDebug() << "Before sunrise/After sunset - using night icons\n";
 
1339
    } else {
 
1340
        conditionList["decreasing cloud"] = FewCloudsDay;
 
1341
        conditionList["mostly cloudy"] = PartlyCloudyDay;
 
1342
        conditionList["partly cloudy"] = PartlyCloudyDay;
 
1343
        conditionList["fair"] = FewCloudsDay;
 
1344
        //kDebug() << "Using daytime icons\n";
 
1345
    }
 
1346
 
 
1347
    data.insert("Condition Icon", getWeatherIcon(conditionList, condition(source)));
 
1348
 
 
1349
    dataFields = temperature(source);
 
1350
    data.insert("Temperature", dataFields["temperature"]);
 
1351
 
 
1352
    // Do we have a comfort temperature? if so display it
 
1353
    if (dataFields["comfortTemperature"] != "N/A" && !dataFields["comfortTemperature"].isEmpty()) {
 
1354
        if (dataFields["comfortTemperature"].toFloat() <= 0) {
 
1355
            data.insert("Windchill", QString("%1").arg(dataFields["comfortTemperature"]));
 
1356
            data.insert("Humidex", i18n("N/A"));
 
1357
        } else {
 
1358
            data.insert("Humidex", QString("%1").arg(dataFields["comfortTemperature"]));
 
1359
            data.insert("Windchill", i18n("N/A"));
 
1360
        }
 
1361
    } else {
 
1362
        data.insert("Windchill", i18n("N/A"));
 
1363
        data.insert("Humidex", i18n("N/A"));
 
1364
    }
 
1365
 
 
1366
    // Used for all temperatures
 
1367
    data.insert("Temperature Unit", dataFields["temperatureUnit"]);
 
1368
 
 
1369
    data.insert("Dewpoint", dewpoint(source));
 
1370
 
 
1371
    dataFields = pressure(source);
 
1372
    data.insert("Pressure", dataFields["pressure"]);
 
1373
    data.insert("Pressure Unit", dataFields["pressureUnit"]);
 
1374
    data.insert("Pressure Tendency", dataFields["pressureTendency"]);
 
1375
 
 
1376
    dataFields = visibility(source);
 
1377
    data.insert("Visibility", dataFields["visibility"]);
 
1378
    data.insert("Visibility Unit", dataFields["visibilityUnit"]);
 
1379
 
 
1380
    dataFields = humidity(source);
 
1381
    data.insert("Humidity", dataFields["humidity"]);
 
1382
    data.insert("Humidity Unit", dataFields["humidityUnit"]);
 
1383
 
 
1384
    dataFields = wind(source);
 
1385
    data.insert("Wind Speed", dataFields["windSpeed"]);
 
1386
    data.insert("Wind Speed Unit", dataFields["windUnit"]);
 
1387
 
 
1388
    data.insert("Wind Gust", dataFields["windGust"]);
 
1389
    data.insert("Wind Direction", dataFields["windDirection"]);
 
1390
    data.insert("Wind Degrees", dataFields["windDegrees"]);
 
1391
    data.insert("Wind Gust Unit", dataFields["windGustUnit"]);
 
1392
 
 
1393
    dataFields = regionalTemperatures(source);
 
1394
    data.insert("Normal High", dataFields["normalHigh"]);
 
1395
    data.insert("Normal Low", dataFields["normalLow"]);
 
1396
 
 
1397
    // Check if UV index is available for the location
 
1398
    dataFields = uvIndex(source);
 
1399
    data.insert("UV Index", dataFields["uvIndex"]);
 
1400
    data.insert("UV Rating", dataFields["uvRating"]);
 
1401
 
 
1402
    dataFields = watches(source);
 
1403
 
 
1404
    // Set number of forecasts per day/night supported
 
1405
    data.insert("Total Watches Issued", m_weatherData[source].watches.size());
 
1406
 
 
1407
    // Check if we have warnings or watches
 
1408
    for (int i = 0; i < m_weatherData[source].watches.size(); i++) {
 
1409
        fieldList = dataFields[QString("watch %1").arg(i)].split('|');
 
1410
        data.insert(QString("Watch Priority %1").arg(i), fieldList[0]);
 
1411
        data.insert(QString("Watch Description %1").arg(i), fieldList[1]);
 
1412
        data.insert(QString("Watch Info %1").arg(i), fieldList[2]);
 
1413
        data.insert(QString("Watch Timestamp %1").arg(i), fieldList[3]);
 
1414
    }
 
1415
 
 
1416
    dataFields = warnings(source);
 
1417
 
 
1418
    data.insert("Total Warnings Issued", m_weatherData[source].warnings.size());
 
1419
 
 
1420
    for (int k = 0; k < m_weatherData[source].warnings.size(); k++) {
 
1421
        fieldList = dataFields[QString("warning %1").arg(k)].split('|');
 
1422
        data.insert(QString("Warning Priority %1").arg(k), fieldList[0]);
 
1423
        data.insert(QString("Warning Description %1").arg(k), fieldList[1]);
 
1424
        data.insert(QString("Warning Info %1").arg(k), fieldList[2]);
 
1425
        data.insert(QString("Warning Timestamp %1").arg(k), fieldList[3]);
 
1426
    }
 
1427
 
 
1428
    forecastList = forecasts(source);
 
1429
 
 
1430
    // Set number of forecasts per day/night supported
 
1431
    data.insert("Total Weather Days", m_weatherData[source].forecasts.size());
 
1432
 
 
1433
    foreach(const QString &forecastItem, forecastList) {
 
1434
        fieldList = forecastItem.split('|');
 
1435
 
 
1436
        data.insert(QString("Short Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5|%6") \
 
1437
                .arg(fieldList[0]).arg(fieldList[1]).arg(fieldList[2]).arg(fieldList[3]).arg(fieldList[4]).arg(fieldList[5]));
 
1438
 
 
1439
        /*
 
1440
                data.insert(QString("Long Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5|%6|%7|%8") \
 
1441
                        .arg(fieldList[0]).arg(fieldList[2]).arg(fieldList[3]).arg(fieldList[4]).arg(fieldList[6]) \
 
1442
                        .arg(fieldList[7]).arg(fieldList[8]).arg(fieldList[9]));
 
1443
        */
 
1444
        i++;
 
1445
    }
 
1446
 
 
1447
    dataFields = yesterdayWeather(source);
 
1448
    data.insert("Yesterday High", dataFields["prevHigh"]);
 
1449
    data.insert("Yesterday Low", dataFields["prevLow"]);
 
1450
 
 
1451
    data.insert("Yesterday Precip Total", dataFields["prevPrecip"]);
 
1452
    data.insert("Yesterday Precip Unit", dataFields["prevPrecipUnit"]);
 
1453
 
 
1454
    dataFields = sunriseSet(source);
 
1455
    data.insert("Sunrise At", dataFields["sunrise"]);
 
1456
    data.insert("Sunset At", dataFields["sunset"]);
 
1457
 
 
1458
    dataFields = moonriseSet(source);
 
1459
    data.insert("Moonrise At", dataFields["moonrise"]);
 
1460
    data.insert("Moonset At", dataFields["moonset"]);
 
1461
 
 
1462
    dataFields = weatherRecords(source);
 
1463
    data.insert("Record High Temperature", dataFields["recordHigh"]);
 
1464
    data.insert("Record Low Temperature", dataFields["recordLow"]);
 
1465
 
 
1466
    data.insert("Record Rainfall", dataFields["recordRain"]);
 
1467
    data.insert("Record Rainfall Unit", dataFields["recordRainUnit"]);
 
1468
    data.insert("Record Snowfall", dataFields["recordSnow"]);
 
1469
    data.insert("Record Snowfall Unit", dataFields["recordSnowUnit"]);
 
1470
 
 
1471
    data.insert("Credit", i18n("Meteorological data is provided by Environment Canada"));
 
1472
    setData(source, data);
 
1473
}
 
1474
 
 
1475
QString const EnvCanadaIon::country(const QString& source) const
 
1476
{
 
1477
    // This will always return Canada
 
1478
    return m_weatherData[source].countryName;
 
1479
}
 
1480
 
 
1481
QString EnvCanadaIon::territory(const QString& source) const
 
1482
{
 
1483
    return m_weatherData[source].shortTerritoryName;
 
1484
}
 
1485
 
 
1486
QString EnvCanadaIon::city(const QString& source) const
 
1487
{
 
1488
    return m_weatherData[source].cityName;
 
1489
}
 
1490
 
 
1491
QString EnvCanadaIon::region(const QString& source) const
 
1492
{
 
1493
    return m_weatherData[source].regionName;
 
1494
}
 
1495
 
 
1496
QString EnvCanadaIon::station(const QString& source) const
 
1497
{
 
1498
    if (!m_weatherData[source].stationID.isEmpty()) {
 
1499
        return m_weatherData[source].stationID.toUpper();
 
1500
    }
 
1501
 
 
1502
    return i18n("N/A");
 
1503
}
 
1504
 
 
1505
QString EnvCanadaIon::latitude(const QString& source) const
 
1506
{
 
1507
    return m_weatherData[source].stationLat;
 
1508
}
 
1509
 
 
1510
QString EnvCanadaIon::longitude(const QString& source) const
 
1511
{
 
1512
    return m_weatherData[source].stationLon;
 
1513
}
 
1514
 
 
1515
QString EnvCanadaIon::observationTime(const QString& source) const
 
1516
{
 
1517
    return m_weatherData[source].obsTimestamp;
 
1518
}
 
1519
 
 
1520
int EnvCanadaIon::periodHour(const QString& source) const
 
1521
{
 
1522
    return m_weatherData[source].iconPeriodHour;
 
1523
}
 
1524
 
 
1525
int EnvCanadaIon::periodMinute(const QString& source) const
 
1526
{
 
1527
    return m_weatherData[source].iconPeriodMinute;
 
1528
}
 
1529
 
 
1530
QString EnvCanadaIon::condition(const QString& source)
 
1531
{
 
1532
    if (m_weatherData[source].condition.isEmpty()) {
 
1533
        m_weatherData[source].condition = i18n("N/A");
 
1534
    }
 
1535
    return (m_weatherData[source].condition.toUtf8());
 
1536
}
 
1537
 
 
1538
QString EnvCanadaIon::dewpoint(const QString& source) const
 
1539
{
 
1540
    if (!m_weatherData[source].dewpoint.isEmpty()) {
 
1541
        return (QString::number(m_weatherData[source].dewpoint.toFloat(), 'f', 1));
 
1542
    }
 
1543
    return i18n("N/A");
 
1544
}
 
1545
 
 
1546
QMap<QString, QString> EnvCanadaIon::humidity(const QString& source) const
 
1547
{
 
1548
    QMap<QString, QString> humidityInfo;
 
1549
    if (!m_weatherData[source].humidity.isEmpty()) {
 
1550
        humidityInfo.insert("humidity", m_weatherData[source].humidity);
 
1551
        humidityInfo.insert("humidityUnit", QString::number(KUnitConversion::Percent));
 
1552
    } else {
 
1553
        humidityInfo.insert("humidity", i18n("N/A"));
 
1554
        humidityInfo.insert("humidityUnit", QString::number(KUnitConversion::NoUnit));
 
1555
    }
 
1556
    return humidityInfo;
 
1557
}
 
1558
 
 
1559
QMap<QString, QString> EnvCanadaIon::visibility(const QString& source) const
 
1560
{
 
1561
    QMap<QString, QString> visibilityInfo;
 
1562
 
 
1563
    if (!m_weatherData[source].visibility == 0) {
 
1564
        visibilityInfo.insert("visibility", QString::number(m_weatherData[source].visibility, 'f', 1));
 
1565
        visibilityInfo.insert("visibilityUnit", QString::number(KUnitConversion::Kilometer));
 
1566
    } else {
 
1567
        visibilityInfo.insert("visibility", i18n("N/A"));
 
1568
        visibilityInfo.insert("visibilityUnit", QString::number(KUnitConversion::NoUnit));
 
1569
    }
 
1570
    return visibilityInfo;
 
1571
}
 
1572
 
 
1573
QMap<QString, QString> EnvCanadaIon::temperature(const QString& source) const
 
1574
{
 
1575
    QMap<QString, QString> temperatureInfo;
 
1576
    if (!m_weatherData[source].temperature.isEmpty()) {
 
1577
        temperatureInfo.insert("temperature", QString::number(m_weatherData[source].temperature.toFloat(), 'f', 1));
 
1578
    }
 
1579
 
 
1580
    if (m_weatherData[source].temperature == i18n("N/A")) {
 
1581
        temperatureInfo.insert("temperature", i18n("N/A"));
 
1582
    }
 
1583
 
 
1584
    temperatureInfo.insert("comfortTemperature", i18n("N/A"));
 
1585
 
 
1586
    if (m_weatherData[source].comforttemp != i18n("N/A")) {
 
1587
        temperatureInfo.insert("comfortTemperature", m_weatherData[source].comforttemp);
 
1588
    }
 
1589
 
 
1590
    // This is used for not just current temperature but also 8 days. Cannot be NoUnit.
 
1591
    temperatureInfo.insert("temperatureUnit", QString::number(KUnitConversion::Celsius));
 
1592
    return temperatureInfo;
 
1593
}
 
1594
 
 
1595
QMap<QString, QString> EnvCanadaIon::watches(const QString& source) const
 
1596
{
 
1597
    QMap<QString, QString> watchData;
 
1598
    QString watchType;
 
1599
    for (int i = 0; i < m_weatherData[source].watches.size(); ++i) {
 
1600
        watchType = QString("watch %1").arg(i);
 
1601
        watchData[watchType] = QString("%1|%2|%3|%4").arg(m_weatherData[source].watches[i]->priority) \
 
1602
                               .arg(m_weatherData[source].watches[i]->description) \
 
1603
                               .arg(m_weatherData[source].watches[i]->url) \
 
1604
                               .arg(m_weatherData[source].watches[i]->timestamp);
 
1605
    }
 
1606
    return watchData;
 
1607
}
 
1608
 
 
1609
QMap<QString, QString> EnvCanadaIon::warnings(const QString& source) const
 
1610
{
 
1611
    QMap<QString, QString> warningData;
 
1612
    QString warnType;
 
1613
    for (int i = 0; i < m_weatherData[source].warnings.size(); ++i) {
 
1614
        warnType = QString("warning %1").arg(i);
 
1615
        warningData[warnType] = QString("%1|%2|%3|%4").arg(m_weatherData[source].warnings[i]->priority) \
 
1616
                                .arg(m_weatherData[source].warnings[i]->description) \
 
1617
                                .arg(m_weatherData[source].warnings[i]->url) \
 
1618
                                .arg(m_weatherData[source].warnings[i]->timestamp);
 
1619
    }
 
1620
    return warningData;
 
1621
}
 
1622
 
 
1623
QVector<QString> EnvCanadaIon::forecasts(const QString& source)
 
1624
{
 
1625
    QVector<QString> forecastData;
 
1626
 
 
1627
    // Do some checks for empty data
 
1628
    for (int i = 0; i < m_weatherData[source].forecasts.size(); ++i) {
 
1629
        if (m_weatherData[source].forecasts[i]->forecastPeriod.isEmpty()) {
 
1630
            m_weatherData[source].forecasts[i]->forecastPeriod = i18n("N/A");
 
1631
        }
 
1632
        if (m_weatherData[source].forecasts[i]->shortForecast.isEmpty()) {
 
1633
            m_weatherData[source].forecasts[i]->shortForecast = i18n("N/A");
 
1634
        }
 
1635
        if (m_weatherData[source].forecasts[i]->iconName.isEmpty()) {
 
1636
            m_weatherData[source].forecasts[i]->iconName = i18n("N/A");
 
1637
        }
 
1638
        if (m_weatherData[source].forecasts[i]->forecastSummary.isEmpty()) {
 
1639
            m_weatherData[source].forecasts[i]->forecastSummary = i18n("N/A");
 
1640
        }
 
1641
        if (m_weatherData[source].forecasts[i]->forecastTempHigh.isEmpty()) {
 
1642
            m_weatherData[source].forecasts[i]->forecastTempHigh = i18n("N/A");
 
1643
        }
 
1644
        if (m_weatherData[source].forecasts[i]->forecastTempLow.isEmpty()) {
 
1645
            m_weatherData[source].forecasts[i]->forecastTempLow = i18n("N/A");
 
1646
        }
 
1647
        if (m_weatherData[source].forecasts[i]->popPrecent.isEmpty()) {
 
1648
            m_weatherData[source].forecasts[i]->popPrecent = i18n("N/A");
 
1649
        }
 
1650
        if (m_weatherData[source].forecasts[i]->windForecast.isEmpty()) {
 
1651
            m_weatherData[source].forecasts[i]->windForecast = i18n("N/A");
 
1652
        }
 
1653
        if (m_weatherData[source].forecasts[i]->precipForecast.isEmpty()) {
 
1654
            m_weatherData[source].forecasts[i]->precipForecast = i18n("N/A");
 
1655
        }
 
1656
        if (m_weatherData[source].forecasts[i]->precipType.isEmpty()) {
 
1657
            m_weatherData[source].forecasts[i]->precipType = i18n("N/A");
 
1658
        }
 
1659
        if (m_weatherData[source].forecasts[i]->precipTotalExpected.isEmpty()) {
 
1660
            m_weatherData[source].forecasts[i]->precipTotalExpected = i18n("N/A");
 
1661
        }
 
1662
    }
 
1663
 
 
1664
    for (int i = 0; i < m_weatherData[source].forecasts.size(); ++i) {
 
1665
        // We need to shortform the day/night strings.
 
1666
 
 
1667
        if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("Today")) {
 
1668
            m_weatherData[source].forecasts[i]->forecastPeriod.replace("Today", i18n("day"));
 
1669
        }
 
1670
 
 
1671
        if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("Tonight")) {
 
1672
            m_weatherData[source].forecasts[i]->forecastPeriod.replace("Tonight", i18nc("Short for tonight", "nite"));
 
1673
        }
 
1674
 
 
1675
        if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("night")) {
 
1676
            m_weatherData[source].forecasts[i]->forecastPeriod.replace("night", i18nc("Short for night, appended to the end of the weekday", "nt"));
 
1677
        }
 
1678
 
 
1679
        if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("Saturday")) {
 
1680
            m_weatherData[source].forecasts[i]->forecastPeriod.replace("Saturday", i18nc("Short for Saturday", "Sat"));
 
1681
        }
 
1682
 
 
1683
        if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("Sunday")) {
 
1684
            m_weatherData[source].forecasts[i]->forecastPeriod.replace("Sunday", i18nc("Short for Sunday", "Sun"));
 
1685
        }
 
1686
 
 
1687
        if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("Monday")) {
 
1688
            m_weatherData[source].forecasts[i]->forecastPeriod.replace("Monday", i18nc("Short for Monday", "Mon"));
 
1689
        }
 
1690
 
 
1691
        if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("Tuesday")) {
 
1692
            m_weatherData[source].forecasts[i]->forecastPeriod.replace("Tuesday", i18nc("Short for Tuesday", "Tue"));
 
1693
        }
 
1694
 
 
1695
        if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("Wednesday")) {
 
1696
            m_weatherData[source].forecasts[i]->forecastPeriod.replace("Wednesday", i18nc("Short for Wednesday", "Wed"));
 
1697
        }
 
1698
 
 
1699
        if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("Thursday")) {
 
1700
            m_weatherData[source].forecasts[i]->forecastPeriod.replace("Thursday", i18nc("Short for Thursday", "Thu"));
 
1701
        }
 
1702
        if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("Friday")) {
 
1703
            m_weatherData[source].forecasts[i]->forecastPeriod.replace("Friday", i18nc("Short for Friday", "Fri"));
 
1704
        }
 
1705
 
 
1706
        forecastData.append(QString("%1|%2|%3|%4|%5|%6") \
 
1707
                            .arg(m_weatherData[source].forecasts[i]->forecastPeriod) \
 
1708
                            .arg(m_weatherData[source].forecasts[i]->iconName) \
 
1709
                            .arg(i18nc("weather forecast", m_weatherData[source].forecasts[i]->shortForecast.toUtf8())) \
 
1710
                            .arg(m_weatherData[source].forecasts[i]->forecastTempHigh) \
 
1711
                            .arg(m_weatherData[source].forecasts[i]->forecastTempLow) \
 
1712
                            .arg(m_weatherData[source].forecasts[i]->popPrecent));
 
1713
        //kDebug() << "i18n summary string: " << qPrintable(i18n(m_weatherData[source].forecasts[i]->shortForecast.toUtf8()));
 
1714
    }
 
1715
    return forecastData;
 
1716
}
 
1717
 
 
1718
QMap<QString, QString> EnvCanadaIon::pressure(const QString& source) const
 
1719
{
 
1720
    QMap<QString, QString> pressureInfo;
 
1721
 
 
1722
    if (m_weatherData[source].pressure == 0) {
 
1723
        pressureInfo.insert("pressure", i18n("N/A"));
 
1724
        pressureInfo.insert("pressureUnit", QString::number(KUnitConversion::NoUnit));
 
1725
        pressureInfo.insert("pressureTendency", "N/A");
 
1726
    } else {
 
1727
        pressureInfo.insert("pressure", QString::number(m_weatherData[source].pressure, 'f', 1));
 
1728
        pressureInfo.insert("pressureUnit", QString::number(KUnitConversion::Kilopascal));
 
1729
        pressureInfo.insert("pressureTendency", i18nc("pressure tendency", m_weatherData[source].pressureTendency.toUtf8()));
 
1730
    }
 
1731
    return pressureInfo;
 
1732
}
 
1733
 
 
1734
QMap<QString, QString> EnvCanadaIon::wind(const QString& source) const
 
1735
{
 
1736
    QMap<QString, QString> windInfo;
 
1737
 
 
1738
    // May not have any winds
 
1739
    if (m_weatherData[source].windSpeed.isEmpty()) {
 
1740
        windInfo.insert("windSpeed", i18n("N/A"));
 
1741
        windInfo.insert("windUnit", QString::number(KUnitConversion::NoUnit));
 
1742
    } else if (m_weatherData[source].windSpeed.toInt() == 0) {
 
1743
        windInfo.insert("windSpeed", i18nc("wind speed", "Calm"));
 
1744
        windInfo.insert("windUnit", QString::number(KUnitConversion::NoUnit));
 
1745
    } else {
 
1746
        windInfo.insert("windSpeed", QString::number(m_weatherData[source].windSpeed.toInt()));
 
1747
        windInfo.insert("windUnit", QString::number(KUnitConversion::KilometerPerHour));
 
1748
    }
 
1749
 
 
1750
    // May not always have gusty winds
 
1751
    if (m_weatherData[source].windGust.isEmpty() || m_weatherData[source].windGust == 0) {
 
1752
        windInfo.insert("windGust", i18n("N/A"));
 
1753
        windInfo.insert("windGustUnit", QString::number(KUnitConversion::NoUnit));
 
1754
    } else {
 
1755
        windInfo.insert("windGust", QString::number(m_weatherData[source].windGust.toInt()));
 
1756
        windInfo.insert("windGustUnit", QString::number(KUnitConversion::KilometerPerHour));
 
1757
    }
 
1758
 
 
1759
    if (m_weatherData[source].windDirection.isEmpty() && m_weatherData[source].windSpeed.isEmpty()) {
 
1760
        windInfo.insert("windDirection", i18n("N/A"));
 
1761
        windInfo.insert("windDegrees", i18n("N/A"));
 
1762
    } else if (m_weatherData[source].windSpeed.toInt() == 0) {
 
1763
        windInfo.insert("windDirection", i18nc("wind direction - wind speed is too low to measure", "VR")); // Variable/calm
 
1764
    } else {
 
1765
        windInfo.insert("windDirection", i18nc("wind direction", m_weatherData[source].windDirection.toUtf8()));
 
1766
        windInfo.insert("windDegrees", m_weatherData[source].windDegrees);
 
1767
    }
 
1768
    return windInfo;
 
1769
}
 
1770
 
 
1771
QMap<QString, QString> EnvCanadaIon::uvIndex(const QString& source) const
 
1772
{
 
1773
    QMap<QString, QString> uvInfo;
 
1774
 
 
1775
    if (m_weatherData[source].UVRating.isEmpty()) {
 
1776
        uvInfo.insert("uvRating", i18n("N/A"));
 
1777
    } else {
 
1778
        uvInfo.insert("uvRating", m_weatherData[source].UVRating);
 
1779
    }
 
1780
 
 
1781
    if (m_weatherData[source].UVIndex.isEmpty()) {
 
1782
        uvInfo.insert("uvIndex", i18n("N/A"));
 
1783
    } else {
 
1784
        uvInfo.insert("uvIndex", m_weatherData[source].UVIndex);
 
1785
    }
 
1786
 
 
1787
    return uvInfo;
 
1788
}
 
1789
 
 
1790
QMap<QString, QString> EnvCanadaIon::regionalTemperatures(const QString& source) const
 
1791
{
 
1792
    QMap<QString, QString> regionalTempInfo;
 
1793
 
 
1794
    if (m_weatherData[source].normalHigh.isEmpty()) {
 
1795
        regionalTempInfo.insert("normalHigh", i18n("N/A"));
 
1796
    } else {
 
1797
        regionalTempInfo.insert("normalHigh", m_weatherData[source].normalHigh);
 
1798
    }
 
1799
 
 
1800
    if (m_weatherData[source].normalLow.isEmpty()) {
 
1801
        regionalTempInfo.insert("normalLow", i18n("N/A"));
 
1802
    } else {
 
1803
        regionalTempInfo.insert("normalLow", m_weatherData[source].normalLow);
 
1804
    }
 
1805
 
 
1806
    return regionalTempInfo;
 
1807
}
 
1808
 
 
1809
QMap<QString, QString> EnvCanadaIon::yesterdayWeather(const QString& source) const
 
1810
{
 
1811
    QMap<QString, QString> yesterdayInfo;
 
1812
 
 
1813
    if (m_weatherData[source].prevHigh.isEmpty()) {
 
1814
        yesterdayInfo.insert("prevHigh", i18n("N/A"));
 
1815
    } else {
 
1816
        yesterdayInfo.insert("prevHigh", m_weatherData[source].prevHigh);
 
1817
    }
 
1818
 
 
1819
    if (m_weatherData[source].prevLow.isEmpty()) {
 
1820
        yesterdayInfo.insert("prevLow", i18n("N/A"));
 
1821
    } else {
 
1822
        yesterdayInfo.insert("prevLow", m_weatherData[source].prevLow);
 
1823
    }
 
1824
 
 
1825
    if (m_weatherData[source].prevPrecipTotal == "Trace") {
 
1826
        yesterdayInfo.insert("prevPrecip", i18nc("precipitation total, very little", "Trace"));
 
1827
        return yesterdayInfo;
 
1828
    }
 
1829
 
 
1830
    if (m_weatherData[source].prevPrecipTotal.isEmpty()) {
 
1831
        yesterdayInfo.insert("prevPrecip", i18n("N/A"));
 
1832
        yesterdayInfo.insert("prevPrecipUnit", QString::number(KUnitConversion::NoUnit));
 
1833
    } else {
 
1834
        yesterdayInfo.insert("prevPrecipTotal", m_weatherData[source].prevPrecipTotal);
 
1835
        if (m_weatherData[source].prevPrecipType == "mm") {
 
1836
            yesterdayInfo.insert("prevPrecipUnit", QString::number(KUnitConversion::Millimeter));
 
1837
        } else if (m_weatherData[source].prevPrecipType == "cm") {
 
1838
            yesterdayInfo.insert("prevPrecipUnit", QString::number(KUnitConversion::Centimeter));
 
1839
        } else {
 
1840
            yesterdayInfo.insert("prevPrecipUnit", QString::number(KUnitConversion::NoUnit));
 
1841
        }
 
1842
    }
 
1843
 
 
1844
    return yesterdayInfo;
 
1845
}
 
1846
 
 
1847
QMap<QString, QString> EnvCanadaIon::sunriseSet(const QString& source) const
 
1848
{
 
1849
    QMap<QString, QString> sunInfo;
 
1850
 
 
1851
    if (m_weatherData[source].sunriseTimestamp.isEmpty()) {
 
1852
        sunInfo.insert("sunrise", i18n("N/A"));
 
1853
    } else {
 
1854
        sunInfo.insert("sunrise", m_weatherData[source].sunriseTimestamp);
 
1855
    }
 
1856
 
 
1857
    if (m_weatherData[source].sunsetTimestamp.isEmpty()) {
 
1858
        sunInfo.insert("sunset", i18n("N/A"));
 
1859
    } else {
 
1860
        sunInfo.insert("sunset", m_weatherData[source].sunsetTimestamp);
 
1861
    }
 
1862
 
 
1863
    return sunInfo;
 
1864
}
 
1865
 
 
1866
QMap<QString, QString> EnvCanadaIon::moonriseSet(const QString& source) const
 
1867
{
 
1868
    QMap<QString, QString> moonInfo;
 
1869
 
 
1870
    if (m_weatherData[source].moonriseTimestamp.isEmpty()) {
 
1871
        moonInfo.insert("moonrise", i18n("N/A"));
 
1872
    } else {
 
1873
        moonInfo.insert("moonrise", m_weatherData[source].moonriseTimestamp);
 
1874
    }
 
1875
 
 
1876
    if (m_weatherData[source].moonsetTimestamp.isEmpty()) {
 
1877
        moonInfo.insert("moonset", i18n("N/A"));
 
1878
    } else {
 
1879
        moonInfo.insert("moonset", m_weatherData[source].moonsetTimestamp);
 
1880
    }
 
1881
 
 
1882
    return moonInfo;
 
1883
}
 
1884
 
 
1885
QMap<QString, QString> EnvCanadaIon::weatherRecords(const QString& source) const
 
1886
{
 
1887
    QMap<QString, QString> recordInfo;
 
1888
 
 
1889
    if (m_weatherData[source].recordHigh == 0) {
 
1890
        recordInfo.insert("recordHigh", i18n("N/A"));
 
1891
    } else {
 
1892
        recordInfo.insert("recordHigh", QString("%1").arg(m_weatherData[source].recordHigh));
 
1893
    }
 
1894
 
 
1895
    if (m_weatherData[source].recordLow == 0) {
 
1896
        recordInfo.insert("recordLow", i18n("N/A"));
 
1897
    } else {
 
1898
        recordInfo.insert("recordLow", QString("%1").arg(m_weatherData[source].recordLow));
 
1899
    }
 
1900
 
 
1901
    if (m_weatherData[source].recordRain == 0) {
 
1902
        recordInfo.insert("recordRain", i18n("N/A"));
 
1903
        recordInfo.insert("recordRainUnit", QString::number(KUnitConversion::NoUnit));
 
1904
    } else {
 
1905
        recordInfo.insert("recordRain", QString("%1").arg(m_weatherData[source].recordRain));
 
1906
        recordInfo.insert("recordRainUnit", QString::number(KUnitConversion::Millimeter));
 
1907
    }
 
1908
 
 
1909
    if (m_weatherData[source].recordSnow == 0) {
 
1910
        recordInfo.insert("recordSnow", i18n("N/A"));
 
1911
        recordInfo.insert("recordSnowUnit", QString::number(KUnitConversion::NoUnit));
 
1912
    } else {
 
1913
        recordInfo.insert("recordSnow", QString("%1").arg(m_weatherData[source].recordSnow));
 
1914
        recordInfo.insert("recordSnowUnit", QString::number(KUnitConversion::Centimeter));
 
1915
    }
 
1916
 
 
1917
    return recordInfo;
 
1918
}
 
1919
 
 
1920
#include "ion_envcan.moc"