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>
* plugins/filebrowser/gedit-file-bookmarks-store.c:
......
......@@ -303,6 +303,12 @@
(return-type "gboolean")
)
(define-method is_local
(of-object "GeditDocument")
(c-name "gedit_document_is_local")
(return-type "gboolean")
)
(define-method get_deleted
(of-object "GeditDocument")
(c-name "gedit_document_get_deleted")
......
......@@ -887,6 +887,40 @@ gedit_document_get_readonly (GeditDocument *doc)
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
reset_temp_loading_data (GeditDocument *doc)
{
......@@ -1202,6 +1236,18 @@ gedit_document_is_untitled (GeditDocument *doc)
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
gedit_document_get_deleted (GeditDocument *doc)
......
......@@ -178,11 +178,9 @@ void gedit_document_save_as (GeditDocument *doc,
gboolean gedit_document_is_untouched (GeditDocument *doc);
gboolean gedit_document_is_untitled (GeditDocument *doc);
gboolean gedit_document_is_local (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,
gint line);
......@@ -234,10 +232,13 @@ gboolean gedit_document_get_enable_search_highlighting
*/
gboolean _gedit_document_is_saving_as (GeditDocument *doc);
// CHECK: va bene un gint?
glong _gedit_document_get_seconds_since_last_save_or_load
(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,
const GtkTextIter *start,
const GtkTextIter *end);
......
......@@ -75,11 +75,12 @@ is_recoverable_error (const GError *error)
return is_recoverable;
}
static GtkWidget *
create_io_loading_error_message_area (const gchar *primary_text,
static void
set_message_area_text_and_icon (GeditMessageArea *message_area,
const gchar *icon_stock_id,
const gchar *primary_text,
const gchar *secondary_text)
{
GtkWidget *message_area;
GtkWidget *hbox_content;
GtkWidget *image;
GtkWidget *vbox;
......@@ -88,14 +89,10 @@ create_io_loading_error_message_area (const gchar *primary_text,
GtkWidget *primary_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);
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_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 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,
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 *
gedit_io_loading_error_message_area_new (const gchar *uri,
const GError *error)
......@@ -1372,3 +1387,60 @@ gedit_unrecoverable_saving_error_message_area_new (const gchar *uri,
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
GtkWidget *gedit_unrecoverable_saving_error_message_area_new (const gchar *uri,
const GError *error);
GtkWidget *gedit_externally_modified_message_area_new (const gchar *uri,
gboolean document_modified);
G_END_DECLS
#endif /* __GEDIT_IO_ERROR_MESSAGE_AREA_H__ */
......@@ -82,6 +82,8 @@ struct _GeditTabPrivate
gint not_editable : 1;
gint auto_save : 1;
gint ask_if_externally_modified : 1;
};
G_DEFINE_TYPE(GeditTab, gedit_tab, GTK_TYPE_VBOX)
......@@ -166,7 +168,6 @@ remove_auto_save_timeout (GeditTab *tab)
tab->priv->auto_save_timeout = 0;
}
static void
gedit_tab_get_property (GObject *object,
guint prop_id,
......@@ -293,7 +294,6 @@ gedit_tab_class_init (GeditTabClass *klass)
g_type_class_add_private (object_class, sizeof (GeditTabPrivate));
}
GeditTabState
gedit_tab_get_state (GeditTab *tab)
{
......@@ -405,8 +405,6 @@ gedit_tab_set_state (GeditTab *tab,
g_object_notify (G_OBJECT (tab), "state");
}
static void
document_uri_notify_handler (GeditDocument *document,
GParamSpec *pspec,
......@@ -1062,6 +1060,8 @@ document_loaded (GeditDocument *document,
gedit_tab_set_state (tab, GEDIT_TAB_STATE_NORMAL);
install_auto_save_timeout_if_needed (tab);
tab->priv->ask_if_externally_modified = TRUE;
}
end:
......@@ -1382,9 +1382,106 @@ document_saved (GeditDocument *document,
else
gedit_tab_set_state (tab, GEDIT_TAB_STATE_NORMAL);
tab->priv->ask_if_externally_modified = TRUE;
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
......@@ -1402,6 +1499,8 @@ gedit_tab_init (GeditTab *tab)
tab->priv->save_flags = 0;
tab->priv->ask_if_externally_modified = TRUE;
/* Create the scrolled window */
sw = gtk_scrolled_window_new (NULL, NULL);
tab->priv->view_scrolled_window = sw;
......@@ -1460,7 +1559,12 @@ gedit_tab_init (GeditTab *tab)
G_CALLBACK (document_saved),
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",
G_CALLBACK (view_realized),
tab);
......@@ -1836,7 +1940,8 @@ _gedit_tab_revert (GeditTab *tab)
gchar *uri;
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);
g_return_if_fail (GEDIT_IS_DOCUMENT (doc));
......@@ -1865,9 +1970,11 @@ void
_gedit_tab_save (GeditTab *tab)
{
GeditDocument *doc;
GeditDocumentSaveFlags save_flags;
g_return_if_fail (GEDIT_IS_TAB (tab));
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));
g_return_if_fail (tab->priv->tmp_save_uri == NULL);
g_return_if_fail (tab->priv->tmp_encoding == NULL);
......@@ -1876,6 +1983,21 @@ _gedit_tab_save (GeditTab *tab)
g_return_if_fail (GEDIT_IS_DOCUMENT (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);
/* uri used in error messages, will be freed in document_saved */
......@@ -1885,7 +2007,7 @@ _gedit_tab_save (GeditTab *tab)
if (tab->priv->auto_save_timeout > 0)
remove_auto_save_timeout (tab);
gedit_document_save (doc, tab->priv->save_flags);
gedit_document_save (doc, save_flags);
}
static gboolean
......
......@@ -54,6 +54,7 @@ typedef enum
GEDIT_TAB_STATE_SAVING_ERROR,
GEDIT_TAB_STATE_GENERIC_ERROR,
GEDIT_TAB_STATE_CLOSING,
GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION,
GEDIT_TAB_NUM_OF_STATES /* This is not a valid state */
} GeditTabState;
......
......@@ -673,6 +673,7 @@ set_sensitivity_according_to_tab (GeditWindow *window,
"FileSave");
gtk_action_set_sensitive (action,
(state_normal ||
(state == GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) ||
(state == GEDIT_TAB_STATE_SHOWING_PRINT_PREVIEW)) &&
!gedit_document_get_readonly (doc) &&
!(lockdown & GEDIT_LOCKDOWN_SAVE_TO_DISK));
......@@ -681,14 +682,16 @@ set_sensitivity_according_to_tab (GeditWindow *window,
"FileSaveAs");
gtk_action_set_sensitive (action,
(state_normal ||
(state == GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) ||
(state == GEDIT_TAB_STATE_SHOWING_PRINT_PREVIEW)) &&
!(lockdown & GEDIT_LOCKDOWN_SAVE_TO_DISK));
action = gtk_action_group_get_action (window->priv->action_group,
"FileRevert");
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,
"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