weather-summary.c 35.8 KB
Newer Older
1
/*  Copyright (c) 2003-2013 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
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);

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
/*
 * TRANSLATORS: This format string belongs to the macro used for
 * printing the "Label: Value Unit" lines on the details tab, e.g.
 * "Temperature: 10 °C" or "Latitude: 95.7°".
 * The %s stand for:
 *   - label
 *   - ": " if label is not empty, else empty
 *   - value
 *   - space if unit is not degree "°" (but this is not °C or °F!)
 *   - unit
 * Usually, you should leave this unchanged, BUT...
 * RTL TRANSLATORS: In case you did not translate the measurement
 * unit, use LRM (left-to-right mark) etc. to align it properly with
 * its numeric value.
 */
67
#define APPEND_TEXT_ITEM(text, item)                            \
68 69
    rawvalue = get_data(conditions, data->units, item,          \
                        FALSE, data->night_time);               \
70
    unit = get_unit(data->units, item);                         \
71
    value = g_strdup_printf(_("\t%s%s%s%s%s\n"),                \
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
                            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);
89

Harald Judt's avatar
Harald Judt committed
90 91 92 93 94 95 96 97 98 99 100 101
#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);                         \

102
#define APPEND_TOOLTIP_ITEM(description, item)                  \
103 104
    value = get_data(fcdata, data->units, item,                 \
                     data->round, data->night_time);            \
105 106 107 108 109 110
    unit = get_unit(data->units, item);                         \
    g_string_append_printf(text, description, value,            \
                           strcmp(unit, "°") ? " " : "",        \
                           unit);                               \
    g_free(value);

111

112 113 114 115 116 117
static gboolean
lnk_clicked(GtkTextTag *tag,
            GObject *obj,
            GdkEvent *event,
            GtkTextIter *iter,
            GtkWidget *textview)
118
{
119 120
    const gchar *url;
    gchar *str;
121

122 123 124 125 126 127 128 129 130 131
    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;
132 133
}

134

135
static gboolean
136
icon_clicked (GtkWidget *widget,
137
              GdkEventButton *event,
138
              gpointer user_data)
139
{
140
    return lnk_clicked(user_data, NULL, (GdkEvent *) (event), NULL, NULL);
141 142
}

143 144 145 146

static gboolean
view_motion_notify(GtkWidget *widget,
                   GdkEventMotion *event,
Harald Judt's avatar
Harald Judt committed
147
                   summary_details *sum)
148
{
Harald Judt's avatar
Harald Judt committed
149 150 151 152 153
    GtkTextIter iter;
    GtkTextTag *tag;
    GSList *tags;
    GSList *cur;
    gint bx, by;
154

Harald Judt's avatar
Harald Judt committed
155
    if (event->x != -1 && event->y != -1) {
Harald Judt's avatar
Harald Judt committed
156
        gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(sum->text_view),
157 158
                                              GTK_TEXT_WINDOW_WIDGET,
                                              event->x, event->y, &bx, &by);
Harald Judt's avatar
Harald Judt committed
159
        gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(sum->text_view),
160 161 162
                                           &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
163
            tag = cur->data;
164
            if (g_object_get_data(G_OBJECT(tag), "url")) {
Harald Judt's avatar
Harald Judt committed
165 166 167 168
                gdk_window_set_cursor
                    (gtk_text_view_get_window(GTK_TEXT_VIEW(sum->text_view),
                                              GTK_TEXT_WINDOW_TEXT),
                     sum->hand_cursor);
169 170 171
                return FALSE;
            }
        }
172
    }
Harald Judt's avatar
Harald Judt committed
173 174 175 176 177
    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);
178
    return FALSE;
179 180
}

181 182 183 184

static gboolean
icon_motion_notify(GtkWidget *widget,
                   GdkEventMotion *event,
Harald Judt's avatar
Harald Judt committed
185
                   summary_details *sum)
186
{
Harald Judt's avatar
Harald Judt committed
187 188 189 190 191
    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);
192
    return FALSE;
193 194
}

195 196 197 198

static gboolean
view_leave_notify(GtkWidget *widget,
                  GdkEventMotion *event,
Harald Judt's avatar
Harald Judt committed
199
                  summary_details *sum)
200
{
Harald Judt's avatar
Harald Judt committed
201 202 203 204 205
    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);
206
    return FALSE;
207 208
}

209 210 211

static void
view_scrolled_cb(GtkAdjustment *adj,
Harald Judt's avatar
Harald Judt committed
212
                 summary_details *sum)
213
{
Harald Judt's avatar
Harald Judt committed
214 215
    gint x, y, x1, y1;

Harald Judt's avatar
Harald Judt committed
216 217 218 219
    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),
220 221
                                              GTK_TEXT_WINDOW_TEXT,
                                              x1, y1, &x, &y);
Harald Judt's avatar
Harald Judt committed
222 223
        gtk_text_view_move_child(GTK_TEXT_VIEW(sum->text_view),
                                 sum->icon_ebox, x, y);
224
    }
225 226
}

227 228 229 230 231

static void
view_size_allocate_cb(GtkWidget *widget,
                      GtkAllocation *allocation,
                      gpointer data)
232
{
Harald Judt's avatar
Harald Judt committed
233
    view_scrolled_cb(NULL, data);
234
}
235

236 237 238

static gchar *
get_logo_path(void)
239
{
240 241 242 243 244 245 246
    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;
247 248
}

249

250
static void
251 252 253
logo_fetched(SoupSession *session,
             SoupMessage *msg,
             gpointer user_data)
254
{
255
    if (msg && msg->response_body && msg->response_body->length > 0) {
256 257 258
        gchar *path = get_logo_path();
        GError *error = NULL;
        GdkPixbuf *pixbuf = NULL;
259 260
        if (!g_file_set_contents(path, msg->response_body->data,
                                 msg->response_body->length, &error)) {
261 262 263
            g_warning(_("Error downloading met.no logo image to %s, "
                        "reason: %s\n"), path,
                      error ? error->message : _("unknown"));
264 265 266 267 268 269 270 271 272 273 274
            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);
        }
    }
275 276
}

277 278

static GtkWidget *
279
weather_summary_get_logo(plugin_data *data)
280
{
281
    GtkWidget *image = gtk_image_new();
Harald Judt's avatar
Harald Judt committed
282
    GdkPixbuf *pixbuf;
283 284 285 286 287
    gchar *path = get_logo_path();

    pixbuf = gdk_pixbuf_new_from_file(path, NULL);
    g_free(path);
    if (pixbuf == NULL)
288 289
        weather_http_queue_request(data->session,
                                   "http://met.no/filestore/met.no-logo.gif",
290
                                   logo_fetched, image);
291 292 293 294 295
    else {
        gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
        g_object_unref(pixbuf);
    }
    return image;
296
}
297

298

299
static GtkWidget *
300
create_summary_tab(plugin_data *data)
301
{
302 303 304
    GtkTextBuffer *buffer;
    GtkTextIter iter;
    GtkTextTag *btag, *ltag0, *ltag1;
Harald Judt's avatar
Harald Judt committed
305
    GtkWidget *view, *frame, *scrolled, *icon;
306 307 308 309
    GtkAdjustment *adj;
    GdkColor lnk_color;
    xml_time *conditions;
    const gchar *unit;
Harald Judt's avatar
Harald Judt committed
310
    gchar *value, *rawvalue, *wind;
311 312
    gchar *last_download, *next_download;
    gchar *interval_start, *interval_end, *point;
313
    gchar *sunrise, *sunset, *moonrise, *moonset;
Harald Judt's avatar
Harald Judt committed
314
    summary_details *sum;
315

Harald Judt's avatar
Harald Judt committed
316 317 318 319 320 321 322
    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();
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
    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);

353 354
    /* TRANSLATORS: Please use as many \t as appropriate to align the
       date/time values as in the original. */
355 356 357 358 359 360 361 362 363 364 365 366
    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);
367 368
    APPEND_TEXT_ITEM_REAL(value);

369 370 371 372 373 374 375 376 377 378 379 380 381 382
    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 */
383
    APPEND_BTEXT(_("\nTimes Used for Calculations\n"));
384
    point = format_date(conditions->point, NULL, TRUE);
385
    value = g_strdup_printf
Harald Judt's avatar
Harald Judt committed
386
        (_("\tTemperatures, wind, atmosphere and cloud data calculated\n"
387
           "\tfor:\t\t%s\n"),
388
         point);
389
    g_free(point);
390 391
    APPEND_TEXT_ITEM_REAL(value);

392 393
    interval_start = format_date(conditions->start, NULL, TRUE);
    interval_end = format_date(conditions->end, NULL, TRUE);
394
    value = g_strdup_printf
Harald Judt's avatar
Harald Judt committed
395
        (_("\n\tPrecipitation and the weather symbol have been calculated\n"
396
           "\tusing the following time interval:\n"
397 398
           "\tStart:\t%s\n"
           "\tEnd:\t%s\n"),
399 400
         interval_start,
         interval_end);
401 402
    g_free(interval_end);
    g_free(interval_start);
403 404
    APPEND_TEXT_ITEM_REAL(value);

405
    /* sun and moon */
406
    APPEND_BTEXT(_("\nAstronomical Data\n"));
407 408 409 410 411 412 413 414
    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 {
415
            sunrise = format_date(data->astrodata->sunrise, NULL, TRUE);
416
            value = g_strdup_printf(_("\tSunrise:\t\t%s\n"), sunrise);
417
            g_free(sunrise);
418 419
            APPEND_TEXT_ITEM_REAL(value);

420
            sunset = format_date(data->astrodata->sunset, NULL, TRUE);
421
            value = g_strdup_printf(_("\tSunset:\t\t%s\n\n"), sunset);
422
            g_free(sunset);
423 424 425 426 427 428 429 430 431 432 433 434
            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) {
435 436
            value =
                g_strdup(_("\tMoonrise:\tThe moon never rises today.\n"));
437 438
            APPEND_TEXT_ITEM_REAL(value);
        } else if (data->astrodata->moon_never_sets) {
439 440
            value =
                g_strdup(_("\tMoonset:\tThe moon never sets today.\n"));
441 442
            APPEND_TEXT_ITEM_REAL(value);
        } else {
443
            moonrise = format_date(data->astrodata->moonrise, NULL, TRUE);
444
            value = g_strdup_printf(_("\tMoonrise:\t%s\n"), moonrise);
445
            g_free(moonrise);
446 447
            APPEND_TEXT_ITEM_REAL(value);

448
            moonset = format_date(data->astrodata->moonset, NULL, TRUE);
449
            value = g_strdup_printf(_("\tMoonset:\t%s\n"), moonset);
450
            g_free(moonset);
451 452 453 454 455 456 457 458
            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
459 460
    /* temperatures */
    APPEND_BTEXT(_("\nTemperatures\n"));
461
    APPEND_TEXT_ITEM(_("Temperature"), TEMPERATURE);
Harald Judt's avatar
Harald Judt committed
462
    APPEND_TEXT_ITEM(_("Dew point"), DEWPOINT);
463
    APPEND_TEXT_ITEM(_("Apparent temperature"), APPARENT_TEMPERATURE);
464 465 466

    /* wind */
    APPEND_BTEXT(_("\nWind\n"));
467 468 469 470
    wind = get_data(conditions, data->units, WIND_SPEED,
                    FALSE, data->night_time);
    rawvalue = get_data(conditions, data->units, WIND_BEAUFORT,
                        FALSE, data->night_time);
471 472
    value = g_strdup_printf(_("\tSpeed: %s %s (%s on the Beaufort scale)\n"),
                            wind, get_unit(data->units, WIND_SPEED),
473
                            rawvalue);
474 475 476 477
    g_free(rawvalue);
    g_free(wind);
    APPEND_TEXT_ITEM_REAL(value);

478 479
    rawvalue = get_data(conditions, data->units, WIND_DIRECTION,
                        FALSE, data->night_time);
480 481
    wind = translate_wind_direction(rawvalue);
    g_free(rawvalue);
482 483
    rawvalue = get_data(conditions, data->units, WIND_DIRECTION_DEG,
                        FALSE, data->night_time);
484 485 486

    /* wind direction */
    value = g_strdup_printf(_("\tDirection: %s (%s%s)\n"),
487
                            wind, rawvalue,
488
                            get_unit(data->units, WIND_DIRECTION_DEG));
489 490 491 492 493 494 495 496 497 498
    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"));
499 500
    APPEND_TEXT_ITEM(_("Barometric pressure"), PRESSURE);
    APPEND_TEXT_ITEM(_("Relative humidity"), HUMIDITY);
501 502 503 504 505

    /* clouds */
    APPEND_BTEXT(_("\nClouds\n"));
    APPEND_TEXT_ITEM(_("Fog"), FOG);
    APPEND_TEXT_ITEM(_("Low clouds"), CLOUDS_LOW);
506
    APPEND_TEXT_ITEM(_("Middle clouds"), CLOUDS_MID);
507 508 509 510 511 512 513 514 515
    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
516
                     G_CALLBACK(view_motion_notify), sum);
517
    g_signal_connect(G_OBJECT(view), "leave-notify-event",
Harald Judt's avatar
Harald Judt committed
518
                     G_CALLBACK(view_leave_notify), sum);
519

Harald Judt's avatar
Harald Judt committed
520
    icon = weather_summary_get_logo(data);
521

Harald Judt's avatar
Harald Judt committed
522 523
    if (icon) {
        sum->icon_ebox = gtk_event_box_new();
524 525
        gtk_event_box_set_visible_window(GTK_EVENT_BOX(sum->icon_ebox), FALSE);
        gtk_container_add(GTK_CONTAINER(sum->icon_ebox), icon);
526
        gtk_text_view_add_child_in_window(GTK_TEXT_VIEW(view),
Harald Judt's avatar
Harald Judt committed
527
                                          sum->icon_ebox,
528
                                          GTK_TEXT_WINDOW_TEXT, 0, 0);
Harald Judt's avatar
Harald Judt committed
529
        gtk_widget_show_all(sum->icon_ebox);
530 531 532
        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
533
                         G_CALLBACK(view_scrolled_cb), sum);
534
        g_signal_connect(G_OBJECT(view), "size_allocate",
Harald Judt's avatar
Harald Judt committed
535 536 537 538 539 540 541 542 543
                         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);
544
    }
Harald Judt's avatar
Harald Judt committed
545

546
    return frame;
547
}
548

549

Harald Judt's avatar
Harald Judt committed
550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
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);
    }
}


571 572 573 574 575 576 577 578 579
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 */
580
    text = g_string_new(_("<b>Times used for calculations</b>\n"));
581
    value = format_date(fcdata->start, NULL, TRUE);
582 583
    g_string_append_printf(text, _("Interval start:\t\t\t%s\n"), value);
    g_free(value);
584
    value = format_date(fcdata->end, NULL, TRUE);
585 586
    g_string_append_printf(text, _("Interval end:\t\t\t%s\n"), value);
    g_free(value);
587
    value = format_date(fcdata->point, NULL, TRUE);
588 589 590
    g_string_append_printf(text, _("Data calculated for:\t%s\n\n"), value);
    g_free(value);

Harald Judt's avatar
Harald Judt committed
591
    g_string_append(text, _("<b>Temperatures</b>\n"));
592 593 594
    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
595

596
    g_string_append(text, _("<b>Atmosphere</b>\n"));
597 598
    APPEND_TOOLTIP_ITEM(_("Barometric pressure:\t%s%s%s\n"), PRESSURE);
    APPEND_TOOLTIP_ITEM(_("Relative humidity:\t\t%s%s%s\n\n"), HUMIDITY);
599 600 601 602 603

    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"));
604 605 606 607 608
    APPEND_TOOLTIP_ITEM(_("Fog:\t\t\t%s%s%s\n"), FOG);
    APPEND_TOOLTIP_ITEM(_("Low clouds:\t\t%s%s%s\n"), CLOUDS_LOW);
    APPEND_TOOLTIP_ITEM(_("Middle clouds:\t%s%s%s\n"), CLOUDS_MID);
    APPEND_TOOLTIP_ITEM(_("High clouds:\t\t%s%s%s\n"), CLOUDS_HIGH);
    APPEND_TOOLTIP_ITEM(_("Cloudiness:\t\t%s%s%s"), CLOUDINESS);
609 610 611 612 613 614 615 616

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


617
static GtkWidget *
Harald Judt's avatar
Harald Judt committed
618 619
wrap_forecast_cell(const GtkWidget *widget,
                   const GdkColor *color)
620
{
621
    GtkWidget *ebox;
Harald Judt's avatar
Harald Judt committed
622

623 624 625 626 627 628 629 630 631 632 633
    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;
}

634

635
static GtkWidget *
636 637 638
add_forecast_header(const gchar *text,
                    const gdouble angle,
                    const GdkColor *color)
639
{
Harald Judt's avatar
Harald Judt committed
640
    GtkWidget *label, *align;
641 642
    gchar *str;

643 644 645 646 647
    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);
648 649

    label = gtk_label_new(NULL);
Harald Judt's avatar
Harald Judt committed
650
    gtk_label_set_angle(GTK_LABEL(label), angle);
651 652 653
    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
654
    gtk_container_add(GTK_CONTAINER(align), GTK_WIDGET(label));
Harald Judt's avatar
Harald Judt committed
655
    return wrap_forecast_cell(align, color);
656 657
}

658

659
static GtkWidget *
660
add_forecast_cell(plugin_data *data,
Harald Judt's avatar
Harald Judt committed
661 662
                  gint day,
                  gint daytime)
663
{
Harald Judt's avatar
Harald Judt committed
664
    GtkWidget *box, *label, *image;
665
    GdkPixbuf *icon;
666
    const GdkColor black = {0, 0x0000, 0x0000, 0x0000};
Harald Judt's avatar
Harald Judt committed
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681
    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 */
682 683
    rawvalue = get_data(fcdata, data->units, SYMBOL,
                        FALSE, data->night_time);
Harald Judt's avatar
Harald Judt committed
684 685 686 687 688 689 690 691
    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 */
692 693
    rawvalue = get_data(fcdata, data->units, SYMBOL,
                        FALSE, data->night_time);
Harald Judt's avatar
Harald Judt committed
694 695 696 697 698 699 700 701 702 703 704
    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 */
705 706
    rawvalue = get_data(fcdata, data->units, TEMPERATURE,
                        data->round, data->night_time);
Harald Judt's avatar
Harald Judt committed
707 708 709 710 711 712 713 714 715 716
    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 */
717 718
    rawvalue = get_data(fcdata, data->units, WIND_DIRECTION,
                        FALSE, data->night_time);
Harald Judt's avatar
Harald Judt committed
719
    wind_direction = translate_wind_direction(rawvalue);
720 721
    wind_speed = get_data(fcdata, data->units, WIND_SPEED,
                          data->round, data->night_time);
Harald Judt's avatar
Harald Judt committed
722 723 724 725 726 727 728 729 730 731 732 733 734
    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);

735 736 737 738
    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
739 740 741 742 743 744
    xml_time_free(fcdata);
    return box;
}


static GtkWidget *
745
make_forecast(plugin_data *data)
Harald Judt's avatar
Harald Judt committed
746 747 748
{
    GtkWidget *table, *ebox, *box, *align;
    GtkWidget *forecast_box;
749 750
    const GdkColor lightbg = {0, 0xeaea, 0xeaea, 0xeaea};
    const GdkColor darkbg = {0, 0x6666, 0x6666, 0x6666};
Harald Judt's avatar
Harald Judt committed
751
    gchar *dayname;
Harald Judt's avatar
Harald Judt committed
752 753 754 755 756 757 758
    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);
759 760 761 762 763 764 765

    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
766
                              wrap_forecast_cell(box, &darkbg),
767 768 769
                              0, 1, 0, 1);

    /* daytime headers */
Harald Judt's avatar
Harald Judt committed
770 771 772 773
    ATTACH_DAYTIME_HEADER(_("Morning"), 1);
    ATTACH_DAYTIME_HEADER(_("Afternoon"), 2);
    ATTACH_DAYTIME_HEADER(_("Evening"), 3);
    ATTACH_DAYTIME_HEADER(_("Night"), 4);
774

775
    for (i = 0; i < data->forecast_days; i++) {
776
        /* forecast day headers */
Harald Judt's avatar
Harald Judt committed
777 778 779
        dayname = get_dayname(i);
        if (data->forecast_layout == FC_LAYOUT_CALENDAR)
            ebox = add_forecast_header(dayname, 0.0, &darkbg);
780
        else
Harald Judt's avatar
Harald Judt committed
781
            ebox = add_forecast_header(dayname, 90.0, &darkbg);
Harald Judt's avatar
Harald Judt committed
782
        g_free(dayname);
783

Harald Judt's avatar
Harald Judt committed
784 785 786 787 788 789
        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);
790

791
        /* get forecast data for each daytime */
792
        for (daytime = MORNING; daytime <= NIGHT; daytime++) {
Harald Judt's avatar
Harald Judt committed
793
            forecast_box = add_forecast_cell(data, i, daytime);
Harald Judt's avatar
Harald Judt committed
794 795 796
            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));
797
            if (i % 2)
Harald Judt's avatar
Harald Judt committed
798
                ebox = wrap_forecast_cell(align, NULL);
799
            else
Harald Judt's avatar
Harald Judt committed
800 801
                ebox = wrap_forecast_cell(align, &lightbg);

Harald Judt's avatar
Harald Judt committed
802 803 804 805 806 807 808 809
            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);
810 811 812
        }
    }
    return table;
813 814
}

815

816
static GtkWidget *
817
create_forecast_tab(plugin_data *data)
818
{
819
    GtkWidget *ebox, *align, *hbox, *scrolled, *table;
820
    GdkWindow *window;
821
    GdkScreen *screen;
822
    GdkRectangle rect;
Harald Judt's avatar
Harald Judt committed
823 824
    gint monitor_num = 0, h_need, h_max, height;
    gint w_need, w_max, width;
825

826 827 828 829 830 831 832 833 834 835
    /* 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);
836

Harald Judt's avatar
Harald Judt committed
837 838 839
    /* calculate maximum width and height */
    h_max = rect.height - 250;
    w_max = rect.width - 50;
840

Harald Judt's avatar
Harald Judt committed
841 842 843 844 845 846 847 848
    /* 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;
    }
849 850 851 852

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

Harald Judt's avatar
Harald Judt committed
853
    /* generate the containing widgets */
854
    align = gtk_alignment_new(0.5, 0, 0.5, 0);
Harald Judt's avatar
Harald Judt committed
855 856 857 858
    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 */
859 860 861 862
        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
863
        /* contents too big, scroll window needed */
864 865 866 867 868 869 870
        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);

871 872
        gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled),
                                              align);
873
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
874 875
                                       GTK_POLICY_AUTOMATIC,
                                       GTK_POLICY_AUTOMATIC);
Harald Judt's avatar
Harald Judt committed
876 877 878 879 880 881

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

882
        ebox = gtk_event_box_new();
883
        gtk_event_box_set_visible_window(GTK_EVENT_BOX(ebox), TRUE);
884 885
        gtk_container_add(GTK_CONTAINER(ebox), GTK_WIDGET(scrolled));
        return ebox;
886
    }
887
}
888

889

890
static void
891 892
summary_dialog_response(const GtkWidget *dlg,
                        const gint response,
893
                        GtkWidget *window)
894
{
895 896
    if (response == GTK_RESPONSE_ACCEPT)
        gtk_widget_destroy(window);
897 898
}

899

900 901 902 903 904 905 906 907 908 909 910 911
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;
}


912
GtkWidget *
913
create_summary_window(plugin_data *data)
914
{
915
    GtkWidget *window, *notebook, *vbox, *hbox, *label;
Harald Judt's avatar
Harald Judt committed
916
    gchar *title, *symbol;
917 918 919
    GdkPixbuf *icon;
    xml_time *conditions;

920 921
    conditions = get_current_conditions(data->weatherdata);
    window = xfce_titled_dialog_new_with_buttons(_("Weather Report"),
922 923 924 925 926
                                                 NULL,
                                                 GTK_DIALOG_NO_SEPARATOR,
                                                 GTK_STOCK_CLOSE,
                                                 GTK_RESPONSE_ACCEPT, NULL);
    if (data->location_name != NULL) {
927
        title = g_strdup_printf("%s", data->location_name);
928 929 930 931 932
        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
933
    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), vbox, TRUE, TRUE, 0);
934

935 936
    symbol = get_data(conditions, data->units, SYMBOL,
                      FALSE, data->night_time);
937
    icon = get_icon(data->icon_theme, symbol, 48, data->night_time);
Harald Judt's avatar
Harald Judt committed
938
    g_free(symbol);
939 940 941 942 943 944

    gtk_window_set_icon(GTK_WINDOW(window), icon);

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

945 946
    if (data->location_name == NULL || data->weatherdata == NULL ||
        data->weatherdata->current_conditions == NULL) {
947 948 949 950 951 952 953 954 955 956 957 958 959 960 961
        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),
962
                                 create_forecast_tab(data),
963 964 965 966 967
                                 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);
968 969 970 971
        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);
972 973 974 975 976 977
    }

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

    return window;
978
}
Harald Judt's avatar
Harald Judt committed
979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996


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