/* docindex.c - Creates the window used by the document index in go and gimp. * * Copyright (C) 1998 Chris Lahey. * * 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. */ #include #include #include #include "docindexif.h" #include "docindex.h" #include "gimprc.h" #include "libgimp/gimpenv.h" #include "libgimp/gimpintl.h" idea_manager *ideas = NULL; static GList *idea_list = NULL; /* of gchar *. */ static gint x = 0, y = 0, width = 0, height = 0; enum { TARGET_URI_LIST }; static void create_idea_list( void ); void docindex_configure_drop_on_widget(GtkWidget * widget); void docindex_cell_configure_drop_on_widget(GtkWidget * widget); static void docindex_dnd_filenames_dropped( GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time) { gint len; gchar *data; gchar *end; switch ( info ) { case TARGET_URI_LIST: data = (gchar *) selection_data->data; len = selection_data->length; while( len > 0 ) { end = strstr( data, "\x0D\x0A" ); if ( end != NULL ) *end = 0; if ( *data != '#' ) { gchar *filename = strchr( data, ':' ); if ( filename != NULL ) filename ++; else filename = data; open_file_in_position( filename, -1 ); } if ( end ) { len -= end - data + 2; data = end + 2; } else len = 0; } break; } return; } void docindex_configure_drop_on_widget(GtkWidget * widget) { static GtkTargetEntry drag_types[] = { { "text/uri-list", 0, TARGET_URI_LIST }, }; static gint n_drag_types = sizeof(drag_types)/sizeof(drag_types[0]); gtk_drag_dest_set (widget, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, drag_types, n_drag_types, GDK_ACTION_COPY); gtk_signal_connect(GTK_OBJECT(widget), "drag_data_received", GTK_SIGNAL_FUNC(docindex_dnd_filenames_dropped), NULL); } static void docindex_cell_dnd_filenames_dropped( GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time) { gint len; gchar *data; gchar *end; gint position = g_list_index( GTK_TREE( ideas->tree )->children, widget ); switch ( info ) { case TARGET_URI_LIST: data = (gchar *) selection_data->data; len = selection_data->length; while( len > 0 ) { end = strstr( data, "\x0D\x0A" ); if ( end != NULL ) *end = 0; if ( *data != '#' ) { gchar *filename = strchr( data, ':' ); if ( filename != NULL ) filename ++; else filename = data; open_file_in_position( filename, position ); } if ( end ) { len -= end - data + 2; data = end + 2; } else len = 0; } break; } return; } void docindex_cell_configure_drop_on_widget(GtkWidget * widget) { static GtkTargetEntry drag_types[] = { { "text/uri-list", 0, TARGET_URI_LIST }, }; static gint n_drag_types = sizeof(drag_types)/sizeof(drag_types[0]); gtk_drag_dest_set (widget, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, drag_types, n_drag_types, GDK_ACTION_COPY); gtk_signal_connect(GTK_OBJECT(widget), "drag_data_received", GTK_SIGNAL_FUNC(docindex_cell_dnd_filenames_dropped), NULL); } gboolean idea_window_delete_event_callback( GtkWidget *widget, GdkEvent *event, gpointer data ) { if ( ! exit_from_go() ) { save_idea_manager( ideas ); create_idea_list(); g_free( ideas ); ideas = 0; } return FALSE; } void idea_hide_callback( GtkWidget *widget, gpointer data ) { if ( ideas || idea_list || width || height ) save_idea_manager( ideas ); /* False if exitting */ if( ( ! exit_from_go() ) && ideas ) { create_idea_list(); gtk_widget_destroy( ideas->window ); g_free( ideas ); ideas = 0; } } void open_idea_window( void ) { make_idea_window( -1, -1 ); } static void load_from_list( gpointer data, gpointer data_null ) { idea_add_in_position( (gchar *) data, -1 ); } FILE * idea_manager_parse_init (/* RETURNS: */ int *window_x, int *window_y, int *window_width, int *window_height) { FILE *fp = NULL; gchar *desktopfile; desktopfile = gimp_personal_rc_file ("ideas"); fp = fopen( desktopfile, "r" ); g_free( desktopfile ); /* Read in persistant desktop information. */ if ( fp ) { *window_x = getinteger( fp ); *window_y = getinteger( fp ); *window_width = getinteger( fp ); *window_height = getinteger( fp ); } return fp; } gchar * idea_manager_parse_line (FILE * fp) { int length; gchar *filename; length = getinteger (fp); if (!feof( fp ) && !ferror (fp)) { filename = g_malloc0 (length + 1); filename[fread (filename, 1, length, fp)] = 0; clear_white (fp); return filename; } return NULL; } void load_idea_manager( idea_manager *ideas ) { FILE *fp = NULL; if ( ! idea_list ) fp = idea_manager_parse_init (&x, &y, &width, &height); if ( idea_list || fp ) { gtk_widget_set_usize( ideas->window, width, height ); gtk_widget_show( ideas->window ); gtk_widget_set_uposition( ideas->window, x, y ); gtk_idle_add( reset_usize, ideas->window ); if( fp ) { gchar *title; clear_white( fp ); while ((title = idea_manager_parse_line (fp))) { idea_add_in_position( title, -1 ); g_free( title ); } fclose( fp ); } else { g_list_foreach( idea_list, load_from_list, NULL ); g_list_foreach( idea_list, (GFunc) g_free, NULL ); g_list_free( idea_list ); idea_list = 0; } } else gtk_widget_show( ideas->window ); } static void save_to_ideas( gpointer data, gpointer user_data ) { gchar *title = GTK_LABEL( GTK_BIN( (GtkWidget *) data )->child )->label; fprintf( (FILE *) user_data, "%d %s\n", strlen( title ), title ); } static void save_list_to_ideas( gpointer data, gpointer user_data ) { gchar *title = (gchar *) data; fprintf( (FILE *) user_data, "%d %s\n", strlen( title ), title ); } void save_idea_manager( idea_manager *ideas ) { FILE *fp; gchar *desktopfile; /* open persistant desktop file. */ desktopfile = gimp_personal_rc_file ("ideas"); fp = fopen( desktopfile, "w" ); g_free( desktopfile ); if ( fp ) { if ( ideas ) { int x, y, width, height; gdk_window_get_geometry( ideas->window->window, &x, &y, &width, &height, NULL ); gdk_window_get_origin( ideas->window->window, &x, &y ); fprintf( fp, "%d %d %d %d\n", x, y, width, height ); g_list_foreach( GTK_TREE( ideas->tree )->children, save_to_ideas, fp ); } else { if ( idea_list ) { fprintf( fp, "%d %d %d %d\n", x, y, width, height ); g_list_foreach( idea_list, save_list_to_ideas, fp ); } } fclose( fp ); } } static void save_to_list( gpointer data, gpointer null_data ) { gchar *title = g_strdup( GTK_LABEL( GTK_BIN( (GtkWidget *) data )->child )->label ); idea_list = g_list_append( idea_list, title ); } static void create_idea_list( void ) { gdk_window_get_geometry( ideas->window->window, &x, &y, &width, &height, NULL ); gdk_window_get_origin( ideas->window->window, &x, &y ); if( idea_list ) { g_list_foreach( idea_list, (GFunc) g_free, NULL ); g_list_free( idea_list ); idea_list = 0; } g_list_foreach( GTK_TREE( ideas->tree )->children, save_to_list, NULL ); } static gint open_or_raise_callback( GtkWidget *widget, GdkEventButton *event, gpointer func_data ) { if ( GTK_IS_TREE_ITEM( widget ) && event->type==GDK_2BUTTON_PRESS ) { open_or_raise( GTK_LABEL( GTK_BIN( widget )->child )->label ); } return FALSE; } void raise_idea_callback( GtkWidget *widget, gpointer data ) { if ( ideas ) gdk_window_raise( ideas->window->window ); else open_idea_window(); } static void check_needed( gpointer data, gpointer user_data ) { GtkWidget *widget = (GtkWidget *) data; struct bool_char_pair *pair = (struct bool_char_pair *) user_data; if ( strcmp( pair->string, GTK_LABEL( GTK_BIN( widget )->child )->label ) == 0 ) { pair->boole = TRUE; } } static void check_needed_list( gpointer data, gpointer user_data ) { struct bool_char_pair *pair = (struct bool_char_pair *) user_data; if ( strcmp( pair->string, (gchar *) data ) == 0 ) { pair->boole = TRUE; } } void idea_add( gchar *title ) { idea_add_in_position( title, 0 ); } static void idea_add_in_position_with_select( gchar *title, gint position, gboolean select ) { GtkWidget *treeitem; struct bool_char_pair pair; pair.boole = FALSE; pair.string = title; if ( ideas ) { g_list_foreach( GTK_TREE( ideas->tree )->children, check_needed, &pair ); if ( ! pair.boole ) { treeitem = gtk_tree_item_new_with_label( title ); if ( position < 0 ) gtk_tree_append( GTK_TREE( ideas->tree ), treeitem ); else gtk_tree_insert( GTK_TREE( ideas->tree ), treeitem, position ); gtk_signal_connect( GTK_OBJECT( treeitem ), "button_press_event", GTK_SIGNAL_FUNC( open_or_raise_callback ), NULL ); docindex_cell_configure_drop_on_widget( treeitem ); gtk_widget_show( treeitem ); if ( select ) gtk_tree_select_item( GTK_TREE( ideas->tree ), gtk_tree_child_position( GTK_TREE( ideas->tree ), treeitem ) ); } } else { if( ! idea_list ) { FILE *fp = NULL; gchar *desktopfile; /* open persistant desktop file. */ desktopfile = gimp_personal_rc_file ("ideas"); fp = fopen( desktopfile, "r" ); g_free( desktopfile ); /* Read in persistant desktop information. */ if ( fp ) { gchar *title; gint length; x = getinteger( fp ); y = getinteger( fp ); width = getinteger( fp ); height = getinteger( fp ); clear_white( fp ); while ( ! feof( fp ) && !ferror( fp ) ) { length = getinteger( fp ); title = g_malloc0( length + 1 ); title[fread( title, 1, length, fp )] = 0; idea_list = g_list_append( idea_list, g_strdup( title ) ); g_free( title ); clear_white( fp ); } fclose( fp ); } } g_list_foreach( idea_list, check_needed_list, &pair ); if ( ! pair.boole ) { if ( position < 0 ) idea_list = g_list_append( idea_list, g_strdup( title ) ); else idea_list = g_list_insert( idea_list, g_strdup( title ), position ); } } } void idea_add_in_position( gchar *title, gint position ) { idea_add_in_position_with_select( title, position, TRUE ); } static gint idea_move( GtkWidget *widget, gint distance, gboolean select ) { gint orig_position = g_list_index( GTK_TREE( ideas->tree )->children, widget ); gint position = orig_position + distance; gchar *title; if( position < 0 ) position = 0; if ( position >= g_list_length( GTK_TREE( ideas->tree )->children ) ) position = g_list_length( GTK_TREE( ideas->tree )->children ) - 1; if ( position != orig_position ) { title = g_strdup( GTK_LABEL( GTK_BIN( widget )->child )->label ); gtk_container_remove( GTK_CONTAINER( ideas->tree ), widget ); idea_add_in_position_with_select( title, position, select ); g_free( title ); } return position - orig_position; } static void idea_remove( GtkWidget *widget ) { gint position = g_list_index( GTK_TREE( ideas->tree )->children, widget ); gtk_container_remove( GTK_CONTAINER( ideas->tree ), widget ); if ( g_list_length( GTK_TREE( ideas->tree )->children ) - 1 < position ) position = g_list_length( GTK_TREE( ideas->tree )->children ) - 1; gtk_tree_select_item( GTK_TREE( ideas->tree ), position ); } void idea_up_callback( GtkWidget *widget, gpointer data ) { GtkWidget *selected; if ( GTK_TREE( ideas->tree )->selection ) { selected = GTK_TREE( ideas->tree )->selection->data; if ( idea_move( selected, -1, TRUE ) != -1 ) gtk_statusbar_push( GTK_STATUSBAR( ideas->status ), ideas->contextid, _("This file cannot be moved up.") ); } else gtk_statusbar_push( GTK_STATUSBAR( ideas->status ), ideas->contextid, _("There's no selection to move up.") ); } void idea_down_callback( GtkWidget *widget, gpointer data ) { GtkWidget *selected; if ( GTK_TREE( ideas->tree )->selection ) { selected = GTK_TREE( ideas->tree )->selection->data; if ( idea_move( selected, 1, TRUE ) != 1 ) gtk_statusbar_push( GTK_STATUSBAR( ideas->status ), ideas->contextid, _("This file cannot be moved down.") ); } else gtk_statusbar_push( GTK_STATUSBAR( ideas->status ), ideas->contextid, _("There's no selection to move down.") ); } void idea_remove_callback( GtkWidget *widget, gpointer data ) { GtkWidget *selected; if ( GTK_TREE( ideas->tree )->selection ) { selected = GTK_TREE( ideas->tree )->selection->data; idea_remove( selected ); } else gtk_statusbar_push( GTK_STATUSBAR( ideas->status ), ideas->contextid, _("There's no selection to remove.") ); } void close_idea_window( void ) { idea_hide_callback( NULL, NULL ); }