weather-summary.c 35.2 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 *last_download, *next_download;
    gchar *interval_start, *interval_end, *point;
297
    gchar *sunrise, *sunset, *moonrise, *moonset;
Harald Judt's avatar
Harald Judt committed
298
    summary_details *sum;
299

Harald Judt's avatar
Harald Judt committed
300 301 302 303 304 305 306
    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();
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 336
    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);

337 338
    /* TRANSLATORS: Please use as many \t as appropriate to align the
       date/time values as in the original. */
339 340 341 342 343 344 345 346 347 348 349 350
    APPEND_BTEXT(_("\nDownloads\n"));
    last_download = format_date(data->weather_update->last, NULL, TRUE);
    next_download = format_date(data->weather_update->next, NULL, TRUE);
    value = g_strdup_printf(_("\tWeather data:\n"
                              "\tLast:\t%s\n"
                              "\tNext:\t%s\n"
                              "\tCurrent failed attempts: %d\n\n"),
                            last_download,
                            next_download,
                            data->weather_update->attempt);
    g_free(last_download);
    g_free(next_download);
351 352
    APPEND_TEXT_ITEM_REAL(value);

353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
    last_download = format_date(data->astro_update->last, NULL, TRUE);
    next_download = format_date(data->astro_update->next, NULL, TRUE);
    value = g_strdup_printf(_("\tAstronomical data:\n"
                              "\tLast:\t%s\n"
                              "\tNext:\t%s\n"
                              "\tCurrent failed attempts: %d\n"),
                            last_download,
                            next_download,
                            data->astro_update->attempt);
    g_free(last_download);
    g_free(next_download);
    APPEND_TEXT_ITEM_REAL(value);

    /* calculation times */
    APPEND_BTEXT(_("\nTimes Used In Calculations\n"));
368
    point = format_date(conditions->point, NULL, TRUE);
369
    value = g_strdup_printf
Harald Judt's avatar
Harald Judt committed
370
        (_("\tTemperatures, wind, atmosphere and cloud data calculated\n"
371
           "\tfor:\t\t%s\n"),
372
         point);
373
    g_free(point);
374 375
    APPEND_TEXT_ITEM_REAL(value);

376 377
    interval_start = format_date(conditions->start, NULL, TRUE);
    interval_end = format_date(conditions->end, NULL, TRUE);
378
    value = g_strdup_printf
Harald Judt's avatar
Harald Judt committed
379
        (_("\n\tPrecipitation and the weather symbol have been calculated\n"
380
           "\tusing the following time interval:\n"
381 382
           "\tStart:\t%s\n"
           "\tEnd:\t%s\n"),
383 384
         interval_start,
         interval_end);
385 386
    g_free(interval_end);
    g_free(interval_start);
387 388
    APPEND_TEXT_ITEM_REAL(value);

389
    /* sun and moon */
390
    APPEND_BTEXT(_("\nAstronomical Data\n"));
391 392 393 394 395 396 397 398
    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 {
399
            sunrise = format_date(data->astrodata->sunrise, NULL, TRUE);
400
            value = g_strdup_printf(_("\tSunrise:\t\t%s\n"), sunrise);
401
            g_free(sunrise);
402 403
            APPEND_TEXT_ITEM_REAL(value);

404
            sunset = format_date(data->astrodata->sunset, NULL, TRUE);
405
            value = g_strdup_printf(_("\tSunset:\t\t%s\n\n"), sunset);
406
            g_free(sunset);
407 408 409 410 411 412 413 414 415 416 417 418
            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) {
419 420
            value =
                g_strdup(_("\tMoonrise:\tThe moon never rises today.\n"));
421 422
            APPEND_TEXT_ITEM_REAL(value);
        } else if (data->astrodata->moon_never_sets) {
423 424
            value =
                g_strdup(_("\tMoonset:\tThe moon never sets today.\n"));
425 426
            APPEND_TEXT_ITEM_REAL(value);
        } else {
427
            moonrise = format_date(data->astrodata->moonrise, NULL, TRUE);
428
            value = g_strdup_printf(_("\tMoonrise:\t%s\n"), moonrise);
429
            g_free(moonrise);
430 431
            APPEND_TEXT_ITEM_REAL(value);

432
            moonset = format_date(data->astrodata->moonset, NULL, TRUE);
433
            value = g_strdup_printf(_("\tMoonset:\t%s\n"), moonset);
434
            g_free(moonset);
435 436 437 438 439 440 441 442
            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
443 444
    /* temperatures */
    APPEND_BTEXT(_("\nTemperatures\n"));
445
    APPEND_TEXT_ITEM(_("Temperature"), TEMPERATURE);
Harald Judt's avatar
Harald Judt committed
446
    APPEND_TEXT_ITEM(_("Dew point"), DEWPOINT);
447
    APPEND_TEXT_ITEM(_("Apparent temperature"), APPARENT_TEMPERATURE);
448 449 450

    /* wind */
    APPEND_BTEXT(_("\nWind\n"));
451 452 453 454
    wind = get_data(conditions, data->units, WIND_SPEED,
                    FALSE, data->night_time);
    rawvalue = get_data(conditions, data->units, WIND_BEAUFORT,
                        FALSE, data->night_time);
455 456 457 458
    value = g_strdup_printf(_("\t%s: %s %s (%s on the Beaufort scale)\n"),
                            _("Speed"), wind,
                            get_unit(data->units, WIND_SPEED),
                            rawvalue);
459 460 461 462
    g_free(rawvalue);
    g_free(wind);
    APPEND_TEXT_ITEM_REAL(value);

463 464
    rawvalue = get_data(conditions, data->units, WIND_DIRECTION,
                        FALSE, data->night_time);
465 466
    wind = translate_wind_direction(rawvalue);
    g_free(rawvalue);
467 468
    rawvalue = get_data(conditions, data->units, WIND_DIRECTION_DEG,
                        FALSE, data->night_time);
469 470
    value = g_strdup_printf("\t%s: %s (%s%s)\n", _("Direction"),
                            wind, rawvalue,
471
                            get_unit(data->units, WIND_DIRECTION_DEG));
472 473 474 475 476 477 478 479 480 481
    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"));
482 483
    APPEND_TEXT_ITEM(_("Barometric pressure"), PRESSURE);
    APPEND_TEXT_ITEM(_("Relative humidity"), HUMIDITY);
484 485 486 487 488

    /* clouds */
    APPEND_BTEXT(_("\nClouds\n"));
    APPEND_TEXT_ITEM(_("Fog"), FOG);
    APPEND_TEXT_ITEM(_("Low clouds"), CLOUDS_LOW);
489
    APPEND_TEXT_ITEM(_("Middle clouds"), CLOUDS_MID);
490 491 492 493 494 495 496 497 498
    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
499
                     G_CALLBACK(view_motion_notify), sum);
500
    g_signal_connect(G_OBJECT(view), "leave-notify-event",
Harald Judt's avatar
Harald Judt committed
501
                     G_CALLBACK(view_leave_notify), sum);
502

Harald Judt's avatar
Harald Judt committed
503
    icon = weather_summary_get_logo(data);
504

Harald Judt's avatar
Harald Judt committed
505 506
    if (icon) {
        sum->icon_ebox = gtk_event_box_new();
507 508
        gtk_event_box_set_visible_window(GTK_EVENT_BOX(sum->icon_ebox), FALSE);
        gtk_container_add(GTK_CONTAINER(sum->icon_ebox), icon);
509
        gtk_text_view_add_child_in_window(GTK_TEXT_VIEW(view),
Harald Judt's avatar
Harald Judt committed
510
                                          sum->icon_ebox,
511
                                          GTK_TEXT_WINDOW_TEXT, 0, 0);
Harald Judt's avatar
Harald Judt committed
512
        gtk_widget_show_all(sum->icon_ebox);
513 514 515
        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
516
                         G_CALLBACK(view_scrolled_cb), sum);
517
        g_signal_connect(G_OBJECT(view), "size_allocate",
Harald Judt's avatar
Harald Judt committed
518 519 520 521 522 523 524 525 526
                         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);
527
    }
Harald Judt's avatar
Harald Judt committed
528

529
    return frame;
530
}
531

532

Harald Judt's avatar
Harald Judt committed
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
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);
    }
}


554 555 556 557 558 559 560 561 562 563
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"));
564
    value = format_date(fcdata->start, NULL, TRUE);
565 566
    g_string_append_printf(text, _("Interval start:\t\t\t%s\n"), value);
    g_free(value);
567
    value = format_date(fcdata->end, NULL, TRUE);
568 569
    g_string_append_printf(text, _("Interval end:\t\t\t%s\n"), value);
    g_free(value);
570
    value = format_date(fcdata->point, NULL, TRUE);
571 572 573
    g_string_append_printf(text, _("Data calculated for:\t%s\n\n"), value);
    g_free(value);

Harald Judt's avatar
Harald Judt committed
574
    g_string_append(text, _("<b>Temperatures</b>\n"));
575 576 577
    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
578

579
    g_string_append(text, _("<b>Atmosphere</b>\n"));
580 581
    APPEND_TOOLTIP_ITEM(_("Barometric pressure:\t%s%s%s\n"), PRESSURE);
    APPEND_TOOLTIP_ITEM(_("Relative humidity:\t\t%s%s%s\n\n"), HUMIDITY);
582 583 584 585 586 587 588

    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);
589
    APPEND_TOOLTIP_ITEM(_("Middle:\t\t%s%s%s\n"), CLOUDS_MID);
590 591 592 593 594 595 596 597 598 599
    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;
}


600
static GtkWidget *
Harald Judt's avatar
Harald Judt committed
601 602
wrap_forecast_cell(const GtkWidget *widget,
                   const GdkColor *color)
603
{
604
    GtkWidget *ebox;
Harald Judt's avatar
Harald Judt committed
605

606 607 608 609 610 611 612 613 614 615 616
    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;
}

617

618
static GtkWidget *
619 620 621
add_forecast_header(const gchar *text,
                    const gdouble angle,
                    const GdkColor *color)
622
{
Harald Judt's avatar
Harald Judt committed
623
    GtkWidget *label, *align;
624 625
    gchar *str;

626 627 628 629 630
    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);
631 632

    label = gtk_label_new(NULL);
Harald Judt's avatar
Harald Judt committed
633
    gtk_label_set_angle(GTK_LABEL(label), angle);
634 635 636
    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
637
    gtk_container_add(GTK_CONTAINER(align), GTK_WIDGET(label));
Harald Judt's avatar
Harald Judt committed
638
    return wrap_forecast_cell(align, color);
639 640
}

641

642
static GtkWidget *
643
add_forecast_cell(plugin_data *data,
Harald Judt's avatar
Harald Judt committed
644 645
                  gint day,
                  gint daytime)
646
{
Harald Judt's avatar
Harald Judt committed
647
    GtkWidget *box, *label, *image;
648
    GdkPixbuf *icon;
649
    const GdkColor black = {0, 0x0000, 0x0000, 0x0000};
Harald Judt's avatar
Harald Judt committed
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
    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 */
665 666
    rawvalue = get_data(fcdata, data->units, SYMBOL,
                        FALSE, data->night_time);
Harald Judt's avatar
Harald Judt committed
667 668 669 670 671 672 673 674
    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 */
675 676
    rawvalue = get_data(fcdata, data->units, SYMBOL,
                        FALSE, data->night_time);
Harald Judt's avatar
Harald Judt committed
677 678 679 680 681 682 683 684 685 686 687
    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 */
688 689
    rawvalue = get_data(fcdata, data->units, TEMPERATURE,
                        data->round, data->night_time);
Harald Judt's avatar
Harald Judt committed
690 691 692 693 694 695 696 697 698 699
    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 */
700 701
    rawvalue = get_data(fcdata, data->units, WIND_DIRECTION,
                        FALSE, data->night_time);
Harald Judt's avatar
Harald Judt committed
702
    wind_direction = translate_wind_direction(rawvalue);
703 704
    wind_speed = get_data(fcdata, data->units, WIND_SPEED,
                          data->round, data->night_time);
Harald Judt's avatar
Harald Judt committed
705 706 707 708 709 710 711 712 713 714 715 716 717
    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);

718 719 720 721
    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
722 723 724 725 726 727
    xml_time_free(fcdata);
    return box;
}


static GtkWidget *
728
make_forecast(plugin_data *data)
Harald Judt's avatar
Harald Judt committed
729 730 731
{
    GtkWidget *table, *ebox, *box, *align;
    GtkWidget *forecast_box;
732 733
    const GdkColor lightbg = {0, 0xeaea, 0xeaea, 0xeaea};
    const GdkColor darkbg = {0, 0x6666, 0x6666, 0x6666};
Harald Judt's avatar
Harald Judt committed
734
    gchar *dayname;
Harald Judt's avatar
Harald Judt committed
735 736 737 738 739 740 741
    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);
742 743 744 745 746 747 748

    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
749
                              wrap_forecast_cell(box, &darkbg),
750 751 752
                              0, 1, 0, 1);

    /* daytime headers */
Harald Judt's avatar
Harald Judt committed
753 754 755 756
    ATTACH_DAYTIME_HEADER(_("Morning"), 1);
    ATTACH_DAYTIME_HEADER(_("Afternoon"), 2);
    ATTACH_DAYTIME_HEADER(_("Evening"), 3);
    ATTACH_DAYTIME_HEADER(_("Night"), 4);
757

758
    for (i = 0; i < data->forecast_days; i++) {
759
        /* forecast day headers */
Harald Judt's avatar
Harald Judt committed
760 761 762
        dayname = get_dayname(i);
        if (data->forecast_layout == FC_LAYOUT_CALENDAR)
            ebox = add_forecast_header(dayname, 0.0, &darkbg);
763
        else
Harald Judt's avatar
Harald Judt committed
764
            ebox = add_forecast_header(dayname, 90.0, &darkbg);
Harald Judt's avatar
Harald Judt committed
765
        g_free(dayname);
766

Harald Judt's avatar
Harald Judt committed
767 768 769 770 771 772
        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);
773

774
        /* get forecast data for each daytime */
775
        for (daytime = MORNING; daytime <= NIGHT; daytime++) {
Harald Judt's avatar
Harald Judt committed
776
            forecast_box = add_forecast_cell(data, i, daytime);
Harald Judt's avatar
Harald Judt committed
777 778 779
            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));
780
            if (i % 2)
Harald Judt's avatar
Harald Judt committed
781
                ebox = wrap_forecast_cell(align, NULL);
782
            else
Harald Judt's avatar
Harald Judt committed
783 784
                ebox = wrap_forecast_cell(align, &lightbg);

Harald Judt's avatar
Harald Judt committed
785 786 787 788 789 790 791 792
            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);
793 794 795
        }
    }
    return table;
796 797
}

798

799
static GtkWidget *
800
create_forecast_tab(plugin_data *data)
801
{
802
    GtkWidget *ebox, *align, *hbox, *scrolled, *table;
803
    GdkWindow *window;
804
    GdkScreen *screen;
805
    GdkRectangle rect;
Harald Judt's avatar
Harald Judt committed
806 807
    gint monitor_num = 0, h_need, h_max, height;
    gint w_need, w_max, width;
808

809 810 811 812 813 814 815 816 817 818
    /* 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);
819

Harald Judt's avatar
Harald Judt committed
820 821 822
    /* calculate maximum width and height */
    h_max = rect.height - 250;
    w_max = rect.width - 50;
823

Harald Judt's avatar
Harald Judt committed
824 825 826 827 828 829 830 831
    /* 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;
    }
832 833 834 835

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

Harald Judt's avatar
Harald Judt committed
836
    /* generate the containing widgets */
837
    align = gtk_alignment_new(0.5, 0, 0.5, 0);
Harald Judt's avatar
Harald Judt committed
838 839 840 841
    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 */
842 843 844 845
        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
846
        /* contents too big, scroll window needed */
847 848 849 850 851 852 853
        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);

854 855
        gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled),
                                              align);
856
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
857 858
                                       GTK_POLICY_AUTOMATIC,
                                       GTK_POLICY_AUTOMATIC);
Harald Judt's avatar
Harald Judt committed
859 860 861 862 863 864

        /* 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);

865
        ebox = gtk_event_box_new();
866
        gtk_event_box_set_visible_window(GTK_EVENT_BOX(ebox), TRUE);
867 868
        gtk_container_add(GTK_CONTAINER(ebox), GTK_WIDGET(scrolled));
        return ebox;
869
    }
870
}
871

872

873
static void
874 875
summary_dialog_response(const GtkWidget *dlg,
                        const gint response,
876
                        GtkWidget *window)
877
{
878 879
    if (response == GTK_RESPONSE_ACCEPT)
        gtk_widget_destroy(window);
880 881
}

882

883 884 885 886 887 888 889 890 891 892 893 894
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;
}


895
GtkWidget *
896
create_summary_window(plugin_data *data)
897
{
898
    GtkWidget *window, *notebook, *vbox, *hbox, *label;
Harald Judt's avatar
Harald Judt committed
899
    gchar *title, *symbol;
900 901 902
    GdkPixbuf *icon;
    xml_time *conditions;

903 904
    conditions = get_current_conditions(data->weatherdata);
    window = xfce_titled_dialog_new_with_buttons(_("Weather Report"),
905 906 907 908 909
                                                 NULL,
                                                 GTK_DIALOG_NO_SEPARATOR,
                                                 GTK_STOCK_CLOSE,
                                                 GTK_RESPONSE_ACCEPT, NULL);
    if (data->location_name != NULL) {
910
        title = g_strdup_printf("%s", data->location_name);
911 912 913 914 915
        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
916
    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), vbox, TRUE, TRUE, 0);
917

918 919
    symbol = get_data(conditions, data->units, SYMBOL,
                      FALSE, data->night_time);
920
    icon = get_icon(data->icon_theme, symbol, 48, data->night_time);
Harald Judt's avatar
Harald Judt committed
921
    g_free(symbol);
922 923 924 925 926 927

    gtk_window_set_icon(GTK_WINDOW(window), icon);

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

928 929
    if (data->location_name == NULL || data->weatherdata == NULL ||
        data->weatherdata->current_conditions == NULL) {
930 931 932 933 934 935 936 937 938 939 940 941 942 943 944
        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),
945
                                 create_forecast_tab(data),
946 947 948 949 950
                                 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);
951 952 953 954
        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);
955 956 957 958 959 960
    }

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

    return window;
961
}
Harald Judt's avatar
Harald Judt committed
962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979


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;
}