blob: f1d47c88413a3182f8571a3e32447ff98b0a609b [file] [log] [blame]
/*
* Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
*
* 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, 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <gtk/gtk.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include "utils.h"
void
pgd_table_add_property_with_custom_widget (GtkGrid *table,
const gchar *markup,
GtkWidget *widget,
gint *row)
{
GtkWidget *label;
label = gtk_label_new (NULL);
g_object_set (G_OBJECT (label), "xalign", 0.0, NULL);
gtk_label_set_markup (GTK_LABEL (label), markup);
gtk_grid_attach (GTK_GRID (table), label, 0, *row, 1, 1);
gtk_widget_show (label);
gtk_grid_attach (GTK_GRID (table), widget, 1, *row, 1, 1);
gtk_widget_set_hexpand (widget, TRUE);
gtk_widget_show (widget);
*row += 1;
}
void
pgd_table_add_property_with_value_widget (GtkGrid *table,
const gchar *markup,
GtkWidget **value_widget,
const gchar *value,
gint *row)
{
GtkWidget *label;
*value_widget = label = gtk_label_new (value);
g_object_set (G_OBJECT (label),
"xalign", 0.0,
"selectable", TRUE,
"ellipsize", PANGO_ELLIPSIZE_END,
NULL);
pgd_table_add_property_with_custom_widget (table, markup, label, row);
}
void
pgd_table_add_property (GtkGrid *table,
const gchar *markup,
const gchar *value,
gint *row)
{
GtkWidget *label;
pgd_table_add_property_with_value_widget (table, markup, &label, value, row);
}
GtkWidget *
pgd_action_view_new (PopplerDocument *document)
{
GtkWidget *frame, *label;
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label), "<b>Action Properties</b>");
gtk_frame_set_label_widget (GTK_FRAME (frame), label);
gtk_widget_show (label);
g_object_set_data (G_OBJECT (frame), "document", document);
return frame;
}
static void
pgd_action_view_add_destination (GtkWidget *action_view,
GtkGrid *table,
PopplerDest *dest,
gboolean remote,
gint *row)
{
PopplerDocument *document;
GEnumValue *enum_value;
gchar *str;
pgd_table_add_property (table, "<b>Type:</b>", "Destination", row);
enum_value = g_enum_get_value ((GEnumClass *) g_type_class_ref (POPPLER_TYPE_DEST_TYPE), dest->type);
pgd_table_add_property (table, "<b>Destination Type:</b>", enum_value->value_name, row);
document = g_object_get_data (G_OBJECT (action_view), "document");
if (dest->type != POPPLER_DEST_NAMED) {
str = NULL;
if (document && !remote) {
PopplerPage *poppler_page;
gchar *page_label;
poppler_page = poppler_document_get_page (document, MAX (0, dest->page_num - 1));
g_object_get (G_OBJECT (poppler_page),
"label", &page_label,
NULL);
if (page_label) {
str = g_strdup_printf ("%d (%s)", dest->page_num, page_label);
g_free (page_label);
}
}
if (!str)
str = g_strdup_printf ("%d", dest->page_num);
pgd_table_add_property (table, "<b>Page:</b>", str, row);
g_free (str);
str = g_strdup_printf ("%.2f", dest->left);
pgd_table_add_property (table, "<b>Left:</b>", str, row);
g_free (str);
str = g_strdup_printf ("%.2f", dest->right);
pgd_table_add_property (table, "<b>Right:</b>", str, row);
g_free (str);
str = g_strdup_printf ("%.2f", dest->top);
pgd_table_add_property (table, "<b>Top:</b>", str, row);
g_free (str);
str = g_strdup_printf ("%.2f", dest->bottom);
pgd_table_add_property (table, "<b>Bottom:</b>", str, row);
g_free (str);
str = g_strdup_printf ("%.2f", dest->zoom);
pgd_table_add_property (table, "<b>Zoom:</b>", str, row);
g_free (str);
} else {
pgd_table_add_property (table, "<b>Named Dest:</b>", dest->named_dest, row);
if (document && !remote) {
PopplerDest *new_dest;
new_dest = poppler_document_find_dest (document, dest->named_dest);
if (new_dest) {
GtkWidget *new_table, *alignment;
gint new_row = 0;
alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 5, 5, 12, 5);
new_table = gtk_grid_new ();
gtk_grid_set_column_spacing (GTK_GRID (new_table), 6);
gtk_grid_set_row_spacing (GTK_GRID (new_table), 6);
gtk_grid_attach (GTK_GRID(table), alignment, 0, *row, 1, 1);
gtk_widget_show (alignment);
pgd_action_view_add_destination (action_view, GTK_GRID (new_table),
new_dest, FALSE, &new_row);
poppler_dest_free (new_dest);
gtk_container_add (GTK_CONTAINER (alignment), new_table);
gtk_widget_show (new_table);
*row += 1;
}
}
}
}
static const gchar *
get_movie_op (PopplerActionMovieOperation op)
{
switch (op) {
case POPPLER_ACTION_MOVIE_PLAY:
return "Play";
case POPPLER_ACTION_MOVIE_PAUSE:
return "Pause";
case POPPLER_ACTION_MOVIE_RESUME:
return "Resume";
case POPPLER_ACTION_MOVIE_STOP:
return "Stop";
}
return NULL;
}
static void
free_tmp_file (GFile *tmp_file)
{
g_file_delete (tmp_file, NULL, NULL);
g_object_unref (tmp_file);
}
static gboolean
save_helper (const gchar *buf,
gsize count,
gpointer data,
GError **error)
{
gint fd = GPOINTER_TO_INT (data);
return write (fd, buf, count) == count;
}
static void
pgd_action_view_play_rendition (GtkWidget *button,
PopplerMedia *media)
{
GFile *file = NULL;
gchar *uri;
if (poppler_media_is_embedded (media)) {
gint fd;
gchar *tmp_filename = NULL;
fd = g_file_open_tmp (NULL, &tmp_filename, NULL);
if (fd != -1) {
if (poppler_media_save_to_callback (media, save_helper, GINT_TO_POINTER (fd), NULL)) {
file = g_file_new_for_path (tmp_filename);
g_object_set_data_full (G_OBJECT (media),
"tmp-file", g_object_ref (file),
(GDestroyNotify)free_tmp_file);
} else {
g_free (tmp_filename);
}
close (fd);
} else if (tmp_filename) {
g_free (tmp_filename);
}
} else {
const gchar *filename;
filename = poppler_media_get_filename (media);
if (g_path_is_absolute (filename)) {
file = g_file_new_for_path (filename);
} else if (g_strrstr (filename, "://")) {
file = g_file_new_for_uri (filename);
} else {
gchar *cwd;
gchar *path;
// FIXME: relative to doc uri, not cwd
cwd = g_get_current_dir ();
path = g_build_filename (cwd, filename, NULL);
g_free (cwd);
file = g_file_new_for_path (path);
g_free (path);
}
}
if (file) {
uri = g_file_get_uri (file);
g_object_unref (file);
if (uri) {
gtk_show_uri (gtk_widget_get_screen (button),
uri, GDK_CURRENT_TIME, NULL);
g_free (uri);
}
}
}
static void
pgd_action_view_do_action_layer (GtkWidget *button,
GList *state_list)
{
GList *l, *m;
for (l = state_list; l; l = g_list_next (l)) {
PopplerActionLayer *action_layer = (PopplerActionLayer *)l->data;
for (m = action_layer->layers; m; m = g_list_next (m)) {
PopplerLayer *layer = (PopplerLayer *)m->data;
switch (action_layer->action) {
case POPPLER_ACTION_LAYER_ON:
poppler_layer_show (layer);
break;
case POPPLER_ACTION_LAYER_OFF:
poppler_layer_hide (layer);
break;
case POPPLER_ACTION_LAYER_TOGGLE:
if (poppler_layer_is_visible (layer))
poppler_layer_hide (layer);
else
poppler_layer_show (layer);
break;
}
}
}
}
void
pgd_action_view_set_action (GtkWidget *action_view,
PopplerAction *action)
{
GtkWidget *alignment;
GtkWidget *table;
gint row = 0;
alignment = gtk_bin_get_child (GTK_BIN (action_view));
if (alignment) {
gtk_container_remove (GTK_CONTAINER (action_view), alignment);
}
alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 5, 5, 12, 5);
gtk_container_add (GTK_CONTAINER (action_view), alignment);
gtk_widget_show (alignment);
if (!action)
return;
table = gtk_grid_new ();
gtk_grid_set_column_spacing (GTK_GRID (table), 6);
gtk_grid_set_row_spacing (GTK_GRID (table), 6);
pgd_table_add_property (GTK_GRID (table), "<b>Title:</b>", action->any.title, &row);
switch (action->type) {
case POPPLER_ACTION_UNKNOWN:
pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "Unknown", &row);
break;
case POPPLER_ACTION_NONE:
pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "None", &row);
break;
case POPPLER_ACTION_GOTO_DEST:
pgd_action_view_add_destination (action_view, GTK_GRID (table), action->goto_dest.dest, FALSE, &row);
break;
case POPPLER_ACTION_GOTO_REMOTE:
pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "Remote Destination", &row);
pgd_table_add_property (GTK_GRID (table), "<b>Filename:</b>", action->goto_remote.file_name, &row);
pgd_action_view_add_destination (action_view, GTK_GRID (table), action->goto_remote.dest, TRUE, &row);
break;
case POPPLER_ACTION_LAUNCH:
pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "Launch", &row);
pgd_table_add_property (GTK_GRID (table), "<b>Filename:</b>", action->launch.file_name, &row);
pgd_table_add_property (GTK_GRID (table), "<b>Params:</b>", action->launch.params, &row);
break;
case POPPLER_ACTION_URI:
pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "External URI", &row);
pgd_table_add_property (GTK_GRID (table), "<b>URI</b>", action->uri.uri, &row);
break;
case POPPLER_ACTION_NAMED:
pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "Named Action", &row);
pgd_table_add_property (GTK_GRID (table), "<b>Name:</b>", action->named.named_dest, &row);
break;
case POPPLER_ACTION_MOVIE: {
GtkWidget *movie_view = pgd_movie_view_new ();
pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "Movie", &row);
pgd_table_add_property (GTK_GRID (table), "<b>Operation:</b>", get_movie_op (action->movie.operation), &row);
pgd_movie_view_set_movie (movie_view, action->movie.movie);
pgd_table_add_property_with_custom_widget (GTK_GRID (table), "<b>Movie:</b>", movie_view, &row);
}
break;
case POPPLER_ACTION_RENDITION: {
gchar *text;
pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "Rendition", &row);
text = g_strdup_printf ("%d", action->rendition.op);
pgd_table_add_property (GTK_GRID (table), "<b>Operation:</b>", text, &row);
g_free (text);
if (action->rendition.media) {
gboolean embedded = poppler_media_is_embedded (action->rendition.media);
GtkWidget *button;
pgd_table_add_property (GTK_GRID (table), "<b>Embedded:</b>", embedded ? "Yes": "No", &row);
if (embedded) {
const gchar *mime_type = poppler_media_get_mime_type (action->rendition.media);
pgd_table_add_property (GTK_GRID (table), "<b>Mime type:</b>",
mime_type ? mime_type : "",
&row);
} else {
pgd_table_add_property (GTK_GRID (table), "<b>Filename:</b>",
poppler_media_get_filename (action->rendition.media),
&row);
}
button = gtk_button_new_from_stock (GTK_STOCK_MEDIA_PLAY);
g_signal_connect (button, "clicked",
G_CALLBACK (pgd_action_view_play_rendition),
action->rendition.media);
pgd_table_add_property_with_custom_widget (GTK_GRID (table), NULL, button, &row);
gtk_widget_show (button);
}
}
break;
case POPPLER_ACTION_OCG_STATE: {
GList *l;
GtkWidget *button;
pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "OCGState", &row);
for (l = action->ocg_state.state_list; l; l = g_list_next (l)) {
PopplerActionLayer *action_layer = (PopplerActionLayer *)l->data;
gchar *text;
gint n_layers = g_list_length (action_layer->layers);
switch (action_layer->action) {
case POPPLER_ACTION_LAYER_ON:
text = g_strdup_printf ("%d layers On", n_layers);
break;
case POPPLER_ACTION_LAYER_OFF:
text = g_strdup_printf ("%d layers Off", n_layers);
break;
case POPPLER_ACTION_LAYER_TOGGLE:
text = g_strdup_printf ("%d layers Toggle", n_layers);
break;
}
pgd_table_add_property (GTK_GRID (table), "<b>Action:</b>", text, &row);
g_free (text);
}
button = gtk_button_new_with_label ("Do action");
g_signal_connect (button, "clicked",
G_CALLBACK (pgd_action_view_do_action_layer),
action->ocg_state.state_list);
pgd_table_add_property_with_custom_widget (GTK_GRID (table), NULL, button, &row);
gtk_widget_show (button);
}
break;
case POPPLER_ACTION_JAVASCRIPT: {
GtkTextBuffer *buffer;
GtkWidget *textview;
GtkWidget *swindow;
pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "JavaScript", &row);
buffer = gtk_text_buffer_new (NULL);
if (action->javascript.script)
gtk_text_buffer_set_text (buffer, action->javascript.script, -1);
textview = gtk_text_view_new_with_buffer (buffer);
gtk_text_view_set_editable (GTK_TEXT_VIEW (textview), FALSE);
g_object_unref (buffer);
swindow = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_container_add (GTK_CONTAINER (swindow), textview);
gtk_widget_show (textview);
pgd_table_add_property_with_custom_widget (GTK_GRID (table), NULL, swindow, &row);
gtk_widget_show (swindow);
}
break;
default:
g_assert_not_reached ();
}
gtk_container_add (GTK_CONTAINER (alignment), table);
gtk_widget_show (table);
}
gchar *
pgd_format_date (time_t utime)
{
time_t time = (time_t) utime;
char s[256];
const char *fmt_hack = "%c";
size_t len;
#ifdef HAVE_LOCALTIME_R
struct tm t;
if (time == 0 || !localtime_r (&time, &t)) return NULL;
len = strftime (s, sizeof (s), fmt_hack, &t);
#else
struct tm *t;
if (time == 0 || !(t = localtime (&time)) ) return NULL;
len = strftime (s, sizeof (s), fmt_hack, t);
#endif
if (len == 0 || s[0] == '\0') return NULL;
return g_locale_to_utf8 (s, -1, NULL, NULL, NULL);
}
GtkWidget *
pgd_movie_view_new (void)
{
GtkWidget *frame, *label;
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label), "<b>Movie Properties</b>");
gtk_frame_set_label_widget (GTK_FRAME (frame), label);
gtk_widget_show (label);
return frame;
}
static void
pgd_movie_view_play_movie (GtkWidget *button,
PopplerMovie *movie)
{
const gchar *filename;
GFile *file;
gchar *uri;
filename = poppler_movie_get_filename (movie);
if (g_path_is_absolute (filename)) {
file = g_file_new_for_path (filename);
} else if (g_strrstr (filename, "://")) {
file = g_file_new_for_uri (filename);
} else {
gchar *cwd;
gchar *path;
// FIXME: relative to doc uri, not cwd
cwd = g_get_current_dir ();
path = g_build_filename (cwd, filename, NULL);
g_free (cwd);
file = g_file_new_for_path (path);
g_free (path);
}
uri = g_file_get_uri (file);
g_object_unref (file);
if (uri) {
gtk_show_uri (gtk_widget_get_screen (button),
uri, GDK_CURRENT_TIME, NULL);
g_free (uri);
}
}
void
pgd_movie_view_set_movie (GtkWidget *movie_view,
PopplerMovie *movie)
{
GtkWidget *alignment;
GtkWidget *table;
GtkWidget *button;
gint row = 0;
alignment = gtk_bin_get_child (GTK_BIN (movie_view));
if (alignment) {
gtk_container_remove (GTK_CONTAINER (movie_view), alignment);
}
alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 5, 5, 12, 5);
gtk_container_add (GTK_CONTAINER (movie_view), alignment);
gtk_widget_show (alignment);
if (!movie)
return;
table = gtk_grid_new ();
gtk_grid_set_column_spacing (GTK_GRID (table), 6);
gtk_grid_set_row_spacing (GTK_GRID (table), 6);
pgd_table_add_property (GTK_GRID (table), "<b>Filename:</b>", poppler_movie_get_filename (movie), &row);
pgd_table_add_property (GTK_GRID (table), "<b>Need Poster:</b>", poppler_movie_need_poster (movie) ? "Yes" : "No", &row);
pgd_table_add_property (GTK_GRID (table), "<b>Show Controls:</b>", poppler_movie_show_controls (movie) ? "Yes" : "No", &row);
button = gtk_button_new_from_stock (GTK_STOCK_MEDIA_PLAY);
g_signal_connect (button, "clicked",
G_CALLBACK (pgd_movie_view_play_movie),
movie);
pgd_table_add_property_with_custom_widget (GTK_GRID (table), NULL, button, &row);
gtk_widget_show (button);
gtk_container_add (GTK_CONTAINER (alignment), table);
gtk_widget_show (table);
}
GdkPixbuf *
pgd_pixbuf_new_for_color (PopplerColor *poppler_color)
{
GdkPixbuf *pixbuf;
gint num, x;
guchar *pixels;
if (!poppler_color)
return NULL;
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
FALSE, 8,
64, 16);
pixels = gdk_pixbuf_get_pixels (pixbuf);
num = gdk_pixbuf_get_width (pixbuf) * gdk_pixbuf_get_height (pixbuf);
for (x = 0; x < num; x++) {
pixels[0] = poppler_color->red;
pixels[1] = poppler_color->green;
pixels[2] = poppler_color->blue;
pixels += 3;
}
return pixbuf;
}