Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/file-roller/ChangeLog,v
retrieving revision 1.241
diff -u -r1.241 ChangeLog
--- ChangeLog   22 Jul 2004 13:35:41 -0000  1.241
+++ ChangeLog   5 Sep 2004 18:21:59 -0000
@@ -1,3 +1,17 @@
+2004-09-05 Srinath C  <sri_nathc@yahoo.com>
+   * src/file_roller.glade: Added entries for a new dialog.
+   * src/dlg-update.h: Defines a function to use the new dialog.
+   * src/dlg-update.c: Provides implementation for the new dialog.
+   * window.h: Added members into FRWindow to manage the open files.
+   * window.c (window_open_files): added code to update 'opened_files' list.
+           (open_files): added a timeout handler.
+           (check_modtime): runs at regular intervals to see if the opened
+                           files are modified externally.
+           (update_start): sets 'window->update_in_progress' to TRUE. This is
+                           called in response to "start" of FRArchive activity.
+           (update_done): sets 'window->update_in_progress' to FALSE. This is
+                           called in response to "done" of FRArchive activity.
+
 2004-07-22  Ross Golder  <ross@golder.org>
                                                                                                                         
    * help/??/Makefile.in: Removed from CVS as it is autogenerated


Index: src/file_roller.glade
===================================================================
RCS file: /cvs/gnome/file-roller/src/file_roller.glade,v
retrieving revision 1.21
diff -u -r1.21 file_roller.glade
--- src/file_roller.glade	4 Jul 2004 07:33:59 -0000	1.21
+++ src/file_roller.glade	5 Sep 2004 17:56:51 -0000
@@ -1674,4 +1674,253 @@
   </child>
 </widget>
 
+<widget class="GtkDialog" id="update_dialog">
+  <property name="border_width">2</property>
+  <property name="title" translatable="yes">File Modified!!</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+  <property name="modal">False</property>
+  <property name="resizable">False</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <property name="has_separator">True</property>
+
+  <child internal-child="vbox">
+    <widget class="GtkVBox" id="dialog-vbox20">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">0</property>
+
+      <child internal-child="action_area">
+	<widget class="GtkHButtonBox" id="dialog-action_area20">
+	  <property name="visible">True</property>
+	  <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+	  <child>
+	    <widget class="GtkButton" id="ok_button">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="response_id">-5</property>
+
+	      <child>
+		<widget class="GtkAlignment" id="alignment2">
+		  <property name="visible">True</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xscale">0</property>
+		  <property name="yscale">0</property>
+		  <property name="top_padding">0</property>
+		  <property name="bottom_padding">0</property>
+		  <property name="left_padding">0</property>
+		  <property name="right_padding">0</property>
+
+		  <child>
+		    <widget class="GtkHBox" id="hbox30">
+		      <property name="visible">True</property>
+		      <property name="homogeneous">False</property>
+		      <property name="spacing">2</property>
+
+		      <child>
+			<widget class="GtkImage" id="image4">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-yes</property>
+			  <property name="icon_size">4</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkLabel" id="label47">
+			  <property name="visible">True</property>
+			  <property name="label" translatable="yes">_Update</property>
+			  <property name="use_underline">True</property>
+			  <property name="use_markup">False</property>
+			  <property name="justify">GTK_JUSTIFY_LEFT</property>
+			  <property name="wrap">False</property>
+			  <property name="selectable">False</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
+		    </widget>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkButton" id="cancel_button">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="response_id">-6</property>
+
+	      <child>
+		<widget class="GtkAlignment" id="alignment3">
+		  <property name="visible">True</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xscale">0</property>
+		  <property name="yscale">0</property>
+		  <property name="top_padding">0</property>
+		  <property name="bottom_padding">0</property>
+		  <property name="left_padding">0</property>
+		  <property name="right_padding">0</property>
+
+		  <child>
+		    <widget class="GtkHBox" id="hbox31">
+		      <property name="visible">True</property>
+		      <property name="homogeneous">False</property>
+		      <property name="spacing">2</property>
+
+		      <child>
+			<widget class="GtkImage" id="image5">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-cancel</property>
+			  <property name="icon_size">4</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkLabel" id="label48">
+			  <property name="visible">True</property>
+			  <property name="label" translatable="yes">_Ignore</property>
+			  <property name="use_underline">True</property>
+			  <property name="use_markup">False</property>
+			  <property name="justify">GTK_JUSTIFY_LEFT</property>
+			  <property name="wrap">False</property>
+			  <property name="selectable">False</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
+		    </widget>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">True</property>
+	  <property name="pack_type">GTK_PACK_END</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkHBox" id="hbox32">
+	  <property name="visible">True</property>
+	  <property name="homogeneous">False</property>
+	  <property name="spacing">0</property>
+
+	  <child>
+	    <widget class="GtkImage" id="image6">
+	      <property name="visible">True</property>
+	      <property name="stock">gtk-dialog-warning</property>
+	      <property name="icon_size">6</property>
+	      <property name="xalign">0.5</property>
+	      <property name="yalign">0.5</property>
+	      <property name="xpad">0</property>
+	      <property name="ypad">0</property>
+	    </widget>
+	    <packing>
+	      <property name="padding">0</property>
+	      <property name="expand">False</property>
+	      <property name="fill">False</property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GtkLabel" id="message_label">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes"></property>
+	      <property name="use_underline">False</property>
+	      <property name="use_markup">False</property>
+	      <property name="justify">GTK_JUSTIFY_LEFT</property>
+	      <property name="wrap">False</property>
+	      <property name="selectable">False</property>
+	      <property name="xalign">0.5</property>
+	      <property name="yalign">0.5</property>
+	      <property name="xpad">0</property>
+	      <property name="ypad">0</property>
+	    </widget>
+	    <packing>
+	      <property name="padding">0</property>
+	      <property name="expand">True</property>
+	      <property name="fill">True</property>
+	    </packing>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">True</property>
+	  <property name="fill">True</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkCheckButton" id="check_ignore">
+	  <property name="visible">True</property>
+	  <property name="can_focus">True</property>
+	  <property name="label" translatable="yes">Ignore all modifications on this file</property>
+	  <property name="use_underline">True</property>
+	  <property name="relief">GTK_RELIEF_NORMAL</property>
+	  <property name="focus_on_click">True</property>
+	  <property name="active">False</property>
+	  <property name="inconsistent">False</property>
+	  <property name="draw_indicator">True</property>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">False</property>
+	</packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
 </glade-interface>
Index: src/window.h
===================================================================
RCS file: /cvs/gnome/file-roller/src/window.h,v
retrieving revision 1.32
diff -u -r1.32 window.h
--- src/window.h	2 May 2004 18:25:57 -0000	1.32
+++ src/window.h	5 Sep 2004 17:56:55 -0000
@@ -30,6 +30,7 @@
 #include "file-list.h"
 
 #define GCONF_NOTIFICATIONS 8
+#define MODCHECK_INTERVAL 3000		//	milliseconds
 
 enum {
 	COLUMN_FILE_DATA,
@@ -70,6 +71,21 @@
 	FR_CLIPBOARD_OP_COPY
 } FRClipboardOp;
 
+typedef enum	{
+	ACTION_UPDATE,
+	ACTION_IGNORE,
+	ACTION_DELETE
+} UpdateAction;
+
+typedef struct {
+	gchar *path;
+	gchar *tmp_dir;
+	gchar *rel_path;
+	gchar *fname;
+	time_t modtime;
+	UpdateAction uaction;
+} OpenedFileData;
+
 typedef struct {
         GtkWidget *      app;
 	GtkWidget *      list_view;
@@ -200,6 +216,12 @@
 
 	gulong     theme_changed_handler_id;
 	gboolean   non_interactive;
+
+	GList *opened_files;
+	guint	timeout_handler_id;
+	gboolean update_in_progress;
+	guint   update_start_handler_id;
+	guint   update_done_handler_id;
 } FRWindow;
 
 
Index: src/window.c
===================================================================
RCS file: /cvs/gnome/file-roller/src/window.c,v
retrieving revision 1.90
diff -u -r1.90 window.c
--- src/window.c	18 Jul 2004 17:19:10 -0000	1.90
+++ src/window.c	5 Sep 2004 17:58:19 -0000
@@ -36,6 +36,7 @@
 #include "actions.h"
 #include "dlg-batch-add.h"
 #include "dlg-delete.h"
+#include "dlg-update.h"
 #include "dlg-extract.h"
 #include "dlg-viewer.h"
 #include "dlg-viewer-or-app.h"
@@ -3159,6 +3160,11 @@
 	window->list_mode = preferences_get_list_mode ();
 	window->history = NULL;
 	window->history_current = NULL;
+	window->opened_files = NULL;
+
+	//	initialize members
+	window->timeout_handler_id = 0;
+	window->update_in_progress = FALSE;
 
 	eel_gconf_set_boolean (PREF_LIST_SHOW_PATH, (window->list_mode == WINDOW_LIST_MODE_FLAT));
 
@@ -3657,6 +3663,27 @@
 }
 
 
+//	frees up memory held by one 'OpenedFileData'
+static void
+free_opened_file_data(OpenedFileData *ofdata)
+{
+	g_free(ofdata->path);
+	g_free(ofdata->tmp_dir);
+	g_free(ofdata->rel_path);
+	g_free(ofdata->fname);
+
+	g_free(ofdata);
+}
+
+
+static void
+_window_free_list(FRWindow *window)
+{
+	g_list_foreach( window->opened_files, (GFunc)free_opened_file_data, NULL );
+	g_list_free(window->opened_files);
+}
+
+
 void
 window_close (FRWindow *window)
 {
@@ -3668,6 +3695,12 @@
 		window->recent_view = NULL;
 	}
 
+	if(window->timeout_handler_id != 0)		//	remove timeouts if any.
+		gtk_timeout_remove(window->timeout_handler_id);
+
+	if(window->opened_files != NULL)
+		_window_free_list(window);			//	free up memory held by the openedfile list.
+
 	gtk_object_destroy (GTK_OBJECT (window->tooltips));
 
 	while (window->activity_ref > 0)
@@ -5222,6 +5255,100 @@
 
 /* -- window_open_files -- */
 
+static gboolean check_modtime(gpointer data);
+
+
+static void
+update_start( FRArchive *archive,
+			FRAction action,
+			gpointer data )
+{
+	FRWindow *window = data;
+	window->update_in_progress = TRUE;
+	g_signal_handler_disconnect( archive, window->update_start_handler_id );
+}
+
+
+static void
+update_done( FRArchive *archive,
+			FRAction action,
+			FRProcError *error,
+			gpointer data )
+{
+	FRWindow *window = data;
+	window->update_in_progress = FALSE;
+	g_signal_handler_disconnect( archive, window->update_done_handler_id );
+	if( window->opened_files != NULL )
+		window->timeout_handler_id = g_timeout_add( MODCHECK_INTERVAL, check_modtime, window );
+}
+
+
+static gboolean
+check_modtime(gpointer data)
+{
+	FRWindow *window = (FRWindow*)data;
+	GList *scan;
+
+	if(window->timeout_handler_id)
+		gtk_timeout_remove(window->timeout_handler_id);		//	remove existing timeout.
+
+	//	check if an updation is already in progress
+	if( window->update_in_progress )	//	remove timeout & dont check further 
+		return;
+
+	for( scan = window->opened_files; scan; )	{
+		time_t curr_mtime = 0;
+		OpenedFileData *ofdata = (OpenedFileData*)scan->data;	//	current file
+		curr_mtime = get_file_mtime(ofdata->path);
+		if( ofdata->modtime == 0 )	{			//	no modtime obtained yet - so set modtime
+			ofdata->modtime = curr_mtime;
+			scan = scan->next;
+		}
+		else if( ofdata->modtime < curr_mtime )	{		//	prompt user for action
+			dlg_update( ofdata, window );				//	run dialog
+			if( ofdata->uaction == ACTION_UPDATE )	{	//	update requested by user
+				GList *tmp = g_list_append( NULL, ofdata->fname );
+				//	set callback signals to update 'window->update_in_progress'
+				window->update_start_handler_id = g_signal_connect( G_OBJECT(window->archive),
+																"start",
+																G_CALLBACK(update_start),
+																window );
+				window->update_done_handler_id = g_signal_connect( G_OBJECT(window->archive),
+																"done",
+																G_CALLBACK(update_done),
+																window );
+				ofdata->modtime = curr_mtime;
+				//	add current file
+				window_archive_add( window, tmp,
+								ofdata->tmp_dir,
+								ofdata->rel_path,
+								window->update_dropped_files,
+								window->password,
+								window->compression );
+				g_list_foreach( tmp, (GFunc)g_free, NULL );
+				g_list_free(tmp);
+				break;			//	force a break out of the loop
+			}
+			else if( ofdata->uaction == ACTION_IGNORE )
+				ofdata->modtime = curr_mtime;		//	update the modtime.
+			else	{
+				GList *new_scan_value = scan->next;	//	keep track of list.
+				window->opened_files = g_list_remove_link( window->opened_files, scan );
+				free_opened_file_data(scan->data);
+				g_list_free(scan);
+				scan = new_scan_value;
+			}
+			if( ofdata->uaction != ACTION_DELETE )
+				scan = scan->next;
+		}
+		else
+			scan = scan->next;
+	}
+	if( window->opened_files != NULL && !window->update_in_progress )		//	no more checks required.
+		window->timeout_handler_id = g_timeout_add( MODCHECK_INTERVAL, check_modtime, window );
+	return FALSE;
+}
+
 
 static void
 open_files (FRArchive   *archive,
@@ -5230,6 +5357,7 @@
 	    gpointer     callback_data)
 {
 	CommandData  *cdata = callback_data;
+	FRWindow     *window = (FRWindow*)(cdata->window);
 	FRProcess    *proc;
 	GList        *scan;
 
@@ -5258,6 +5386,9 @@
 	fr_process_end_command (proc);
 
 	command_list = g_list_prepend (command_list, cdata);
+	//	add a timeout signal handler
+	window->timeout_handler_id = g_timeout_add( MODCHECK_INTERVAL, check_modtime, window );
+
 	fr_process_start (proc);
 }
 
@@ -5288,6 +5419,15 @@
 					"/",
 					file,
 					NULL);
+				//	add the file to the list of open files
+		OpenedFileData *open_data = g_malloc0( sizeof(OpenedFileData) );
+		open_data->path = strdup(filename);
+		open_data->tmp_dir = strdup( cdata->temp_dir );
+		open_data->rel_path = remove_level_from_path(file);
+		open_data->fname = strdup( file_name_from_path(file) );
+		open_data->modtime = 0;
+		window->opened_files = g_list_append( window->opened_files, open_data );
+
 		cdata->file_list = g_list_prepend (cdata->file_list,
 						   shell_escape (filename));
 		g_free (filename);


Index: src/dlg-update.h
===================================================================
--- /dev/null	2004-02-24 02:32:56.000000000 +0530
+++ src/dlg-update.h	2004-08-24 20:57:26.000000000 +0530
@@ -0,0 +1,30 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  File-Roller
+ *
+ *  Copyright (C) 2001 The Free Software Foundation, Inc.
+ *
+ *  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 Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef DLG_UPDATE_H
+#define DLG_UPDATE_H
+
+#include "window.h"
+
+void dlg_update( OpenedFileData *fdata, gpointer data );
+
+#endif


Index: src/dlg-update.c
===================================================================
--- /dev/null	2004-02-24 02:32:56.000000000 +0530
+++ src/dlg-update.c	2004-08-30 20:58:40.000000000 +0530
@@ -0,0 +1,128 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  File-Roller
+ *
+ *  Copyright (C) 2001 The Free Software Foundation, Inc.
+ *
+ *  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 Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include "dlg-update.h"
+#include "window.h"
+
+#define PROP_GLADE_FILE "file_roller.glade"
+
+typedef struct	{
+	GladeXML *gui;
+	FRWindow *window;
+	OpenedFileData *odata;
+	GtkWidget *dialog;
+	GtkWidget *message_label;
+	GtkWidget *check_button;
+	gboolean ignore_all;
+} DialogData;
+
+
+static void
+destroy_cb( GtkWidget *widget,
+			DialogData *data)
+{
+//	TODO:	add an action
+	g_object_unref( data->gui );
+	g_free(data);
+}
+
+
+static void
+ignore_all_toggled_cb( GtkWidget *widget,
+					DialogData *data)
+{
+	data->ignore_all = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+}
+
+
+static gint
+run_dialog(DialogData *data,
+			OpenedFileData *fdata,
+			gpointer callback_data)
+{
+	FRWindow *window = callback_data;
+	gchar *msgstr = NULL;
+
+	if( fdata == NULL )
+		return;
+
+	data->ignore_all = FALSE;
+	data->odata = fdata;
+	data->window = window;
+	data->gui = glade_xml_new( GLADEDIR "/" PROP_GLADE_FILE, NULL, NULL);
+	if(!data->gui)	{
+		g_warning( "Could not find " PROP_GLADE_FILE "\n" );
+		return;
+	}
+
+	/*	Get the widgets.	*/
+	data->dialog = glade_xml_get_widget( data->gui, "update_dialog" );
+	data->check_button = glade_xml_get_widget( data->gui, "check_ignore" );
+	data->message_label = glade_xml_get_widget( data->gui, "message_label" );
+
+	/*	Set widgets data.	*/
+	msgstr = g_strdup_printf( "The file %s has changed.\nDo you want to update this change into the archive?", fdata->path );
+	gtk_label_set_text( GTK_LABEL(data->message_label), msgstr );
+	g_free(msgstr);
+
+	/*	Set the signal handlers.	*/
+	g_signal_connect(G_OBJECT(data->dialog),
+				"destroy",
+				G_CALLBACK(destroy_cb),
+				data);
+
+/*	g_signal_connect(G_OBJECT(data->dialog),
+				"response",
+				G_CALLBACK(response_cb),
+				data);*/
+
+	g_signal_connect(G_OBJECT(data->check_button),
+				"toggled",
+				G_CALLBACK(ignore_all_toggled_cb),
+				data);
+
+	/*	Run dialog.	*/
+	gtk_window_set_transient_for( GTK_WINDOW(data->dialog), GTK_WINDOW(window->app) );
+	gtk_window_set_modal( GTK_WINDOW(data->dialog), TRUE );
+	return gtk_dialog_run(GTK_DIALOG(data->dialog));
+}
+
+
+void dlg_update(OpenedFileData *fdata,
+				gpointer callback_data)
+{
+	DialogData *data = g_new( DialogData, 1);
+	gint response_id = run_dialog( data, fdata, callback_data);
+	switch(response_id)	{
+		case GTK_RESPONSE_OK:
+				fdata->uaction = ACTION_UPDATE;
+				break;
+		case GTK_RESPONSE_CANCEL:
+				fdata->uaction = (data->ignore_all) ? ACTION_DELETE : ACTION_IGNORE;
+				break;
+	}
+	gtk_widget_destroy(data->dialog);
+}
+
+

