Pull upstream fixes for gtk and gtksourceview changes

* fix errors in xed-metadata-manager
* upstream changes for file loading and saving
* modernize some code in xed-document

Closes https://github.com/linuxmint/xed/issues/146
This commit is contained in:
JosephMcc 2017-12-04 00:00:51 -08:00
parent 4c813f2c7f
commit ef9294aae2
12 changed files with 1200 additions and 1009 deletions

View File

@ -149,8 +149,8 @@ PKG_CHECK_MODULES(XED, [
$GMODULE_ADD $GMODULE_ADD
gthread-2.0 >= 2.13.0 gthread-2.0 >= 2.13.0
gio-2.0 >= 2.40.0 gio-2.0 >= 2.40.0
gtk+-3.0 >= 3.18.0 gtk+-3.0 >= 3.19.3
gtksourceview-3.0 >= 3.18.0 gtksourceview-3.0 >= 3.19.0
libpeas-1.0 >= 1.12.0 libpeas-1.0 >= 1.12.0
libpeas-gtk-1.0 >= 1.12.0 libpeas-gtk-1.0 >= 1.12.0
]) ])

View File

@ -40,10 +40,12 @@ NOINST_H_FILES = \
xed-close-button.h \ xed-close-button.h \
xed-close-confirmation-dialog.h \ xed-close-confirmation-dialog.h \
xed-dirs.h \ xed-dirs.h \
xed-document-private.h \
xed-documents-panel.h \ xed-documents-panel.h \
xed-encodings-dialog.h \ xed-encodings-dialog.h \
xed-history-entry.h \ xed-history-entry.h \
xed-io-error-info-bar.h \ xed-io-error-info-bar.h \
xed-metadata-manager.h \
xed-paned.h \ xed-paned.h \
xed-plugins-engine.h \ xed-plugins-engine.h \
xed-preferences-dialog.h \ xed-preferences-dialog.h \
@ -80,10 +82,6 @@ INST_H_FILES = \
xed-window.h \ xed-window.h \
xed-window-activatable.h xed-window-activatable.h
if !ENABLE_GVFS_METADATA
NOINST_H_FILES += xed-metadata-manager.h
endif
headerdir = $(prefix)/include/xed headerdir = $(prefix)/include/xed
header_DATA = \ header_DATA = \
@ -119,6 +117,7 @@ libxed_c_files = \
xed-message-bus.c \ xed-message-bus.c \
xed-message-type.c \ xed-message-type.c \
xed-message.c \ xed-message.c \
xed-metadata-manager.c \
xed-notebook.c \ xed-notebook.c \
xed-paned.c \ xed-paned.c \
xed-panel.c \ xed-panel.c \
@ -146,10 +145,6 @@ libxed_la_SOURCES = \
$(NOINST_H_FILES) \ $(NOINST_H_FILES) \
$(INST_H_FILES) $(INST_H_FILES)
if !ENABLE_GVFS_METADATA
libxed_la_SOURCES += xed-metadata-manager.c
endif
xed-enum-types.h: xed-enum-types.h.template $(INST_H_FILES) $(GLIB_MKENUMS) xed-enum-types.h: xed-enum-types.h.template $(INST_H_FILES) $(GLIB_MKENUMS)
$(AM_V_GEN) (cd $(srcdir) && $(GLIB_MKENUMS) --template xed-enum-types.h.template $(INST_H_FILES)) > $@ $(AM_V_GEN) (cd $(srcdir) && $(GLIB_MKENUMS) --template xed-enum-types.h.template $(INST_H_FILES)) > $@

View File

@ -32,10 +32,13 @@
#include <config.h> #include <config.h>
#endif #endif
#include "xed-close-confirmation-dialog.h"
#include <glib/gi18n.h> #include <glib/gi18n.h>
#include "xed-close-confirmation-dialog.h"
#include <xed/xed-app.h> #include <xed/xed-app.h>
#include <xed/xed-document.h>
#include <xed/xed-document-private.h>
#include <xed/xed-utils.h> #include <xed/xed-utils.h>
#include <xed/xed-window.h> #include <xed/xed-window.h>

View File

@ -38,31 +38,27 @@
#include <gio/gio.h> #include <gio/gio.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include "xed-debug.h"
#include "xed-document.h"
#include "xed-document-private.h"
#include "xed-commands.h" #include "xed-commands.h"
#include "xed-window.h" #include "xed-window.h"
#include "xed-window-private.h" #include "xed-window-private.h"
#include "xed-statusbar.h" #include "xed-statusbar.h"
#include "xed-debug.h"
#include "xed-utils.h" #include "xed-utils.h"
#include "xed-file-chooser-dialog.h" #include "xed-file-chooser-dialog.h"
#include "xed-close-confirmation-dialog.h" #include "xed-close-confirmation-dialog.h"
/* Defined constants */ /* Defined constants */
#define XED_OPEN_DIALOG_KEY "xed-open-dialog-key" #define XED_OPEN_DIALOG_KEY "xed-open-dialog-key"
#define XED_TAB_TO_SAVE_AS "xed-tab-to-save-as"
#define XED_LIST_OF_TABS_TO_SAVE_AS "xed-list-of-tabs-to-save-as"
#define XED_IS_CLOSING_ALL "xed-is-closing-all" #define XED_IS_CLOSING_ALL "xed-is-closing-all"
#define XED_IS_QUITTING "xed-is-quitting" #define XED_IS_QUITTING "xed-is-quitting"
#define XED_IS_CLOSING_TAB "xed-is-closing-tab"
#define XED_IS_QUITTING_ALL "xed-is-quitting-all" #define XED_IS_QUITTING_ALL "xed-is-quitting-all"
static void tab_state_changed_while_saving (XedTab *tab, static void tab_state_changed_while_saving (XedTab *tab,
GParamSpec *pspec, GParamSpec *pspec,
XedWindow *window); XedWindow *window);
static void save_as_tab (XedTab *tab,
XedWindow *window);
void void
_xed_cmd_file_new (GtkAction *action, _xed_cmd_file_new (GtkAction *action,
XedWindow *window) XedWindow *window)
@ -521,110 +517,73 @@ replace_read_only_file (GtkWindow *parent,
} }
static void static void
save_finish_cb (XedTab *tab, tab_save_as_ready_cb (XedTab *tab,
GAsyncResult *result, GAsyncResult *result,
gpointer user_data) GTask *task)
{ {
_xed_tab_save_finish (tab, result); gboolean success = _xed_tab_save_finish (tab, result);
g_task_return_boolean (task, success);
g_object_unref (task);
} }
static void static void
save_dialog_response_cb (XedFileChooserDialog *dialog, save_dialog_response_cb (XedFileChooserDialog *dialog,
gint response_id, gint response_id,
XedWindow *window) GTask *task)
{ {
XedTab *tab; XedTab *tab;
gpointer data; XedWindow *window;
GSList *tabs_to_save_as; XedDocument *doc;
GtkSourceFile *file;
GFile *location;
gchar *parse_name;
GtkSourceNewlineType newline_type;
const GtkSourceEncoding *encoding;
xed_debug (DEBUG_COMMANDS); xed_debug (DEBUG_COMMANDS);
tab = XED_TAB (g_object_get_data (G_OBJECT (dialog), XED_TAB_TO_SAVE_AS)); tab = g_task_get_source_object (task);
window = g_task_get_task_data (task);
if (response_id != GTK_RESPONSE_OK) if (response_id != GTK_RESPONSE_OK)
{ {
gtk_widget_destroy (GTK_WIDGET (dialog)); gtk_widget_destroy (GTK_WIDGET (dialog));
goto save_next_tab; g_task_return_boolean (task, FALSE);
} g_object_unref (task);
if (tab != NULL)
{
GFile *location;
XedDocument *doc;
gchar *parse_name;
GtkSourceNewlineType newline_type;
const GtkSourceEncoding *encoding;
doc = xed_tab_get_document (tab);
location = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
g_return_if_fail (location != NULL);
encoding = xed_file_chooser_dialog_get_encoding (dialog);
newline_type = xed_file_chooser_dialog_get_newline_type (dialog);
gtk_widget_destroy (GTK_WIDGET (dialog));
doc = xed_tab_get_document (tab);
g_return_if_fail (XED_IS_DOCUMENT (doc));
parse_name = g_file_get_parse_name (location);
xed_statusbar_flash_message (XED_STATUSBAR (window->priv->statusbar),
window->priv->generic_message_cid,
_("Saving file '%s'\342\200\246"),
parse_name);
g_free (parse_name);
/* let's remember the dir we navigated too,
* even if the saving fails... */
_xed_window_set_default_location (window, location);
_xed_tab_save_as_async (tab,
location,
encoding,
newline_type,
NULL,
(GAsyncReadyCallback) save_finish_cb,
NULL);
g_object_unref (location);
}
save_next_tab:
data = g_object_get_data (G_OBJECT (window), XED_LIST_OF_TABS_TO_SAVE_AS);
if (data == NULL)
{
return; return;
} }
/* Save As the next tab of the list (we are Saving All files) */ doc = xed_tab_get_document (tab);
tabs_to_save_as = (GSList *)data; location = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
g_return_if_fail (tab == XED_TAB (tabs_to_save_as->data)); g_return_if_fail (location != NULL);
/* Remove the first item of the list */ encoding = xed_file_chooser_dialog_get_encoding (dialog);
tabs_to_save_as = g_slist_delete_link (tabs_to_save_as, tabs_to_save_as); newline_type = xed_file_chooser_dialog_get_newline_type (dialog);
g_object_set_data (G_OBJECT (window), XED_LIST_OF_TABS_TO_SAVE_AS, tabs_to_save_as); gtk_widget_destroy (GTK_WIDGET (dialog));
if (tabs_to_save_as != NULL) parse_name = g_file_get_parse_name (location);
{
tab = XED_TAB (tabs_to_save_as->data);
if (GPOINTER_TO_BOOLEAN (g_object_get_data (G_OBJECT (tab), XED_IS_CLOSING_TAB)) == TRUE) xed_statusbar_flash_message (XED_STATUSBAR (window->priv->statusbar),
{ window->priv->generic_message_cid,
g_object_set_data (G_OBJECT (tab), XED_IS_CLOSING_TAB, NULL); _("Saving file '%s'\342\200\246"),
parse_name);
/* Trace tab state changes */ g_free (parse_name);
g_signal_connect (tab, "notify::state", G_CALLBACK (tab_state_changed_while_saving), window);
}
xed_window_set_active_tab (window, tab); /* let's remember the dir we navigated too, even if the saving fails... */
save_as_tab (tab, window); _xed_window_set_default_location (window, location);
}
_xed_tab_save_as_async (tab,
location,
encoding,
newline_type,
g_task_get_cancellable (task),
(GAsyncReadyCallback) tab_save_as_ready_cb,
task);
g_object_unref (location);
} }
static GtkFileChooserConfirmation static GtkFileChooserConfirmation
@ -663,16 +622,20 @@ confirm_overwrite_callback (GtkFileChooser *dialog,
return res; return res;
} }
/* Call save_as_tab_finish() in @callback. */
static void static void
save_as_tab (XedTab *tab, save_as_tab_async (XedTab *tab,
XedWindow *window) XedWindow *window,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{ {
GTask *task;
GtkWidget *save_dialog; GtkWidget *save_dialog;
GtkWindowGroup *wg; GtkWindowGroup *wg;
XedDocument *doc; XedDocument *doc;
GtkSourceFile *file; GtkSourceFile *file;
GFile *location; GFile *location;
gboolean uri_set = FALSE;
const GtkSourceEncoding *encoding; const GtkSourceEncoding *encoding;
GtkSourceNewlineType newline_type; GtkSourceNewlineType newline_type;
@ -681,6 +644,9 @@ save_as_tab (XedTab *tab,
xed_debug (DEBUG_COMMANDS); xed_debug (DEBUG_COMMANDS);
task = g_task_new (tab, cancellable, callback, user_data);
g_task_set_task_data (task, g_object_ref (window), g_object_unref);
save_dialog = xed_file_chooser_dialog_new (_("Save As\342\200\246"), save_dialog = xed_file_chooser_dialog_new (_("Save As\342\200\246"),
GTK_WINDOW (window), GTK_WINDOW (window),
GTK_FILE_CHOOSER_ACTION_SAVE, GTK_FILE_CHOOSER_ACTION_SAVE,
@ -706,11 +672,11 @@ save_as_tab (XedTab *tab,
if (location != NULL) if (location != NULL)
{ {
uri_set = gtk_file_chooser_set_file (GTK_FILE_CHOOSER (save_dialog), location, NULL); gtk_file_chooser_set_file (GTK_FILE_CHOOSER (save_dialog), location, NULL);
} }
if (!uri_set) else
{ {
GFile *default_path; GFile *default_path;
gchar *docname; gchar *docname;
@ -734,7 +700,7 @@ save_as_tab (XedTab *tab,
g_free (docname); g_free (docname);
} }
/* Set suggested encoding */ /* Set suggested encoding and newline type */
encoding = gtk_source_file_get_encoding (file); encoding = gtk_source_file_get_encoding (file);
if (encoding == NULL) if (encoding == NULL)
@ -748,39 +714,94 @@ save_as_tab (XedTab *tab,
xed_file_chooser_dialog_set_newline_type (XED_FILE_CHOOSER_DIALOG (save_dialog), newline_type); xed_file_chooser_dialog_set_newline_type (XED_FILE_CHOOSER_DIALOG (save_dialog), newline_type);
g_object_set_data (G_OBJECT (save_dialog), XED_TAB_TO_SAVE_AS, tab); g_signal_connect (save_dialog, "response", G_CALLBACK (save_dialog_response_cb), task);
g_signal_connect (save_dialog, "response", G_CALLBACK (save_dialog_response_cb), window);
gtk_widget_show (save_dialog); gtk_widget_show (save_dialog);
} }
static void static gboolean
save_tab (XedTab *tab, save_as_tab_finish (XedTab *tab,
XedWindow *window) GAsyncResult *result)
{ {
XedDocument *doc; g_return_val_if_fail (g_task_is_valid (result, tab), FALSE);
return g_task_propagate_boolean (G_TASK (result), NULL);
}
static void
save_as_tab_ready_cb (XedTab *tab,
GAsyncResult *result,
GTask *task)
{
gboolean success = save_as_tab_finish (tab, result);
g_task_return_boolean (task, success);
g_object_unref (task);
}
static void
tab_save_ready_cb (XedTab *tab,
GAsyncResult *result,
GTask *task)
{
gboolean success = _xed_tab_save_finish (tab, result);
g_task_return_boolean (task, success);
g_object_unref (task);
}
/**
* xed_commands_save_document_async:
* @document: the #XedDocument to save.
* @window: a #XedWindow.
* @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
* @callback: (scope async): a #GAsyncReadyCallback to call when the operation
* is finished.
* @user_data: (closure): the data to pass to the @callback function.
*
* Asynchronously save the @document. @document must belong to @window. The
* source object of the async task is @document (which will be the first
* parameter of the #GAsyncReadyCallback).
*
* When the operation is finished, @callback will be called. You can then call
* xed_commands_save_document_finish() to get the result of the operation.
*/
void
xed_commands_save_document_async (XedDocument *document,
XedWindow *window,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
XedTab *tab;
gchar *uri_for_display; gchar *uri_for_display;
xed_debug (DEBUG_COMMANDS); xed_debug (DEBUG_COMMANDS);
g_return_if_fail (XED_IS_TAB (tab)); g_return_if_fail (XED_IS_DOCUMENT (document));
g_return_if_fail (XED_IS_WINDOW (window)); g_return_if_fail (XED_IS_WINDOW (window));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
doc = xed_tab_get_document (tab); task = g_task_new (document, cancellable, callback, user_data);
g_return_if_fail (XED_IS_DOCUMENT (doc));
if (xed_document_is_untitled (doc) || tab = xed_tab_get_from_document (document);
xed_document_get_readonly (doc))
if (xed_document_is_untitled (document) ||
xed_document_get_readonly (document))
{ {
xed_debug_message (DEBUG_COMMANDS, "Untitled or Readonly"); xed_debug_message (DEBUG_COMMANDS, "Untitled or Readonly");
save_as_tab (tab, window); save_as_tab_async (tab,
window,
cancellable,
(GAsyncReadyCallback) save_as_tab_ready_cb,
task);
return; return;
} }
uri_for_display = xed_document_get_uri_for_display (doc); uri_for_display = xed_document_get_uri_for_display (document);
xed_statusbar_flash_message (XED_STATUSBAR (window->priv->statusbar), xed_statusbar_flash_message (XED_STATUSBAR (window->priv->statusbar),
window->priv->generic_message_cid, window->priv->generic_message_cid,
_("Saving file '%s'\342\200\246"), _("Saving file '%s'\342\200\246"),
@ -789,9 +810,53 @@ save_tab (XedTab *tab,
g_free (uri_for_display); g_free (uri_for_display);
_xed_tab_save_async (tab, _xed_tab_save_async (tab,
NULL, cancellable,
(GAsyncReadyCallback) save_finish_cb, (GAsyncReadyCallback) tab_save_ready_cb,
NULL); task);
}
/**
* xed_commands_save_document_finish:
* @document: a #XedDocument.
* @result: a #GAsyncResult.
*
* Finishes an asynchronous document saving operation started with
* xed_commands_save_document_async().
*
* Note that there is no error parameter because the errors are already handled
* by xed.
*
* Returns: %TRUE if the document has been correctly saved, %FALSE otherwise.
*/
gboolean
xed_commands_save_document_finish (XedDocument *document,
GAsyncResult *result)
{
g_return_val_if_fail (g_task_is_valid (result, document), FALSE);
return g_task_propagate_boolean (G_TASK (result), NULL);
}
static void
save_tab_ready_cb (XedDocument *doc,
GAsyncResult *result,
gpointer user_data)
{
xed_commands_save_document_finish (doc, result);
}
/* Save tab asynchronously, but without results. */
static void
save_tab (XedTab *tab,
XedWindow *window)
{
XedDocument *doc = xed_tab_get_document (tab);
xed_commands_save_document_async (doc,
window,
NULL,
(GAsyncReadyCallback) save_tab_ready_cb,
NULL);
} }
void void
@ -803,12 +868,18 @@ _xed_cmd_file_save (GtkAction *action,
xed_debug (DEBUG_COMMANDS); xed_debug (DEBUG_COMMANDS);
tab = xed_window_get_active_tab (window); tab = xed_window_get_active_tab (window);
if (tab == NULL) if (tab != NULL)
{ {
return; save_tab (tab, window);
} }
}
save_tab (tab, window); static void
_xed_cmd_file_save_as_cb (XedTab *tab,
GAsyncResult *result,
gpointer user_data)
{
save_as_tab_finish (tab, result);
} }
void void
@ -820,12 +891,149 @@ _xed_cmd_file_save_as (GtkAction *action,
xed_debug (DEBUG_COMMANDS); xed_debug (DEBUG_COMMANDS);
tab = xed_window_get_active_tab (window); tab = xed_window_get_active_tab (window);
if (tab == NULL) if (tab != NULL)
{
save_as_tab_async (tab,
window,
NULL,
(GAsyncReadyCallback) _xed_cmd_file_save_as_cb,
NULL);
}
}
static void
quit_if_needed (XedWindow *window)
{
gboolean is_quitting;
gboolean is_quitting_all;
is_quitting = GPOINTER_TO_BOOLEAN (g_object_get_data (G_OBJECT (window), XED_IS_QUITTING));
is_quitting_all = GPOINTER_TO_BOOLEAN (g_object_get_data (G_OBJECT (window), XED_IS_QUITTING_ALL));
if (is_quitting)
{
gtk_widget_destroy (GTK_WIDGET (window));
}
if (is_quitting_all)
{
GtkApplication *app;
app = GTK_APPLICATION (g_application_get_default ());
if (gtk_application_get_windows (app) == NULL)
{
g_application_quit (G_APPLICATION (app));
}
}
}
static gboolean
really_close_tab (XedTab *tab)
{
GtkWidget *toplevel;
XedWindow *window;
xed_debug (DEBUG_COMMANDS);
g_return_val_if_fail (xed_tab_get_state (tab) == XED_TAB_STATE_CLOSING, FALSE);
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tab));
g_return_val_if_fail (XED_IS_WINDOW (toplevel), FALSE);
window = XED_WINDOW (toplevel);
xed_window_close_tab (window, tab);
if (xed_window_get_active_tab (window) == NULL)
{
quit_if_needed (window);
}
return FALSE;
}
static void
close_tab (XedTab *tab)
{
XedDocument *doc;
doc = xed_tab_get_document (tab);
g_return_if_fail (doc != NULL);
/* If the user has modified again the document, do not close the tab. */
if (_xed_document_needs_saving (doc))
{ {
return; return;
} }
save_as_tab (tab, window); /* Close the document only if it has been succesfully saved.
* Tab state is set to CLOSING (it is a state without exiting
* transitions) and the tab is closed in an idle handler.
*/
_xed_tab_mark_for_closing (tab);
g_idle_add_full (G_PRIORITY_HIGH_IDLE,
(GSourceFunc) really_close_tab,
tab,
NULL);
}
typedef struct _SaveAsData SaveAsData;
struct _SaveAsData
{
/* Reffed */
XedWindow *window;
/* List of reffed GeditTab's */
GSList *tabs_to_save_as;
guint close_tabs : 1;
};
static void save_as_documents_list (SaveAsData *data);
static void
save_as_documents_list_cb (XedTab *tab,
GAsyncResult *result,
SaveAsData *data)
{
gboolean saved = save_as_tab_finish (tab, result);
if (saved && data->close_tabs)
{
close_tab (tab);
}
g_return_if_fail (tab == XED_TAB (data->tabs_to_save_as->data));
g_object_unref (data->tabs_to_save_as->data);
data->tabs_to_save_as = g_slist_delete_link (data->tabs_to_save_as, data->tabs_to_save_as);
if (data->tabs_to_save_as != NULL)
{
save_as_documents_list (data);
}
else
{
g_object_unref (data->window);
g_slice_free (SaveAsData, data);
}
}
static void
save_as_documents_list (SaveAsData *data)
{
XedTab *next_tab = XED_TAB (data->tabs_to_save_as->data);
xed_window_set_active_tab (data->window, next_tab);
save_as_tab_async (next_tab,
data->window,
NULL,
(GAsyncReadyCallback) save_as_documents_list_cb,
data);
} }
/* /*
@ -835,8 +1043,8 @@ static void
save_documents_list (XedWindow *window, save_documents_list (XedWindow *window,
GList *docs) GList *docs)
{ {
SaveAsData *data = NULL;
GList *l; GList *l;
GSList *tabs_to_save_as = NULL;
xed_debug (DEBUG_COMMANDS); xed_debug (DEBUG_COMMANDS);
@ -868,9 +1076,17 @@ save_documents_list (XedWindow *window,
if (xed_document_is_untitled (doc) || xed_document_get_readonly (doc)) if (xed_document_is_untitled (doc) || xed_document_get_readonly (doc))
{ {
if (_xed_document_needs_saving (doc)) if (_xed_document_needs_saving (doc))
{
if (data == NULL)
{ {
tabs_to_save_as = g_slist_prepend (tabs_to_save_as, t); data = g_slice_new (SaveAsData);
data->window = g_object_ref (window);
data->tabs_to_save_as = NULL;
data->close_tabs = FALSE;
} }
data->tabs_to_save_as = g_slist_prepend (data->tabs_to_save_as, g_object_ref (t));
}
} }
else else
{ {
@ -913,23 +1129,21 @@ save_documents_list (XedWindow *window,
l = g_list_next (l); l = g_list_next (l);
} }
if (tabs_to_save_as != NULL) if (data != NULL)
{ {
XedTab *tab; data->tabs_to_save_as = g_slist_reverse (data->tabs_to_save_as);
save_as_documents_list (data);
tabs_to_save_as = g_slist_reverse (tabs_to_save_as );
g_return_if_fail (g_object_get_data (G_OBJECT (window), XED_LIST_OF_TABS_TO_SAVE_AS) == NULL);
g_object_set_data (G_OBJECT (window), XED_LIST_OF_TABS_TO_SAVE_AS, tabs_to_save_as);
tab = XED_TAB (tabs_to_save_as->data);
xed_window_set_active_tab (window, tab);
save_as_tab (tab, window);
} }
} }
/**
* xed_commands_save_all_documents:
* @window: a #XedWindow.
*
* Asynchronously save all documents belonging to @window. The result of the
* operation is not available, so it's difficult to know whether all the
* documents are correctly saved.
*/
void void
xed_commands_save_all_documents (XedWindow *window) xed_commands_save_all_documents (XedWindow *window)
{ {
@ -953,6 +1167,14 @@ _xed_cmd_file_save_all (GtkAction *action,
xed_commands_save_all_documents (window); xed_commands_save_all_documents (window);
} }
/**
* xed_commands_save_document:
* @window: a #XedWindow.
* @document: the #XedDocument to save.
*
* Asynchronously save @document. @document must belong to @window. If you need
* the result of the operation, use xed_commands_save_document_async().
*/
void void
xed_commands_save_document (XedWindow *window, xed_commands_save_document (XedWindow *window,
XedDocument *document) XedDocument *document)
@ -1161,39 +1383,6 @@ _xed_cmd_file_revert (GtkAction *action,
gtk_widget_show (dialog); gtk_widget_show (dialog);
} }
/* Close tab */
static gboolean
really_close_tab (XedTab *tab)
{
GtkWidget *toplevel;
XedWindow *window;
xed_debug (DEBUG_COMMANDS);
g_return_val_if_fail (xed_tab_get_state (tab) == XED_TAB_STATE_CLOSING, FALSE);
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tab));
g_return_val_if_fail (XED_IS_WINDOW (toplevel), FALSE);
window = XED_WINDOW (toplevel);
xed_window_close_tab (window, tab);
if (xed_window_get_active_tab (window) == NULL)
{
gboolean is_quitting;
is_quitting = GPOINTER_TO_BOOLEAN (g_object_get_data (G_OBJECT (window), XED_IS_QUITTING));
if (is_quitting)
{
gtk_widget_destroy (GTK_WIDGET (window));
}
}
return FALSE;
}
static void static void
tab_state_changed_while_saving (XedTab *tab, tab_state_changed_while_saving (XedTab *tab,
GParamSpec *pspec, GParamSpec *pspec,
@ -1209,26 +1398,9 @@ tab_state_changed_while_saving (XedTab *tab,
finished */ finished */
if (ts == XED_TAB_STATE_NORMAL) if (ts == XED_TAB_STATE_NORMAL)
{ {
XedDocument *doc;
g_signal_handlers_disconnect_by_func (tab, G_CALLBACK (tab_state_changed_while_saving), window); g_signal_handlers_disconnect_by_func (tab, G_CALLBACK (tab_state_changed_while_saving), window);
doc = xed_tab_get_document (tab); close_tab (tab);
g_return_if_fail (doc != NULL);
/* If the saving operation failed or was interrupted, then the
document is still "modified" -> do not close the tab */
if (_xed_document_needs_saving (doc))
{
return;
}
/* Close the document only if it has been succesfully saved.
Tab state is set to CLOSING (it is a state without exiting
transitions) and the tab is closed in a idle handler */
_xed_tab_mark_for_closing (tab);
g_idle_add_full (G_PRIORITY_HIGH_IDLE, (GSourceFunc)really_close_tab, tab, NULL);
} }
} }
@ -1244,21 +1416,6 @@ save_and_close (XedTab *tab,
save_tab (tab, window); save_tab (tab, window);
} }
static void
save_as_and_close (XedTab *tab,
XedWindow *window)
{
xed_debug (DEBUG_COMMANDS);
g_object_set_data (G_OBJECT (tab), XED_IS_CLOSING_TAB, NULL);
/* Trace tab state changes */
g_signal_connect (tab, "notify::state", G_CALLBACK (tab_state_changed_while_saving), window);
xed_window_set_active_tab (window, tab);
save_as_tab (tab, window);
}
static void static void
save_and_close_all_documents (const GList *docs, save_and_close_all_documents (const GList *docs,
XedWindow *window) XedWindow *window)
@ -1266,9 +1423,9 @@ save_and_close_all_documents (const GList *docs,
GList *tabs; GList *tabs;
GList *l; GList *l;
GSList *sl; GSList *sl;
GSList *tabs_to_save_as; SaveAsData *data = NULL;
GSList *tabs_to_save_and_close; GSList *tabs_to_save_and_close = NULL;
GList *tabs_to_close; GList *tabs_to_close = NULL;
xed_debug (DEBUG_COMMANDS); xed_debug (DEBUG_COMMANDS);
@ -1276,19 +1433,13 @@ save_and_close_all_documents (const GList *docs,
tabs = gtk_container_get_children (GTK_CONTAINER (_xed_window_get_notebook (window))); tabs = gtk_container_get_children (GTK_CONTAINER (_xed_window_get_notebook (window)));
tabs_to_save_as = NULL;
tabs_to_save_and_close = NULL;
tabs_to_close = NULL;
l = tabs; l = tabs;
while (l != NULL) while (l != NULL)
{ {
XedTab *t; XedTab *t = XED_TAB (l->data);;
XedTabState state; XedTabState state;
XedDocument *doc; XedDocument *doc;
t = XED_TAB (l->data);
state = xed_tab_get_state (t); state = xed_tab_get_state (t);
doc = xed_tab_get_document (t); doc = xed_tab_get_document (t);
@ -1337,9 +1488,15 @@ save_and_close_all_documents (const GList *docs,
user is running xed - Paolo (Dec. 8, 2005) */ user is running xed - Paolo (Dec. 8, 2005) */
if (xed_document_is_untitled (doc) || xed_document_get_readonly (doc)) if (xed_document_is_untitled (doc) || xed_document_get_readonly (doc))
{ {
g_object_set_data (G_OBJECT (t), XED_IS_CLOSING_TAB, GBOOLEAN_TO_POINTER (TRUE)); if (data == NULL)
{
data = g_slice_new (SaveAsData);
data->window = g_object_ref (window);
data->tabs_to_save_as = NULL;
data->close_tabs = TRUE;
}
tabs_to_save_as = g_slist_prepend (tabs_to_save_as, t); data->tabs_to_save_as = g_slist_prepend (data->tabs_to_save_as, g_object_ref (t));
} }
else else
{ {
@ -1371,20 +1528,11 @@ save_and_close_all_documents (const GList *docs,
} }
g_slist_free (tabs_to_save_and_close); g_slist_free (tabs_to_save_and_close);
/* Save As and close all the files in tabs_to_save_as */ /* Save As and close all the files in data->tabs_to_save_as. */
if (tabs_to_save_as != NULL) if (data != NULL)
{ {
XedTab *tab; data->tabs_to_save_as = g_slist_reverse (data->tabs_to_save_as);
save_as_documents_list (data);
tabs_to_save_as = g_slist_reverse (tabs_to_save_as );
g_return_if_fail (g_object_get_data (G_OBJECT (window), XED_LIST_OF_TABS_TO_SAVE_AS) == NULL);
g_object_set_data (G_OBJECT (window), XED_LIST_OF_TABS_TO_SAVE_AS, tabs_to_save_as);
tab = XED_TAB (tabs_to_save_as->data);
save_as_and_close (tab, window);
} }
} }

View File

@ -12,6 +12,8 @@ void xed_commands_load_location (XedWindow *window, GFile *location, const GtkSo
/* Ignore non-existing URIs */ /* Ignore non-existing URIs */
GSList *xed_commands_load_locations (XedWindow *window, const GSList *locations, const GtkSourceEncoding *encoding, gint line_pos); GSList *xed_commands_load_locations (XedWindow *window, const GSList *locations, const GtkSourceEncoding *encoding, gint line_pos);
void xed_commands_save_document (XedWindow *window, XedDocument *document); void xed_commands_save_document (XedWindow *window, XedDocument *document);
void xed_commands_save_document_async (XedDocument *document, XedWindow *window, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
gboolean xed_commands_save_document_finish (XedDocument *document, GAsyncResult *result);
void xed_commands_save_all_documents (XedWindow *window); void xed_commands_save_all_documents (XedWindow *window);
/* /*

View File

@ -0,0 +1,21 @@
#ifndef __XED_DOCUMENT_PRIVATE_H__
#define __XED_DOCUMENT_PRIVATE_H__
#include "xed-document.h"
G_BEGIN_DECLS
glong _xed_document_get_seconds_since_last_save_or_load (XedDocument *doc);
gboolean _xed_document_needs_saving (XedDocument *doc);
gboolean _xed_document_get_empty_search (XedDocument *doc);
void _xed_document_set_create (XedDocument *doc,
gboolean create);
gboolean _xed_document_get_create (XedDocument *doc);
G_END_DECLS
#endif /* __XED_DOCUMENT_PRIVATE_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -37,29 +37,14 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#define XED_TYPE_DOCUMENT (xed_document_get_type()) #define XED_TYPE_DOCUMENT (xed_document_get_type())
#define XED_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_DOCUMENT, XedDocument))
#define XED_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XED_TYPE_DOCUMENT, XedDocumentClass)) G_DECLARE_DERIVABLE_TYPE (XedDocument, xed_document, XED, DOCUMENT, GtkSourceBuffer)
#define XED_IS_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XED_TYPE_DOCUMENT))
#define XED_IS_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_DOCUMENT))
#define XED_DOCUMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_DOCUMENT, XedDocumentClass))
#define XED_METADATA_ATTRIBUTE_POSITION "metadata::xed-position" #define XED_METADATA_ATTRIBUTE_POSITION "metadata::xed-position"
#define XED_METADATA_ATTRIBUTE_ENCODING "metadata::xed-encoding" #define XED_METADATA_ATTRIBUTE_ENCODING "metadata::xed-encoding"
#define XED_METADATA_ATTRIBUTE_LANGUAGE "metadata::xed-language" #define XED_METADATA_ATTRIBUTE_LANGUAGE "metadata::xed-language"
typedef struct _XedDocument XedDocument;
typedef struct _XedDocumentPrivate XedDocumentPrivate;
typedef struct _XedDocumentClass XedDocumentClass;
struct _XedDocument
{
GtkSourceBuffer buffer;
/*< private > */
XedDocumentPrivate *priv;
};
struct _XedDocumentClass struct _XedDocumentClass
{ {
GtkSourceBufferClass parent_class; GtkSourceBufferClass parent_class;
@ -77,8 +62,6 @@ struct _XedDocumentClass
void (* saved) (XedDocument *document); void (* saved) (XedDocument *document);
}; };
GType xed_document_get_type (void) G_GNUC_CONST;
XedDocument *xed_document_new (void); XedDocument *xed_document_new (void);
GtkSourceFile *xed_document_get_file (XedDocument *doc); GtkSourceFile *xed_document_get_file (XedDocument *doc);
@ -138,24 +121,6 @@ void xed_document_set_search_context (XedDocument *doc,
GtkSourceSearchContext *xed_document_get_search_context (XedDocument *doc); GtkSourceSearchContext *xed_document_get_search_context (XedDocument *doc);
/* Non exported functions */
glong _xed_document_get_seconds_since_last_save_or_load (XedDocument *doc);
void _xed_document_apply_error_style (XedDocument *doc,
GtkTextIter *start,
GtkTextIter *end);
/* Note: this is a sync stat: use only on local files */
gboolean _xed_document_check_externally_modified (XedDocument *doc);
gboolean _xed_document_needs_saving (XedDocument *doc);
void _xed_document_set_create (XedDocument *doc,
gboolean create);
gboolean _xed_document_get_create (XedDocument *doc);
G_END_DECLS G_END_DECLS
#endif /* __XED_DOCUMENT_H__ */ #endif /* __XED_DOCUMENT_H__ */

View File

@ -21,23 +21,15 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
/*
* Modified by the xed Team, 2003-2007. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
#include <time.h>
#include <stdlib.h>
#include <libxml/xmlreader.h> #include <libxml/xmlreader.h>
#include "xed-metadata-manager.h" #include "xed-metadata-manager.h"
#include "xed-debug.h" #include "xed-debug.h"
/* /*
#define XED_METADATA_VERBOSE_DEBUG 1 #define XED_METADATA_VERBOSE_DEBUG 1
*/ */
#define MAX_ITEMS 50 #define MAX_ITEMS 50
typedef struct _XedMetadataManager XedMetadataManager; typedef struct _XedMetadataManager XedMetadataManager;
@ -45,21 +37,21 @@ typedef struct _Item Item;
struct _Item struct _Item
{ {
time_t atime; /* time of last access */ gint64 atime; /* time of last access in seconds since January 1, 1970 UTC */
GHashTable *values; GHashTable *values;
}; };
struct _XedMetadataManager struct _XedMetadataManager
{ {
gboolean values_loaded; /* It is true if the file gboolean values_loaded; /* It is true if the file
has been read */ has been read */
guint timeout_id; guint timeout_id;
GHashTable *items; GHashTable *items;
gchar *metadata_filename; gchar *metadata_filename;
}; };
static gboolean xed_metadata_manager_save (gpointer data); static gboolean xed_metadata_manager_save (gpointer data);
@ -70,34 +62,34 @@ static XedMetadataManager *xed_metadata_manager = NULL;
static void static void
item_free (gpointer data) item_free (gpointer data)
{ {
Item *item; Item *item;
g_return_if_fail (data != NULL); g_return_if_fail (data != NULL);
#ifdef XED_METADATA_VERBOSE_DEBUG #ifdef XED_METADATA_VERBOSE_DEBUG
xed_debug (DEBUG_METADATA); xed_debug (DEBUG_METADATA);
#endif #endif
item = (Item *)data; item = (Item *)data;
if (item->values != NULL) if (item->values != NULL)
g_hash_table_destroy (item->values); g_hash_table_destroy (item->values);
g_free (item); g_free (item);
} }
static void static void
xed_metadata_manager_arm_timeout (void) xed_metadata_manager_arm_timeout (void)
{ {
if (xed_metadata_manager->timeout_id == 0) if (xed_metadata_manager->timeout_id == 0)
{ {
xed_metadata_manager->timeout_id = xed_metadata_manager->timeout_id =
g_timeout_add_seconds_full (G_PRIORITY_DEFAULT_IDLE, g_timeout_add_seconds_full (G_PRIORITY_DEFAULT_IDLE,
2, 2,
(GSourceFunc)xed_metadata_manager_save, (GSourceFunc)xed_metadata_manager_save,
NULL, NULL,
NULL); NULL);
} }
} }
/** /**
@ -110,22 +102,22 @@ xed_metadata_manager_arm_timeout (void)
void void
xed_metadata_manager_init (const gchar *metadata_filename) xed_metadata_manager_init (const gchar *metadata_filename)
{ {
xed_debug (DEBUG_METADATA); xed_debug (DEBUG_METADATA);
if (xed_metadata_manager != NULL) if (xed_metadata_manager != NULL)
return; return;
xed_metadata_manager = g_new0 (XedMetadataManager, 1); xed_metadata_manager = g_new0 (XedMetadataManager, 1);
xed_metadata_manager->values_loaded = FALSE; xed_metadata_manager->values_loaded = FALSE;
xed_metadata_manager->items = xed_metadata_manager->items =
g_hash_table_new_full (g_str_hash, g_hash_table_new_full (g_str_hash,
g_str_equal, g_str_equal,
g_free, g_free,
item_free); item_free);
xed_metadata_manager->metadata_filename = g_strdup (metadata_filename); xed_metadata_manager->metadata_filename = g_strdup (metadata_filename);
return; return;
} }
@ -139,154 +131,159 @@ xed_metadata_manager_init (const gchar *metadata_filename)
void void
xed_metadata_manager_shutdown (void) xed_metadata_manager_shutdown (void)
{ {
xed_debug (DEBUG_METADATA); xed_debug (DEBUG_METADATA);
if (xed_metadata_manager == NULL) if (xed_metadata_manager == NULL)
return; return;
if (xed_metadata_manager->timeout_id) if (xed_metadata_manager->timeout_id)
{ {
g_source_remove (xed_metadata_manager->timeout_id); g_source_remove (xed_metadata_manager->timeout_id);
xed_metadata_manager->timeout_id = 0; xed_metadata_manager->timeout_id = 0;
xed_metadata_manager_save (NULL); xed_metadata_manager_save (NULL);
} }
if (xed_metadata_manager->items != NULL) if (xed_metadata_manager->items != NULL)
g_hash_table_destroy (xed_metadata_manager->items); g_hash_table_destroy (xed_metadata_manager->items);
g_free (gedit_metadata_manager->metadata_filename); g_free (xed_metadata_manager->metadata_filename);
g_free (xed_metadata_manager); g_free (xed_metadata_manager);
xed_metadata_manager = NULL; xed_metadata_manager = NULL;
} }
static void static void
parseItem (xmlDocPtr doc, xmlNodePtr cur) parseItem (xmlDocPtr doc, xmlNodePtr cur)
{ {
Item *item; Item *item;
xmlChar *uri; xmlChar *uri;
xmlChar *atime; xmlChar *atime;
#ifdef XED_METADATA_VERBOSE_DEBUG #ifdef XED_METADATA_VERBOSE_DEBUG
xed_debug (DEBUG_METADATA); xed_debug (DEBUG_METADATA);
#endif #endif
if (xmlStrcmp (cur->name, (const xmlChar *)"document") != 0) if (xmlStrcmp (cur->name, (const xmlChar *)"document") != 0)
return; return;
uri = xmlGetProp (cur, (const xmlChar *)"uri"); uri = xmlGetProp (cur, (const xmlChar *)"uri");
if (uri == NULL) if (uri == NULL)
return; return;
atime = xmlGetProp (cur, (const xmlChar *)"atime"); atime = xmlGetProp (cur, (const xmlChar *)"atime");
if (atime == NULL) if (atime == NULL)
{ {
xmlFree (uri); xmlFree (uri);
return; return;
} }
item = g_new0 (Item, 1); item = g_new0 (Item, 1);
item->atime = g_ascii_strtoull ((char *)atime, NULL, 0); item->atime = g_ascii_strtoll ((char *)atime, NULL, 0);
item->values = g_hash_table_new_full (g_str_hash, item->values = g_hash_table_new_full (g_str_hash,
g_str_equal, g_str_equal,
g_free, g_free,
g_free); g_free);
cur = cur->xmlChildrenNode; cur = cur->xmlChildrenNode;
while (cur != NULL) while (cur != NULL)
{ {
if (xmlStrcmp (cur->name, (const xmlChar *)"entry") == 0) if (xmlStrcmp (cur->name, (const xmlChar *)"entry") == 0)
{ {
xmlChar *key; xmlChar *key;
xmlChar *value; xmlChar *value;
key = xmlGetProp (cur, (const xmlChar *)"key"); key = xmlGetProp (cur, (const xmlChar *)"key");
value = xmlGetProp (cur, (const xmlChar *)"value"); value = xmlGetProp (cur, (const xmlChar *)"value");
if ((key != NULL) && (value != NULL)) if ((key != NULL) && (value != NULL))
g_hash_table_insert (item->values, g_hash_table_insert (item->values,
g_strdup ((gchar *)key), g_strdup ((gchar *)key),
g_strdup ((gchar *)value)); g_strdup ((gchar *)value));
if (key != NULL) if (key != NULL)
xmlFree (key); xmlFree (key);
if (value != NULL) if (value != NULL)
xmlFree (value); xmlFree (value);
} }
cur = cur->next; cur = cur->next;
} }
g_hash_table_insert (xed_metadata_manager->items, g_hash_table_insert (xed_metadata_manager->items,
g_strdup ((gchar *)uri), g_strdup ((gchar *)uri),
item); item);
xmlFree (uri); xmlFree (uri);
xmlFree (atime); xmlFree (atime);
} }
static gboolean static gboolean
load_values (void) load_values (void)
{ {
xmlDocPtr doc; xmlDocPtr doc;
xmlNodePtr cur; xmlNodePtr cur;
xed_debug (DEBUG_METADATA); xed_debug (DEBUG_METADATA);
g_return_val_if_fail (xed_metadata_manager != NULL, FALSE); g_return_val_if_fail (xed_metadata_manager != NULL, FALSE);
g_return_val_if_fail (xed_metadata_manager->values_loaded == FALSE, FALSE); g_return_val_if_fail (xed_metadata_manager->values_loaded == FALSE, FALSE);
xed_metadata_manager->values_loaded = TRUE; xed_metadata_manager->values_loaded = TRUE;
xmlKeepBlanksDefault (0); xmlKeepBlanksDefault (0);
/* FIXME: file locking - Paolo */ /* FIXME: file locking - Paolo */
if ((xed_metadata_manager->metadata_filename == NULL) || if (xed_metadata_manager->metadata_filename == NULL)
(!g_file_test (xed_metadata_manager->metadata_filename, G_FILE_TEST_EXISTS))) {
{ return FALSE;
return FALSE; }
}
doc = xmlParseFile (xed_metadata_manager->metadata_filename); /* TODO: avoid races */
if (!g_file_test (xed_metadata_manager->metadata_filename, G_FILE_TEST_EXISTS))
{
return TRUE;
}
if (doc == NULL) doc = xmlParseFile (xed_metadata_manager->metadata_filename);
{
return FALSE;
}
cur = xmlDocGetRootElement (doc); if (doc == NULL)
if (cur == NULL) {
{ return FALSE;
g_message ("The metadata file '%s' is empty", g_path_get_basename (xed_metadata_manager->metadata_filename)); }
xmlFreeDoc (doc);
return FALSE; cur = xmlDocGetRootElement (doc);
} if (cur == NULL)
{
g_message ("The metadata file '%s' is empty", g_path_get_basename (xed_metadata_manager->metadata_filename));
xmlFreeDoc (doc);
if (xmlStrcmp (cur->name, (const xmlChar *) "metadata")) return TRUE;
{ }
g_message ("File '%s' is of the wrong type", g_path_get_basename (xed_metadata_manager->metadata_filename));
xmlFreeDoc (doc);
return FALSE; if (xmlStrcmp (cur->name, (const xmlChar *) "metadata"))
} {
g_message ("File '%s' is of the wrong type", g_path_get_basename (xed_metadata_manager->metadata_filename));
xmlFreeDoc (doc);
cur = xmlDocGetRootElement (doc); return FALSE;
cur = cur->xmlChildrenNode; }
while (cur != NULL) cur = xmlDocGetRootElement (doc);
{ cur = cur->xmlChildrenNode;
parseItem (doc, cur);
cur = cur->next; while (cur != NULL)
} {
parseItem (doc, cur);
xmlFreeDoc (doc); cur = cur->next;
}
return TRUE; xmlFreeDoc (doc);
return TRUE;
} }
/** /**
@ -298,48 +295,51 @@ load_values (void)
*/ */
gchar * gchar *
xed_metadata_manager_get (GFile *location, xed_metadata_manager_get (GFile *location,
const gchar *key) const gchar *key)
{ {
Item *item; Item *item;
gchar *value; gchar *value;
gchar *uri; gchar *uri;
g_return_val_if_fail (G_IS_FILE (location), NULL); g_return_val_if_fail (G_IS_FILE (location), NULL);
g_return_val_if_fail (key != NULL, NULL); g_return_val_if_fail (key != NULL, NULL);
uri = g_file_get_uri (location); uri = g_file_get_uri (location);
xed_debug_message (DEBUG_METADATA, "URI: %s --- key: %s", uri, key ); xed_debug_message (DEBUG_METADATA, "URI: %s --- key: %s", uri, key );
if (!xed_metadata_manager->values_loaded) if (!xed_metadata_manager->values_loaded)
{ {
gboolean res; gboolean res;
res = load_values (); res = load_values ();
if (!res) if (!res)
return NULL; {
} g_free (uri);
return NULL;
}
}
item = (Item *)g_hash_table_lookup (xed_metadata_manager->items, item = (Item *)g_hash_table_lookup (xed_metadata_manager->items,
uri); uri);
g_free (uri); g_free (uri);
if (item == NULL) if (item == NULL)
return NULL; return NULL;
item->atime = time (NULL); item->atime = g_get_real_time () / 1000;
if (item->values == NULL) if (item->values == NULL)
return NULL; return NULL;
value = g_hash_table_lookup (item->values, key); value = g_hash_table_lookup (item->values, key);
if (value == NULL) if (value == NULL)
return NULL; return NULL;
else else
return g_strdup (value); return g_strdup (value);
} }
/** /**
@ -352,219 +352,221 @@ xed_metadata_manager_get (GFile *location,
*/ */
void void
xed_metadata_manager_set (GFile *location, xed_metadata_manager_set (GFile *location,
const gchar *key, const gchar *key,
const gchar *value) const gchar *value)
{ {
Item *item; Item *item;
gchar *uri; gchar *uri;
g_return_if_fail (G_IS_FILE (location)); g_return_if_fail (G_IS_FILE (location));
g_return_if_fail (key != NULL); g_return_if_fail (key != NULL);
uri = g_file_get_uri (location); uri = g_file_get_uri (location);
xed_debug_message (DEBUG_METADATA, "URI: %s --- key: %s --- value: %s", uri, key, value); xed_debug_message (DEBUG_METADATA, "URI: %s --- key: %s --- value: %s", uri, key, value);
if (!xed_metadata_manager->values_loaded) if (!xed_metadata_manager->values_loaded)
{ {
gboolean res; gboolean ok;
res = load_values (); ok = load_values ();
if (!res) if (!ok)
return; {
} g_free (uri);
return;
}
}
item = (Item *)g_hash_table_lookup (xed_metadata_manager->items, item = (Item *)g_hash_table_lookup (xed_metadata_manager->items,
uri); uri);
if (item == NULL) if (item == NULL)
{ {
item = g_new0 (Item, 1); item = g_new0 (Item, 1);
g_hash_table_insert (xed_metadata_manager->items, g_hash_table_insert (xed_metadata_manager->items,
g_strdup (uri), g_strdup (uri),
item); item);
} }
if (item->values == NULL) if (item->values == NULL)
item->values = g_hash_table_new_full (g_str_hash, item->values = g_hash_table_new_full (g_str_hash,
g_str_equal, g_str_equal,
g_free, g_free,
g_free); g_free);
if (value != NULL) if (value != NULL)
g_hash_table_insert (item->values, g_hash_table_insert (item->values,
g_strdup (key), g_strdup (key),
g_strdup (value)); g_strdup (value));
else else
g_hash_table_remove (item->values, g_hash_table_remove (item->values,
key); key);
item->atime = time (NULL); item->atime = g_get_real_time () / 1000;
g_free (uri); g_free (uri);
xed_metadata_manager_arm_timeout (); xed_metadata_manager_arm_timeout ();
} }
static void static void
save_values (const gchar *key, const gchar *value, xmlNodePtr parent) save_values (const gchar *key, const gchar *value, xmlNodePtr parent)
{ {
xmlNodePtr xml_node; xmlNodePtr xml_node;
#ifdef XED_METADATA_VERBOSE_DEBUG #ifdef XED_METADATA_VERBOSE_DEBUG
xed_debug (DEBUG_METADATA); xed_debug (DEBUG_METADATA);
#endif #endif
g_return_if_fail (key != NULL); g_return_if_fail (key != NULL);
if (value == NULL) if (value == NULL)
return; return;
xml_node = xmlNewChild (parent, xml_node = xmlNewChild (parent,
NULL, NULL,
(const xmlChar *)"entry", (const xmlChar *)"entry",
NULL); NULL);
xmlSetProp (xml_node, xmlSetProp (xml_node,
(const xmlChar *)"key", (const xmlChar *)"key",
(const xmlChar *)key); (const xmlChar *)key);
xmlSetProp (xml_node, xmlSetProp (xml_node,
(const xmlChar *)"value", (const xmlChar *)"value",
(const xmlChar *)value); (const xmlChar *)value);
#ifdef XED_METADATA_VERBOSE_DEBUG #ifdef XED_METADATA_VERBOSE_DEBUG
xed_debug_message (DEBUG_METADATA, "entry: %s = %s", key, value); xed_debug_message (DEBUG_METADATA, "entry: %s = %s", key, value);
#endif #endif
} }
static void static void
save_item (const gchar *key, const gpointer *data, xmlNodePtr parent) save_item (const gchar *key, const gpointer *data, xmlNodePtr parent)
{ {
xmlNodePtr xml_node; xmlNodePtr xml_node;
const Item *item = (const Item *)data; const Item *item = (const Item *)data;
gchar *atime; gchar *atime;
#ifdef XED_METADATA_VERBOSE_DEBUG #ifdef XED_METADATA_VERBOSE_DEBUG
xed_debug (DEBUG_METADATA); xed_debug (DEBUG_METADATA);
#endif #endif
g_return_if_fail (key != NULL); g_return_if_fail (key != NULL);
if (item == NULL) if (item == NULL)
return; return;
xml_node = xmlNewChild (parent, NULL, (const xmlChar *)"document", NULL); xml_node = xmlNewChild (parent, NULL, (const xmlChar *)"document", NULL);
xmlSetProp (xml_node, (const xmlChar *)"uri", (const xmlChar *)key); xmlSetProp (xml_node, (const xmlChar *)"uri", (const xmlChar *)key);
#ifdef XED_METADATA_VERBOSE_DEBUG #ifdef XED_METADATA_VERBOSE_DEBUG
xed_debug_message (DEBUG_METADATA, "uri: %s", key); xed_debug_message (DEBUG_METADATA, "uri: %s", key);
#endif #endif
atime = g_strdup_printf ("%ld", item->atime); atime = g_strdup_printf ("%" G_GINT64_FORMAT, item->atime);
xmlSetProp (xml_node, (const xmlChar *)"atime", (const xmlChar *)atime); xmlSetProp (xml_node, (const xmlChar *)"atime", (const xmlChar *)atime);
#ifdef XED_METADATA_VERBOSE_DEBUG #ifdef XED_METADATA_VERBOSE_DEBUG
xed_debug_message (DEBUG_METADATA, "atime: %s", atime); xed_debug_message (DEBUG_METADATA, "atime: %s", atime);
#endif #endif
g_free (atime); g_free (atime);
g_hash_table_foreach (item->values, g_hash_table_foreach (item->values,
(GHFunc)save_values, (GHFunc)save_values,
xml_node); xml_node);
} }
static void static void
get_oldest (const gchar *key, const gpointer value, const gchar ** key_to_remove) get_oldest (const gchar *key, const gpointer value, const gchar ** key_to_remove)
{ {
const Item *item = (const Item *)value; const Item *item = (const Item *)value;
if (*key_to_remove == NULL) if (*key_to_remove == NULL)
{ {
*key_to_remove = key; *key_to_remove = key;
} }
else else
{ {
const Item *item_to_remove = const Item *item_to_remove =
g_hash_table_lookup (xed_metadata_manager->items, g_hash_table_lookup (xed_metadata_manager->items,
*key_to_remove); *key_to_remove);
g_return_if_fail (item_to_remove != NULL); g_return_if_fail (item_to_remove != NULL);
if (item->atime < item_to_remove->atime) if (item->atime < item_to_remove->atime)
{ {
*key_to_remove = key; *key_to_remove = key;
} }
} }
} }
static void static void
resize_items (void) resize_items (void)
{ {
while (g_hash_table_size (xed_metadata_manager->items) > MAX_ITEMS) while (g_hash_table_size (xed_metadata_manager->items) > MAX_ITEMS)
{ {
gpointer key_to_remove = NULL; gpointer key_to_remove = NULL;
g_hash_table_foreach (xed_metadata_manager->items, g_hash_table_foreach (xed_metadata_manager->items,
(GHFunc)get_oldest, (GHFunc)get_oldest,
&key_to_remove); &key_to_remove);
g_return_if_fail (key_to_remove != NULL); g_return_if_fail (key_to_remove != NULL);
g_hash_table_remove (xed_metadata_manager->items, g_hash_table_remove (xed_metadata_manager->items,
key_to_remove); key_to_remove);
} }
} }
static gboolean static gboolean
xed_metadata_manager_save (gpointer data) xed_metadata_manager_save (gpointer data)
{ {
xmlDocPtr doc; xmlDocPtr doc;
xmlNodePtr root; xmlNodePtr root;
xed_debug (DEBUG_METADATA); xed_debug (DEBUG_METADATA);
xed_metadata_manager->timeout_id = 0; xed_metadata_manager->timeout_id = 0;
resize_items (); resize_items ();
xmlIndentTreeOutput = TRUE; xmlIndentTreeOutput = TRUE;
doc = xmlNewDoc ((const xmlChar *)"1.0"); doc = xmlNewDoc ((const xmlChar *)"1.0");
if (doc == NULL) if (doc == NULL)
return TRUE; return TRUE;
/* Create metadata root */ /* Create metadata root */
root = xmlNewDocNode (doc, NULL, (const xmlChar *)"metadata", NULL); root = xmlNewDocNode (doc, NULL, (const xmlChar *)"metadata", NULL);
xmlDocSetRootElement (doc, root); xmlDocSetRootElement (doc, root);
g_hash_table_foreach (xed_metadata_manager->items, g_hash_table_foreach (xed_metadata_manager->items,
(GHFunc)save_item, (GHFunc)save_item,
root); root);
/* FIXME: lock file - Paolo */ /* FIXME: lock file - Paolo */
if (xed_metadata_manager->metadata_filename != NULL) if (xed_metadata_manager->metadata_filename != NULL)
{ {
gchar *cache_dir; gchar *cache_dir;
int res; int res;
/* make sure the cache dir exists */ /* make sure the cache dir exists */
cache_dir = g_path_get_dirname (xed_metadata_manager->metadata_filename); cache_dir = g_path_get_dirname (xed_metadata_manager->metadata_filename);
res = g_mkdir_with_parents (cache_dir, 0755); res = g_mkdir_with_parents (cache_dir, 0755);
if (res != -1) if (res != -1)
{ {
xmlSaveFormatFile (xed_metadata_manager->metadata_filename, doc, 1); xmlSaveFormatFile (xed_metadata_manager->metadata_filename, doc, 1);
} }
g_free (cache_dir); g_free (cache_dir);
} }
xmlFreeDoc (doc); xmlFreeDoc (doc);
xed_debug_message (DEBUG_METADATA, "DONE"); xed_debug_message (DEBUG_METADATA, "DONE");
return FALSE; return FALSE;
} }

View File

@ -30,7 +30,7 @@
#ifndef __XED_METADATA_MANAGER_H__ #ifndef __XED_METADATA_MANAGER_H__
#define __XED_METADATA_MANAGER_H__ #define __XED_METADATA_MANAGER_H__
#include <glib.h> #include <gio/gio.h>
G_BEGIN_DECLS G_BEGIN_DECLS

View File

@ -43,6 +43,8 @@
#include "xed-print-preview.h" #include "xed-print-preview.h"
#include "xed-progress-info-bar.h" #include "xed-progress-info-bar.h"
#include "xed-debug.h" #include "xed-debug.h"
#include "xed-document.h"
#include "xed-document-private.h"
#include "xed-enum-types.h" #include "xed-enum-types.h"
#include "xed-settings.h" #include "xed-settings.h"
#include "xed-view-frame.h" #include "xed-view-frame.h"
@ -1112,39 +1114,39 @@ view_focused_in (GtkWidget *widget,
XedTab *tab) XedTab *tab)
{ {
XedDocument *doc; XedDocument *doc;
GtkSourceFile *file;
g_return_val_if_fail (XED_IS_TAB (tab), FALSE); g_return_val_if_fail (XED_IS_TAB (tab), FALSE);
/* we try to detect file changes only in the normal state */ /* we try to detect file changes only in the normal state */
if (tab->priv->state != XED_TAB_STATE_NORMAL) if (tab->priv->state != XED_TAB_STATE_NORMAL)
{ {
return FALSE; return GDK_EVENT_PROPAGATE;
} }
/* we already asked, don't bug the user again */ /* we already asked, don't bug the user again */
if (!tab->priv->ask_if_externally_modified) if (!tab->priv->ask_if_externally_modified)
{ {
return FALSE; return GDK_EVENT_PROPAGATE;
} }
doc = xed_tab_get_document (tab); doc = xed_tab_get_document (tab);
file = xed_document_get_file (doc);
/* If file was never saved or is remote we do not check */ /* If file was never saved or is remote we do not check */
if (!xed_document_is_local (doc)) if (gtk_source_file_is_local (file))
{ {
return FALSE; gtk_source_file_check_file_on_disk (file);
if (gtk_source_file_is_externally_modified (file))
{
xed_tab_set_state (tab, XED_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION);
display_externally_modified_notification (tab);
}
} }
if (_xed_document_check_externally_modified (doc)) return GDK_EVENT_PROPAGATE;
{
xed_tab_set_state (tab, XED_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION);
display_externally_modified_notification (tab);
return FALSE;
}
return FALSE;
} }
static void static void

View File

@ -20,6 +20,8 @@
#include "xed-utils.h" #include "xed-utils.h"
#include "xed-commands.h" #include "xed-commands.h"
#include "xed-debug.h" #include "xed-debug.h"
#include "xed-document.h"
#include "xed-document-private.h"
#include "xed-panel.h" #include "xed-panel.h"
#include "xed-documents-panel.h" #include "xed-documents-panel.h"
#include "xed-plugins-engine.h" #include "xed-plugins-engine.h"