places-view: implement a view for Other Locations

GtkFileChooser received a Other Locations view that lists
persistent devices, as well as networks and the root location
for the computer's hard drive.

Since Nautilus is a file management tool too, it should keep
consistency between Gtk+ file chooser, something that doesn't
happen since it doesn't display Other Locations.

To fix that, add NautilusPlacesView, a NautilusView implementation
that displays the GtkPlacesView widget. In order to implement that,
update window-slot to correctly display the places-view whenever
Other Locations is clicked.

https://bugzilla.gnome.org/show_bug.cgi?id=753871
This commit is contained in:
Georges Basile Stavracas Neto 2015-08-18 15:23:02 -03:00
parent abef8cac2f
commit 404f1492db
20 changed files with 3956 additions and 111 deletions

View file

@ -103,7 +103,9 @@ bookmark_set_name_from_ready_file (NautilusBookmark *self,
display_name = nautilus_file_get_display_name (self->details->file);
if (nautilus_file_is_home (self->details->file)) {
if (nautilus_file_is_other_locations (self->details->file)) {
nautilus_bookmark_set_name_internal (self, _("Other Locations"));
} else if (nautilus_file_is_home (self->details->file)) {
nautilus_bookmark_set_name_internal (self, _("Home"));
} else if (g_strcmp0 (self->details->name, display_name) != 0) {
nautilus_bookmark_set_name_internal (self, display_name);

View file

@ -268,10 +268,16 @@ nautilus_compute_title_for_location (GFile *location)
title = NULL;
if (location) {
file = nautilus_file_get (location);
title = nautilus_file_get_description (file);
if (title == NULL) {
title = nautilus_file_get_display_name (file);
}
if (nautilus_file_is_other_locations (file)) {
title = g_strdup (_("Other Locations"));
} else {
title = nautilus_file_get_description (file);
if (title == NULL) {
title = nautilus_file_get_display_name (file);
}
}
nautilus_file_unref (file);
}

View file

@ -7015,6 +7015,31 @@ nautilus_file_is_in_network (NautilusFile *file)
return nautilus_directory_is_in_network (file->details->directory);
}
/**
* nautilus_file_is_other_locations
*
* Check if this file is Other Locations.
* @file: NautilusFile representing the file in question.
*
* Returns: TRUE if @file is Other Locations.
*
**/
gboolean
nautilus_file_is_other_locations (NautilusFile *file)
{
gboolean is_other_locations;
gchar *uri;
g_assert (NAUTILUS_IS_FILE (file));
uri = nautilus_file_get_uri (file);
is_other_locations = g_strcmp0 (uri, "other-locations:///") == 0;
g_free (uri);
return is_other_locations;
}
GError *
nautilus_file_get_file_info_error (NautilusFile *file)
{

View file

@ -191,6 +191,7 @@ gboolean nautilus_file_is_in_search (Nautilu
gboolean nautilus_file_is_in_trash (NautilusFile *file);
gboolean nautilus_file_is_in_recent (NautilusFile *file);
gboolean nautilus_file_is_in_network (NautilusFile *file);
gboolean nautilus_file_is_other_locations (NautilusFile *file);
gboolean nautilus_file_is_home (NautilusFile *file);
gboolean nautilus_file_is_desktop_directory (NautilusFile *file);
GError * nautilus_file_get_file_info_error (NautilusFile *file);

View file

@ -139,6 +139,10 @@ nautilus_built_sources = \
$(NULL)
nautilus_SOURCES = \
gtk/gtkplacesview.c \
gtk/gtkplacesviewprivate.h \
gtk/gtkplacesviewrow.c \
gtk/gtkplacesviewrowprivate.h \
nautilus-application.c \
nautilus-application.h \
nautilus-application-actions.c \
@ -189,6 +193,8 @@ nautilus_SOURCES = \
nautilus-notebook.h \
nautilus-pathbar.c \
nautilus-pathbar.h \
nautilus-places-view.c \
nautilus-places-view.h \
nautilus-previewer.c \
nautilus-previewer.h \
nautilus-progress-info-widget.c \

2436
src/gtk/gtkplacesview.c Normal file

File diff suppressed because it is too large Load diff

332
src/gtk/gtkplacesview.ui Normal file
View file

@ -0,0 +1,332 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="gtk30">
<requires lib="gtk+" version="3.16"/>
<object class="GtkListStore" id="completion_store">
<columns>
<!-- column-name name -->
<column type="gchararray"/>
<!-- column-name uri -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkEntryCompletion" id="address_entry_completion">
<property name="model">completion_store</property>
<property name="minimum_key_length">1</property>
<property name="text_column">1</property>
<property name="inline_completion">True</property>
<property name="popup_completion">False</property>
</object>
<object class="GtkPopover" id="recent_servers_popover">
<child>
<object class="GtkStack" id="recent_servers_stack">
<property name="visible">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="vexpand">True</property>
<property name="valign">center</property>
<property name="orientation">vertical</property>
<property name="spacing">18</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixel-size">48</property>
<property name="icon_name">network-server-symbolic</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes" comments="Translators: Server as any successfully connected network address">No recent servers found</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="name">empty</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="border_width">12</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Recent Servers</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="vexpand">True</property>
<property name="shadow_type">in</property>
<property name="min_content_width">250</property>
<property name="min_content_height">150</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkListBox" id="recent_servers_listbox">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="selection_mode">none</property>
<signal name="row-activated" handler="on_recent_servers_listbox_row_activated" object="GtkPlacesView" swapped="yes" />
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="name">list</property>
</packing>
</child>
</object>
</child>
</object>
<template class="GtkPlacesView" parent="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<signal name="key-press-event" handler="on_key_press_event" object="GtkPlacesView" swapped="no" />
<child>
<object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="vhomogeneous">False</property>
<property name="transition_type">crossfade</property>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkListBox" id="listbox">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="selection_mode">none</property>
<signal name="row-activated" handler="on_listbox_row_activated" object="GtkPlacesView" swapped="yes" />
</object>
</child>
<style>
<class name="view"/>
</style>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="name">browse</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixel_size">72</property>
<property name="icon_name">edit-find-symbolic</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">No results found</property>
<attributes>
<attribute name="weight" value="bold"/>
<attribute name="scale" value="1.44"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Try a different search</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="name">empty-search</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkActionBar" id="actionbar">
<property name="visible">True</property>
<property name="hexpand">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="hexpand">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Connect to _Server</property>
<property name="mnemonic_widget">address_entry</property>
<property name="use_underline">True</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
</child>
<child>
<object class="GtkButton" id="connect_button">
<property name="label" translatable="yes">Con_nect</property>
<property name="use_underline">True</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="sensitive">False</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_connect_button_clicked" object="GtkPlacesView" swapped="yes" />
</object>
<packing>
<property name="pack_type">end</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="hexpand">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkEntry" id="address_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="width_chars">20</property>
<property name="placeholder_text" translatable="yes">Enter server address…</property>
<property name="completion">address_entry_completion</property>
<signal name="notify::text" handler="on_address_entry_text_changed" object="GtkPlacesView" swapped="yes" />
<signal name="activate" handler="on_connect_button_clicked" object="GtkPlacesView" swapped="yes" />
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<object class="GtkMenuButton" id="server_list_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="direction">up</property>
<property name="popover">recent_servers_popover</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">pan-up-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
</packing>
</child>
<style>
<class name="linked"/>
</style>
</object>
<packing>
<property name="pack_type">end</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</template>
</interface>

View file

@ -0,0 +1,91 @@
/* gtkplacesview.h
*
* Copyright (C) 2015 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GTK_PLACES_VIEW_H
#define GTK_PLACES_VIEW_H
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GTK_TYPE_PLACES_VIEW (gtk_places_view_get_type ())
#define GTK_PLACES_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PLACES_VIEW, GtkPlacesView))
#define GTK_PLACES_VIEW_CLASS(klass)(G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PLACES_VIEW, GtkPlacesViewClass))
#define GTK_IS_PLACES_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PLACES_VIEW))
#define GTK_IS_PLACES_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PLACES_VIEW))
#define GTK_PLACES_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PLACES_VIEW, GtkPlacesViewClass))
typedef struct _GtkPlacesView GtkPlacesView;
typedef struct _GtkPlacesViewClass GtkPlacesViewClass;
typedef struct _GtkPlacesViewPrivate GtkPlacesViewPrivate;
struct _GtkPlacesViewClass
{
GtkBoxClass parent_class;
void (* open_location) (GtkPlacesView *view,
GFile *location,
GtkPlacesOpenFlags open_flags);
void (* show_error_message) (GtkPlacesSidebar *sidebar,
const gchar *primary,
const gchar *secondary);
/*< private >*/
/* Padding for future expansion */
gpointer reserved[10];
};
struct _GtkPlacesView
{
GtkBox parent_instance;
};
GDK_AVAILABLE_IN_3_18
GType gtk_places_view_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_18
GtkPlacesOpenFlags gtk_places_view_get_open_flags (GtkPlacesView *view);
GDK_AVAILABLE_IN_3_18
void gtk_places_view_set_open_flags (GtkPlacesView *view,
GtkPlacesOpenFlags flags);
GDK_AVAILABLE_IN_3_18
const gchar* gtk_places_view_get_search_query (GtkPlacesView *view);
GDK_AVAILABLE_IN_3_18
void gtk_places_view_set_search_query (GtkPlacesView *view,
const gchar *query_text);
GDK_AVAILABLE_IN_3_18
gboolean gtk_places_view_get_local_only (GtkPlacesView *view);
GDK_AVAILABLE_IN_3_18
void gtk_places_view_set_local_only (GtkPlacesView *view,
gboolean local_only);
GDK_AVAILABLE_IN_3_18
gboolean gtk_places_view_get_loading (GtkPlacesView *view);
GDK_AVAILABLE_IN_3_18
GtkWidget * gtk_places_view_new (void);
G_END_DECLS
#endif /* GTK_PLACES_VIEW_H */

326
src/gtk/gtkplacesviewrow.c Normal file
View file

@ -0,0 +1,326 @@
/* gtkplacesviewrow.c
*
* Copyright (C) 2015 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <glib/gi18n.h>
#include <gio/gio.h>
#include <gtk/gtk.h>
#include "gtkplacesviewrowprivate.h"
struct _GtkPlacesViewRow
{
GtkListBoxRow parent_instance;
GtkSpinner *busy_spinner;
GtkButton *eject_button;
GtkImage *eject_icon;
GtkEventBox *event_box;
GtkImage *icon_image;
GtkLabel *name_label;
GtkLabel *path_label;
GVolume *volume;
GMount *mount;
GFile *file;
gint is_network : 1;
};
G_DEFINE_TYPE (GtkPlacesViewRow, gtk_places_view_row, GTK_TYPE_LIST_BOX_ROW)
enum {
PROP_0,
PROP_ICON,
PROP_NAME,
PROP_PATH,
PROP_VOLUME,
PROP_MOUNT,
PROP_FILE,
PROP_IS_NETWORK,
LAST_PROP
};
static GParamSpec *properties [LAST_PROP];
static void
gtk_places_view_row_finalize (GObject *object)
{
GtkPlacesViewRow *self = GTK_PLACES_VIEW_ROW (object);
g_clear_object (&self->volume);
g_clear_object (&self->mount);
g_clear_object (&self->file);
G_OBJECT_CLASS (gtk_places_view_row_parent_class)->finalize (object);
}
static void
gtk_places_view_row_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkPlacesViewRow *self;
GIcon *icon;
self = GTK_PLACES_VIEW_ROW (object);
icon = NULL;
switch (prop_id)
{
case PROP_ICON:
gtk_image_get_gicon (self->icon_image, &icon, NULL);
g_value_set_object (value, icon);
break;
case PROP_NAME:
g_value_set_string (value, gtk_label_get_label (self->name_label));
break;
case PROP_PATH:
g_value_set_string (value, gtk_label_get_label (self->path_label));
break;
case PROP_VOLUME:
g_value_set_object (value, self->volume);
break;
case PROP_MOUNT:
g_value_set_object (value, self->mount);
break;
case PROP_FILE:
g_value_set_object (value, self->file);
break;
case PROP_IS_NETWORK:
g_value_set_boolean (value, self->is_network);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_places_view_row_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkPlacesViewRow *self = GTK_PLACES_VIEW_ROW (object);
switch (prop_id)
{
case PROP_ICON:
gtk_image_set_from_gicon (self->icon_image,
g_value_get_object (value),
GTK_ICON_SIZE_LARGE_TOOLBAR);
break;
case PROP_NAME:
gtk_label_set_label (self->name_label, g_value_get_string (value));
break;
case PROP_PATH:
gtk_label_set_label (self->path_label, g_value_get_string (value));
break;
case PROP_VOLUME:
g_set_object (&self->volume, g_value_get_object (value));
break;
case PROP_MOUNT:
g_set_object (&self->mount, g_value_get_object (value));
gtk_widget_set_visible (GTK_WIDGET (self->eject_button), self->mount != NULL);
break;
case PROP_FILE:
g_set_object (&self->file, g_value_get_object (value));
break;
case PROP_IS_NETWORK:
gtk_places_view_row_set_is_network (self, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_places_view_row_class_init (GtkPlacesViewRowClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = gtk_places_view_row_finalize;
object_class->get_property = gtk_places_view_row_get_property;
object_class->set_property = gtk_places_view_row_set_property;
properties[PROP_ICON] =
g_param_spec_object ("icon",
_("Icon of the row"),
_("The icon representing the volume"),
G_TYPE_ICON,
G_PARAM_READWRITE);
properties[PROP_NAME] =
g_param_spec_string ("name",
_("Name of the volume"),
_("The name of the volume"),
"",
G_PARAM_READWRITE);
properties[PROP_PATH] =
g_param_spec_string ("path",
_("Path of the volume"),
_("The path of the volume"),
"",
G_PARAM_READWRITE);
properties[PROP_VOLUME] =
g_param_spec_object ("volume",
_("Volume represented by the row"),
_("The volume represented by the row"),
G_TYPE_VOLUME,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_MOUNT] =
g_param_spec_object ("mount",
_("Mount represented by the row"),
_("The mount point represented by the row, if any"),
G_TYPE_MOUNT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_FILE] =
g_param_spec_object ("file",
_("File represented by the row"),
_("The file represented by the row, if any"),
G_TYPE_FILE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_IS_NETWORK] =
g_param_spec_boolean ("is-network",
_("Whether the row represents a network location"),
_("Whether the row represents a network location"),
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, LAST_PROP, properties);
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/nautilus/gtk/gtkplacesviewrow.ui");
gtk_widget_class_bind_template_child (widget_class, GtkPlacesViewRow, busy_spinner);
gtk_widget_class_bind_template_child (widget_class, GtkPlacesViewRow, eject_button);
gtk_widget_class_bind_template_child (widget_class, GtkPlacesViewRow, eject_icon);
gtk_widget_class_bind_template_child (widget_class, GtkPlacesViewRow, event_box);
gtk_widget_class_bind_template_child (widget_class, GtkPlacesViewRow, icon_image);
gtk_widget_class_bind_template_child (widget_class, GtkPlacesViewRow, name_label);
gtk_widget_class_bind_template_child (widget_class, GtkPlacesViewRow, path_label);
}
static void
gtk_places_view_row_init (GtkPlacesViewRow *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
}
GtkWidget*
gtk_places_view_row_new (GVolume *volume,
GMount *mount)
{
return g_object_new (GTK_TYPE_PLACES_VIEW_ROW,
"volume", volume,
"mount", mount,
NULL);
}
GMount*
gtk_places_view_row_get_mount (GtkPlacesViewRow *row)
{
g_return_val_if_fail (GTK_IS_PLACES_VIEW_ROW (row), NULL);
return row->mount;
}
GVolume*
gtk_places_view_row_get_volume (GtkPlacesViewRow *row)
{
g_return_val_if_fail (GTK_IS_PLACES_VIEW_ROW (row), NULL);
return row->volume;
}
GFile*
gtk_places_view_row_get_file (GtkPlacesViewRow *row)
{
g_return_val_if_fail (GTK_IS_PLACES_VIEW_ROW (row), NULL);
return row->file;
}
GtkWidget*
gtk_places_view_row_get_eject_button (GtkPlacesViewRow *row)
{
g_return_val_if_fail (GTK_IS_PLACES_VIEW_ROW (row), NULL);
return GTK_WIDGET (row->eject_button);
}
GtkWidget*
gtk_places_view_row_get_event_box (GtkPlacesViewRow *row)
{
g_return_val_if_fail (GTK_IS_PLACES_VIEW_ROW (row), NULL);
return GTK_WIDGET (row->event_box);
}
void
gtk_places_view_row_set_busy (GtkPlacesViewRow *row,
gboolean is_busy)
{
g_return_if_fail (GTK_IS_PLACES_VIEW_ROW (row));
gtk_widget_set_visible (GTK_WIDGET (row->busy_spinner), is_busy);
}
gboolean
gtk_places_view_row_get_is_network (GtkPlacesViewRow *row)
{
g_return_val_if_fail (GTK_IS_PLACES_VIEW_ROW (row), FALSE);
return row->is_network;
}
void
gtk_places_view_row_set_is_network (GtkPlacesViewRow *row,
gboolean is_network)
{
if (row->is_network != is_network)
{
row->is_network = is_network;
gtk_image_set_from_icon_name (row->eject_icon,
is_network ? "network-offline-symbolic" : "media-eject-symbolic",
GTK_ICON_SIZE_BUTTON);
gtk_widget_set_tooltip_text (GTK_WIDGET (row->eject_button), is_network ? _("Disconnect") : _("Unmount"));
}
}

109
src/gtk/gtkplacesviewrow.ui Normal file
View file

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="gtk30">
<requires lib="gtk+" version="3.16"/>
<template class="GtkPlacesViewRow" parent="GtkListBoxRow">
<property name="width_request">100</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<style>
<class name="volume-row" />
</style>
<child>
<object class="GtkEventBox" id="event_box">
<property name="visible">True</property>
<child>
<object class="GtkBox" id="box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_start">12</property>
<property name="margin_end">12</property>
<property name="margin_top">6</property>
<property name="margin_bottom">6</property>
<property name="border_width">0</property>
<property name="spacing">18</property>
<child>
<object class="GtkImage" id="icon_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixel_size">32</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="name_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="path_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="justify">right</property>
<property name="ellipsize">middle</property>
<property name="xalign">1</property>
<property name="width_chars">15</property>
<property name="max_width_chars">15</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="eject_button">
<property name="visible">False</property>
<property name="halign">end</property>
<property name="valign">center</property>
<property name="tooltip-text" translatable="yes">Unmount</property>
<child>
<object class="GtkImage" id="eject_icon">
<property name="visible">True</property>
<property name="icon_name">media-eject-symbolic</property>
<property name="icon_size">1</property>
</object>
</child>
<style>
<class name="image-button"/>
<class name="sidebar-button"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkSpinner" id="busy_spinner">
<property name="visible">False</property>
<property name="can_focus">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>

View file

@ -0,0 +1,53 @@
/* gtkplacesviewrow.h
*
* Copyright (C) 2015 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GTK_PLACES_VIEW_ROW_H
#define GTK_PLACES_VIEW_ROW_H
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GTK_TYPE_PLACES_VIEW_ROW (gtk_places_view_row_get_type())
G_DECLARE_FINAL_TYPE (GtkPlacesViewRow, gtk_places_view_row, GTK, PLACES_VIEW_ROW, GtkListBoxRow)
GtkWidget* gtk_places_view_row_new (GVolume *volume,
GMount *mount);
GtkWidget* gtk_places_view_row_get_eject_button (GtkPlacesViewRow *row);
GtkWidget* gtk_places_view_row_get_event_box (GtkPlacesViewRow *row);
GMount* gtk_places_view_row_get_mount (GtkPlacesViewRow *row);
GVolume* gtk_places_view_row_get_volume (GtkPlacesViewRow *row);
GFile* gtk_places_view_row_get_file (GtkPlacesViewRow *row);
void gtk_places_view_row_set_busy (GtkPlacesViewRow *row,
gboolean is_busy);
gboolean gtk_places_view_row_get_is_network (GtkPlacesViewRow *row);
void gtk_places_view_row_set_is_network (GtkPlacesViewRow *row,
gboolean is_network);
G_END_DECLS
#endif /* GTK_PLACES_VIEW_ROW_H */

View file

@ -389,7 +389,7 @@ get_window_slot_for_location (NautilusApplication *application, GFile *location)
slot = NULL;
file = nautilus_file_get (location);
if (!nautilus_file_is_directory (file)) {
if (!nautilus_file_is_directory (file) && !nautilus_file_is_other_locations (file)) {
location = g_file_get_parent (location);
} else {
g_object_ref (location);

View file

@ -43,6 +43,7 @@ enum {
typedef enum {
NORMAL_BUTTON,
OTHER_LOCATIONS_BUTTON,
ROOT_BUTTON,
HOME_BUTTON,
MOUNT_BUTTON
@ -400,11 +401,14 @@ nautilus_path_bar_dispose (GObject *object)
static const char *
get_dir_name (ButtonData *button_data)
{
if (button_data->type == HOME_BUTTON) {
return _("Home");
} else {
return button_data->dir_name;
}
switch (button_data->type) {
case HOME_BUTTON:
return _("Home");
case OTHER_LOCATIONS_BUTTON:
return _("Other Locations");
default:
return button_data->dir_name;
}
}
/* We always want to request the same size for the label, whether
@ -1629,8 +1633,13 @@ setup_button_type (ButtonData *button_data,
GFile *location)
{
GMount *mount;
gchar *uri;
if (nautilus_is_root_directory (location)) {
uri = g_file_get_uri (location);
if (g_strcmp0 (uri, "other-locations:///") == 0) {
button_data->type = OTHER_LOCATIONS_BUTTON;
} else if (nautilus_is_root_directory (location)) {
button_data->type = ROOT_BUTTON;
} else if (nautilus_is_home_directory (location)) {
button_data->type = HOME_BUTTON;
@ -1644,6 +1653,8 @@ setup_button_type (ButtonData *button_data,
} else {
button_data->type = NORMAL_BUTTON;
}
g_free (uri);
}
static void

359
src/nautilus-places-view.c Normal file
View file

@ -0,0 +1,359 @@
/* nautilus-places-view.c
*
* Copyright (C) 2015 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nautilus-mime-actions.h"
#include "nautilus-places-view.h"
#include "nautilus-window-slot.h"
#include "gtk/gtkplacesviewprivate.h"
typedef struct
{
GFile *location;
GIcon *icon;
NautilusQuery *search_query;
GtkWidget *places_view;
} NautilusPlacesViewPrivate;
struct _NautilusPlacesView
{
GtkFrameClass parent;
};
static void nautilus_places_view_iface_init (NautilusViewInterface *iface);
G_DEFINE_TYPE_WITH_CODE (NautilusPlacesView, nautilus_places_view, GTK_TYPE_BOX,
G_ADD_PRIVATE (NautilusPlacesView)
G_IMPLEMENT_INTERFACE (NAUTILUS_TYPE_VIEW, nautilus_places_view_iface_init));
enum {
PROP_0,
PROP_ICON,
PROP_LOCATION,
PROP_SEARCH_QUERY,
PROP_VIEW_WIDGET,
PROP_IS_LOADING,
PROP_IS_SEARCHING,
LAST_PROP
};
static void
open_location_cb (NautilusPlacesView *view,
GFile *location,
GtkPlacesOpenFlags open_flags)
{
NautilusWindowOpenFlags flags;
GtkWidget *slot;
slot = gtk_widget_get_ancestor (GTK_WIDGET (view), NAUTILUS_TYPE_WINDOW_SLOT);
switch (open_flags) {
case GTK_PLACES_OPEN_NEW_TAB:
flags = NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB;
break;
case GTK_PLACES_OPEN_NEW_WINDOW:
flags = NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW;
break;
case GTK_PLACES_OPEN_NORMAL: /* fall-through */
default:
flags = 0;
break;
}
if (slot) {
NautilusFile *file;
GtkWidget *window;
char *path;
path = "other-locations:///";
file = nautilus_file_get (location);
window = gtk_widget_get_toplevel (GTK_WIDGET (view));
nautilus_mime_activate_file (GTK_WINDOW (window),
NAUTILUS_WINDOW_SLOT (slot),
file,
path,
flags);
}
}
static void
loading_cb (NautilusView *view)
{
g_object_notify (G_OBJECT (view), "is-loading");
}
static void
nautilus_places_view_finalize (GObject *object)
{
NautilusPlacesView *self = (NautilusPlacesView *)object;
NautilusPlacesViewPrivate *priv = nautilus_places_view_get_instance_private (self);
g_clear_object (&priv->icon);
g_clear_object (&priv->location);
g_clear_object (&priv->search_query);
G_OBJECT_CLASS (nautilus_places_view_parent_class)->finalize (object);
}
static void
nautilus_places_view_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
NautilusView *view = NAUTILUS_VIEW (object);
switch (prop_id) {
case PROP_ICON:
g_value_set_object (value, nautilus_view_get_icon (view));
break;
case PROP_LOCATION:
g_value_set_object (value, nautilus_view_get_location (view));
break;
case PROP_SEARCH_QUERY:
g_value_set_object (value, nautilus_view_get_search_query (view));
break;
case PROP_VIEW_WIDGET:
g_value_set_object (value, nautilus_view_get_view_widget (view));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
nautilus_places_view_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
NautilusView *view = NAUTILUS_VIEW (object);
switch (prop_id) {
case PROP_LOCATION:
nautilus_view_set_location (view, g_value_get_object (value));
break;
case PROP_SEARCH_QUERY:
nautilus_view_set_search_query (view, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static GIcon*
nautilus_places_view_get_icon (NautilusView *view)
{
NautilusPlacesViewPrivate *priv;
priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
return priv->icon;
}
static GFile*
nautilus_places_view_get_location (NautilusView *view)
{
NautilusPlacesViewPrivate *priv;
priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
return priv->location;
}
static void
nautilus_places_view_set_location (NautilusView *view,
GFile *location)
{
if (location) {
NautilusPlacesViewPrivate *priv;
gchar *uri;
priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
uri = g_file_get_uri (location);
/*
* If it's not trying to open the places view itself, simply
* delegates the location to window-slot, which takes care of
* selecting the appropriate view.
*/
if (!g_strcmp0 (uri, "other-locations:///") == 0) {
GtkWidget *slot;
slot = gtk_widget_get_ancestor (GTK_WIDGET (view), NAUTILUS_TYPE_WINDOW_SLOT);
g_assert (slot != NULL);
nautilus_window_slot_open_location (NAUTILUS_WINDOW_SLOT (slot), location, 0);
} else {
g_set_object (&priv->location, location);
}
g_free (uri);
}
}
static GList*
nautilus_places_view_get_selection (NautilusView *view)
{
/* STUB */
return NULL;
}
static void
nautilus_places_view_set_selection (NautilusView *view,
GList *selection)
{
/* STUB */
}
static NautilusQuery*
nautilus_places_view_get_search_query (NautilusView *view)
{
NautilusPlacesViewPrivate *priv;
priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
return priv->search_query;
}
static void
nautilus_places_view_set_search_query (NautilusView *view,
NautilusQuery *query)
{
NautilusPlacesViewPrivate *priv;
gchar *text;
priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
g_set_object (&priv->search_query, query);
text = query ? nautilus_query_get_text (query) : NULL;
gtk_places_view_set_search_query (GTK_PLACES_VIEW (priv->places_view), text);
g_free (text);
}
static GtkWidget*
nautilus_places_view_get_view_widget (NautilusView *view)
{
/* By returning NULL, the view menu button turns insensitive */
return NULL;
}
static gboolean
nautilus_places_view_is_loading (NautilusView *view)
{
NautilusPlacesViewPrivate *priv;
priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
return gtk_places_view_get_loading (GTK_PLACES_VIEW (priv->places_view));
}
static gboolean
nautilus_places_view_is_searching (NautilusView *view)
{
NautilusPlacesViewPrivate *priv;
priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
return priv->search_query != NULL;
}
static void
nautilus_places_view_iface_init (NautilusViewInterface *iface)
{
iface->get_icon = nautilus_places_view_get_icon;
iface->get_location = nautilus_places_view_get_location;
iface->set_location = nautilus_places_view_set_location;
iface->get_selection = nautilus_places_view_get_selection;
iface->set_selection = nautilus_places_view_set_selection;
iface->get_search_query = nautilus_places_view_get_search_query;
iface->set_search_query = nautilus_places_view_set_search_query;
iface->get_view_widget = nautilus_places_view_get_view_widget;
iface->is_loading = nautilus_places_view_is_loading;
iface->is_searching = nautilus_places_view_is_searching;
}
static void
nautilus_places_view_class_init (NautilusPlacesViewClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = nautilus_places_view_finalize;
object_class->get_property = nautilus_places_view_get_property;
object_class->set_property = nautilus_places_view_set_property;
g_object_class_override_property (object_class, PROP_ICON, "icon");
g_object_class_override_property (object_class, PROP_IS_LOADING, "is-loading");
g_object_class_override_property (object_class, PROP_IS_SEARCHING, "is-searching");
g_object_class_override_property (object_class, PROP_LOCATION, "location");
g_object_class_override_property (object_class, PROP_SEARCH_QUERY, "search-query");
g_object_class_override_property (object_class, PROP_VIEW_WIDGET, "view-widget");
}
static void
nautilus_places_view_init (NautilusPlacesView *self)
{
NautilusPlacesViewPrivate *priv;
priv = nautilus_places_view_get_instance_private (self);
/* Icon */
priv->icon = g_themed_icon_new_with_default_fallbacks ("view-list-symbolic");
/* Location */
priv->location = g_file_new_for_uri ("other-locations:///");
/* Places view */
priv->places_view = gtk_places_view_new ();
gtk_places_view_set_open_flags (GTK_PLACES_VIEW (priv->places_view),
GTK_PLACES_OPEN_NEW_TAB | GTK_PLACES_OPEN_NEW_WINDOW | GTK_PLACES_OPEN_NORMAL);
gtk_widget_set_hexpand (priv->places_view, TRUE);
gtk_widget_set_vexpand (priv->places_view, TRUE);
gtk_widget_show (priv->places_view);
gtk_container_add (GTK_CONTAINER (self), priv->places_view);
g_signal_connect_swapped (priv->places_view,
"notify::loading",
G_CALLBACK (loading_cb),
self);
g_signal_connect_swapped (priv->places_view,
"open-location",
G_CALLBACK (open_location_cb),
self);
}
NautilusPlacesView *
nautilus_places_view_new (void)
{
return g_object_new (NAUTILUS_TYPE_PLACES_VIEW, NULL);
}

View file

@ -0,0 +1,37 @@
/* nautilus-places-view.h
*
* Copyright (C) 2015 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NAUTILUS_PLACES_VIEW_H
#define NAUTILUS_PLACES_VIEW_H
#include <glib.h>
#include <gtk/gtk.h>
#include "nautilus-view.h"
G_BEGIN_DECLS
#define NAUTILUS_TYPE_PLACES_VIEW (nautilus_places_view_get_type())
G_DECLARE_FINAL_TYPE (NautilusPlacesView, nautilus_places_view, NAUTILUS, PLACES_VIEW, GtkBox)
NautilusPlacesView* nautilus_places_view_new (void);
G_END_DECLS
#endif /* NAUTILUS_PLACES_VIEW_H */

View file

@ -360,7 +360,13 @@ slot_proxy_handle_drop (GtkWidget *widget,
target_view = NULL;
if (target_slot != NULL) {
target_view = nautilus_window_slot_get_current_view (target_slot);
NautilusView *view;
view = nautilus_window_slot_get_current_view (target_slot);
if (view && NAUTILUS_IS_FILES_VIEW (view)) {
target_view = NAUTILUS_FILES_VIEW (view);
}
}
if (target_slot != NULL && target_view != NULL) {

View file

@ -29,6 +29,7 @@
#include "nautilus-desktop-window.h"
#include "nautilus-list-view.h"
#include "nautilus-mime-actions.h"
#include "nautilus-places-view.h"
#include "nautilus-special-location-bar.h"
#include "nautilus-trash-bar.h"
#include "nautilus-view.h"
@ -121,6 +122,7 @@ struct NautilusWindowSlotDetails {
NautilusWindowGoToCallback open_callback;
gpointer open_callback_user_data;
gchar *view_mode_before_search;
gchar *view_mode_before_places;
};
static guint signals[LAST_SIGNAL] = { 0 };
@ -133,15 +135,108 @@ static void nautilus_window_slot_sync_actions (NautilusWindowSlot *slot);
static void nautilus_window_slot_connect_new_content_view (NautilusWindowSlot *slot);
static void nautilus_window_slot_disconnect_content_view (NautilusWindowSlot *slot);
static void nautilus_window_slot_emit_location_change (NautilusWindowSlot *slot, GFile *from, GFile *to);
static gboolean nautilus_window_slot_content_view_matches (NautilusWindowSlot *slot, const char *iid);
static NautilusView* nautilus_window_slot_get_view_for_location (NautilusWindowSlot *slot, GFile *location);
static NautilusView*
nautilus_window_slot_get_view_for_location (NautilusWindowSlot *slot,
GFile *location)
{
NautilusWindow *window;
NautilusView *view;
NautilusFile *file;
window = nautilus_window_slot_get_window (slot);
file = nautilus_file_get (location);
view = NULL;
/* FIXME bugzilla.gnome.org 41243:
* We should use inheritance instead of these special cases
* for the desktop window.
*/
if (NAUTILUS_IS_DESKTOP_WINDOW (window)) {
view = NAUTILUS_VIEW (nautilus_files_view_new (NAUTILUS_DESKTOP_ICON_VIEW_IID, slot));
} else if (nautilus_file_is_other_locations (file)) {
view = NAUTILUS_VIEW (nautilus_places_view_new ());
/* Save the current view, so we can go back after places view */
if (slot->details->content_view && NAUTILUS_IS_FILES_VIEW (slot->details->content_view)) {
g_clear_pointer (&slot->details->view_mode_before_places, g_free);
slot->details->view_mode_before_places = g_strdup (nautilus_files_view_get_view_id (NAUTILUS_FILES_VIEW (slot->details->content_view)));
}
} else {
gchar *view_id;
view_id = NULL;
/* If we are in search, try to use by default list view. This will be deactivated
* if the user manually switch to a diferent view mode */
if (nautilus_file_is_in_search (file)) {
if (g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_LIST_VIEW_ON_SEARCH)) {
/* 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,
* which is not the one we are interested in */
if (slot->details->view_mode_before_search == NULL) {
slot->details->view_mode_before_search = g_strdup (nautilus_files_view_get_view_id (NAUTILUS_FILES_VIEW (slot->details->content_view)));
}
view_id = g_strdup (NAUTILUS_LIST_VIEW_IID);
} else {
g_free (slot->details->view_mode_before_search);
slot->details->view_mode_before_search = NULL;
}
}
/* If there is already a view, just use the view mode that it's currently using, or
* if we were on search before, use what we were using before entering
* search mode */
if (slot->details->content_view != NULL && view_id == NULL) {
if (slot->details->view_mode_before_search != NULL) {
view_id = slot->details->view_mode_before_search;
slot->details->view_mode_before_search = NULL;
} else if (NAUTILUS_IS_PLACES_VIEW (slot->details->content_view)) {
view_id = slot->details->view_mode_before_places;
slot->details->view_mode_before_places = NULL;
} else {
view_id = g_strdup (nautilus_files_view_get_view_id (NAUTILUS_FILES_VIEW (slot->details->content_view)));
}
}
/* If there is not previous view in this slot, use the default view mode
* from preferences */
if (view_id == NULL) {
view_id = nautilus_global_preferences_get_default_folder_viewer_preference_as_iid ();
}
/* Try to reuse the current view */
if (nautilus_window_slot_content_view_matches (slot, view_id)) {
view = slot->details->content_view;
} else {
view = NAUTILUS_VIEW (nautilus_files_view_new (view_id, slot));
}
g_free (view_id);
}
nautilus_file_unref (file);
return g_object_ref (view);
}
static gboolean
nautilus_window_slot_content_view_matches_iid (NautilusWindowSlot *slot,
const char *iid)
nautilus_window_slot_content_view_matches (NautilusWindowSlot *slot,
const char *iid)
{
if (slot->details->content_view == NULL) {
return FALSE;
}
return g_strcmp0 (nautilus_files_view_get_view_id (NAUTILUS_FILES_VIEW (slot->details->content_view)), iid) == 0;
if (!iid && NAUTILUS_IS_PLACES_VIEW (slot->details->content_view)) {
return TRUE;
} else if (iid && NAUTILUS_IS_FILES_VIEW (slot->details->content_view)){
return g_strcmp0 (nautilus_files_view_get_view_id (NAUTILUS_FILES_VIEW (slot->details->content_view)), iid) == 0;
} else {
return FALSE;
}
}
static void
@ -170,10 +265,11 @@ nautilus_window_slot_sync_actions (NautilusWindowSlot *slot)
/* View mode */
action = g_action_map_lookup_action (G_ACTION_MAP (slot->details->window), "view-mode");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), TRUE);
if (nautilus_window_slot_content_view_matches_iid (slot, NAUTILUS_LIST_VIEW_ID)) {
if (nautilus_window_slot_content_view_matches (slot, NAUTILUS_LIST_VIEW_ID)) {
g_action_change_state (action, g_variant_new_string ("list"));
} else if (nautilus_window_slot_content_view_matches_iid (slot, NAUTILUS_CANVAS_VIEW_ID)) {
} else if (nautilus_window_slot_content_view_matches (slot, NAUTILUS_CANVAS_VIEW_ID)) {
g_action_change_state (action, g_variant_new_string ("grid"));
} else {
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
@ -521,8 +617,8 @@ static void end_location_change (NautilusWindowSlot
static void cancel_location_change (NautilusWindowSlot *slot);
static void got_file_info_for_view_selection_callback (NautilusFile *file,
gpointer callback_data);
static gboolean create_content_view (NautilusWindowSlot *slot,
const char *view_id,
static gboolean setup_view (NautilusWindowSlot *slot,
NautilusView *view,
GError **error);
static void load_new_location (NautilusWindowSlot *slot,
GFile *location,
@ -742,13 +838,11 @@ begin_location_change (NautilusWindowSlot *slot,
nautilus_profile_start (NULL);
directory = nautilus_directory_get (location);
/* Avoid to update status from the current view in our async calls */
nautilus_window_slot_disconnect_content_view (slot);
/* We are going to change the location, so make sure we stop any loading
* or searching of the previous view, so we avoid to be slow */
if (slot->details->content_view) {
if (slot->details->content_view && NAUTILUS_IS_FILES_VIEW (slot->details->content_view)) {
nautilus_files_view_stop_loading (NAUTILUS_FILES_VIEW (slot->details->content_view));
}
@ -796,6 +890,8 @@ begin_location_change (NautilusWindowSlot *slot,
* after determining an initial view (in the components), then
* we end up fetching things twice.
*/
directory = nautilus_directory_get (location);
if (type == NAUTILUS_LOCATION_CHANGE_RELOAD) {
force_reload = TRUE;
} else if (!nautilus_monitor_active ()) {
@ -819,7 +915,8 @@ begin_location_change (NautilusWindowSlot *slot,
/* Set current_bookmark scroll pos */
if (slot->details->current_location_bookmark != NULL &&
slot->details->content_view != NULL) {
slot->details->content_view != NULL &&
NAUTILUS_IS_FILES_VIEW (slot->details->content_view)) {
current_pos = nautilus_files_view_get_first_visible_file (NAUTILUS_FILES_VIEW (slot->details->content_view));
nautilus_bookmark_set_scroll_pos (slot->details->current_location_bookmark, current_pos);
g_free (current_pos);
@ -1016,10 +1113,10 @@ got_file_info_for_view_selection_callback (NautilusFile *file,
gpointer callback_data)
{
GError *error = NULL;
char *view_id;
NautilusWindow *window;
NautilusWindowSlot *slot;
NautilusFile *viewed_file, *parent_file;
NautilusView *view;
GFile *location, *default_location;
GMountOperation *mount_op;
MountNotMountedData *data;
@ -1116,54 +1213,16 @@ got_file_info_for_view_selection_callback (NautilusFile *file,
nautilus_file_unref (parent_file);
location = slot->details->pending_location;
view_id = NULL;
view = NULL;
if (error == NULL ||
(error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_SUPPORTED)) {
/* We got the information we need, now pick what view to use: */
/* If we are in search, try to use by default list view. This will be deactivated
* if the user manually switch to a diferent view mode */
if (nautilus_file_is_in_search (nautilus_file_get (location))) {
if (g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_LIST_VIEW_ON_SEARCH)) {
/* 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,
* which is not the one we are interested in */
if (slot->details->view_mode_before_search == NULL) {
slot->details->view_mode_before_search = g_strdup (nautilus_files_view_get_view_id (NAUTILUS_FILES_VIEW (slot->details->content_view)));
}
view_id = g_strdup (NAUTILUS_LIST_VIEW_IID);
} else {
g_free (slot->details->view_mode_before_search);
slot->details->view_mode_before_search = NULL;
}
}
/* If there is already a view, just use the view mode that it's currently using, or
* if we were on search before, use what we were using before entering
* search mode */
if (slot->details->content_view != NULL && view_id == NULL) {
if (slot->details->view_mode_before_search != NULL) {
view_id = g_strdup (slot->details->view_mode_before_search);
g_free (slot->details->view_mode_before_search);
slot->details->view_mode_before_search = NULL;
} else {
view_id = g_strdup (nautilus_files_view_get_view_id (NAUTILUS_FILES_VIEW (slot->details->content_view)));
}
}
/* If there is not previous view in this slot, use the default view mode
* from preferences */
if (view_id == NULL) {
view_id = nautilus_global_preferences_get_default_folder_viewer_preference_as_iid ();
}
if (!error || (error && error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_SUPPORTED)) {
view = nautilus_window_slot_get_view_for_location (slot, location);
}
if (view_id != NULL) {
if (view != NULL) {
GError *err = NULL;
create_content_view (slot, view_id, &err);
g_free (view_id);
setup_view (slot, view, &err);
report_callback (slot, err);
g_clear_error (&err);
@ -1240,7 +1299,6 @@ got_file_info_for_view_selection_callback (NautilusFile *file,
g_clear_error (&error);
nautilus_file_unref (file);
nautilus_profile_end (NULL);
}
@ -1252,52 +1310,26 @@ got_file_info_for_view_selection_callback (NautilusFile *file,
* view, and the current location will be used.
*/
static gboolean
create_content_view (NautilusWindowSlot *slot,
const char *view_id,
GError **error_out)
setup_view (NautilusWindowSlot *slot,
NautilusView *view,
GError **error_out)
{
NautilusWindow *window;
NautilusView *view;
GList *selection;
gboolean ret = TRUE;
GError *error = NULL;
GFile *old_location;
window = nautilus_window_slot_get_window (slot);
nautilus_profile_start (NULL);
/* FIXME bugzilla.gnome.org 41243:
* We should use inheritance instead of these special cases
* for the desktop window.
*/
if (NAUTILUS_IS_DESKTOP_WINDOW (window)) {
/* We force the desktop to use a desktop_icon_view. It's simpler
* to fix it here than trying to make it pick the right view in
* the first place.
*/
view_id = NAUTILUS_DESKTOP_ICON_VIEW_IID;
}
nautilus_window_slot_disconnect_content_view (slot);
if (nautilus_window_slot_content_view_matches_iid (slot, view_id)) {
/* reuse existing content view */
view = slot->details->content_view;
slot->details->new_content_view = view;
g_object_ref (view);
} else {
/* create a new content view */
view = NAUTILUS_VIEW (nautilus_files_view_new (view_id, slot));
slot->details->new_content_view = view;
}
slot->details->new_content_view = view;
nautilus_window_slot_connect_new_content_view (slot);
/* Forward search selection and state before loading the new model */
old_location = slot->details->content_view ? nautilus_view_get_location (slot->details->content_view) : NULL;
/* Actually load the pending location and selection: */
if (slot->details->pending_location != NULL) {
load_new_location (slot,
slot->details->pending_location,
@ -1345,13 +1377,11 @@ load_new_location (NautilusWindowSlot *slot,
gboolean tell_current_content_view,
gboolean tell_new_content_view)
{
GList *selection_copy;
NautilusView *view;
g_assert (slot != NULL);
g_assert (location != NULL);
selection_copy = g_list_copy_deep (selection, (GCopyFunc) g_object_ref, NULL);
view = NULL;
nautilus_profile_start (NULL);
@ -1373,8 +1403,6 @@ load_new_location (NautilusWindowSlot *slot,
nautilus_view_set_selection (view, selection);
}
g_list_free_full (selection_copy, g_object_unref);
nautilus_profile_end (NULL);
}
@ -1447,7 +1475,8 @@ cancel_location_change (NautilusWindowSlot *slot)
if (slot->details->pending_location != NULL
&& location != NULL
&& slot->details->content_view != NULL) {
&& slot->details->content_view != NULL
&& NAUTILUS_IS_FILES_VIEW (slot->details->content_view)) {
/* No need to tell the new view - either it is the
* same as the old view, in which case it will already
@ -1548,7 +1577,7 @@ nautilus_window_slot_set_content_view (NautilusWindowSlot *slot,
DEBUG ("Change view of window %s to %s", uri, id);
g_free (uri);
if (nautilus_window_slot_content_view_matches_iid (slot, id)) {
if (nautilus_window_slot_content_view_matches (slot, id)) {
return;
}
@ -1564,14 +1593,13 @@ nautilus_window_slot_set_content_view (NautilusWindowSlot *slot,
* is currently visible */
slot->details->pending_scroll_to = nautilus_files_view_get_first_visible_file (NAUTILUS_FILES_VIEW (slot->details->content_view));
}
slot->details->location_change_type = NAUTILUS_LOCATION_CHANGE_RELOAD;
if (!create_content_view (slot, id, NULL)) {
if (!setup_view (slot, NAUTILUS_VIEW (view), NULL)) {
/* Just load the homedir. */
nautilus_window_slot_go_home (slot, FALSE);
}
nautilus_file_list_free (selection);
}
void
@ -2152,7 +2180,7 @@ nautilus_window_slot_connect_new_content_view (NautilusWindowSlot *slot)
static void
nautilus_window_slot_disconnect_content_view (NautilusWindowSlot *slot)
{
if (slot->details->content_view != NULL) {
if (slot->details->new_content_view && NAUTILUS_IS_FILES_VIEW (slot->details->new_content_view)) {
/* disconnect old view */
g_signal_handlers_disconnect_by_func (slot->details->content_view,
G_CALLBACK (view_is_loading_changed_cb),

View file

@ -986,6 +986,18 @@ places_sidebar_show_connect_to_server_cb (GtkPlacesSidebar *sidebar,
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
}
static void
places_sidebar_show_other_locations (NautilusWindow *window)
{
GFile *location;
location = g_file_new_for_uri ("other-locations:///");
open_location_cb (window, location, GTK_PLACES_OPEN_NORMAL);
g_object_unref (location);
}
static GList *
build_selection_list_from_gfile_list (GList *gfile_list)
{
@ -1271,7 +1283,6 @@ nautilus_window_set_up_sidebar (NautilusWindow *window)
(GTK_PLACES_OPEN_NORMAL
| GTK_PLACES_OPEN_NEW_TAB
| GTK_PLACES_OPEN_NEW_WINDOW));
gtk_places_sidebar_set_show_connect_to_server (GTK_PLACES_SIDEBAR (window->priv->places_sidebar), TRUE);
g_signal_connect_swapped (window->priv->places_sidebar, "open-location",
G_CALLBACK (open_location_cb), window);
@ -2534,6 +2545,8 @@ nautilus_window_class_init (NautilusWindowClass *class)
gtk_widget_class_bind_template_child_private (wclass, NautilusWindow, notification_operation_open);
gtk_widget_class_bind_template_child_private (wclass, NautilusWindow, notification_operation_close);
gtk_widget_class_bind_template_callback (wclass, places_sidebar_show_other_locations);
properties[PROP_DISABLE_CHROME] =
g_param_spec_boolean ("disable-chrome",
"Disable chrome",

View file

@ -33,6 +33,8 @@
<object class="GtkPlacesSidebar" id="places_sidebar">
<property name="visible">True</property>
<property name="populate-all">True</property>
<property name="show-other-locations">True</property>
<signal name="show-other-locations" handler="places_sidebar_show_other_locations" object="NautilusWindow" swapped="yes" />
</object>
<packing>
<property name="pack_type">start</property>

View file

@ -16,6 +16,8 @@
<file>nautilus-window.ui</file>
<file>nautilus-no-search-results.ui</file>
<file>nautilus-folder-is-empty.ui</file>
<file>gtk/gtkplacesview.ui</file>
<file>gtk/gtkplacesviewrow.ui</file>
<file alias="icons/thumbnail_frame.png">../icons/thumbnail_frame.png</file>
<file alias="icons/filmholes.png">../icons/filmholes.png</file>
<file alias="icons/knob.png">../icons/knob.png</file>