gpredict/src/map-selector.c
2010-10-31 14:46:55 +00:00

329 lines
10 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
Gpredict: Real-time satellite tracking and orbit prediction program
Copyright (C) 2001-2009 Alexandru Csete, OZ9AEC.
Authors: Alexandru Csete <oz9aec@gmail.com>
Comments, questions and bugreports should be submitted via
http://sourceforge.net/projects/gpredict/
More details can be found at the project home page:
http://gpredict.oz9aec.net/
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.
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.
You should have received a copy of the GNU General Public License
along with this program; if not, visit http://www.fsf.org/
*/
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <sys/stat.h> /*** FIXME: ok for win32? see thunar-vfs-io-local.c */
#ifdef HAVE_CONFIG_H
# include <build-config.h>
#endif
#include "sat-log.h"
#include "map-selector.h"
#include "compat.h"
static GtkWidget *create_preview_widget (const gchar *selection);
static void update_preview_widget (GtkFileChooser *chooser, gpointer data);
static gchar *get_map_humanize_size (gint64 size, gchar *buffer, gsize buflen);
/** \brief Execute map selector.
* \param curmap The name of the current map.
* \return A newly allocated string with filename of the selected map
* or NULL if action was cancelled.
*
* This function creates and executes a file chooser dialog
* and selects the currently selected map curmap. The file chooser dialogue
* has a custom map preview widget showing the scaled down copty of
* the selected map as well as the size of the map.
*
*/
gchar *
select_map (const gchar *curmap)
{
GtkWidget *chooser; /* file chooser dialogue */
GtkFileFilter *filter; /* file filter object */
gchar *selection; /* full path of selected file */
gchar *mapsdir; /* stock maps directory */
gchar *ret = NULL;
GtkWidget *preview;
/* we are going to need this as a shortcut folder
and to find out whether selected map is stock
or user specific
*/
mapsdir = get_maps_dir ();
/* create a new file chooser dialogue in "open file" mode */
chooser = gtk_file_chooser_dialog_new (_("Select Map"),
NULL,
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
NULL);
/* single selection only */
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (chooser), FALSE);
/* add shortcut */
gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (chooser), mapsdir, NULL);
/* create filter */
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("Image files"));
gtk_file_filter_add_pixbuf_formats (filter);
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
/* select current map file */
if (g_path_is_absolute (curmap)) {
/* map is user specific, ie. in USER_CONF_DIR/maps/ */
selection = g_strdup (curmap);
}
else {
/* build complete path */
selection = map_file_name (curmap);
}
gtk_file_chooser_select_filename (GTK_FILE_CHOOSER (chooser), selection);
/* preview widget */
preview = create_preview_widget (selection);
gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (chooser), preview);
gtk_file_chooser_set_preview_widget_active (GTK_FILE_CHOOSER (chooser), TRUE);
/* sig connect */
g_signal_connect (G_OBJECT (chooser), "update-preview",
G_CALLBACK (update_preview_widget), preview);
/* we don't need this anymore */
g_free (selection);
/* run the dialogue */
if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_ACCEPT) {
char *filename;
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
/* find out whether selected file is a
stock map or user map */
if (g_str_has_prefix (filename, mapsdir)) {
/* selected map is a stock map */
/* get file name without dir component */
ret = g_path_get_basename (filename);
}
else {
ret = g_strdup (filename);
}
/* clean up */
g_free (filename);
}
gtk_widget_destroy (chooser);
g_free (mapsdir);
return ret;
}
/** \brief Create the preview widget and load the current map */
static GtkWidget *
create_preview_widget (const gchar *selection)
{
GtkWidget *vbox;
GtkWidget *img;
GtkWidget *label;
GdkPixbuf *obuf,*sbuf;
gchar *buff;
gint w,h;
gint64 size;
struct stat sb;
gchar *bf = NULL;
label = gtk_label_new (NULL);
img = gtk_image_new ();
vbox = gtk_vbox_new (FALSE, 5);
g_object_set_data (G_OBJECT (vbox), "image", img);
g_object_set_data (G_OBJECT (vbox), "label", label);
gtk_box_pack_start (GTK_BOX (vbox), img, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
gtk_widget_show_all (vbox);
/* load current map into preview widget */
obuf = gdk_pixbuf_new_from_file (selection, NULL);
if (G_LIKELY (obuf != NULL)) {
/* store data */
w = gdk_pixbuf_get_width (obuf);
h = gdk_pixbuf_get_height (obuf);
/* try to stat the file */
if (G_UNLIKELY (g_stat (selection, &sb) < 0)) {
sat_log_log (SAT_LOG_LEVEL_ERROR,
_("%s:%d: Could not stat %s"),
__FILE__, __LINE__, selection);
size = 0;
}
else {
size = sb.st_size;
}
bf = get_map_humanize_size (size, bf, 0);
buff = g_strdup_printf ("%dx%d pixels\n%s", w, h, bf);
gtk_label_set_text (GTK_LABEL (label), buff);
g_free (buff);
g_free (bf);
/* scale the pixbuf */
sbuf = gdk_pixbuf_scale_simple (obuf, 160, 80, GDK_INTERP_HYPER);
g_object_unref (obuf);
/* update the GtkImage from the pixbuf */
gtk_image_set_from_pixbuf (GTK_IMAGE (img), sbuf);
g_object_unref (sbuf);
}
else {
gtk_image_set_from_stock (GTK_IMAGE (img),
GTK_STOCK_MISSING_IMAGE,
GTK_ICON_SIZE_LARGE_TOOLBAR);
}
return vbox;
}
static void
update_preview_widget (GtkFileChooser *chooser, gpointer data)
{
GtkWidget *box = GTK_WIDGET (data);
GtkImage *img = GTK_IMAGE (g_object_get_data (G_OBJECT (box), "image"));
GtkLabel *lab = GTK_LABEL (g_object_get_data (G_OBJECT (box), "label"));
gchar *sel = NULL;
GdkPixbuf *obuf,*sbuf;
gint w,h;
gint64 size;
struct stat sb;
gchar *buff = NULL;
sel = gtk_file_chooser_get_preview_filename (chooser);
if (G_LIKELY (sel != NULL)) {
obuf = gdk_pixbuf_new_from_file (sel, NULL);
/* try to stat the file */
if (G_UNLIKELY (g_stat (sel, &sb) < 0)) {
sat_log_log (SAT_LOG_LEVEL_ERROR,
_("%s:%d: Could not stat %s"),
__FILE__, __LINE__, sel);
size = 0;
}
else {
size = sb.st_size;
}
g_free (sel);
if (G_LIKELY (obuf != NULL)) {
/* store data */
w = gdk_pixbuf_get_width (obuf);
h = gdk_pixbuf_get_height (obuf);
buff = get_map_humanize_size (size, buff, 0);
sel = g_strdup_printf ("%dx%d pixels\n%s", w, h, buff);
gtk_label_set_text (lab, sel);
g_free (sel);
g_free (buff);
/* scale the pixbuf */
sbuf = gdk_pixbuf_scale_simple (obuf, 160, 80, GDK_INTERP_HYPER);
g_object_unref (obuf);
/* update the GtkImage from the pixbuf */
gtk_image_clear (img);
gtk_image_set_from_pixbuf (img, sbuf);
g_object_unref (sbuf);
/* report success */
gtk_file_chooser_set_preview_widget_active (chooser, TRUE);
}
else {
gtk_image_clear (img);
gtk_image_set_from_stock (GTK_IMAGE (img),
GTK_STOCK_MISSING_IMAGE,
GTK_ICON_SIZE_LARGE_TOOLBAR);
/* report failure */
gtk_file_chooser_set_preview_widget_active (chooser, FALSE);
}
}
}
/** \brief Convert map filesize into a human readable format
* \param size Size in bytes.
* \param buffer Destination buffer or NULL to dynamically allocate a buffer.
* \param buflen Length of @buffer in bytes.
* \return A string containing a human readable description of size.
*
* The caller is responsible to free the returned string using g_free()
* if you pass NULL for buffer. Else the returned string will be a
* pointer to buffer.
*
* Credits: Thunar (XFCE file manager).
*
**/
static gchar*
get_map_humanize_size (gint64 size,
gchar *buffer,
gsize buflen)
{
/* allocate buffer if necessary */
if (buffer == NULL) {
buffer = g_new (gchar, 32);
buflen = 32;
}
if (G_UNLIKELY (size > 1024ul * 1024ul * 1024ul))
g_snprintf (buffer, buflen, "%0.1f GB", size / (1024.0 * 1024.0 * 1024.0));
else if (size > 1024ul * 1024ul)
g_snprintf (buffer, buflen, "%0.1f MB", size / (1024.0 * 1024.0));
else if (size > 1024ul)
g_snprintf (buffer, buflen, "%0.1f kB", size / 1024.0);
else
g_snprintf (buffer, buflen, "%lu B", (gulong) size);
return buffer;
}