Commit 10bed707 authored by Paolo Borelli's avatar Paolo Borelli Committed by Paolo Borelli

Show a warning message when the file is modified from another program.

2007-01-08  Paolo Borelli  <pborelli@katamail.com>

	* bindings/python/gedit.defs:
	* gedit/gedit-document.[ch]:
	* gedit/gedit-io-error-message-area.[ch]:
	* gedit/gedit-tab.[ch]:
	* gedit/gedit-window.c:

	Show a warning message when the file is modified from
	another program. Patch by  Emmanuel Touzery.
	Fixes bug #371188.


svn path=/trunk/; revision=5428
parent 02299b1e
2007-01-08 Paolo Borelli <pborelli@katamail.com>
* bindings/python/gedit.defs:
* gedit/gedit-document.[ch]:
* gedit/gedit-io-error-message-area.[ch]:
* gedit/gedit-tab.[ch]:
* gedit/gedit-window.c:
Show a warning message when the file is modified from
another program. Patch by Emmanuel Touzery.
Fixes bug #371188.
2007-01-08 Paolo Borelli <pborelli@katamail.com> 2007-01-08 Paolo Borelli <pborelli@katamail.com>
* plugins/filebrowser/gedit-file-bookmarks-store.c: * plugins/filebrowser/gedit-file-bookmarks-store.c:
......
...@@ -303,6 +303,12 @@ ...@@ -303,6 +303,12 @@
(return-type "gboolean") (return-type "gboolean")
) )
(define-method is_local
(of-object "GeditDocument")
(c-name "gedit_document_is_local")
(return-type "gboolean")
)
(define-method get_deleted (define-method get_deleted
(of-object "GeditDocument") (of-object "GeditDocument")
(c-name "gedit_document_get_deleted") (c-name "gedit_document_get_deleted")
......
...@@ -887,6 +887,40 @@ gedit_document_get_readonly (GeditDocument *doc) ...@@ -887,6 +887,40 @@ gedit_document_get_readonly (GeditDocument *doc)
return doc->priv->readonly; return doc->priv->readonly;
} }
gboolean
_gedit_document_check_externally_modified (GeditDocument *doc)
{
GnomeVFSFileInfo *info;
GnomeVFSResult result;
gint file_mtime;
g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), FALSE);
if (doc->priv->uri == NULL)
{
return FALSE;
}
info = gnome_vfs_file_info_new ();
result = gnome_vfs_get_file_info_uri (doc->priv->vfs_uri,
info,
GNOME_VFS_FILE_INFO_DEFAULT|
GNOME_VFS_FILE_INFO_FOLLOW_LINKS);
if (result != GNOME_VFS_OK)
{
gnome_vfs_file_info_unref (info);
return FALSE;
}
file_mtime = info->mtime;
gnome_vfs_file_info_unref (info);
return (file_mtime > doc->priv->mtime);
}
static void static void
reset_temp_loading_data (GeditDocument *doc) reset_temp_loading_data (GeditDocument *doc)
{ {
...@@ -1202,6 +1236,18 @@ gedit_document_is_untitled (GeditDocument *doc) ...@@ -1202,6 +1236,18 @@ gedit_document_is_untitled (GeditDocument *doc)
return (doc->priv->uri == NULL); return (doc->priv->uri == NULL);
} }
gboolean
gedit_document_is_local (GeditDocument *doc)
{
g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), FALSE);
if (doc->priv->uri == NULL)
{
return FALSE;
}
return gedit_utils_uri_has_file_scheme (doc->priv->uri);
}
gboolean gboolean
gedit_document_get_deleted (GeditDocument *doc) gedit_document_get_deleted (GeditDocument *doc)
......
...@@ -178,11 +178,9 @@ void gedit_document_save_as (GeditDocument *doc, ...@@ -178,11 +178,9 @@ void gedit_document_save_as (GeditDocument *doc,
gboolean gedit_document_is_untouched (GeditDocument *doc); gboolean gedit_document_is_untouched (GeditDocument *doc);
gboolean gedit_document_is_untitled (GeditDocument *doc); gboolean gedit_document_is_untitled (GeditDocument *doc);
gboolean gedit_document_is_local (GeditDocument *doc);
gboolean gedit_document_get_deleted (GeditDocument *doc); gboolean gedit_document_get_deleted (GeditDocument *doc);
/* Ancora da discutere
gboolean gedit_document_get_externally_modified
(GeditDocument *doc);
*/
gboolean gedit_document_goto_line (GeditDocument *doc, gboolean gedit_document_goto_line (GeditDocument *doc,
gint line); gint line);
...@@ -234,10 +232,13 @@ gboolean gedit_document_get_enable_search_highlighting ...@@ -234,10 +232,13 @@ gboolean gedit_document_get_enable_search_highlighting
*/ */
gboolean _gedit_document_is_saving_as (GeditDocument *doc); gboolean _gedit_document_is_saving_as (GeditDocument *doc);
// CHECK: va bene un gint?
glong _gedit_document_get_seconds_since_last_save_or_load glong _gedit_document_get_seconds_since_last_save_or_load
(GeditDocument *doc); (GeditDocument *doc);
/* Note: this is a sync stat: use only on local files */
gboolean _gedit_document_check_externally_modified
(GeditDocument *doc);
void _gedit_document_search_region (GeditDocument *doc, void _gedit_document_search_region (GeditDocument *doc,
const GtkTextIter *start, const GtkTextIter *start,
const GtkTextIter *end); const GtkTextIter *end);
......
...@@ -75,11 +75,12 @@ is_recoverable_error (const GError *error) ...@@ -75,11 +75,12 @@ is_recoverable_error (const GError *error)
return is_recoverable; return is_recoverable;
} }
static GtkWidget * static void
create_io_loading_error_message_area (const gchar *primary_text, set_message_area_text_and_icon (GeditMessageArea *message_area,
const gchar *icon_stock_id,
const gchar *primary_text,
const gchar *secondary_text) const gchar *secondary_text)
{ {
GtkWidget *message_area;
GtkWidget *hbox_content; GtkWidget *hbox_content;
GtkWidget *image; GtkWidget *image;
GtkWidget *vbox; GtkWidget *vbox;
...@@ -88,14 +89,10 @@ create_io_loading_error_message_area (const gchar *primary_text, ...@@ -88,14 +89,10 @@ create_io_loading_error_message_area (const gchar *primary_text,
GtkWidget *primary_label; GtkWidget *primary_label;
GtkWidget *secondary_label; GtkWidget *secondary_label;
message_area = gedit_message_area_new_with_buttons (
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
NULL);
hbox_content = gtk_hbox_new (FALSE, 8); hbox_content = gtk_hbox_new (FALSE, 8);
gtk_widget_show (hbox_content); gtk_widget_show (hbox_content);
image = gtk_image_new_from_stock ("gtk-dialog-error", GTK_ICON_SIZE_DIALOG); image = gtk_image_new_from_stock (icon_stock_id, GTK_ICON_SIZE_DIALOG);
gtk_widget_show (image); gtk_widget_show (image);
gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0);
gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0); gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0);
...@@ -135,6 +132,24 @@ create_io_loading_error_message_area (const gchar *primary_text, ...@@ -135,6 +132,24 @@ create_io_loading_error_message_area (const gchar *primary_text,
return message_area; return message_area;
} }
static GtkWidget *
create_io_loading_error_message_area (const gchar *primary_text,
const gchar *secondary_text)
{
GtkWidget *message_area;
message_area = gedit_message_area_new_with_buttons (
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
NULL);
set_message_area_text_and_icon (GEDIT_MESSAGE_AREA (message_area),
"gtk-dialog-error",
primary_text,
secondary_text);
return message_area;
}
GtkWidget * GtkWidget *
gedit_io_loading_error_message_area_new (const gchar *uri, gedit_io_loading_error_message_area_new (const gchar *uri,
const GError *error) const GError *error)
...@@ -1372,3 +1387,60 @@ gedit_unrecoverable_saving_error_message_area_new (const gchar *uri, ...@@ -1372,3 +1387,60 @@ gedit_unrecoverable_saving_error_message_area_new (const gchar *uri,
return message_area; return message_area;
} }
GtkWidget *
gedit_externally_modified_message_area_new (const gchar *uri,
gboolean document_modified)
{
gchar *full_formatted_uri;
gchar *uri_for_display;
gchar *temp_uri_for_display;
const gchar *primary_text;
const gchar *secondary_text;
GtkWidget *message_area;
g_return_val_if_fail (uri != NULL, NULL);
full_formatted_uri = gedit_utils_format_uri_for_display (uri);
/* Truncate the URI so it doesn't get insanely wide. Note that even
* though the dialog uses wrapped text, if the URI doesn't contain
* white space then the text-wrapping code is too stupid to wrap it.
*/
temp_uri_for_display = gedit_utils_str_middle_truncate (full_formatted_uri,
MAX_URI_IN_DIALOG_LENGTH);
g_free (full_formatted_uri);
uri_for_display = g_markup_printf_escaped ("<i>%s</i>", temp_uri_for_display);
g_free (temp_uri_for_display);
// FIXME: review this message, it's not clear since for the user the "modification"
// could be interpreted as the changes he made in the document. beside "reading" is
// not accurate (since last load/save)
primary_text = g_strdup_printf (_("The file %s changed on disk."),
uri_for_display);
g_free (uri_for_display);
if (document_modified)
secondary_text = _("Do you want to drop your changes and reload the file?");
else
secondary_text = _("Do you want to reload the file?");
message_area = gedit_message_area_new ();
set_message_area_text_and_icon (GEDIT_MESSAGE_AREA (message_area),
"gtk-dialog-warning",
primary_text,
secondary_text);
gedit_message_area_add_stock_button_with_text (GEDIT_MESSAGE_AREA (message_area),
_("_Reload"),
GTK_STOCK_REFRESH,
GTK_RESPONSE_OK);
gedit_message_area_add_button (GEDIT_MESSAGE_AREA (message_area),
GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL);
return message_area;
}
...@@ -63,6 +63,9 @@ GtkWidget *gedit_no_backup_saving_error_message_area_new (const gchar ...@@ -63,6 +63,9 @@ GtkWidget *gedit_no_backup_saving_error_message_area_new (const gchar
GtkWidget *gedit_unrecoverable_saving_error_message_area_new (const gchar *uri, GtkWidget *gedit_unrecoverable_saving_error_message_area_new (const gchar *uri,
const GError *error); const GError *error);
GtkWidget *gedit_externally_modified_message_area_new (const gchar *uri,
gboolean document_modified);
G_END_DECLS G_END_DECLS
#endif /* __GEDIT_IO_ERROR_MESSAGE_AREA_H__ */ #endif /* __GEDIT_IO_ERROR_MESSAGE_AREA_H__ */
...@@ -82,6 +82,8 @@ struct _GeditTabPrivate ...@@ -82,6 +82,8 @@ struct _GeditTabPrivate
gint not_editable : 1; gint not_editable : 1;
gint auto_save : 1; gint auto_save : 1;
gint ask_if_externally_modified : 1;
}; };
G_DEFINE_TYPE(GeditTab, gedit_tab, GTK_TYPE_VBOX) G_DEFINE_TYPE(GeditTab, gedit_tab, GTK_TYPE_VBOX)
...@@ -166,7 +168,6 @@ remove_auto_save_timeout (GeditTab *tab) ...@@ -166,7 +168,6 @@ remove_auto_save_timeout (GeditTab *tab)
tab->priv->auto_save_timeout = 0; tab->priv->auto_save_timeout = 0;
} }
static void static void
gedit_tab_get_property (GObject *object, gedit_tab_get_property (GObject *object,
guint prop_id, guint prop_id,
...@@ -293,7 +294,6 @@ gedit_tab_class_init (GeditTabClass *klass) ...@@ -293,7 +294,6 @@ gedit_tab_class_init (GeditTabClass *klass)
g_type_class_add_private (object_class, sizeof (GeditTabPrivate)); g_type_class_add_private (object_class, sizeof (GeditTabPrivate));
} }
GeditTabState GeditTabState
gedit_tab_get_state (GeditTab *tab) gedit_tab_get_state (GeditTab *tab)
{ {
...@@ -405,8 +405,6 @@ gedit_tab_set_state (GeditTab *tab, ...@@ -405,8 +405,6 @@ gedit_tab_set_state (GeditTab *tab,
g_object_notify (G_OBJECT (tab), "state"); g_object_notify (G_OBJECT (tab), "state");
} }
static void static void
document_uri_notify_handler (GeditDocument *document, document_uri_notify_handler (GeditDocument *document,
GParamSpec *pspec, GParamSpec *pspec,
...@@ -1062,6 +1060,8 @@ document_loaded (GeditDocument *document, ...@@ -1062,6 +1060,8 @@ document_loaded (GeditDocument *document,
gedit_tab_set_state (tab, GEDIT_TAB_STATE_NORMAL); gedit_tab_set_state (tab, GEDIT_TAB_STATE_NORMAL);
install_auto_save_timeout_if_needed (tab); install_auto_save_timeout_if_needed (tab);
tab->priv->ask_if_externally_modified = TRUE;
} }
end: end:
...@@ -1382,9 +1382,106 @@ document_saved (GeditDocument *document, ...@@ -1382,9 +1382,106 @@ document_saved (GeditDocument *document,
else else
gedit_tab_set_state (tab, GEDIT_TAB_STATE_NORMAL); gedit_tab_set_state (tab, GEDIT_TAB_STATE_NORMAL);
tab->priv->ask_if_externally_modified = TRUE;
end_saving (tab); end_saving (tab);
} }
}
static void
externally_modified_notification_message_area_response (GeditMessageArea *message_area,
gint response_id,
GeditTab *tab)
{
GeditView *view;
set_message_area (tab, NULL);
view = gedit_tab_get_view (tab);
if (response_id == GTK_RESPONSE_OK)
{
_gedit_tab_revert (tab);
}
else
{
tab->priv->ask_if_externally_modified = FALSE;
/* go back to normal state */
gedit_tab_set_state (tab, GEDIT_TAB_STATE_NORMAL);
}
gtk_widget_grab_focus (GTK_WIDGET (view));
}
static void
display_externally_modified_notification (GeditTab *tab)
{
GtkWidget *message_area;
GeditDocument *doc;
gchar *uri;
gboolean document_modified;
doc = gedit_tab_get_document (tab);
g_return_if_fail (GEDIT_IS_DOCUMENT (doc));
/* uri cannot be NULL, we're here because
* the file we're editing changed on disk */
uri = gedit_document_get_uri (doc);
g_return_if_fail (uri != NULL);
document_modified = gtk_text_buffer_get_modified (GTK_TEXT_BUFFER(doc));
message_area = gedit_externally_modified_message_area_new (uri, document_modified);
g_free (uri);
tab->priv->message_area = NULL;
set_message_area (tab, message_area);
gtk_widget_show (message_area);
g_signal_connect (message_area,
"response",
G_CALLBACK (externally_modified_notification_message_area_response),
tab);
}
static gboolean
view_focused_in (GtkWidget *widget,
GdkEventFocus *event,
GeditTab *tab)
{
GeditDocument *doc;
g_return_val_if_fail (GEDIT_IS_TAB (tab), FALSE);
/* we try to detect file changes only in the normal state */
if (tab->priv->state != GEDIT_TAB_STATE_NORMAL)
{
return FALSE;
}
/* we already asked, don't bug the user again */
if (!tab->priv->ask_if_externally_modified)
{
return FALSE;
}
doc = gedit_tab_get_document (tab);
/* If file was never saved or is remote we do not check */
if (!gedit_document_is_local (doc))
{
return FALSE;
}
if (_gedit_document_check_externally_modified (doc))
{
gedit_tab_set_state (tab, GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION);
display_externally_modified_notification (tab);
return FALSE;
}
return FALSE;
} }
static void static void
...@@ -1402,6 +1499,8 @@ gedit_tab_init (GeditTab *tab) ...@@ -1402,6 +1499,8 @@ gedit_tab_init (GeditTab *tab)
tab->priv->save_flags = 0; tab->priv->save_flags = 0;
tab->priv->ask_if_externally_modified = TRUE;
/* Create the scrolled window */ /* Create the scrolled window */
sw = gtk_scrolled_window_new (NULL, NULL); sw = gtk_scrolled_window_new (NULL, NULL);
tab->priv->view_scrolled_window = sw; tab->priv->view_scrolled_window = sw;
...@@ -1460,7 +1559,12 @@ gedit_tab_init (GeditTab *tab) ...@@ -1460,7 +1559,12 @@ gedit_tab_init (GeditTab *tab)
G_CALLBACK (document_saved), G_CALLBACK (document_saved),
tab); tab);
g_signal_connect_after(tab->priv->view, g_signal_connect_after (tab->priv->view,
"focus-in-event",
G_CALLBACK (view_focused_in),
tab);
g_signal_connect_after (tab->priv->view,
"realize", "realize",
G_CALLBACK (view_realized), G_CALLBACK (view_realized),
tab); tab);
...@@ -1836,7 +1940,8 @@ _gedit_tab_revert (GeditTab *tab) ...@@ -1836,7 +1940,8 @@ _gedit_tab_revert (GeditTab *tab)
gchar *uri; gchar *uri;
g_return_if_fail (GEDIT_IS_TAB (tab)); g_return_if_fail (GEDIT_IS_TAB (tab));
g_return_if_fail (tab->priv->state == GEDIT_TAB_STATE_NORMAL); g_return_if_fail ((tab->priv->state == GEDIT_TAB_STATE_NORMAL) ||
(tab->priv->state == GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION));
doc = gedit_tab_get_document (tab); doc = gedit_tab_get_document (tab);
g_return_if_fail (GEDIT_IS_DOCUMENT (doc)); g_return_if_fail (GEDIT_IS_DOCUMENT (doc));
...@@ -1865,9 +1970,11 @@ void ...@@ -1865,9 +1970,11 @@ void
_gedit_tab_save (GeditTab *tab) _gedit_tab_save (GeditTab *tab)
{ {
GeditDocument *doc; GeditDocument *doc;
GeditDocumentSaveFlags save_flags;
g_return_if_fail (GEDIT_IS_TAB (tab)); g_return_if_fail (GEDIT_IS_TAB (tab));
g_return_if_fail ((tab->priv->state == GEDIT_TAB_STATE_NORMAL) || g_return_if_fail ((tab->priv->state == GEDIT_TAB_STATE_NORMAL) ||
(tab->priv->state == GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) ||
(tab->priv->state == GEDIT_TAB_STATE_SHOWING_PRINT_PREVIEW)); (tab->priv->state == GEDIT_TAB_STATE_SHOWING_PRINT_PREVIEW));
g_return_if_fail (tab->priv->tmp_save_uri == NULL); g_return_if_fail (tab->priv->tmp_save_uri == NULL);
g_return_if_fail (tab->priv->tmp_encoding == NULL); g_return_if_fail (tab->priv->tmp_encoding == NULL);
...@@ -1876,6 +1983,21 @@ _gedit_tab_save (GeditTab *tab) ...@@ -1876,6 +1983,21 @@ _gedit_tab_save (GeditTab *tab)
g_return_if_fail (GEDIT_IS_DOCUMENT (doc)); g_return_if_fail (GEDIT_IS_DOCUMENT (doc));
g_return_if_fail (!gedit_document_is_untitled (doc)); g_return_if_fail (!gedit_document_is_untitled (doc));
if (tab->priv->state == GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION)
{
/* We already told the user about the external
* modification: hide the message area and set
* the save flag.
*/
set_message_area (tab, NULL);
save_flags = tab->priv->save_flags | GEDIT_DOCUMENT_SAVE_IGNORE_MTIME;
}
else
{
save_flags = tab->priv->save_flags;
}
gedit_tab_set_state (tab, GEDIT_TAB_STATE_SAVING); gedit_tab_set_state (tab, GEDIT_TAB_STATE_SAVING);
/* uri used in error messages, will be freed in document_saved */ /* uri used in error messages, will be freed in document_saved */
...@@ -1885,7 +2007,7 @@ _gedit_tab_save (GeditTab *tab) ...@@ -1885,7 +2007,7 @@ _gedit_tab_save (GeditTab *tab)
if (tab->priv->auto_save_timeout > 0) if (tab->priv->auto_save_timeout > 0)
remove_auto_save_timeout (tab); remove_auto_save_timeout (tab);
gedit_document_save (doc, tab->priv->save_flags); gedit_document_save (doc, save_flags);
} }
static gboolean static gboolean
......
...@@ -54,6 +54,7 @@ typedef enum ...@@ -54,6 +54,7 @@ typedef enum
GEDIT_TAB_STATE_SAVING_ERROR, GEDIT_TAB_STATE_SAVING_ERROR,
GEDIT_TAB_STATE_GENERIC_ERROR, GEDIT_TAB_STATE_GENERIC_ERROR,
GEDIT_TAB_STATE_CLOSING, GEDIT_TAB_STATE_CLOSING,
GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION,
GEDIT_TAB_NUM_OF_STATES /* This is not a valid state */ GEDIT_TAB_NUM_OF_STATES /* This is not a valid state */
} GeditTabState; } GeditTabState;
......
...@@ -673,6 +673,7 @@ set_sensitivity_according_to_tab (GeditWindow *window, ...@@ -673,6 +673,7 @@ set_sensitivity_according_to_tab (GeditWindow *window,
"FileSave"); "FileSave");
gtk_action_set_sensitive (action, gtk_action_set_sensitive (action,
(state_normal || (state_normal ||
(state == GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) ||
(state == GEDIT_TAB_STATE_SHOWING_PRINT_PREVIEW)) && (state == GEDIT_TAB_STATE_SHOWING_PRINT_PREVIEW)) &&
!gedit_document_get_readonly (doc) && !gedit_document_get_readonly (doc) &&
!(lockdown & GEDIT_LOCKDOWN_SAVE_TO_DISK)); !(lockdown & GEDIT_LOCKDOWN_SAVE_TO_DISK));
...@@ -681,14 +682,16 @@ set_sensitivity_according_to_tab (GeditWindow *window, ...@@ -681,14 +682,16 @@ set_sensitivity_according_to_tab (GeditWindow *window,
"FileSaveAs"); "FileSaveAs");
gtk_action_set_sensitive (action, gtk_action_set_sensitive (action,
(state_normal || (state_normal ||
(state == GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) ||
(state == GEDIT_TAB_STATE_SHOWING_PRINT_PREVIEW)) && (state == GEDIT_TAB_STATE_SHOWING_PRINT_PREVIEW)) &&
!(lockdown & GEDIT_LOCKDOWN_SAVE_TO_DISK)); !(lockdown & GEDIT_LOCKDOWN_SAVE_TO_DISK));
action = gtk_action_group_get_action (window->priv->action_group, action = gtk_action_group_get_action (window->priv->action_group,
"FileRevert"); "FileRevert");
gtk_action_set_sensitive (action, gtk_action_set_sensitive (action,
!gedit_document_is_untitled (doc) && (state_normal ||
state_normal); (state == GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION)) &&
!gedit_document_is_untitled (doc));
action = gtk_action_group_get_action (window->priv->action_group, action = gtk_action_group_get_action (window->priv->action_group,
"FilePrintPreview"); "FilePrintPreview");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment