Logo Search packages:      
Sourcecode: easytag version File versions  Download package

picture.c

/* picture.c - 2004/11/21 */
/*
 *  EasyTAG - Tag editor for MP3 and Ogg Vorbis files
 *  Copyright (C) 2000-2003  Jerome Couderc <easytag@gmail.com>
 *
 *  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, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */


#include <config.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <gdk/gdk.h>
#include <glib/gi18n-lib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>

#include "picture.h"
#include "easytag.h"
#include "misc.h"
#include "setting.h"
#include "msgbox.h"
#include "bar.h"
#include "charset.h"

#ifdef WIN32
#   include "win32dep.h"
#endif


/****************
 * Declarations *
 ****************/


/**************
 * Prototypes *
 **************/

void Tag_Area_Picture_Drag_Data (GtkWidget *widget, GdkDragContext *dc, 
                                 gint x, gint y, GtkSelectionData *selection_data,
                                 guint info, guint t, gpointer data);
void Picture_Selection_Changed_cb (GtkTreeSelection *selection, gpointer data);
void Picture_Load_Filename (gchar *filename, gpointer user_data);

void Picture_Add_Button_Clicked         (GObject *object);
void Picture_Properties_Button_Clicked  (GObject *object);
void Picture_Save_Button_Clicked        (GObject *object);
void Picture_Clear_Button_Clicked       (GObject *object);

gint Picture_Format (Picture *pic);
const gchar *Picture_Format_String (gint format);
const gchar *Picture_Type_String   (gint type);
gchar *Picture_Info (Picture *pic);
void PictureEntry_Clear  (void);
void PictureEntry_Update (Picture *pic, gint select);

Picture *Picture_Allocate (void);
Picture *Picture_Copy_One (const Picture *pic);
Picture *Picture_Copy     (const Picture *pic);
void     Picture_Free     (Picture *pic);
Picture *Picture_Load_File_Data (const gchar *filename);
gboolean Picture_Save_File_Data (const Picture *pic, const gchar *filename);

gboolean Picture_Entry_View_Button_Pressed (GtkTreeView *treeview, GdkEventButton *event, gpointer data);
gboolean Picture_Entry_View_Key_Pressed    (GtkTreeView *treeview, GdkEvent *event, gpointer data);


/*
 * Note :
 * -> MP4_TAG :
 *      Just has one picture (PICTURE_TYPE_FRONT_COVER).
 *      The format's don't matter to the MP4 side.
 *
 */

/*************
 * Functions *
 *************/

void Tag_Area_Picture_Drag_Data (GtkWidget *widget, GdkDragContext *dc, 
                                 gint x, gint y, GtkSelectionData *selection_data,
                                 guint info, guint t, gpointer data)
{
    GtkTreeSelection *selection;
    gchar **uri_list, **uri;

    gtk_drag_finish(dc, TRUE, FALSE, t);

    if (info != TARGET_URI_LIST
    ||  !selection_data
    ||  !PictureEntryView)
        return;

    selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(PictureEntryView));
    gtk_tree_selection_unselect_all(selection);
    
    uri = uri_list = g_strsplit((const gchar *)selection_data->data, "\r\n", 0);
    while (*uri && strlen(*uri))
    {
        //Picture *pic;
        gchar *filename;

        filename = g_filename_from_uri(*uri, 0, 0);
        if (filename)
        {
            Picture_Load_Filename(filename,NULL);
            /*pic = Picture_Load_File_Data(filename);
            g_free(filename);
            if (pic)
                PictureEntry_Update(pic, 1);*/
        }
        uri++;
    }
    g_strfreev(uri_list);
}

void Picture_Selection_Changed_cb (GtkTreeSelection *selection, gpointer data)
{
    //if (gtk_tree_selection_count_selected_rows(GTK_TREE_SELECTION(selection)) == 1)
    //{
        gtk_widget_set_sensitive(GTK_WIDGET(PictureSaveButton), TRUE);
        gtk_widget_set_sensitive(GTK_WIDGET(PicturePropertiesButton), TRUE);
    //}else
    //{
    //    gtk_widget_set_sensitive(GTK_WIDGET(PictureSaveButton), FALSE);
    //    gtk_widget_set_sensitive(GTK_WIDGET(PicturePropertiesButton), FALSE);
    //}
}

void Picture_Clear_Button_Clicked (GObject *object)
{
    GList *paths, *refs = NULL, *node = NULL;
    GtkTreeSelection *selection;
    GtkTreeModel *model;
    GtkTreeIter iter;
    gpointer proxy;
    gint n = 0;
    
    if (!PictureEntryView) return;

    model = gtk_tree_view_get_model(GTK_TREE_VIEW(PictureEntryView));
    selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(PictureEntryView));
    paths = gtk_tree_selection_get_selected_rows(selection, 0);
    proxy = g_object_newv(G_TYPE_OBJECT, 0, NULL);

    // List of items to delete
    for (node = paths; node; node = node->next)
    {
        refs = g_list_append(refs, gtk_tree_row_reference_new_proxy(proxy, model, node->data));
        gtk_tree_path_free(node->data);
    }
    g_list_free(paths);

    for (node = refs; node; node = node->next)
    {
        GtkTreePath *path = gtk_tree_row_reference_get_path(node->data);
        Picture *pic;
      
        gtk_tree_model_get_iter(model, &iter, path);
        
        gtk_tree_model_get(model, &iter, PICTURE_COLUMN_DATA, &pic,-1);
        Picture_Free(pic);
        
        gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
        gtk_tree_row_reference_deleted(proxy, path);
        gtk_tree_path_free(path);
        gtk_tree_row_reference_free(node->data);
        n++;
    }
    g_list_free(refs);
    
    if (!n)
        // Delete all if no one was selected.
        PictureEntry_Clear();
}

/*
 * - 'filename' : path + filename of picture file
 */
void Picture_Load_Filename (gchar *filename, gpointer user_data)
{
    Picture *pic;
    gchar *filename_utf8;
    gchar *filename_utf8_folded = NULL;
    gchar *front_folded = NULL;
    gchar *back_folded = NULL;
    gchar *cd_folded = NULL;
    gchar *inside_folded = NULL;
    //gchar *inlay_folded = NULL;
    
    // Filename must be passed in filesystem encoding!
    pic = Picture_Load_File_Data(filename);

    filename_utf8 = filename_to_display(filename);

    if (pic && filename_utf8)
    {
        // Behaviour following the tag type...
        switch (ETCore->ETFileDisplayed->ETFileDescription->TagType)
        {
            case MP4_TAG:
            {
                pic->type = PICTURE_TYPE_FRONT_COVER;
                break;
            }
            
            // Other tag types
            default:
            {
                // By default, set the filename in the description
                pic->description = g_path_get_basename(filename_utf8);
                
                // Try to identify the type of the picture from the file name
                filename_utf8_folded = g_utf8_casefold(pic->description, -1);
                front_folded         = g_utf8_casefold("Front", -1);
                back_folded          = g_utf8_casefold("Back", -1);
                cd_folded            = g_utf8_casefold("CD", -1);
                inside_folded        = g_utf8_casefold("inside", -1);
                //inlay_folded         = g_utf8_casefold("inlay", -1);
                if ( strstr(filename_utf8_folded, front_folded) != NULL )
                    pic->type = PICTURE_TYPE_FRONT_COVER;
                else if ( strstr(filename_utf8_folded, back_folded) != NULL )
                    pic->type = PICTURE_TYPE_BACK_COVER;
                else if ( strstr(filename_utf8_folded, cd_folded) != NULL )
                    pic->type = PICTURE_TYPE_MEDIA;
                else if ( strstr(filename_utf8_folded, inside_folded) != NULL )
                    pic->type = PICTURE_TYPE_LEAFLET_PAGE;
                //else if ( strstr(filename_utf8_folded, inlay_folded) != NULL )
                //    pic->type = PICTURE_TYPE_LEAFLET_PAGE;

                break;
            }
        }

        PictureEntry_Update(pic, 1);

        // FIXME: Call Picture_Free(pic) here? It seems PictureEntry_Update makes copies of pic.
        //Picture_Free(pic);
    }
    
    g_free(filename_utf8);
    g_free(filename_utf8_folded);
    g_free(front_folded);
    g_free(back_folded);
    g_free(cd_folded);
    g_free(inside_folded);
    //g_free(inlay_folded);
}

/*
 * To add an image in the list -> call a FileSelectionWindow
 */
void Picture_Add_Button_Clicked (GObject *object)
{
    GtkWidget *FileSelectionWindow;
    GtkFileFilter *filter;
    GtkWindow *parent_window = NULL;
    static gchar *init_dir = NULL;

    if (!PictureEntryView) return;

    parent_window = (GtkWindow *) gtk_widget_get_toplevel(GTK_WIDGET(object));
    if (!GTK_WIDGET_TOPLEVEL(parent_window))
    {
        g_warning("Could not get parent window\n");
        return;
    }


    FileSelectionWindow = gtk_file_chooser_dialog_new(_("Add pictures"),
                                                      parent_window,
                                                      GTK_FILE_CHOOSER_ACTION_OPEN,
                                                      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                                      GTK_STOCK_OPEN, GTK_RESPONSE_OK,
                                                      NULL);

    // Add files filters
    // "All files" filter
    filter = gtk_file_filter_new ();
    gtk_file_filter_set_name(GTK_FILE_FILTER(filter), _("All Files"));
    gtk_file_filter_add_pattern(GTK_FILE_FILTER(filter), "*");
    gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(FileSelectionWindow), GTK_FILE_FILTER(filter));

    // "PNG and JPEG" filter
    filter = gtk_file_filter_new ();
    gtk_file_filter_set_name(GTK_FILE_FILTER(filter), _("PNG and JPEG"));
    gtk_file_filter_add_mime_type(GTK_FILE_FILTER(filter), "image/jpeg");
    gtk_file_filter_add_mime_type(GTK_FILE_FILTER(filter), "image/png");
    gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (FileSelectionWindow), GTK_FILE_FILTER(filter));
    // Make this filter the default
    gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(FileSelectionWindow),  GTK_FILE_FILTER(filter));

    // Set window position
    if (MESSAGE_BOX_POSITION_NONE)
        gtk_window_set_position(GTK_WINDOW(FileSelectionWindow),GTK_WIN_POS_NONE);
    else if (MESSAGE_BOX_POSITION_CENTER)
        gtk_window_set_position(GTK_WINDOW(FileSelectionWindow),GTK_WIN_POS_CENTER);
    else if (MESSAGE_BOX_POSITION_MOUSE)
        gtk_window_set_position(GTK_WINDOW(FileSelectionWindow),GTK_WIN_POS_MOUSE);
    
    // Behaviour following the tag type...
    switch (ETCore->ETFileDisplayed->ETFileDescription->TagType)
    {
        case MP4_TAG:
        {
            gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(FileSelectionWindow), FALSE);
            break;
        }
        
        // Other tag types
        default:
        {
            gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(FileSelectionWindow), TRUE);
            break;
        }
    }

    gtk_dialog_set_default_response(GTK_DIALOG(FileSelectionWindow), GTK_RESPONSE_OK);
    if (init_dir)
        gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(FileSelectionWindow),init_dir);

    if (gtk_dialog_run(GTK_DIALOG(FileSelectionWindow)) == GTK_RESPONSE_OK)
    {
        GtkTreeSelection *selection;
        GSList *list;

        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(PictureEntryView));
        gtk_tree_selection_unselect_all(selection);
    
        list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(FileSelectionWindow));
        g_slist_foreach(list, (GFunc) Picture_Load_Filename, 0);
        g_slist_free(list);
        
        // Save the directory selected for initialize next time
        g_free(init_dir);
        init_dir = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(FileSelectionWindow));
    }
    gtk_widget_destroy(FileSelectionWindow);
}


void Picture_Properties_Button_Clicked (GObject *object)
{
    GtkWidget *ScrollWindowPictureTypes, *PictureTypesWindow;
    GtkWidget *type, *label, *desc;
    GtkCellRenderer *renderer;
    GtkTreeViewColumn *column;
    GtkTreeSelection *selection;
    GtkListStore *store;
    GtkTreeIter type_iter_to_select, iter;
    GtkTreeModel *model;
    GtkWindow *parent_window = NULL;
    GList *selection_list = NULL;
    gint i;
    gint selection_nbr, selection_i = 1;
    gint picture_types[] = 
        {
            PICTURE_TYPE_OTHER,
            PICTURE_TYPE_FILE_ICON,
            PICTURE_TYPE_OTHER_FILE_ICON,
            PICTURE_TYPE_FRONT_COVER,
            PICTURE_TYPE_BACK_COVER,
            PICTURE_TYPE_LEAFLET_PAGE,
            PICTURE_TYPE_MEDIA,
            PICTURE_TYPE_LEAD_ARTIST_LEAD_PERFORMER_SOLOIST,
            PICTURE_TYPE_ARTIST_PERFORMER,
            PICTURE_TYPE_CONDUCTOR,
            PICTURE_TYPE_BAND_ORCHESTRA,
            PICTURE_TYPE_COMPOSER,
            PICTURE_TYPE_LYRICIST_TEXT_WRITER,
            PICTURE_TYPE_RECORDING_LOCATION,
            PICTURE_TYPE_DURING_RECORDING,
            PICTURE_TYPE_DURING_PERFORMANCE,
            PICTURE_TYPE_MOVIDE_VIDEO_SCREEN_CAPTURE,
            PICTURE_TYPE_A_BRIGHT_COLOURED_FISH,
            PICTURE_TYPE_ILLUSTRATION,
            PICTURE_TYPE_BAND_ARTIST_LOGOTYPE,
            PICTURE_TYPE_PUBLISHER_STUDIO_LOGOTYPE
        };


    if (!PictureEntryView) return;

    parent_window = (GtkWindow *) gtk_widget_get_toplevel(GTK_WIDGET(object));
    if (!GTK_WIDGET_TOPLEVEL(parent_window))
    {
        g_warning("Could not get parent window\n");
        return;
    }

    model          = gtk_tree_view_get_model(GTK_TREE_VIEW(PictureEntryView));
    selection      = gtk_tree_view_get_selection(GTK_TREE_VIEW(PictureEntryView));
    selection_list = gtk_tree_selection_get_selected_rows(selection, NULL);
    selection_nbr  = gtk_tree_selection_count_selected_rows(GTK_TREE_SELECTION(selection));
    while (selection_list)
    {
        GtkTreePath *path = selection_list->data;
        Picture *pic;
        GtkTreeSelection *selectiontype;
        gchar *title;
        GtkTreePath *rowPath;

        // Get corresponding picture
        gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path);
        gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, PICTURE_COLUMN_DATA, &pic, -1);

        title = g_strdup_printf(_("Picture Properties %d/%d"),selection_i++,selection_nbr);
        PictureTypesWindow = gtk_dialog_new_with_buttons(title,
                                                         parent_window,
                                                         GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
                                                         GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
                                                         GTK_STOCK_OK, GTK_RESPONSE_OK,
                                                         NULL);
        g_free(title);
        
        // Set window position
        if (MESSAGE_BOX_POSITION_NONE)
            gtk_window_set_position(GTK_WINDOW(PictureTypesWindow),GTK_WIN_POS_NONE);
        else if (MESSAGE_BOX_POSITION_CENTER)
            gtk_window_set_position(GTK_WINDOW(PictureTypesWindow),GTK_WIN_POS_CENTER);
        else if (MESSAGE_BOX_POSITION_MOUSE)
            gtk_window_set_position(GTK_WINDOW(PictureTypesWindow),GTK_WIN_POS_MOUSE);

        gtk_dialog_set_default_response(GTK_DIALOG(PictureTypesWindow), GTK_RESPONSE_OK);
    
        ScrollWindowPictureTypes = gtk_scrolled_window_new(NULL, NULL);
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ScrollWindowPictureTypes),
                                       GTK_POLICY_AUTOMATIC,
                                       GTK_POLICY_AUTOMATIC);
        store = gtk_list_store_new(PICTURE_TYPE_COLUMN_COUNT, G_TYPE_STRING, G_TYPE_INT);
        type = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
        gtk_container_add(GTK_CONTAINER(ScrollWindowPictureTypes), type);
        
        renderer = gtk_cell_renderer_text_new();
        column = gtk_tree_view_column_new();
        gtk_tree_view_column_pack_start(column, renderer, FALSE);
        gtk_tree_view_column_set_title(column, _("Picture Type"));
        gtk_tree_view_column_set_attributes(column, renderer,
                                            "text", PICTURE_TYPE_COLUMN_TEXT,
                                            NULL);
        gtk_tree_view_append_column(GTK_TREE_VIEW(type), column);
        gtk_widget_set_size_request(type, 256, 256);
        gtk_box_pack_start(GTK_BOX(GTK_DIALOG(PictureTypesWindow)->vbox),ScrollWindowPictureTypes,TRUE,TRUE,0);
    
        // Behaviour following the tag type...
        switch (ETCore->ETFileDisplayed->ETFileDescription->TagType)
        {
            case MP4_TAG:
            {
                // Load picture type (only Front Cover!)
                GtkTreeIter itertype;
                
                gtk_list_store_append(store, &itertype);
                gtk_list_store_set(store, &itertype,
                                   PICTURE_TYPE_COLUMN_TEXT, _(Picture_Type_String(PICTURE_TYPE_FRONT_COVER)),
                                   PICTURE_TYPE_COLUMN_TYPE_CODE, PICTURE_TYPE_FRONT_COVER,
                                   -1);
                // Line to select by default
                type_iter_to_select = itertype;
                break;
            }
            
            // Other tag types
            default:
            {
                // Load pictures types
                for (i = 0; i < sizeof(picture_types)/sizeof(picture_types[0]); i++)
                {
                    GtkTreeIter itertype;
                    
                    gtk_list_store_append(store, &itertype);
                    gtk_list_store_set(store, &itertype,
                                       PICTURE_TYPE_COLUMN_TEXT, _(Picture_Type_String(picture_types[i])),
                                       PICTURE_TYPE_COLUMN_TYPE_CODE, picture_types[i],
                                       -1);
                    // Line to select by default
                    if (pic->type == picture_types[i])
                        type_iter_to_select = itertype;
                }
                break;
            }
        }
        
        // Select the line by default
        selectiontype = gtk_tree_view_get_selection(GTK_TREE_VIEW(type));
        gtk_tree_selection_select_iter(selectiontype, &type_iter_to_select);

        // Set visible the current selected line
        rowPath = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &type_iter_to_select);
        gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(type), rowPath, NULL, FALSE, 0, 0);
        gtk_tree_path_free(rowPath);

        // Description
        label = gtk_label_new(_("Picture Description:"));
        gtk_box_pack_start(GTK_BOX(GTK_DIALOG(PictureTypesWindow)->vbox),label,FALSE,FALSE,4);
    
        // Entry for the description
        desc = gtk_entry_new();
        gtk_box_pack_start(GTK_BOX(GTK_DIALOG(PictureTypesWindow)->vbox),desc,FALSE,FALSE,0);
        if (pic->description)
        {
            gchar *tmp = ET_Utf8_Validate_Full_String(pic->description);
            gtk_entry_set_text(GTK_ENTRY(desc), tmp);
            g_free(tmp);
        }
    
        // Behaviour following the tag type...
        switch (ETCore->ETFileDisplayed->ETFileDescription->TagType)
        {
            case MP4_TAG:
            {
                gtk_widget_set_sensitive(GTK_WIDGET(label), FALSE);
                gtk_widget_set_sensitive(GTK_WIDGET(desc), FALSE);
                break;
            }
            
            // Other tag types
            default:
            {
                break;
            }
        }
        
        gtk_widget_show_all(PictureTypesWindow);
        
        if (gtk_dialog_run(GTK_DIALOG(PictureTypesWindow)) == GTK_RESPONSE_OK)
        {
            GtkTreeModel *modeltype;
            GtkTreeIter itertype;
            
            modeltype     = gtk_tree_view_get_model(GTK_TREE_VIEW(type));
            selectiontype = gtk_tree_view_get_selection(GTK_TREE_VIEW(type));
            if (gtk_tree_selection_get_selected(selectiontype, &modeltype, &itertype))
            {
                gchar *buffer, *pic_info;
                gint t;
                
                gtk_tree_model_get(modeltype, &itertype,
                                   PICTURE_TYPE_COLUMN_TYPE_CODE, &t, -1);
                pic->type = t;
    
                buffer = g_strdup(gtk_entry_get_text(GTK_ENTRY(desc)));
                Strip_String(buffer);
                if (pic->description)
                    g_free(pic->description);
                if ( g_utf8_strlen(buffer, -1) > 0 )
                {
                    pic->description = buffer;
                }else
                {
                    pic->description = 0;
                    g_free(buffer);
                }
                
                // Update value in the PictureEntryView
                pic_info = Picture_Info(pic);
                gtk_list_store_set(GTK_LIST_STORE(model), &iter,
                                   PICTURE_COLUMN_TEXT, pic_info,
                                   -1);
                g_free(pic_info);
            }
        }
        gtk_widget_destroy(PictureTypesWindow);
        
        if (!selection_list->next) break;
        selection_list = selection_list->next;
    }
}


void Picture_Save_Button_Clicked (GObject *object)
{
    GtkWidget *FileSelectionWindow;
    GtkFileFilter *filter;
    GtkWindow *parent_window = NULL;
    static gchar *init_dir = NULL;

    GtkTreeSelection *selection;
    GList *selection_list = NULL;
    GtkTreeModel *model;
    gint selection_nbr, selection_i = 1;


    if (!PictureEntryView) return;

    parent_window = (GtkWindow*) gtk_widget_get_toplevel(GTK_WIDGET(object));
    if (!GTK_WIDGET_TOPLEVEL(parent_window))
    {
        g_warning("Could not get parent window\n");
        return;
    }

    model          = gtk_tree_view_get_model(GTK_TREE_VIEW(PictureEntryView));
    selection      = gtk_tree_view_get_selection(GTK_TREE_VIEW(PictureEntryView));
    selection_list = gtk_tree_selection_get_selected_rows(selection, NULL);
    selection_nbr  = gtk_tree_selection_count_selected_rows(GTK_TREE_SELECTION(selection));

    while (selection_list)
    {
        GtkTreePath *path = selection_list->data;
        GtkTreeIter iter;
        Picture *pic;
        gchar *title;
        
        // Get corresponding picture
        gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path);
        gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, PICTURE_COLUMN_DATA, &pic, -1);

        title = g_strdup_printf(_("Save picture %d/%d"),selection_i++,selection_nbr);
        FileSelectionWindow = gtk_file_chooser_dialog_new(title,
                                                          parent_window,
                                                          GTK_FILE_CHOOSER_ACTION_SAVE,
                                                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                                          GTK_STOCK_SAVE, GTK_RESPONSE_OK,
                                                          NULL);
        g_free(title);
        
        // Add files filters
        // "All files" filter
        filter = gtk_file_filter_new ();
        gtk_file_filter_set_name(GTK_FILE_FILTER(filter), _("All Files"));
        gtk_file_filter_add_pattern(GTK_FILE_FILTER(filter), "*");
        gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(FileSelectionWindow), GTK_FILE_FILTER(filter));
    
        // "PNG and JPEG" filter
        filter = gtk_file_filter_new ();
        gtk_file_filter_set_name(GTK_FILE_FILTER(filter), _("PNG and JPEG"));
        gtk_file_filter_add_mime_type(GTK_FILE_FILTER(filter), "image/jpeg");
        gtk_file_filter_add_mime_type(GTK_FILE_FILTER(filter), "image/png");
        gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (FileSelectionWindow), GTK_FILE_FILTER(filter));
        // Make this filter the default
        gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(FileSelectionWindow),  GTK_FILE_FILTER(filter));
        
        // Set window position
        if (MESSAGE_BOX_POSITION_NONE)
            gtk_window_set_position(GTK_WINDOW(FileSelectionWindow),GTK_WIN_POS_NONE);
        else if (MESSAGE_BOX_POSITION_CENTER)
            gtk_window_set_position(GTK_WINDOW(FileSelectionWindow),GTK_WIN_POS_CENTER);
        else if (MESSAGE_BOX_POSITION_MOUSE)
            gtk_window_set_position(GTK_WINDOW(FileSelectionWindow),GTK_WIN_POS_MOUSE);
        
        gtk_dialog_set_default_response(GTK_DIALOG(FileSelectionWindow), GTK_RESPONSE_OK);

        // Set the default folder if defined
        if (init_dir)
            gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(FileSelectionWindow),init_dir);
        
        // Suggest a filename to the user
        if ( pic->description && strlen(pic->description) )
        {
            gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(FileSelectionWindow), pic->description); //filename in UTF8
        }else
        {
            gchar *image_name = NULL;
            switch (Picture_Format(pic))
            {
                case PICTURE_FORMAT_JPEG :
                    image_name = g_strdup("image_name.jpg");
                    break;
                case PICTURE_FORMAT_PNG :
                    image_name = g_strdup("image_name.png");
                    break;
                case PICTURE_FORMAT_UNKNOWN :
                    image_name = g_strdup("image_name.ext");
                    break;
            }
            gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(FileSelectionWindow), image_name); //filename in UTF8
            g_free(image_name);
        }
        
        if (gtk_dialog_run(GTK_DIALOG(FileSelectionWindow)) == GTK_RESPONSE_OK)
        {
            FILE *file;
            gchar *filename, *filename_utf8;
        
            // Save the directory selected for initialize next time
            g_free(init_dir);
            init_dir = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(FileSelectionWindow));

            filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(FileSelectionWindow));
            filename_utf8 = filename_to_display(filename);
            
            // Warn user if the file already exists, else saves directly
            if ( (file=fopen(filename_utf8,"r"))!=NULL )
            {
                gchar *msg;
                GtkWidget *msgbox;
                gint button;

                fclose(file);
                
                msg = g_strdup_printf(_("The following file already exists :\n'%s'\n"
                    "Do you want to overwrite?"),filename_utf8);
                msgbox = msg_box_new (_("Save file..."),msg,GTK_STOCK_DIALOG_QUESTION,BUTTON_NO,BUTTON_YES,0);
                g_free(msg);
                msg_box_hide_check_button(MSG_BOX(msgbox));
                button = msg_box_run(MSG_BOX(msgbox));
                gtk_widget_destroy(msgbox);
                
                if (button == BUTTON_YES)
                {
                    Picture_Save_File_Data(pic, filename_utf8);
                }
            }else
            {
                Picture_Save_File_Data(pic, filename_utf8);
            }
            g_free(filename_utf8);
        }
        gtk_widget_destroy(FileSelectionWindow);

        if (!selection_list->next) break;
        selection_list = selection_list->next;
    }
}


/* FIXME: Possibly use gnome_vfs_get_mime_type_for_buffer. */
gint Picture_Format (Picture *pic)
{
    if (pic->data && pic->size > 2
    &&  pic->data[0] == 0xff 
    &&  pic->data[1] == 0xd8)
        return PICTURE_FORMAT_JPEG;
        
    if (pic->data && pic->size > 8
    &&  pic->data[0] == 0x89 
    &&  pic->data[1] == 0x50
    &&  pic->data[2] == 0x4e
    &&  pic->data[3] == 0x47
    &&  pic->data[4] == 0x0d
    &&  pic->data[5] == 0x0a
    &&  pic->data[6] == 0x1a
    &&  pic->data[7] == 0x0a)
        return PICTURE_FORMAT_PNG;
        
    return PICTURE_FORMAT_UNKNOWN;
}

const gchar *Picture_Format_String (gint format)
{
    switch (format)
    {
        case PICTURE_FORMAT_JPEG:
            return _("JPEG image");
        case PICTURE_FORMAT_PNG:
            return _("PNG image");
        default:
            return _("Unknown image");
    }
}

const gchar *Picture_Type_String (gint type)
{
    switch (type)
    {
        case PICTURE_TYPE_OTHER:
            return _("Other");
        case PICTURE_TYPE_FILE_ICON:
            return _("32x32 pixel PNG file icon");
        case PICTURE_TYPE_OTHER_FILE_ICON:
            return _("Other file icon");
        case PICTURE_TYPE_FRONT_COVER:
            return _("Cover (front)");
        case PICTURE_TYPE_BACK_COVER:
            return _("Cover (back)");
        case PICTURE_TYPE_LEAFLET_PAGE:
            return _("Leaflet page");
        case PICTURE_TYPE_MEDIA:
            return _("Media (e.g. label side of CD)");
        case PICTURE_TYPE_LEAD_ARTIST_LEAD_PERFORMER_SOLOIST:
            return _("Lead artist/lead performer/soloist");
        case PICTURE_TYPE_ARTIST_PERFORMER:
            return _("Artist/performer");
        case PICTURE_TYPE_CONDUCTOR:
            return _("Conductor");
        case PICTURE_TYPE_BAND_ORCHESTRA:
            return _("Band/Orchestra");
        case PICTURE_TYPE_COMPOSER:
            return _("Composer");
        case PICTURE_TYPE_LYRICIST_TEXT_WRITER:
            return _("Lyricist/text writer");
        case PICTURE_TYPE_RECORDING_LOCATION:
            return _("Recording location");
        case PICTURE_TYPE_DURING_RECORDING:
            return _("During recording");
        case PICTURE_TYPE_DURING_PERFORMANCE:
            return _("During performance");
        case PICTURE_TYPE_MOVIDE_VIDEO_SCREEN_CAPTURE:
            return _("Movie/video screen capture");
        case PICTURE_TYPE_A_BRIGHT_COLOURED_FISH:
            return _("A bright coloured fish");
        case PICTURE_TYPE_ILLUSTRATION:
            return _("Illustration");
        case PICTURE_TYPE_BAND_ARTIST_LOGOTYPE:
            return _("Band/Artist logotype");
        case PICTURE_TYPE_PUBLISHER_STUDIO_LOGOTYPE:
            return _("Publisher/studio logotype");
        default:
            return _("Unknown picture type");
    }
}

gchar *Picture_Info (Picture *pic)
{
    gchar *format, *desc, *type, *r, *size_str;
    GString *s;

    format = (gchar *)Picture_Format_String(Picture_Format(pic));
    
    if (pic->description)
        desc = pic->description;
    else
        desc = "";

    type = (gchar *)Picture_Type_String(pic->type);
    size_str = Convert_Size_1((gfloat)pic->size);

    s = g_string_new(0);
    // Behaviour following the tag type...
    switch (ETCore->ETFileDisplayed->ETFileDescription->TagType)
    {
        case MP4_TAG:
        {
            g_string_sprintf(s, "%s (%s - %dx%d %s)\n%s: %s",
                             format, 
                             size_str,
                             pic->width, pic->height, _("pixels"),
                             _("Type"), type);
            break;
        }
        
        // Other tag types
        default:
        {
            g_string_sprintf(s, "%s (%s - %dx%d %s)\n%s: %s\n%s: %s",
                             format, 
                             size_str,
                             pic->width, pic->height, _("pixels"),
                             _("Type"), type,
                             _("Description"), desc);
            break;
        }
    }
    r = ET_Utf8_Validate_Full_String(s->str);
    g_string_free(s, TRUE); // TRUE to free also 's->str'!
    g_free(size_str);
    
    return r;
}

void PictureEntry_Clear (void)
{
    GtkListStore *picture_store;
    GtkTreeModel *model;
    GtkTreeIter iter;
    Picture *pic;
    
    model = gtk_tree_view_get_model(GTK_TREE_VIEW(PictureEntryView));
    if (gtk_tree_model_get_iter_first(model, &iter))
    {
        do
        {
            gtk_tree_model_get(model, &iter, PICTURE_COLUMN_DATA, &pic,-1);
            Picture_Free(pic);
        } while (gtk_tree_model_iter_next(model, &iter));
    }
    
    picture_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(PictureEntryView)));
    if (picture_store)
        gtk_list_store_clear(picture_store);
}

void PictureEntry_Update (Picture *pic, gint select)
{
    GdkPixbufLoader *loader = 0;

    if (!pic || !PictureEntryView) return;

    if (!pic->data)
    {
        PictureEntry_Clear();
        return;
    }
    
    loader = gdk_pixbuf_loader_new();
    if (loader)
    {
        if (gdk_pixbuf_loader_write(loader, pic->data, pic->size, 0))
        {
            GtkTreeSelection *selection;
            GdkPixbuf *pixbuf;
            
            selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(PictureEntryView));
            
            pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
            if (pixbuf)
            {
                GtkListStore *picture_store;
                GtkTreeIter iter1;
                GdkPixbuf *scaled_pixbuf;
                gint scaled_pixbuf_width;
                gint scaled_pixbuf_height;
                gchar *pic_info;
                
                // Keep aspect ratio of the picture
                pic->width  = gdk_pixbuf_get_width (pixbuf);
                pic->height = gdk_pixbuf_get_height (pixbuf);
                if (pic->width > pic->height)
                {
                    scaled_pixbuf_width  = 96;
                    scaled_pixbuf_height = 96 * pic->height / pic->width;
                }else
                {
                    scaled_pixbuf_width = 96 * pic->width / pic->height;
                    scaled_pixbuf_height = 96;
                }
                
                scaled_pixbuf = gdk_pixbuf_scale_simple(pixbuf, 
                                    scaled_pixbuf_width, scaled_pixbuf_height,
                                    //GDK_INTERP_NEAREST); // Lower quality but better speed
                                    GDK_INTERP_BILINEAR);
                gdk_pixbuf_unref(pixbuf);
            
                picture_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(PictureEntryView)));
                gtk_list_store_append(picture_store, &iter1);
                pic_info = Picture_Info(pic);
                gtk_list_store_set(picture_store, &iter1,
                                   PICTURE_COLUMN_PIC, scaled_pixbuf,
                                   PICTURE_COLUMN_TEXT, pic_info,
                                   PICTURE_COLUMN_DATA, Picture_Copy_One(pic),
                                   -1);
                g_free(pic_info);
                
                if (select)
                    gtk_tree_selection_select_iter(selection, &iter1);
                gdk_pixbuf_unref(scaled_pixbuf);
            }else
            {
                GtkWidget *msgbox = NULL;
                gchar *msg = NULL;
                
                msg = g_strdup(_("Can't display the picture, as not enough data "
                    "has been read to determine how to create the image buffer."));
                g_print("%s\n",msg);
                msgbox = msg_box_new (_("Loading Picture File..."),msg,
                    GTK_STOCK_DIALOG_ERROR,BUTTON_YES,0);
                msg_box_hide_check_button(MSG_BOX(msgbox));
                g_free(msg);
                msg_box_run(MSG_BOX(msgbox));
                gtk_widget_destroy(msgbox);
            }
        }
    }
    gdk_pixbuf_loader_close(loader, 0);
    
    // Do also for next picture
    if (pic->next)
        PictureEntry_Update(pic->next, select);
    
    return;
}


Picture *Picture_Allocate (void)
{
    Picture *pic = g_malloc0(sizeof(Picture));
    return pic;
}

Picture *Picture_Copy_One (const Picture *pic)
{
    Picture *pic2;
    
    if (!pic)
        return 0;
    pic2 = Picture_Allocate();
    pic2->type = pic->type;
    pic2->width  = pic->width;
    pic2->height = pic->height;
    if (pic->description)
        pic2->description = g_strdup(pic->description);
    if (pic->data)
    {
        pic2->size = pic->size;
        pic2->data = g_malloc(pic2->size);
        memcpy(pic2->data, pic->data, pic->size);
    }
    return pic2;
}

Picture *Picture_Copy (const Picture *pic)
{
    Picture *pic2 = Picture_Copy_One(pic);
    if (pic->next)
        pic2->next = Picture_Copy(pic->next);
    return pic2;
}

void Picture_Free (Picture *pic)
{
    if (!pic)
        return;
    if (pic->next)
        Picture_Free(pic->next);
    if (pic->description)
        g_free(pic->description);
    if (pic->data)
        g_free(pic->data);
    g_free(pic);
}


/*
 * Load the picture represented by the 'filename' (must be passed in
 * file system encoding, not UTF-8)
 */
Picture *Picture_Load_File_Data (const gchar *filename)
{
    Picture *pic;
    gchar *buffer = 0;
    size_t size = 0;
    struct stat st;

    if (lstat(filename, &st)==-1)
        return (Picture *)NULL;

    size = st.st_size;
    buffer = g_malloc(size);
    
    FILE *fd = fopen(filename, "rb");
    if (!fd)
    {
        gchar *msg;
        gchar *filename_utf8;
        GtkWidget *msgbox;

        /* Picture file not opened */
        filename_utf8 = filename_to_display(filename);
        msg = g_strdup_printf(_("Can't open file :\n'%s'!\n(%s)"),
                                filename_utf8,g_strerror(errno)); 
        msgbox = msg_box_new (_("Error..."),msg,GTK_STOCK_DIALOG_ERROR,BUTTON_OK,0);
        g_free(msg);
        msg_box_hide_check_button(MSG_BOX(msgbox));
        msg_box_run(MSG_BOX(msgbox));
        gtk_widget_destroy(msgbox);

        Statusbar_Message(_("Picture file not loaded..."),TRUE);
        g_free(filename_utf8);
        return FALSE;
    }
    
    if (fread(buffer, size, 1, fd) != 1)
      goto fail;

    fclose(fd);
    
    pic = Picture_Allocate();
    pic->size = size;
    pic->data = buffer;
    return pic;

    fail:
        if (buffer)
            g_free(buffer);
        fclose(fd);
        return (Picture *)NULL;
}

/*
 * Save picture data to a file (jpeg, png)
 */ 
gboolean Picture_Save_File_Data (const Picture *pic, const gchar *filename)
{
    gint fd;
      
    fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
    if (fd == -1)
        return FALSE;
    
    if (write(fd, pic->data, pic->size) != pic->size)
    {
        close(fd);
        return FALSE;
    }
    
    close(fd);
    return TRUE;
}

/*
 * If double clicking the PictureEntryView :
 *  - over a selected row : opens properties window
 *  - over an empty area : open the adding window
 */
gboolean Picture_Entry_View_Button_Pressed (GtkTreeView *treeview, GdkEventButton *event, gpointer data)
{
    if (event->type==GDK_2BUTTON_PRESS && event->button==1)
    {
        GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(PictureEntryView));
        
        if (gtk_tree_selection_count_selected_rows(GTK_TREE_SELECTION(selection)) != 0)
            Picture_Properties_Button_Clicked(G_OBJECT(PicturePropertiesButton));
        else
            Picture_Add_Button_Clicked(G_OBJECT(PictureAddButton));

        return TRUE;
    }
    
    return FALSE;
}


/* 
 * Key press into picture entry
 *   - Delete = delete selected picture files
 */
gboolean Picture_Entry_View_Key_Pressed (GtkTreeView *treeview, GdkEvent *event, gpointer data)
{
    GdkEventKey *kevent;

    kevent = (GdkEventKey *)event;
    if (event && event->type==GDK_KEY_PRESS)
    {
        switch(kevent->keyval)
        {
            case GDK_Delete:
                Picture_Clear_Button_Clicked(NULL);
                return TRUE;
        }
    }

    return FALSE;
}

Generated by  Doxygen 1.6.0   Back to index