add "restore tab" action

Adds option to reopen closed tabs with Ctrl+Shift+T.

In order to do so, keep a list with data needed to restore closed
tabs. So, this list keeps the location bookmark, the view id before
search, which is needed in case the closed tab was a search and
the back/forward history.

https://bugzilla.gnome.org/show_bug.cgi?id=561136
This commit is contained in:
Alexandru Pandelea 2017-03-27 23:00:43 +03:00
parent e4e9eb83d5
commit 6e16bc32e8
5 changed files with 138 additions and 1 deletions

View file

@ -11,6 +11,9 @@ also owns those files.
Window slot is the creator of the file if the file was already not present due Window slot is the creator of the file if the file was already not present due
to be a bookmark. to be a bookmark.
The window has a queue with information of the closed tabs, owning references
to previous files.
= Directory Ownership = = Directory Ownership =
Every file has a directory associated, that is usually the parent. However, when Every file has a directory associated, that is usually the parent. However, when
the file is a root and has no parent, the file is called self_owned, and the directory the file is a root and has no parent, the file is called self_owned, and the directory

View file

@ -153,6 +153,54 @@ static void trash_state_changed_cb (NautilusTrashMonitor *monitor,
gboolean is_empty, gboolean is_empty,
gpointer user_data); gpointer user_data);
void
nautilus_window_slot_restore_from_data (NautilusWindowSlot *self,
RestoreTabData *data)
{
NautilusWindowSlotPrivate *priv;
priv = nautilus_window_slot_get_instance_private (self);
priv->back_list = g_list_copy_deep (data->back_list, (GCopyFunc) g_object_ref, NULL);
priv->forward_list = g_list_copy_deep (data->forward_list, (GCopyFunc) g_object_ref, NULL);
priv->view_mode_before_search = data->view_before_search;
priv->location_change_type = NAUTILUS_LOCATION_CHANGE_RELOAD;
}
RestoreTabData*
nautilus_window_slot_get_restore_tab_data (NautilusWindowSlot *self)
{
NautilusWindowSlotPrivate *priv;
RestoreTabData *data;
GList *back_list;
GList *forward_list;
priv = nautilus_window_slot_get_instance_private (self);
back_list = g_list_copy_deep (priv->back_list,
(GCopyFunc) g_object_ref,
NULL);
forward_list = g_list_copy_deep (priv->forward_list,
(GCopyFunc) g_object_ref,
NULL);
/* This data is used to restore a tab after it was closed.
* In order to do that we need to keep the history, what was
* the view mode before search and a reference to the file.
* A GFile isn't enough, as the NautilusFile also keeps a
* reference to the search directory */
data = g_new0 (RestoreTabData, 1);
data->back_list = back_list;
data->forward_list = forward_list;
data->file = nautilus_file_get (priv->location);
data->view_before_search = priv->view_mode_before_search;
return data;
}
gboolean gboolean
nautilus_window_slot_handles_location (NautilusWindowSlot *self, nautilus_window_slot_handles_location (NautilusWindowSlot *self,
GFile *location) GFile *location)
@ -204,7 +252,7 @@ real_get_view_for_location (NautilusWindowSlot *self,
/* If it's already set, is because we already made the change to search mode, /* If it's already set, is because we already made the change to search mode,
* so the view mode of the current view will be the one search is using, * so the view mode of the current view will be the one search is using,
* which is not the one we are interested in */ * which is not the one we are interested in */
if (priv->view_mode_before_search == NAUTILUS_VIEW_INVALID_ID) if (priv->view_mode_before_search == NAUTILUS_VIEW_INVALID_ID && priv->content_view)
{ {
priv->view_mode_before_search = nautilus_files_view_get_view_id (priv->content_view); priv->view_mode_before_search = nautilus_files_view_get_view_id (priv->content_view);
} }
@ -2170,8 +2218,10 @@ handle_go_elsewhere (NautilusWindowSlot *self,
NautilusWindowSlotPrivate *priv; NautilusWindowSlotPrivate *priv;
priv = nautilus_window_slot_get_instance_private (self); priv = nautilus_window_slot_get_instance_private (self);
/* Clobber the entire forward list, and move displayed location to back list */ /* Clobber the entire forward list, and move displayed location to back list */
nautilus_window_slot_clear_forward_list (self); nautilus_window_slot_clear_forward_list (self);
slot_location = nautilus_window_slot_get_location (self); slot_location = nautilus_window_slot_get_location (self);
if (slot_location != NULL) if (slot_location != NULL)

View file

@ -42,6 +42,13 @@ G_DECLARE_DERIVABLE_TYPE (NautilusWindowSlot, nautilus_window_slot, NAUTILUS, WI
#include "nautilus-window.h" #include "nautilus-window.h"
#include "nautilus-toolbar-menu-sections.h" #include "nautilus-toolbar-menu-sections.h"
typedef struct
{
NautilusFile *file;
gint view_before_search;
GList *back_list;
GList *forward_list;
} RestoreTabData;
struct _NautilusWindowSlotClass { struct _NautilusWindowSlotClass {
GtkBoxClass parent_class; GtkBoxClass parent_class;
@ -110,6 +117,11 @@ void nautilus_window_slot_search (NautilusWindowSlot *
gboolean nautilus_window_slot_handles_location (NautilusWindowSlot *self, gboolean nautilus_window_slot_handles_location (NautilusWindowSlot *self,
GFile *location); GFile *location);
void nautilus_window_slot_restore_from_data (NautilusWindowSlot *self,
RestoreTabData *data);
RestoreTabData* nautilus_window_slot_get_restore_tab_data (NautilusWindowSlot *self);
/* Only used by slot-dnd */ /* Only used by slot-dnd */
NautilusView* nautilus_window_slot_get_current_view (NautilusWindowSlot *slot); NautilusView* nautilus_window_slot_get_current_view (NautilusWindowSlot *slot);

View file

@ -81,6 +81,8 @@ static GtkWidget *nautilus_window_ensure_location_entry (NautilusWindow *window)
static void close_slot (NautilusWindow *window, static void close_slot (NautilusWindow *window,
NautilusWindowSlot *slot, NautilusWindowSlot *slot,
gboolean remove_from_notebook); gboolean remove_from_notebook);
static void free_restore_tab_data (gpointer data,
gpointer user_data);
/* Sanity check: highest mouse button value I could find was 14. 5 is our /* Sanity check: highest mouse button value I could find was 14. 5 is our
* lower threshold (well-documented to be the one of the button events for the * lower threshold (well-documented to be the one of the button events for the
@ -139,6 +141,8 @@ typedef struct
guint sidebar_width_handler_id; guint sidebar_width_handler_id;
guint bookmarks_id; guint bookmarks_id;
GQueue *tab_data_queue;
} NautilusWindowPrivate; } NautilusWindowPrivate;
enum enum
@ -1343,6 +1347,43 @@ should_show_format_command (GVolume *volume)
return show_format; return show_format;
} }
static void
action_restore_tab (GSimpleAction *action,
GVariant *state,
gpointer user_data)
{
NautilusWindowPrivate *priv;
NautilusWindow *window = NAUTILUS_WINDOW (user_data);
NautilusWindowOpenFlags flags;
g_autoptr (GFile) location = NULL;
NautilusWindowSlot *slot;
RestoreTabData *data;
priv = nautilus_window_get_instance_private (window);
if (g_queue_get_length (priv->tab_data_queue) == 0)
{
return;
}
flags = g_settings_get_enum (nautilus_preferences, NAUTILUS_PREFERENCES_NEW_TAB_POSITION);
flags |= NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB;
flags |= NAUTILUS_WINDOW_OPEN_FLAG_DONT_MAKE_ACTIVE;
data = g_queue_pop_head (priv->tab_data_queue);
location = nautilus_file_get_location (data->file);
slot = nautilus_window_create_slot (window, location);
nautilus_window_initialize_slot (window, slot, flags);
nautilus_window_slot_open_location_full (slot, location, flags, NULL);
nautilus_window_slot_restore_from_data (slot, data);
free_restore_tab_data (data, NULL);
}
static void static void
action_format (GSimpleAction *action, action_format (GSimpleAction *action,
GVariant *variant, GVariant *variant,
@ -1552,6 +1593,7 @@ nautilus_window_slot_close (NautilusWindow *window,
{ {
NautilusWindowPrivate *priv; NautilusWindowPrivate *priv;
NautilusWindowSlot *next_slot; NautilusWindowSlot *next_slot;
RestoreTabData *data;
DEBUG ("Requesting to remove slot %p from window %p", slot, window); DEBUG ("Requesting to remove slot %p from window %p", slot, window);
if (window == NULL) if (window == NULL)
@ -1567,6 +1609,9 @@ nautilus_window_slot_close (NautilusWindow *window,
nautilus_window_set_active_slot (window, next_slot); nautilus_window_set_active_slot (window, next_slot);
} }
data = nautilus_window_slot_get_restore_tab_data (slot);
g_queue_push_head (priv->tab_data_queue, data);
close_slot (window, slot, TRUE); close_slot (window, slot, TRUE);
/* If that was the last slot in the window, close the window. */ /* If that was the last slot in the window, close the window. */
@ -2244,6 +2289,7 @@ const GActionEntry win_entries[] =
{ "empty-trash", action_empty_trash }, { "empty-trash", action_empty_trash },
{ "properties", action_properties }, { "properties", action_properties },
{ "format", action_format }, { "format", action_format },
{ "restore-tab", action_restore_tab },
}; };
static void static void
@ -2289,6 +2335,7 @@ nautilus_window_initialize_actions (NautilusWindow *window)
nautilus_application_set_accelerator (app, "win.prompt-root-location", "slash"); nautilus_application_set_accelerator (app, "win.prompt-root-location", "slash");
nautilus_application_set_accelerator (app, "win.prompt-home-location", "asciitilde"); nautilus_application_set_accelerator (app, "win.prompt-home-location", "asciitilde");
nautilus_application_set_accelerator (app, "win.view-menu", "F10"); nautilus_application_set_accelerator (app, "win.view-menu", "F10");
nautilus_application_set_accelerator (app, "win.restore-tab", "<shift><control>t");
/* Alt+N for the first 9 tabs */ /* Alt+N for the first 9 tabs */
for (i = 0; i < 9; ++i) for (i = 0; i < 9; ++i)
@ -2477,6 +2524,19 @@ nautilus_window_destroy (GtkWidget *object)
GTK_WIDGET_CLASS (nautilus_window_parent_class)->destroy (object); GTK_WIDGET_CLASS (nautilus_window_parent_class)->destroy (object);
} }
static void
free_restore_tab_data (gpointer data,
gpointer user_data)
{
RestoreTabData *tab_data = data;
g_list_free_full (tab_data->back_list, g_object_unref);
g_list_free_full (tab_data->forward_list, g_object_unref);
nautilus_file_unref (tab_data->file);
g_free (tab_data);
}
static void static void
nautilus_window_finalize (GObject *object) nautilus_window_finalize (GObject *object)
{ {
@ -2511,6 +2571,9 @@ nautilus_window_finalize (GObject *object)
G_CALLBACK (nautilus_window_on_undo_changed), G_CALLBACK (nautilus_window_on_undo_changed),
window); window);
g_queue_foreach (priv->tab_data_queue, (GFunc) free_restore_tab_data, NULL);
g_queue_free (priv->tab_data_queue);
/* nautilus_window_close() should have run */ /* nautilus_window_close() should have run */
g_assert (priv->slots == NULL); g_assert (priv->slots == NULL);
@ -2840,6 +2903,8 @@ nautilus_window_init (NautilusWindow *window)
window_group = gtk_window_group_new (); window_group = gtk_window_group_new ();
gtk_window_group_add_window (window_group, GTK_WINDOW (window)); gtk_window_group_add_window (window_group, GTK_WINDOW (window));
g_object_unref (window_group); g_object_unref (window_group);
priv->tab_data_queue = g_queue_new();
} }
static void static void

View file

@ -149,6 +149,13 @@
<property name="accelerator">&lt;shift&gt;&lt;Primary&gt;Page_Down</property> <property name="accelerator">&lt;shift&gt;&lt;Primary&gt;Page_Down</property>
</object> </object>
</child> </child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">True</property>
<property name="title" translatable="yes" context="shortcut window">Restore tab</property>
<property name="accelerator">&lt;shift&gt;&lt;Primary&gt;T</property>
</object>
</child>
</object> </object>
</child> </child>
<child> <child>