weather-summary.c 34.1 KB
Newer Older
1
/*  Copyright (c) 2003-2012 Xfce Development Team
2
 *
3 4 5 6
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
7
 *
8 9 10 11
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
12
 *
13 14 15 16
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
17 18 19
 */

#ifdef HAVE_CONFIG_H
20
#include <config.h>
21 22
#endif

23
#include <libxfce4ui/libxfce4ui.h>
24

Nick Schermer's avatar
Nick Schermer committed
25 26 27 28 29 30
#include "weather-parsers.h"
#include "weather-data.h"
#include "weather.h"
#include "weather-summary.h"
#include "weather-translate.h"
#include "weather-icon.h"
31

32

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
static gboolean
lnk_clicked(GtkTextTag *tag,
            GObject *obj,
            GdkEvent *event,
            GtkTextIter *iter,
            GtkWidget *textview);


#define BORDER 8

#define APPEND_BTEXT(text)                                          \
    gtk_text_buffer_insert_with_tags(GTK_TEXT_BUFFER(buffer),       \
                                     &iter, text, -1, btag, NULL);

#define APPEND_TEXT_ITEM_REAL(text)                 \
    gtk_text_buffer_insert(GTK_TEXT_BUFFER(buffer), \
                           &iter, text, -1);        \
    g_free(value);

#define APPEND_TEXT_ITEM(text, item)                            \
53 54
    rawvalue = get_data(conditions, data->units, item,          \
                        FALSE, data->night_time);               \
55
    unit = get_unit(data->units, item);                         \
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
    value = g_strdup_printf("\t%s%s%s%s%s\n",                   \
                            text, text ? ": " : "",             \
                            rawvalue,                           \
                            strcmp(unit, "°") ? " " : "",       \
                            unit);                              \
    g_free(rawvalue);                                           \
    APPEND_TEXT_ITEM_REAL(value);

#define APPEND_LINK_ITEM(prefix, text, url, lnk_tag)                    \
    gtk_text_buffer_insert(GTK_TEXT_BUFFER(buffer),                     \
                           &iter, prefix, -1);                          \
    gtk_text_buffer_insert_with_tags(GTK_TEXT_BUFFER(buffer),           \
                                     &iter, text, -1, lnk_tag, NULL);   \
    gtk_text_buffer_insert(GTK_TEXT_BUFFER(buffer),                     \
                           &iter, "\n", -1);                            \
    g_object_set_data_full(G_OBJECT(lnk_tag), "url", g_strdup(url), g_free); \
    g_signal_connect(G_OBJECT(lnk_tag), "event",                        \
                     G_CALLBACK(lnk_clicked), NULL);
74

Harald Judt's avatar
Harald Judt committed
75 76 77 78 79 80 81 82 83 84 85 86
#define ATTACH_DAYTIME_HEADER(title, pos)               \
    if (data->forecast_layout == FC_LAYOUT_CALENDAR)    \
        gtk_table_attach_defaults                       \
            (GTK_TABLE(table),                          \
             add_forecast_header(title, 90.0, &darkbg), \
             0, 1, pos, pos+1);                         \
    else                                                \
        gtk_table_attach_defaults                       \
            (GTK_TABLE(table),                          \
             add_forecast_header(title, 0.0, &darkbg),  \
             pos, pos+1, 0, 1);                         \

87
#define APPEND_TOOLTIP_ITEM(description, item)                  \
88 89
    value = get_data(fcdata, data->units, item,                 \
                     data->round, data->night_time);            \
90 91 92 93 94 95
    unit = get_unit(data->units, item);                         \
    g_string_append_printf(text, description, value,            \
                           strcmp(unit, "°") ? " " : "",        \
                           unit);                               \
    g_free(value);

96

97 98 99 100 101 102
static gboolean
lnk_clicked(GtkTextTag *tag,
            GObject *obj,
            GdkEvent *event,
            GtkTextIter *iter,
            GtkWidget *textview)
103
{
104 105
    const gchar *url;
    gchar *str;
106

107 108 109 110 111 112 113 114 115 116
    if (event->type == GDK_BUTTON_RELEASE) {
        url = g_object_get_data(G_OBJECT(tag), "url");
        str = g_strdup_printf("exo-open --launch WebBrowser %s", url);
        g_spawn_command_line_async(str, NULL);
        g_free(str);
    } else if (event->type == GDK_LEAVE_NOTIFY)
        gdk_window_set_cursor(gtk_text_view_get_window(GTK_TEXT_VIEW(obj),
                                                       GTK_TEXT_WINDOW_TEXT),
                              NULL);
    return FALSE;
117 118
}

119

120
static gboolean
121
icon_clicked (GtkWidget *widget,
122
              GdkEventButton *event,
123
              gpointer user_data)
124
{
125
    return lnk_clicked(user_data, NULL, (GdkEvent *) (event), NULL, NULL);
126 127
}

128 129 130 131

static gboolean
view_motion_notify(GtkWidget *widget,
                   GdkEventMotion *event,
Harald Judt's avatar
Harald Judt committed
132
                   summary_details *sum)
133
{
Harald Judt's avatar
Harald Judt committed
134 135 136 137 138
    GtkTextIter iter;
    GtkTextTag *tag;
    GSList *tags;
    GSList *cur;
    gint bx, by;
139

Harald Judt's avatar
Harald Judt committed
140
    if (event->x != -1 && event->y != -1) {
Harald Judt's avatar
Harald Judt committed
141
        gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(sum->text_view),
142 143
                                              GTK_TEXT_WINDOW_WIDGET,
                                              event->x, event->y, &bx, &by);
Harald Judt's avatar
Harald Judt committed
144
        gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(sum->text_view),
145 146 147
                                           &iter, bx, by);
        tags = gtk_text_iter_get_tags(&iter);
        for (cur = tags; cur != NULL; cur = cur->next) {
Harald Judt's avatar
Harald Judt committed
148
            tag = cur->data;
149
            if (g_object_get_data(G_OBJECT(tag), "url")) {
Harald Judt's avatar
Harald Judt committed
150 151 152 153
                gdk_window_set_cursor
                    (gtk_text_view_get_window(GTK_TEXT_VIEW(sum->text_view),
                                              GTK_TEXT_WINDOW_TEXT),
                     sum->hand_cursor);
154 155 156
                return FALSE;
            }
        }
157
    }
Harald Judt's avatar
Harald Judt committed
158 159 160 161 162
    if (!sum->on_icon)
        gdk_window_set_cursor
            (gtk_text_view_get_window(GTK_TEXT_VIEW(sum->text_view),
                                      GTK_TEXT_WINDOW_TEXT),
             sum->text_cursor);
163
    return FALSE;
164 165
}

166 167 168 169

static gboolean
icon_motion_notify(GtkWidget *widget,
                   GdkEventMotion *event,
Harald Judt's avatar
Harald Judt committed
170
                   summary_details *sum)
171
{
Harald Judt's avatar
Harald Judt committed
172 173 174 175 176
    sum->on_icon = TRUE;
    gdk_window_set_cursor
        (gtk_text_view_get_window(GTK_TEXT_VIEW(sum->text_view),
                                  GTK_TEXT_WINDOW_TEXT),
         sum->hand_cursor);
177
    return FALSE;
178 179
}

180 181 182 183

static gboolean
view_leave_notify(GtkWidget *widget,
                  GdkEventMotion *event,
Harald Judt's avatar
Harald Judt committed
184
                  summary_details *sum)
185
{
Harald Judt's avatar
Harald Judt committed
186 187 188 189 190
    sum->on_icon = FALSE;
    gdk_window_set_cursor
        (gtk_text_view_get_window(GTK_TEXT_VIEW(sum->text_view),
                                  GTK_TEXT_WINDOW_TEXT),
         sum->text_cursor);
191
    return FALSE;
192 193
}

194 195 196

static void
view_scrolled_cb(GtkAdjustment *adj,
Harald Judt's avatar
Harald Judt committed
197
                 summary_details *sum)
198
{
Harald Judt's avatar
Harald Judt committed
199 200
    gint x, y, x1, y1;

Harald Judt's avatar
Harald Judt committed
201 202 203 204
    if (sum->icon_ebox) {
        x1 = sum->text_view->allocation.width - 191 - 15;
        y1 = sum->text_view->requisition.height - 60 - 15;
        gtk_text_view_buffer_to_window_coords(GTK_TEXT_VIEW(sum->text_view),
205 206
                                              GTK_TEXT_WINDOW_TEXT,
                                              x1, y1, &x, &y);
Harald Judt's avatar
Harald Judt committed
207 208
        gtk_text_view_move_child(GTK_TEXT_VIEW(sum->text_view),
                                 sum->icon_ebox, x, y);
209
    }
210 211
}

212 213 214 215 216

static void
view_size_allocate_cb(GtkWidget *widget,
                      GtkAllocation *allocation,
                      gpointer data)
217
{
Harald Judt's avatar
Harald Judt committed
218
    view_scrolled_cb(NULL, data);
219
}
220

221 222 223

static gchar *
get_logo_path(void)
224
{
225 226 227 228 229 230 231
    gchar *cache_dir, *logo_path;

    cache_dir = get_cache_directory();
    logo_path = g_strconcat(cache_dir, G_DIR_SEPARATOR_S,
                            "weather_logo.gif", NULL);
    g_free(cache_dir);
    return logo_path;
232 233
}

234

235
static void
236 237 238
logo_fetched(SoupSession *session,
             SoupMessage *msg,
             gpointer user_data)
239
{
240
    if (msg && msg->response_body && msg->response_body->length > 0) {
241 242 243
        gchar *path = get_logo_path();
        GError *error = NULL;
        GdkPixbuf *pixbuf = NULL;
244 245 246 247
        if (!g_file_set_contents(path, msg->response_body->data,
                                 msg->response_body->length, &error)) {
            g_warning("Error downloading met.no logo image to %s, "
                      "err %s\n", path, error ? error->message : "?");
248 249 250 251 252 253 254 255 256 257 258
            g_error_free(error);
            g_free(path);
            return;
        }
        pixbuf = gdk_pixbuf_new_from_file(path, NULL);
        g_free(path);
        if (pixbuf) {
            gtk_image_set_from_pixbuf(GTK_IMAGE(user_data), pixbuf);
            g_object_unref(pixbuf);
        }
    }
259 260
}

261 262

static GtkWidget *
263
weather_summary_get_logo(plugin_data *data)
264
{
265
    GtkWidget *image = gtk_image_new();
Harald Judt's avatar
Harald Judt committed
266
    GdkPixbuf *pixbuf;
267 268 269 270 271
    gchar *path = get_logo_path();

    pixbuf = gdk_pixbuf_new_from_file(path, NULL);
    g_free(path);
    if (pixbuf == NULL)
272 273
        weather_http_queue_request(data->session,
                                   "http://met.no/filestore/met.no-logo.gif",
274
                                   logo_fetched, image);
275 276 277 278 279
    else {
        gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
        g_object_unref(pixbuf);
    }
    return image;
280
}
281

282

283
static GtkWidget *
284
create_summary_tab(plugin_data *data)
285
{
286 287 288
    GtkTextBuffer *buffer;
    GtkTextIter iter;
    GtkTextTag *btag, *ltag0, *ltag1;
Harald Judt's avatar
Harald Judt committed
289
    GtkWidget *view, *frame, *scrolled, *icon;
290 291 292 293
    GtkAdjustment *adj;
    GdkColor lnk_color;
    xml_time *conditions;
    const gchar *unit;
Harald Judt's avatar
Harald Judt committed
294
    gchar *value, *rawvalue, *wind;
295 296
    gchar *interval_start, *interval_end, *point, *last_weather_update;
    gchar *sunrise, *sunset, *moonrise, *moonset;
Harald Judt's avatar
Harald Judt committed
297
    summary_details *sum;
298

Harald Judt's avatar
Harald Judt committed
299 300 301 302 303 304 305
    sum = g_slice_new0(summary_details);
    sum->on_icon = FALSE;
    sum->hand_cursor = gdk_cursor_new(GDK_HAND2);
    sum->text_cursor = gdk_cursor_new(GDK_XTERM);
    data->summary_details = sum;

    sum->text_view = view = gtk_text_view_new();
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
    gtk_text_view_set_editable(GTK_TEXT_VIEW(view), FALSE);
    gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(view), FALSE);
    frame = gtk_frame_new(NULL);
    scrolled = gtk_scrolled_window_new(NULL, NULL);

    gtk_container_add(GTK_CONTAINER(scrolled), view);
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

    gtk_container_set_border_width(GTK_CONTAINER(frame), BORDER);
    gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
    gtk_container_add(GTK_CONTAINER(frame), scrolled);

    buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
    gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER(buffer), &iter, 0);
    btag = gtk_text_buffer_create_tag(buffer, NULL, "weight",
                                      PANGO_WEIGHT_BOLD, NULL);

    gdk_color_parse("#0000ff", &lnk_color);
    ltag0 = gtk_text_buffer_create_tag(buffer, "lnk0",
                                       "foreground-gdk", &lnk_color, NULL);
    ltag1 = gtk_text_buffer_create_tag(buffer, "lnk1",
                                       "foreground-gdk", &lnk_color, NULL);

    conditions = get_current_conditions(data->weatherdata);
    APPEND_BTEXT(_("Coordinates\n"));
    APPEND_TEXT_ITEM(_("Altitude"), ALTITUDE);
    APPEND_TEXT_ITEM(_("Latitude"), LATITUDE);
    APPEND_TEXT_ITEM(_("Longitude"), LONGITUDE);

336 337
    /* TRANSLATORS: Please use as many \t as appropriate to align the
       date/time values as in the original. */
338
    APPEND_BTEXT(_("\nTime\n"));
339 340 341 342 343 344 345
    last_weather_update = format_date(data->weather_update->last, NULL, TRUE);
    value = g_strdup_printf(_("\tLast updated:\t%s\n\n"),
                            last_weather_update);
    g_free(last_weather_update);
    APPEND_TEXT_ITEM_REAL(value);

    point = format_date(conditions->point, NULL, TRUE);
346
    value = g_strdup_printf
Harald Judt's avatar
Harald Judt committed
347
        (_("\tTemperatures, wind, atmosphere and cloud data calculated\n"
348
           "\tfor:\t\t\t%s\n"),
349
         point);
350
    g_free(point);
351 352
    APPEND_TEXT_ITEM_REAL(value);

353 354
    interval_start = format_date(conditions->start, NULL, TRUE);
    interval_end = format_date(conditions->end, NULL, TRUE);
355
    value = g_strdup_printf
Harald Judt's avatar
Harald Judt committed
356
        (_("\n\tPrecipitation and the weather symbol have been calculated\n"
357 358 359
           "\tusing the following time interval:\n"
           "\tStart:\t\t%s\n"
           "\tEnd:\t\t%s\n"),
360 361
         interval_start,
         interval_end);
362 363
    g_free(interval_end);
    g_free(interval_start);
364 365
    APPEND_TEXT_ITEM_REAL(value);

366
    /* sun and moon */
367
    APPEND_BTEXT(_("\nAstronomical Data\n"));
368 369 370 371 372 373 374 375
    if (data->astrodata) {
        if (data->astrodata->sun_never_rises) {
            value = g_strdup(_("\tSunrise:\t\tThe sun never rises today.\n"));
            APPEND_TEXT_ITEM_REAL(value);
        } else if (data->astrodata->sun_never_sets) {
            value = g_strdup(_("\tSunset:\t\tThe sun never sets today.\n"));
            APPEND_TEXT_ITEM_REAL(value);
        } else {
376
            sunrise = format_date(data->astrodata->sunrise, NULL, TRUE);
377
            value = g_strdup_printf(_("\tSunrise:\t\t%s\n"), sunrise);
378
            g_free(sunrise);
379 380
            APPEND_TEXT_ITEM_REAL(value);

381
            sunset = format_date(data->astrodata->sunset, NULL, TRUE);
382
            value = g_strdup_printf(_("\tSunset:\t\t%s\n\n"), sunset);
383
            g_free(sunset);
384 385 386 387 388 389 390 391 392 393 394 395
            APPEND_TEXT_ITEM_REAL(value);
        }

        if (data->astrodata->moon_phase)
            value = g_strdup_printf(_("\tMoon phase:\t%s\n"),
                                    translate_moon_phase
                                    (data->astrodata->moon_phase));
        else
            value = g_strdup(_("\tMoon phase:\tUnknown\n"));
        APPEND_TEXT_ITEM_REAL(value);

        if (data->astrodata->moon_never_rises) {
396 397
            value =
                g_strdup(_("\tMoonrise:\tThe moon never rises today.\n"));
398 399
            APPEND_TEXT_ITEM_REAL(value);
        } else if (data->astrodata->moon_never_sets) {
400 401
            value =
                g_strdup(_("\tMoonset:\tThe moon never sets today.\n"));
402 403
            APPEND_TEXT_ITEM_REAL(value);
        } else {
404
            moonrise = format_date(data->astrodata->moonrise, NULL, TRUE);
405
            value = g_strdup_printf(_("\tMoonrise:\t%s\n"), moonrise);
406
            g_free(moonrise);
407 408
            APPEND_TEXT_ITEM_REAL(value);

409
            moonset = format_date(data->astrodata->moonset, NULL, TRUE);
410
            value = g_strdup_printf(_("\tMoonset:\t%s\n"), moonset);
411
            g_free(moonset);
412 413 414 415 416 417 418 419
            APPEND_TEXT_ITEM_REAL(value);
        }
    } else {
        value = g_strdup(_("\tData not available, will use sane "
                           "default values for night and day.\n"));
        APPEND_TEXT_ITEM_REAL(value);
    }

Harald Judt's avatar
Harald Judt committed
420 421
    /* temperatures */
    APPEND_BTEXT(_("\nTemperatures\n"));
422
    APPEND_TEXT_ITEM(_("Temperature"), TEMPERATURE);
Harald Judt's avatar
Harald Judt committed
423
    APPEND_TEXT_ITEM(_("Dew point"), DEWPOINT);
424
    APPEND_TEXT_ITEM(_("Apparent temperature"), APPARENT_TEMPERATURE);
425 426 427

    /* wind */
    APPEND_BTEXT(_("\nWind\n"));
428 429 430 431
    wind = get_data(conditions, data->units, WIND_SPEED,
                    FALSE, data->night_time);
    rawvalue = get_data(conditions, data->units, WIND_BEAUFORT,
                        FALSE, data->night_time);
432 433 434 435
    value = g_strdup_printf(_("\t%s: %s %s (%s on the Beaufort scale)\n"),
                            _("Speed"), wind,
                            get_unit(data->units, WIND_SPEED),
                            rawvalue);
436 437 438 439
    g_free(rawvalue);
    g_free(wind);
    APPEND_TEXT_ITEM_REAL(value);

440 441
    rawvalue = get_data(conditions, data->units, WIND_DIRECTION,
                        FALSE, data->night_time);
442 443
    wind = translate_wind_direction(rawvalue);
    g_free(rawvalue);
444 445
    rawvalue = get_data(conditions, data->units, WIND_DIRECTION_DEG,
                        FALSE, data->night_time);
446 447
    value = g_strdup_printf("\t%s: %s (%s%s)\n", _("Direction"),
                            wind, rawvalue,
448
                            get_unit(data->units, WIND_DIRECTION_DEG));
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
    g_free(rawvalue);
    g_free(wind);
    APPEND_TEXT_ITEM_REAL(value);

    /* precipitation */
    APPEND_BTEXT(_("\nPrecipitations\n"));
    APPEND_TEXT_ITEM(_("Precipitations amount"), PRECIPITATIONS);

    /* atmosphere */
    APPEND_BTEXT(_("\nAtmosphere\n"));
    APPEND_TEXT_ITEM(_("Pressure"), PRESSURE);
    APPEND_TEXT_ITEM(_("Humidity"), HUMIDITY);

    /* clouds */
    APPEND_BTEXT(_("\nClouds\n"));
    APPEND_TEXT_ITEM(_("Fog"), FOG);
    APPEND_TEXT_ITEM(_("Low clouds"), CLOUDS_LOW);
    APPEND_TEXT_ITEM(_("Medium clouds"), CLOUDS_MED);
    APPEND_TEXT_ITEM(_("High clouds"), CLOUDS_HIGH);
    APPEND_TEXT_ITEM(_("Cloudiness"), CLOUDINESS);

    APPEND_BTEXT(_("\nData from The Norwegian Meteorological Institute\n"));
    value = g_strdup("http://met.no");
    g_object_set_data_full(G_OBJECT(ltag0), "url", value, g_free);
    APPEND_LINK_ITEM("\t", _("Thanks to met.no"), "http://met.no/", ltag1);

    g_signal_connect(G_OBJECT(view), "motion-notify-event",
Harald Judt's avatar
Harald Judt committed
476
                     G_CALLBACK(view_motion_notify), sum);
477
    g_signal_connect(G_OBJECT(view), "leave-notify-event",
Harald Judt's avatar
Harald Judt committed
478
                     G_CALLBACK(view_leave_notify), sum);
479

Harald Judt's avatar
Harald Judt committed
480
    icon = weather_summary_get_logo(data);
481

Harald Judt's avatar
Harald Judt committed
482 483
    if (icon) {
        sum->icon_ebox = gtk_event_box_new();
484 485
        gtk_event_box_set_visible_window(GTK_EVENT_BOX(sum->icon_ebox), FALSE);
        gtk_container_add(GTK_CONTAINER(sum->icon_ebox), icon);
486
        gtk_text_view_add_child_in_window(GTK_TEXT_VIEW(view),
Harald Judt's avatar
Harald Judt committed
487
                                          sum->icon_ebox,
488
                                          GTK_TEXT_WINDOW_TEXT, 0, 0);
Harald Judt's avatar
Harald Judt committed
489
        gtk_widget_show_all(sum->icon_ebox);
490 491 492
        adj =
            gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scrolled));
        g_signal_connect(G_OBJECT(adj), "value-changed",
Harald Judt's avatar
Harald Judt committed
493
                         G_CALLBACK(view_scrolled_cb), sum);
494
        g_signal_connect(G_OBJECT(view), "size_allocate",
Harald Judt's avatar
Harald Judt committed
495 496 497 498 499 500 501 502 503
                         G_CALLBACK(view_size_allocate_cb), sum);
        g_signal_connect(G_OBJECT(sum->icon_ebox), "button-release-event",
                         G_CALLBACK(icon_clicked), ltag0);
        g_signal_connect(G_OBJECT(sum->icon_ebox), "enter-notify-event",
                         G_CALLBACK(icon_motion_notify), sum);
        g_signal_connect(G_OBJECT(sum->icon_ebox), "motion-notify-event",
                         G_CALLBACK(icon_motion_notify), sum);
        g_signal_connect(G_OBJECT(sum->icon_ebox), "leave-notify-event",
                         G_CALLBACK(view_leave_notify), sum);
504
    }
Harald Judt's avatar
Harald Judt committed
505

506
    return frame;
507
}
508

509

Harald Judt's avatar
Harald Judt committed
510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
static gchar *
get_dayname(gint day)
{
    struct tm fcday_tm;
    time_t now_t = time(NULL), fcday_t;
    gint weekday;

    fcday_tm = *localtime(&now_t);
    fcday_t = time_calc_day(fcday_tm, day);
    weekday = localtime(&fcday_t)->tm_wday;
    switch (day) {
    case 0:
        return g_strdup_printf(_("Today"));
    case 1:
        return g_strdup_printf(_("Tomorrow"));
    default:
        return translate_day(weekday);
    }
}


531 532 533 534 535 536 537 538 539 540
static gchar *
forecast_cell_get_tooltip_text(plugin_data *data,
                               xml_time *fcdata)
{
    GString *text;
    gchar *result, *value;
    const gchar *unit;

    /* TRANSLATORS: Please use \t as needed to properly align the values */
    text = g_string_new(_("<b>Times used for calculation</b>\n"));
541
    value = format_date(fcdata->start, NULL, TRUE);
542 543
    g_string_append_printf(text, _("Interval start:\t\t\t%s\n"), value);
    g_free(value);
544
    value = format_date(fcdata->end, NULL, TRUE);
545 546
    g_string_append_printf(text, _("Interval end:\t\t\t%s\n"), value);
    g_free(value);
547
    value = format_date(fcdata->point, NULL, TRUE);
548 549 550
    g_string_append_printf(text, _("Data calculated for:\t%s\n\n"), value);
    g_free(value);

Harald Judt's avatar
Harald Judt committed
551
    g_string_append(text, _("<b>Temperatures</b>\n"));
552 553 554
    APPEND_TOOLTIP_ITEM(_("Dew point:\t\t\t%s%s%s\n"), DEWPOINT);
    APPEND_TOOLTIP_ITEM(_("Apparent temperature:\t%s%s%s\n\n"),
                        APPARENT_TEMPERATURE);
Harald Judt's avatar
Harald Judt committed
555

556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
    g_string_append(text, _("<b>Atmosphere</b>\n"));
    APPEND_TOOLTIP_ITEM(_("Pressure:\t%s%s%s\n"), PRESSURE);
    APPEND_TOOLTIP_ITEM(_("Humidity:\t%s%s%s\n\n"), HUMIDITY);

    g_string_append(text, _("<b>Precipitations</b>\n"));
    APPEND_TOOLTIP_ITEM(_("Amount:\t\t%s%s%s\n\n"), PRECIPITATIONS);

    g_string_append(text, _("<b>Clouds</b>\n"));
    APPEND_TOOLTIP_ITEM(_("Fog:\t\t%s%s%s\n"), FOG);
    APPEND_TOOLTIP_ITEM(_("Low:\t\t%s%s%s\n"), CLOUDS_LOW);
    APPEND_TOOLTIP_ITEM(_("Medium\t\t%s%s%s\n"), CLOUDS_MED);
    APPEND_TOOLTIP_ITEM(_("High:\t\t%s%s%s\n"), CLOUDS_HIGH);
    APPEND_TOOLTIP_ITEM(_("Cloudiness:\t%s%s%s"), CLOUDINESS);

    /* Free GString only and return its character data */
    result = text->str;
    g_string_free(text, FALSE);
    return result;
}


577
static GtkWidget *
Harald Judt's avatar
Harald Judt committed
578 579
wrap_forecast_cell(const GtkWidget *widget,
                   const GdkColor *color)
580
{
581
    GtkWidget *ebox;
Harald Judt's avatar
Harald Judt committed
582

583 584 585 586 587 588 589 590 591 592 593
    ebox = gtk_event_box_new();
    if (color == NULL)
        gtk_event_box_set_visible_window(GTK_EVENT_BOX(ebox), FALSE);
    else {
        gtk_event_box_set_visible_window(GTK_EVENT_BOX(ebox), TRUE);
        gtk_widget_modify_bg(GTK_WIDGET(ebox), GTK_STATE_NORMAL, color);
    }
    gtk_container_add(GTK_CONTAINER(ebox), GTK_WIDGET(widget));
    return ebox;
}

594

595
static GtkWidget *
596 597 598
add_forecast_header(const gchar *text,
                    const gdouble angle,
                    const GdkColor *color)
599
{
Harald Judt's avatar
Harald Judt committed
600
    GtkWidget *label, *align;
601 602
    gchar *str;

603 604 605 606 607
    if (angle)
        align = gtk_alignment_new(1, 1, 0, 1);
    else
        align = gtk_alignment_new(1, 1, 1, 0);
    gtk_container_set_border_width(GTK_CONTAINER(align), 4);
608 609

    label = gtk_label_new(NULL);
Harald Judt's avatar
Harald Judt committed
610
    gtk_label_set_angle(GTK_LABEL(label), angle);
611 612 613
    str = g_strdup_printf("<span foreground=\"white\"><b>%s</b></span>", text ? text : "");
    gtk_label_set_markup(GTK_LABEL(label), str);
    g_free(str);
Harald Judt's avatar
Harald Judt committed
614
    gtk_container_add(GTK_CONTAINER(align), GTK_WIDGET(label));
Harald Judt's avatar
Harald Judt committed
615
    return wrap_forecast_cell(align, color);
616 617
}

618

619
static GtkWidget *
620
add_forecast_cell(plugin_data *data,
Harald Judt's avatar
Harald Judt committed
621 622
                  gint day,
                  gint daytime)
623
{
Harald Judt's avatar
Harald Judt committed
624
    GtkWidget *box, *label, *image;
625
    GdkPixbuf *icon;
626
    const GdkColor black = {0, 0x0000, 0x0000, 0x0000};
Harald Judt's avatar
Harald Judt committed
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
    gchar *wind_speed, *wind_direction, *value, *rawvalue;
    xml_time *fcdata;

    box = gtk_vbox_new(FALSE, 0);

    fcdata = make_forecast_data(data->weatherdata, day, daytime);
    if (fcdata == NULL)
        return box;

    if (fcdata->location == NULL) {
        xml_time_free(fcdata);
        return box;
    }

    /* symbol */
642 643
    rawvalue = get_data(fcdata, data->units, SYMBOL,
                        FALSE, data->night_time);
Harald Judt's avatar
Harald Judt committed
644 645 646 647 648 649 650 651
    icon = get_icon(data->icon_theme, rawvalue, 48, (daytime == NIGHT));
    g_free(rawvalue);
    image = gtk_image_new_from_pixbuf(icon);
    gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(image), TRUE, TRUE, 0);
    if (G_LIKELY(icon))
        g_object_unref(G_OBJECT(icon));

    /* symbol description */
652 653
    rawvalue = get_data(fcdata, data->units, SYMBOL,
                        FALSE, data->night_time);
Harald Judt's avatar
Harald Judt committed
654 655 656 657 658 659 660 661 662 663 664
    value = g_strdup_printf("%s",
                            translate_desc(rawvalue, (daytime == NIGHT)));
    g_free(rawvalue);
    label = gtk_label_new(NULL);
    gtk_label_set_markup(GTK_LABEL(label), value);
    if (!(day % 2))
        gtk_widget_modify_fg(GTK_WIDGET(label), GTK_STATE_NORMAL, &black);
    gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(label), TRUE, TRUE, 0);
    g_free(value);

    /* temperature */
665 666
    rawvalue = get_data(fcdata, data->units, TEMPERATURE,
                        data->round, data->night_time);
Harald Judt's avatar
Harald Judt committed
667 668 669 670 671 672 673 674 675 676
    value = g_strdup_printf("%s %s", rawvalue,
                            get_unit(data->units, TEMPERATURE));
    g_free(rawvalue);
    label = gtk_label_new(value);
    if (!(day % 2))
        gtk_widget_modify_fg(GTK_WIDGET(label), GTK_STATE_NORMAL, &black);
    gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(label), TRUE, TRUE, 0);
    g_free(value);

    /* wind direction and speed */
677 678
    rawvalue = get_data(fcdata, data->units, WIND_DIRECTION,
                        FALSE, data->night_time);
Harald Judt's avatar
Harald Judt committed
679
    wind_direction = translate_wind_direction(rawvalue);
680 681
    wind_speed = get_data(fcdata, data->units, WIND_SPEED,
                          data->round, data->night_time);
Harald Judt's avatar
Harald Judt committed
682 683 684 685 686 687 688 689 690 691 692 693 694
    value = g_strdup_printf("%s %s %s", wind_direction, wind_speed,
                            get_unit(data->units, WIND_SPEED));
    g_free(wind_speed);
    g_free(wind_direction);
    g_free(rawvalue);
    label = gtk_label_new(value);
    if (!(day % 2))
        gtk_widget_modify_fg(GTK_WIDGET(label), GTK_STATE_NORMAL, &black);
    gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0);
    g_free(value);

    gtk_widget_set_size_request(GTK_WIDGET(box), 150, -1);

695 696 697 698
    value = forecast_cell_get_tooltip_text(data, fcdata);
    gtk_widget_set_tooltip_markup(GTK_WIDGET(box), value);
    g_free(value);

Harald Judt's avatar
Harald Judt committed
699 700 701 702 703 704
    xml_time_free(fcdata);
    return box;
}


static GtkWidget *
705
make_forecast(plugin_data *data)
Harald Judt's avatar
Harald Judt committed
706 707 708
{
    GtkWidget *table, *ebox, *box, *align;
    GtkWidget *forecast_box;
709 710
    const GdkColor lightbg = {0, 0xeaea, 0xeaea, 0xeaea};
    const GdkColor darkbg = {0, 0x6666, 0x6666, 0x6666};
Harald Judt's avatar
Harald Judt committed
711
    gchar *dayname;
Harald Judt's avatar
Harald Judt committed
712 713 714 715 716 717 718
    gint i;
    daytime daytime;

    if (data->forecast_layout == FC_LAYOUT_CALENDAR)
        table = gtk_table_new(5, data->forecast_days + 1, FALSE);
    else
        table = gtk_table_new(data->forecast_days + 1, 5, FALSE);
719 720 721 722 723 724 725

    gtk_table_set_row_spacings(GTK_TABLE(table), 0);
    gtk_table_set_col_spacings(GTK_TABLE(table), 0);

    /* empty upper left corner */
    box = gtk_vbox_new(FALSE, 0);
    gtk_table_attach_defaults(GTK_TABLE(table),
Harald Judt's avatar
Harald Judt committed
726
                              wrap_forecast_cell(box, &darkbg),
727 728 729
                              0, 1, 0, 1);

    /* daytime headers */
Harald Judt's avatar
Harald Judt committed
730 731 732 733
    ATTACH_DAYTIME_HEADER(_("Morning"), 1);
    ATTACH_DAYTIME_HEADER(_("Afternoon"), 2);
    ATTACH_DAYTIME_HEADER(_("Evening"), 3);
    ATTACH_DAYTIME_HEADER(_("Night"), 4);
734

735
    for (i = 0; i < data->forecast_days; i++) {
736
        /* forecast day headers */
Harald Judt's avatar
Harald Judt committed
737 738 739
        dayname = get_dayname(i);
        if (data->forecast_layout == FC_LAYOUT_CALENDAR)
            ebox = add_forecast_header(dayname, 0.0, &darkbg);
740
        else
Harald Judt's avatar
Harald Judt committed
741
            ebox = add_forecast_header(dayname, 90.0, &darkbg);
Harald Judt's avatar
Harald Judt committed
742
        g_free(dayname);
743

Harald Judt's avatar
Harald Judt committed
744 745 746 747 748 749
        if (data->forecast_layout == FC_LAYOUT_CALENDAR)
            gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(ebox),
                                      i+1, i+2, 0, 1);
        else
            gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(ebox),
                                      0, 1, i+1, i+2);
750

751
        /* get forecast data for each daytime */
752
        for (daytime = MORNING; daytime <= NIGHT; daytime++) {
Harald Judt's avatar
Harald Judt committed
753
            forecast_box = add_forecast_cell(data, i, daytime);
Harald Judt's avatar
Harald Judt committed
754 755 756
            align = gtk_alignment_new(0.5, 0.5, 1, 1);
            gtk_container_set_border_width(GTK_CONTAINER(align), 4);
            gtk_container_add(GTK_CONTAINER(align), GTK_WIDGET(forecast_box));
757
            if (i % 2)
Harald Judt's avatar
Harald Judt committed
758
                ebox = wrap_forecast_cell(align, NULL);
759
            else
Harald Judt's avatar
Harald Judt committed
760 761
                ebox = wrap_forecast_cell(align, &lightbg);

Harald Judt's avatar
Harald Judt committed
762 763 764 765 766 767 768 769
            if (data->forecast_layout == FC_LAYOUT_CALENDAR)
                gtk_table_attach_defaults(GTK_TABLE(table),
                                          GTK_WIDGET(ebox),
                                          i+1, i+2, 1+daytime, 2+daytime);
            else
                gtk_table_attach_defaults(GTK_TABLE(table),
                                          GTK_WIDGET(ebox),
                                          1+daytime, 2+daytime, i+1, i+2);
770 771 772
        }
    }
    return table;
773 774
}

775

776
static GtkWidget *
777
create_forecast_tab(plugin_data *data)
778
{
779
    GtkWidget *ebox, *align, *hbox, *scrolled, *table;
780
    GdkWindow *window;
781
    GdkScreen *screen;
782
    GdkRectangle rect;
Harald Judt's avatar
Harald Judt committed
783 784
    gint monitor_num = 0, h_need, h_max, height;
    gint w_need, w_max, width;
785

786 787 788 789 790 791 792 793 794 795
    /* To avoid causing a GDK assertion, determine the monitor
     * geometry using the weather icon window, which has already been
     * realized in contrast to the summary window. Then calculate the
     * maximum height we may use, subtracting some sane value just to
     * be on the safe side. */
    window = GDK_WINDOW(gtk_widget_get_window(GTK_WIDGET(data->iconimage)));
    screen = GDK_SCREEN(gdk_window_get_screen(window));
    if (G_LIKELY(window && screen))
        monitor_num = gdk_screen_get_monitor_at_window(screen, window);
    gdk_screen_get_monitor_geometry(screen, monitor_num, &rect);
796

Harald Judt's avatar
Harald Judt committed
797 798 799
    /* calculate maximum width and height */
    h_max = rect.height - 250;
    w_max = rect.width - 50;
800

Harald Judt's avatar
Harald Judt committed
801 802 803 804 805 806 807 808
    /* calculate needed space using a good arbitrary value */
    if (data->forecast_layout == FC_LAYOUT_CALENDAR) {
        w_need = ((data->forecast_days < 8) ? data->forecast_days : 7) * 142;
        h_need = 500;
    } else {
        w_need = (rect.width <= 720) ? 650 : 700;
        h_need = data->forecast_days * 110;
    }
809 810 811 812

    /* generate the forecast table */
    table = GTK_WIDGET(make_forecast(data));

Harald Judt's avatar
Harald Judt committed
813
    /* generate the containing widgets */
814
    align = gtk_alignment_new(0.5, 0, 0.5, 0);
Harald Judt's avatar
Harald Judt committed
815 816 817 818
    if ((data->forecast_layout == FC_LAYOUT_CALENDAR &&
         w_need < w_max && data->forecast_days < 8) ||
        (data->forecast_layout == FC_LAYOUT_LIST && h_need < h_max)) {
        /* no scroll window needed, just align the contents */
819 820 821 822
        gtk_container_add(GTK_CONTAINER(align), GTK_WIDGET(table));
        gtk_container_set_border_width(GTK_CONTAINER(align), BORDER);
        return align;
    } else {
Harald Judt's avatar
Harald Judt committed
823
        /* contents too big, scroll window needed */
824 825 826 827 828 829 830
        hbox = gtk_hbox_new(FALSE, 0);
        gtk_box_pack_start(GTK_BOX(hbox), table, TRUE, FALSE, 0);
        gtk_container_add(GTK_CONTAINER(align), GTK_WIDGET(hbox));

        scrolled = gtk_scrolled_window_new (NULL, NULL);
        gtk_container_set_border_width(GTK_CONTAINER(scrolled), BORDER);

831 832
        gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled),
                                              align);
833
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
834 835
                                       GTK_POLICY_AUTOMATIC,
                                       GTK_POLICY_AUTOMATIC);
Harald Judt's avatar
Harald Judt committed
836 837 838 839 840 841

        /* set scroll window size */
        width = (w_need > w_max) ? w_max : w_need;
        height = (h_need > h_max) ? h_max : h_need;
        gtk_widget_set_size_request(GTK_WIDGET(scrolled), width, height);

842
        ebox = gtk_event_box_new();
843
        gtk_event_box_set_visible_window(GTK_EVENT_BOX(ebox), TRUE);
844 845
        gtk_container_add(GTK_CONTAINER(ebox), GTK_WIDGET(scrolled));
        return ebox;
846
    }
847
}
848

849

850
static void
851 852
summary_dialog_response(const GtkWidget *dlg,
                        const gint response,
853
                        GtkWidget *window)
854
{
855 856
    if (response == GTK_RESPONSE_ACCEPT)
        gtk_widget_destroy(window);
857 858
}

859

860 861 862 863 864 865 866 867 868 869 870 871
static void
cb_notebook_page_switched(GtkNotebook *notebook,
                          GtkNotebookPage *page,
                          guint page_num,
                          gpointer user_data)
{
    plugin_data *data = (plugin_data *) user_data;

    data->summary_remember_tab = page_num;
}


872
GtkWidget *
873
create_summary_window(plugin_data *data)
874
{
875
    GtkWidget *window, *notebook, *vbox, *hbox, *label;
Harald Judt's avatar
Harald Judt committed
876
    gchar *title, *symbol;
877 878 879
    GdkPixbuf *icon;
    xml_time *conditions;

880 881
    conditions = get_current_conditions(data->weatherdata);
    window = xfce_titled_dialog_new_with_buttons(_("Weather Report"),
882 883 884 885 886
                                                 NULL,
                                                 GTK_DIALOG_NO_SEPARATOR,
                                                 GTK_STOCK_CLOSE,
                                                 GTK_RESPONSE_ACCEPT, NULL);
    if (data->location_name != NULL) {
887
        title = g_strdup_printf("%s", data->location_name);
888 889 890 891 892
        xfce_titled_dialog_set_subtitle(XFCE_TITLED_DIALOG(window), title);
        g_free(title);
    }

    vbox = gtk_vbox_new(FALSE, 0);
Harald Judt's avatar
Harald Judt committed
893
    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), vbox, TRUE, TRUE, 0);
894

895 896
    symbol = get_data(conditions, data->units, SYMBOL,
                      FALSE, data->night_time);
897
    icon = get_icon(data->icon_theme, symbol, 48, data->night_time);
Harald Judt's avatar
Harald Judt committed
898
    g_free(symbol);
899 900 901 902 903 904

    gtk_window_set_icon(GTK_WINDOW(window), icon);

    if (G_LIKELY(icon))
        g_object_unref(G_OBJECT(icon));

905 906
    if (data->location_name == NULL || data->weatherdata == NULL ||
        data->weatherdata->current_conditions == NULL) {
907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
        hbox = gtk_hbox_new(FALSE, 0);
        if (data->location_name == NULL)
            label = gtk_label_new(_("Please set a location in the plugin settings."));
        else
            label = gtk_label_new(_("Currently no data available."));
        gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label),
                           TRUE, TRUE, 0);

        gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox),
                           TRUE, TRUE, 0);
        gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);
    } else {
        notebook = gtk_notebook_new();
        gtk_container_set_border_width(GTK_CONTAINER(notebook), BORDER);
        gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
922
                                 create_forecast_tab(data),
923 924 925 926 927
                                 gtk_label_new_with_mnemonic(_("_Forecast")));
        gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
                                 create_summary_tab(data),
                                 gtk_label_new_with_mnemonic(_("_Details")));
        gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
928 929 930 931
        gtk_widget_show_all(GTK_WIDGET(notebook));
        gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), data->summary_remember_tab);
        g_signal_connect(GTK_NOTEBOOK(notebook), "switch-page",
                         G_CALLBACK(cb_notebook_page_switched), data);
932 933 934 935 936 937
    }

    g_signal_connect(G_OBJECT(window), "response",
                     G_CALLBACK(summary_dialog_response), window);

    return window;
938
}
Harald Judt's avatar
Harald Judt committed
939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956


void
summary_details_free(summary_details *sum)
{
    g_assert(sum != NULL);
    if (G_UNLIKELY(sum == NULL))
        return;

    sum->icon_ebox = NULL;
    sum->text_view = NULL;
    if (sum->hand_cursor)
        gdk_cursor_unref(sum->hand_cursor);
    sum->hand_cursor = NULL;
    if (sum->text_cursor)
        gdk_cursor_unref(sum->text_cursor);
    sum->text_cursor = NULL;
}