Merge branch 'wip/carlosg/favorites' into 'master'

Add starred files

See https://gitlab.gnome.org/GNOME/nautilus/merge_requests/21
This commit is contained in:
Carlos Soriano 2017-11-05 20:33:15 +00:00
commit 6af42427f8
34 changed files with 2516 additions and 35 deletions

View file

@ -255,11 +255,11 @@
<summary>Default list view zoom level</summary>
</key>
<key type="as" name="default-visible-columns">
<default>[ 'name', 'size', 'date_modified' ]</default>
<default>[ 'name', 'size', 'date_modified', 'favorite' ]</default>
<summary>Columns visible in list view</summary>
</key>
<key type="as" name="default-column-order">
<default>[ 'name', 'size', 'type', 'owner', 'group', 'permissions', 'mime_type', 'where', 'date_modified', 'date_modified_with_time', 'date_accessed' ]</default>
<default>[ 'name', 'size', 'type', 'owner', 'group', 'permissions', 'mime_type', 'where', 'date_modified', 'date_modified_with_time', 'date_accessed', 'recency', 'favorite' ]</default>
<summary>Column order in list view</summary>
</key>
<key type="b" name="use-tree-view">

View file

@ -37,6 +37,12 @@
#include <string.h>
#include <stdlib.h>
gboolean
eel_uri_is_favorites (const gchar *uri)
{
return g_str_has_prefix (uri, "favorites:");
}
gboolean
eel_uri_is_trash (const char *uri)
{

View file

@ -35,6 +35,7 @@ G_BEGIN_DECLS
#define EEL_DESKTOP_URI "x-nautilus-desktop:"
#define EEL_SEARCH_URI "x-nautilus-search:"
gboolean eel_uri_is_favorites (const char *uri);
gboolean eel_uri_is_trash (const char *uri);
gboolean eel_uri_is_trash_folder (const char *uri);
gboolean eel_uri_is_in_trash (const char *uri);

View file

@ -259,7 +259,11 @@ libnautilus_sources = [
'nautilus-batch-rename-utilities.c',
'nautilus-batch-rename-utilities.h',
'nautilus-search-engine-tracker.c',
'nautilus-search-engine-tracker.h'
'nautilus-search-engine-tracker.h',
'nautilus-tag-manager.c',
'nautilus-tag-manager.h',
'nautilus-favorite-directory.c',
'nautilus-favorite-directory.h'
]
nautilus_deps = [glib,

View file

@ -39,6 +39,7 @@
#include "nautilus-window.h"
#include "nautilus-window-slot.h"
#include "nautilus-preferences-window.h"
#include "nautilus-tag-manager.h"
#include "nautilus-directory-private.h"
#include "nautilus-file-utilities.h"
@ -80,6 +81,9 @@ typedef struct
GHashTable *notifications;
NautilusFileUndoManager *undo_manager;
NautilusTagManager *tag_manager;
GCancellable *tag_manager_cancellable;
} NautilusApplicationPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (NautilusApplication, nautilus_application, GTK_TYPE_APPLICATION);
@ -612,6 +616,11 @@ nautilus_application_finalize (GObject *object)
g_clear_object (&priv->undo_manager);
g_clear_object (&priv->tag_manager);
g_cancellable_cancel (priv->tag_manager_cancellable);
g_clear_object (&priv->tag_manager_cancellable);
G_OBJECT_CLASS (nautilus_application_parent_class)->finalize (object);
}
@ -1103,6 +1112,11 @@ nautilus_application_init (NautilusApplication *self)
priv->undo_manager = nautilus_file_undo_manager_new ();
priv->tag_manager_cancellable = g_cancellable_new ();
priv->tag_manager = nautilus_tag_manager_get ();
nautilus_tag_manager_set_cancellable (priv->tag_manager,
priv->tag_manager_cancellable);
g_application_add_main_option_entries (G_APPLICATION (self), options);
nautilus_ensure_extension_points ();

View file

@ -643,6 +643,11 @@ nautilus_bookmark_list_can_bookmark_location (NautilusBookmarkList *list,
return FALSE;
}
if (nautilus_is_favorite_directory (location))
{
return FALSE;
}
bookmark = nautilus_bookmark_new (location, NULL);
is_builtin = nautilus_bookmark_get_is_builtin (bookmark);
g_object_unref (bookmark);

View file

@ -42,6 +42,7 @@ static const char *default_column_order[] =
"date_modified",
"date_accessed",
"recency",
"favorite",
NULL
};
@ -149,6 +150,16 @@ get_builtin_columns (void)
"xalign", 1.0,
NULL));
columns = g_list_append (columns,
g_object_new (NAUTILUS_TYPE_COLUMN,
"name", "favorite",
"attribute", "favorite",
"label", _("Star"),
"description", _("Shows if file is favorite."),
"default-sort-order", GTK_SORT_DESCENDING,
"xalign", 0.5,
NULL));
return columns;
}

View file

@ -27,6 +27,7 @@
#include "nautilus-file-private.h"
#include "nautilus-file-utilities.h"
#include "nautilus-search-directory.h"
#include "nautilus-favorite-directory.h"
#include "nautilus-search-directory-file.h"
#include "nautilus-vfs-file.h"
#include "nautilus-global-preferences.h"
@ -801,6 +802,19 @@ nautilus_directory_is_in_recent (NautilusDirectory *directory)
return g_file_has_uri_scheme (directory->details->location, "recent");
}
gboolean
nautilus_directory_is_in_starred (NautilusDirectory *directory)
{
g_assert (NAUTILUS_IS_DIRECTORY (directory));
if (directory->details->location == NULL)
{
return FALSE;
}
return g_file_has_uri_scheme (directory->details->location, "favorites");
}
gboolean
nautilus_directory_is_in_admin (NautilusDirectory *directory)
{

View file

@ -227,6 +227,7 @@ gboolean nautilus_directory_is_local_or_fuse (NautilusDirector
gboolean nautilus_directory_is_in_trash (NautilusDirectory *directory);
gboolean nautilus_directory_is_in_recent (NautilusDirectory *directory);
gboolean nautilus_directory_is_in_starred (NautilusDirectory *directory);
gboolean nautilus_directory_is_in_admin (NautilusDirectory *directory);
/* Return false if directory contains anything besides a Nautilus metafile.

View file

@ -0,0 +1,585 @@
/* nautilus-favorite-directory.c
*
* Copyright (C) 2017 Alexandru Pandelea <alexandru.pandelea@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 2 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-favorite-directory.h"
#include "nautilus-tag-manager.h"
#include "nautilus-file-utilities.h"
#include "nautilus-directory-private.h"
#include <glib/gi18n.h>
struct NautilusFavoriteDirectoryDetails
{
NautilusTagManager *tag_manager;
GList *files;
GList *monitor_list;
GList *callback_list;
GList *pending_callback_list;
};
typedef struct
{
gboolean monitor_hidden_files;
NautilusFileAttributes monitor_attributes;
gconstpointer client;
} FavoriteMonitor;
typedef struct
{
NautilusFavoriteDirectory *favorite_directory;
NautilusDirectoryCallback callback;
gpointer callback_data;
NautilusFileAttributes wait_for_attributes;
gboolean wait_for_file_list;
GList *file_list;
} FavoriteCallback;
G_DEFINE_TYPE_WITH_CODE (NautilusFavoriteDirectory, nautilus_favorite_directory, NAUTILUS_TYPE_DIRECTORY,
nautilus_ensure_extension_points ();
g_io_extension_point_implement (NAUTILUS_DIRECTORY_PROVIDER_EXTENSION_POINT_NAME,
g_define_type_id,
NAUTILUS_FAVORITE_DIRECTORY_PROVIDER_NAME,
0));
static void
file_changed (NautilusFile *file,
NautilusFavoriteDirectory *favorite)
{
GList list;
list.data = file;
list.next = NULL;
nautilus_directory_emit_files_changed (NAUTILUS_DIRECTORY (favorite), &list);
}
static void
nautilus_favorite_directory_update_files (NautilusFavoriteDirectory *self)
{
GList *l;
GList *tmp_l;
GList *new_favorite_files;
GList *monitor_list;
FavoriteMonitor *monitor;
NautilusFile *file;
GHashTable *uri_table;
GList *files_added;
GList *files_removed;
gchar *uri;
files_added = NULL;
files_removed = NULL;
uri_table = g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify) g_free,
NULL);
for (l = self->details->files; l != NULL; l = l->next)
{
g_hash_table_add (uri_table, nautilus_file_get_uri (NAUTILUS_FILE (l->data)));
}
new_favorite_files = nautilus_tag_manager_get_favorite_files (self->details->tag_manager);
for (l = new_favorite_files; l != NULL; l = l->next)
{
if (!g_hash_table_contains (uri_table, l->data))
{
file = nautilus_file_get_by_uri ((gchar*) l->data);
for (monitor_list = self->details->monitor_list; monitor_list; monitor_list = monitor_list->next)
{
monitor = monitor_list->data;
/* Add monitors */
nautilus_file_monitor_add (file, monitor, monitor->monitor_attributes);
}
g_signal_connect (file, "changed", G_CALLBACK (file_changed), self);
files_added = g_list_prepend (files_added, file);
}
}
l = self->details->files;
while (l != NULL)
{
uri = nautilus_file_get_uri (NAUTILUS_FILE (l->data));
if (!nautilus_tag_manager_file_is_favorite (self->details->tag_manager, uri))
{
files_removed = g_list_prepend (files_removed,
nautilus_file_ref (NAUTILUS_FILE (l->data)));
g_signal_handlers_disconnect_by_func (NAUTILUS_FILE (l->data),
file_changed,
self);
/* Remove monitors */
for (monitor_list = self->details->monitor_list; monitor_list;
monitor_list = monitor_list->next)
{
monitor = monitor_list->data;
nautilus_file_monitor_remove (NAUTILUS_FILE (l->data), monitor);
}
if (l == self->details->files)
{
self->details->files = g_list_delete_link (self->details->files, l);
l = self->details->files;
}
else
{
tmp_l = l->prev;
self->details->files = g_list_delete_link (self->details->files, l);
l = tmp_l->next;
}
}
else
{
l = l->next;
}
g_free (uri);
}
if (files_added)
{
nautilus_directory_emit_files_added (NAUTILUS_DIRECTORY (self), files_added);
for (l = files_added; l != NULL; l = l->next)
{
self->details->files = g_list_prepend (self->details->files, nautilus_file_ref (NAUTILUS_FILE (l->data)));
}
}
if (files_removed)
{
nautilus_directory_emit_files_changed (NAUTILUS_DIRECTORY (self), files_removed);
}
nautilus_file_list_free (files_added);
nautilus_file_list_free (files_removed);
g_hash_table_destroy (uri_table);
}
static void
on_favorites_files_changed (NautilusTagManager *tag_manager,
GList *changed_files,
gpointer user_data)
{
NautilusFavoriteDirectory *self;
self = NAUTILUS_FAVORITE_DIRECTORY (user_data);
nautilus_favorite_directory_update_files (self);
}
static gboolean
real_contains_file (NautilusDirectory *directory,
NautilusFile *file)
{
NautilusFavoriteDirectory *self;
g_autofree gchar *uri = NULL;
self = NAUTILUS_FAVORITE_DIRECTORY (directory);
uri = nautilus_file_get_uri (file);
return nautilus_tag_manager_file_is_favorite (self->details->tag_manager, uri);
}
static gboolean
real_is_editable (NautilusDirectory *directory)
{
return FALSE;
}
static void
real_force_reload (NautilusDirectory *directory)
{
nautilus_favorite_directory_update_files (NAUTILUS_FAVORITE_DIRECTORY (directory));
}
static void
real_call_when_ready (NautilusDirectory *directory,
NautilusFileAttributes file_attributes,
gboolean wait_for_file_list,
NautilusDirectoryCallback callback,
gpointer callback_data)
{
GList *file_list;
NautilusFavoriteDirectory *favorite;
favorite = NAUTILUS_FAVORITE_DIRECTORY (directory);
file_list = nautilus_file_list_copy (favorite->details->files);
callback (NAUTILUS_DIRECTORY (directory),
file_list,
callback_data);
}
static gboolean
real_are_all_files_seen (NautilusDirectory *directory)
{
return TRUE;
}
static void
real_file_monitor_add (NautilusDirectory *directory,
gconstpointer client,
gboolean monitor_hidden_files,
NautilusFileAttributes file_attributes,
NautilusDirectoryCallback callback,
gpointer callback_data)
{
GList *list;
FavoriteMonitor *monitor;
NautilusFavoriteDirectory *favorite;
NautilusFile *file;
favorite = NAUTILUS_FAVORITE_DIRECTORY (directory);
monitor = g_new0 (FavoriteMonitor, 1);
monitor->monitor_hidden_files = monitor_hidden_files;
monitor->monitor_attributes = file_attributes;
monitor->client = client;
favorite->details->monitor_list = g_list_prepend (favorite->details->monitor_list, monitor);
if (callback != NULL)
{
(*callback) (directory, favorite->details->files, callback_data);
}
for (list = favorite->details->files; list != NULL; list = list->next)
{
file = list->data;
/* Add monitors */
nautilus_file_monitor_add (file, monitor, file_attributes);
}
}
static void
favorite_monitor_destroy (FavoriteMonitor *monitor,
NautilusFavoriteDirectory *favorite)
{
GList *l;
NautilusFile *file;
for (l = favorite->details->files; l != NULL; l = l->next)
{
file = l->data;
nautilus_file_monitor_remove (file, monitor);
}
g_free (monitor);
}
static void
real_monitor_remove (NautilusDirectory *directory,
gconstpointer client)
{
NautilusFavoriteDirectory *favorite;
FavoriteMonitor *monitor;
GList *list;
favorite = NAUTILUS_FAVORITE_DIRECTORY (directory);
for (list = favorite->details->monitor_list; list != NULL; list = list->next)
{
monitor = list->data;
if (monitor->client != client)
continue;
favorite->details->monitor_list = g_list_delete_link (favorite->details->monitor_list, list);
favorite_monitor_destroy (monitor, favorite);
break;
}
}
static gboolean
real_handles_location (GFile *location)
{
g_autofree gchar *uri = NULL;
uri = g_file_get_uri (location);
if (eel_uri_is_favorites (uri))
{
return TRUE;
}
return FALSE;
}
static FavoriteCallback*
favorite_callback_find_pending (NautilusFavoriteDirectory *favorite,
NautilusDirectoryCallback callback,
gpointer callback_data)
{
FavoriteCallback *favorite_callback;
GList *list;
for (list = favorite->details->pending_callback_list; list != NULL; list = list->next)
{
favorite_callback = list->data;
if (favorite_callback->callback == callback &&
favorite_callback->callback_data == callback_data)
{
return favorite_callback;
}
}
return NULL;
}
static FavoriteCallback*
favorite_callback_find (NautilusFavoriteDirectory *favorite,
NautilusDirectoryCallback callback,
gpointer callback_data)
{
FavoriteCallback *favorite_callback;
GList *list;
for (list = favorite->details->callback_list; list != NULL; list = list->next)
{
favorite_callback = list->data;
if (favorite_callback->callback == callback &&
favorite_callback->callback_data == callback_data)
{
return favorite_callback;
}
}
return NULL;
}
static void
favorite_callback_destroy (FavoriteCallback *favorite_callback)
{
nautilus_file_list_free (favorite_callback->file_list);
g_free (favorite_callback);
}
static void
real_cancel_callback (NautilusDirectory *directory,
NautilusDirectoryCallback callback,
gpointer callback_data)
{
NautilusFavoriteDirectory *favorite;
FavoriteCallback *favorite_callback;
favorite = NAUTILUS_FAVORITE_DIRECTORY (directory);
favorite_callback = favorite_callback_find (favorite, callback, callback_data);
if (favorite_callback)
{
favorite->details->callback_list = g_list_remove (favorite->details->callback_list, favorite_callback);
favorite_callback_destroy (favorite_callback);
return;
}
/* Check for a pending callback */
favorite_callback = favorite_callback_find_pending (favorite, callback, callback_data);
if (favorite_callback)
{
favorite->details->pending_callback_list = g_list_remove (favorite->details->pending_callback_list, favorite_callback);
favorite_callback_destroy (favorite_callback);
}
}
static GList*
real_get_file_list (NautilusDirectory *directory)
{
NautilusFavoriteDirectory *favorite;
favorite = NAUTILUS_FAVORITE_DIRECTORY (directory);
return nautilus_file_list_copy (favorite->details->files);
}
static void
nautilus_favorite_directory_set_files (NautilusFavoriteDirectory *self)
{
GList *favorite_files;
NautilusFile *file;
GList *l;
GList *file_list;
FavoriteMonitor *monitor;
GList *monitor_list;
file_list = NULL;
favorite_files = nautilus_tag_manager_get_favorite_files (self->details->tag_manager);
for (l = favorite_files; l != NULL; l = l->next)
{
file = nautilus_file_get_by_uri ((gchar*) l->data);
g_signal_connect (file, "changed", G_CALLBACK (file_changed), self);
for (monitor_list = self->details->monitor_list; monitor_list; monitor_list = monitor_list->next)
{
monitor = monitor_list->data;
/* Add monitors */
nautilus_file_monitor_add (file, monitor, monitor->monitor_attributes);
}
file_list = g_list_prepend (file_list, file);
}
nautilus_directory_emit_files_added (NAUTILUS_DIRECTORY (self), file_list);
self->details->files = file_list;
}
static void
nautilus_favorite_directory_finalize (GObject *object)
{
NautilusFavoriteDirectory *self;
self = NAUTILUS_FAVORITE_DIRECTORY (object);
g_signal_handlers_disconnect_by_func (self->details->tag_manager,
on_favorites_files_changed,
self);
g_object_unref (self->details->tag_manager);
nautilus_file_list_free (self->details->files);
G_OBJECT_CLASS (nautilus_favorite_directory_parent_class)->finalize (object);
}
static void
nautilus_favorite_directory_dispose (GObject *object)
{
NautilusFavoriteDirectory *favorite;
GList *l;
GList *monitor_list;
FavoriteMonitor *monitor;
NautilusFile *file;
favorite = NAUTILUS_FAVORITE_DIRECTORY (object);
/* Remove file connections */
for (l = favorite->details->files; l != NULL; l = l->next)
{
file = l->data;
/* Disconnect change handler */
g_signal_handlers_disconnect_by_func (file, file_changed, favorite);
/* Remove monitors */
for (monitor_list = favorite->details->monitor_list; monitor_list;
monitor_list = monitor_list->next)
{
monitor = monitor_list->data;
nautilus_file_monitor_remove (file, monitor);
}
}
/* Remove search monitors */
if (favorite->details->monitor_list)
{
for (l = favorite->details->monitor_list; l != NULL; l = l->next)
{
favorite_monitor_destroy ((FavoriteMonitor*) l->data, favorite);
}
g_list_free (favorite->details->monitor_list);
favorite->details->monitor_list = NULL;
}
G_OBJECT_CLASS (nautilus_favorite_directory_parent_class)->dispose (object);
}
static void
nautilus_favorite_directory_class_init (NautilusFavoriteDirectoryClass *klass)
{
GObjectClass *oclass;
NautilusDirectoryClass *directory_class;
oclass = G_OBJECT_CLASS (klass);
directory_class = NAUTILUS_DIRECTORY_CLASS (klass);
oclass->finalize = nautilus_favorite_directory_finalize;
oclass->dispose = nautilus_favorite_directory_dispose;
directory_class->handles_location = real_handles_location;
directory_class->contains_file = real_contains_file;
directory_class->is_editable = real_is_editable;
directory_class->force_reload = real_force_reload;
directory_class->call_when_ready = real_call_when_ready;
directory_class->are_all_files_seen = real_are_all_files_seen;
directory_class->file_monitor_add = real_file_monitor_add;
directory_class->file_monitor_remove = real_monitor_remove;
directory_class->cancel_callback = real_cancel_callback;
directory_class->get_file_list = real_get_file_list;
g_type_class_add_private (klass, sizeof (NautilusFavoriteDirectoryDetails));
}
NautilusFavoriteDirectory*
nautilus_favorite_directory_new ()
{
NautilusFavoriteDirectory *self;
self = g_object_new (NAUTILUS_TYPE_FAVORITE_DIRECTORY, NULL);
return self;
}
static void
nautilus_favorite_directory_init (NautilusFavoriteDirectory *self)
{
NautilusTagManager *tag_manager;
self->details = G_TYPE_INSTANCE_GET_PRIVATE (self, NAUTILUS_TYPE_FAVORITE_DIRECTORY,
NautilusFavoriteDirectoryDetails);
tag_manager = nautilus_tag_manager_get ();
g_signal_connect (tag_manager,
"favorites-changed",
(GCallback) on_favorites_files_changed,
self);
self->details->tag_manager = tag_manager;
nautilus_favorite_directory_set_files (self);
}

View file

@ -0,0 +1,57 @@
/* nautilus-favorite-directory.h
*
* Copyright (C) 2017 Alexandru Pandelea <alexandru.pandelea@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 2 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_FAVORITE_DIRECTORY_H
#define NAUTILUS_FAVORITE_DIRECTORY_H
#include "nautilus-directory.h"
G_BEGIN_DECLS
#define NAUTILUS_FAVORITE_DIRECTORY_PROVIDER_NAME "favorite-directory-provider"
#define NAUTILUS_TYPE_FAVORITE_DIRECTORY nautilus_favorite_directory_get_type()
#define NAUTILUS_FAVORITE_DIRECTORY(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_FAVORITE_DIRECTORY, NautilusFavoriteDirectory))
#define NAUTILUS_FAVORITE_DIRECTORY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_FAVORITE_DIRECTORY, NautilusFavoriteDirectoryClass))
#define NAUTILUS_IS_FAVORITE_DIRECTORY(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_FAVORITE_DIRECTORY))
#define NAUTILUS_IS_FAVORITE_DIRECTORY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_FAVORITE_DIRECTORY))
#define NAUTILUS_FAVORITE_DIRECTORY_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), NAUTILUS_TYPE_FAVORITE_DIRECTORY, NautilusFavoriteDirectoryClass))
typedef struct NautilusFavoriteDirectoryDetails NautilusFavoriteDirectoryDetails;
typedef struct {
NautilusDirectory parent_slot;
NautilusFavoriteDirectoryDetails *details;
} NautilusFavoriteDirectory;
typedef struct {
NautilusDirectoryClass parent_slot;
} NautilusFavoriteDirectoryClass;
GType nautilus_favorite_directory_get_type (void);
NautilusFavoriteDirectory* nautilus_favorite_directory_new ();
G_END_DECLS
#endif

View file

@ -33,6 +33,7 @@
#include "nautilus-file-undo-manager.h"
#include "nautilus-batch-rename-dialog.h"
#include "nautilus-batch-rename-utilities.h"
#include "nautilus-tag-manager.h"
/* Since we use g_get_current_time for setting "orig_trash_time" in the undo
@ -1304,6 +1305,226 @@ nautilus_file_undo_info_batch_rename_set_data_post (NautilusFileUndoInfoBatchRen
self->priv->new_display_names = g_list_reverse (self->priv->new_display_names);
}
/* favorite files */
G_DEFINE_TYPE (NautilusFileUndoInfoFavorites, nautilus_file_undo_info_favorites, NAUTILUS_TYPE_FILE_UNDO_INFO);
struct _NautilusFileUndoInfoFavoritesDetails
{
GList *files;
/* Whether the action was starring or unstarring */
gboolean starred;
};
enum
{
PROP_FILES = 1,
PROP_STARRED,
NUM_PROPERTIES
};
static void
favorites_strings_func (NautilusFileUndoInfo *info,
gchar **undo_label,
gchar **undo_description,
gchar **redo_label,
gchar **redo_description)
{
NautilusFileUndoInfoFavorites *self = NAUTILUS_FILE_UNDO_INFO_FAVORITES (info);
if (self->priv->starred)
{
*undo_description = g_strdup_printf (ngettext ("Unstar %d file",
"Unstar %d files",
g_list_length (self->priv->files)),
g_list_length (self->priv->files));
*redo_description = g_strdup_printf (ngettext ("Star %d file",
"Star %d files",
g_list_length (self->priv->files)),
g_list_length (self->priv->files));
*undo_label = g_strdup (_("_Undo Starring"));
*redo_label = g_strdup (_("_Redo Starring"));
}
else
{
*undo_description = g_strdup_printf (ngettext ("Star %d file",
"Star %d files",
g_list_length (self->priv->files)),
g_list_length (self->priv->files));
*redo_description = g_strdup_printf (ngettext ("Unstar %d file",
"Unstar %d files",
g_list_length (self->priv->files)),
g_list_length (self->priv->files));
*undo_label = g_strdup (_("_Undo Unstarring"));
*redo_label = g_strdup (_("_Redo Unstarring"));
}
}
static void
on_undo_favorite_tags_updated (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
GTask *task;
NautilusFileUndoInfo *undo_info;
undo_info = NAUTILUS_FILE_UNDO_INFO (object);
task = user_data;
g_clear_object (&task);
file_undo_info_operation_callback (NULL, NULL, NULL, undo_info);
}
static void
favorites_redo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window)
{
NautilusFileUndoInfoFavorites *self = NAUTILUS_FILE_UNDO_INFO_FAVORITES (info);
NautilusTagManager *tag_manager;
tag_manager = nautilus_tag_manager_get ();
if (self->priv->starred)
{
nautilus_tag_manager_star_files (tag_manager,
G_OBJECT (info),
self->priv->files,
on_undo_favorite_tags_updated,
NULL);
}
else
{
nautilus_tag_manager_unstar_files (tag_manager,
G_OBJECT (info),
self->priv->files,
on_undo_favorite_tags_updated,
NULL);
}
}
static void
favorites_undo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window)
{
NautilusFileUndoInfoFavorites *self = NAUTILUS_FILE_UNDO_INFO_FAVORITES (info);
NautilusTagManager *tag_manager;
tag_manager = nautilus_tag_manager_get ();
if (self->priv->starred)
{
nautilus_tag_manager_unstar_files (tag_manager,
G_OBJECT (info),
self->priv->files,
on_undo_favorite_tags_updated,
NULL);
}
else
{
nautilus_tag_manager_star_files (tag_manager,
G_OBJECT (info),
self->priv->files,
on_undo_favorite_tags_updated,
NULL);
}
}
static void
nautilus_file_undo_info_favorites_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
NautilusFileUndoInfoFavorites *self = NAUTILUS_FILE_UNDO_INFO_FAVORITES (object);
switch (prop_id)
{
case PROP_FILES:
{
self->priv->files = nautilus_file_list_copy (g_value_get_pointer (value));
}
break;
case PROP_STARRED:
{
self->priv->starred = g_value_get_boolean (value);
}
break;
default:
{
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
}
static void
nautilus_file_undo_info_favorites_init (NautilusFileUndoInfoFavorites *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, nautilus_file_undo_info_favorites_get_type (),
NautilusFileUndoInfoFavoritesDetails);
}
static void
nautilus_file_undo_info_favorites_finalize (GObject *obj)
{
NautilusFileUndoInfoFavorites *self = NAUTILUS_FILE_UNDO_INFO_FAVORITES (obj);
nautilus_file_list_free (self->priv->files);
G_OBJECT_CLASS (nautilus_file_undo_info_favorites_parent_class)->finalize (obj);
}
static void
nautilus_file_undo_info_favorites_class_init (NautilusFileUndoInfoFavoritesClass *klass)
{
GObjectClass *oclass = G_OBJECT_CLASS (klass);
NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
oclass->finalize = nautilus_file_undo_info_favorites_finalize;
oclass->set_property = nautilus_file_undo_info_favorites_set_property;
iclass->undo_func = favorites_undo_func;
iclass->redo_func = favorites_redo_func;
iclass->strings_func = favorites_strings_func;
g_type_class_add_private (klass, sizeof (NautilusFileUndoInfoFavoritesDetails));
g_object_class_install_property (oclass,
PROP_FILES,
g_param_spec_pointer ("files",
"files",
"The files for which to undo star/unstar",
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (oclass,
PROP_STARRED,
g_param_spec_boolean ("starred",
"starred",
"Whether the files were starred or unstarred",
FALSE,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY));
}
NautilusFileUndoInfo *
nautilus_file_undo_info_favorites_new (GList *files,
gboolean starred)
{
NautilusFileUndoInfoFavorites *self;
self = g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_FAVORITES,
"op-type", NAUTILUS_FILE_UNDO_OP_FAVORITES,
"item-count", g_list_length (files),
"files", files,
"starred", starred,
NULL);
return NAUTILUS_FILE_UNDO_INFO (self);
}
/* trash */
G_DEFINE_TYPE (NautilusFileUndoInfoTrash, nautilus_file_undo_info_trash, NAUTILUS_TYPE_FILE_UNDO_INFO)

View file

@ -35,6 +35,7 @@ typedef enum {
NAUTILUS_FILE_UNDO_OP_MOVE,
NAUTILUS_FILE_UNDO_OP_RENAME,
NAUTILUS_FILE_UNDO_OP_BATCH_RENAME,
NAUTILUS_FILE_UNDO_OP_FAVORITES,
NAUTILUS_FILE_UNDO_OP_CREATE_EMPTY_FILE,
NAUTILUS_FILE_UNDO_OP_CREATE_FILE_FROM_TEMPLATE,
NAUTILUS_FILE_UNDO_OP_CREATE_FOLDER,
@ -217,6 +218,31 @@ void nautilus_file_undo_info_batch_rename_set_data_pre (NautilusFileUndoInfoBatc
void nautilus_file_undo_info_batch_rename_set_data_post (NautilusFileUndoInfoBatchRename *self,
GList *new_files);
/* favorite files */
#define NAUTILUS_TYPE_FILE_UNDO_INFO_FAVORITES (nautilus_file_undo_info_favorites_get_type ())
#define NAUTILUS_FILE_UNDO_INFO_FAVORITES(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NAUTILUS_TYPE_FILE_UNDO_INFO_FAVORITES, NautilusFileUndoInfoFavorites))
#define NAUTILUS_FILE_UNDO_INFO_FAVORITES_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NAUTILUS_TYPE_FILE_UNDO_INFO_FAVORITES, NautilusFileUndoInfoFavoritesClass))
#define NAUTILUS_IS_FILE_UNDO_INFO_FAVORITES(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NAUTILUS_TYPE_FILE_UNDO_INFO_FAVORITES))
#define NAUTILUS_IS_FILE_UNDO_INFO_FAVORITES_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NAUTILUS_TYPE_FILE_UNDO_INFO_FAVORITES))
#define NAUTILUS_FILE_UNDO_INFO_FAVORITES_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NAUTILUS_TYPE_FILE_UNDO_INFO_FAVORITES, NautilusFileUndoInfoFavoritesClass))
typedef struct _NautilusFileUndoInfoFavorites NautilusFileUndoInfoFavorites;
typedef struct _NautilusFileUndoInfoFavoritesClass NautilusFileUndoInfoFavoritesClass;
typedef struct _NautilusFileUndoInfoFavoritesDetails NautilusFileUndoInfoFavoritesDetails;
struct _NautilusFileUndoInfoFavorites {
NautilusFileUndoInfo parent;
NautilusFileUndoInfoFavoritesDetails *priv;
};
struct _NautilusFileUndoInfoFavoritesClass {
NautilusFileUndoInfoClass parent_class;
};
GType nautilus_file_undo_info_favorites_get_type (void) G_GNUC_CONST;
NautilusFileUndoInfo *nautilus_file_undo_info_favorites_new (GList *files,
gboolean starred);
/* trash */
#define NAUTILUS_TYPE_FILE_UNDO_INFO_TRASH (nautilus_file_undo_info_trash_get_type ())
#define NAUTILUS_FILE_UNDO_INFO_TRASH(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NAUTILUS_TYPE_FILE_UNDO_INFO_TRASH, NautilusFileUndoInfoTrash))

View file

@ -322,7 +322,10 @@ nautilus_compute_title_for_location (GFile *location)
{
title = g_strdup (_("Other Locations"));
}
else
else if (nautilus_file_is_favorite_location (file))
{
title = g_strdup (_("Starred"));
}
{
title = nautilus_file_get_description (file);
@ -592,6 +595,19 @@ nautilus_is_search_directory (GFile *dir)
return eel_uri_is_search (uri);
}
gboolean
nautilus_is_favorite_directory (GFile *dir)
{
g_autofree gchar *uri = NULL;
uri = g_file_get_uri (dir);
if (eel_uri_is_favorites (uri))
return TRUE;
return FALSE;
}
gboolean
nautilus_is_other_locations_directory (GFile *dir)
{

View file

@ -45,6 +45,7 @@ gboolean nautilus_is_home_directory_file (GFile *dir,
const char *filename);
gboolean nautilus_is_in_system_dir (GFile *location);
gboolean nautilus_is_search_directory (GFile *dir);
gboolean nautilus_is_favorite_directory (GFile *dir);
gboolean nautilus_is_other_locations_directory (GFile *dir);
GMount * nautilus_get_mounted_mount_for_root (GFile *location);

View file

@ -40,6 +40,7 @@
#include "nautilus-vfs-file.h"
#include "nautilus-file-undo-operations.h"
#include "nautilus-file-undo-manager.h"
#include "nautilus-tag-manager.h"
#include <eel/eel-debug.h>
#include <eel/eel-glib-extensions.h>
#include <eel/eel-gtk-extensions.h>
@ -159,7 +160,8 @@ static GQuark attribute_name_q,
attribute_where_q,
attribute_link_target_q,
attribute_volume_q,
attribute_free_space_q;
attribute_free_space_q,
attribute_favorite_q;
static void nautilus_file_info_iface_init (NautilusFileInfoIface *iface);
static char *nautilus_file_get_owner_as_string (NautilusFile *file,
@ -3660,6 +3662,39 @@ compare_by_type (NautilusFile *file_1,
return result;
}
static int
compare_by_favorite (NautilusFile *file_1,
NautilusFile *file_2)
{
NautilusTagManager *tag_manager;
g_autofree gchar *uri_1 = NULL;
g_autofree gchar *uri_2 = NULL;
gboolean file_1_is_favorite;
gboolean file_2_is_favorite;
tag_manager = nautilus_tag_manager_get ();
uri_1 = nautilus_file_get_uri (file_1);
uri_2 = nautilus_file_get_uri (file_2);
file_1_is_favorite = nautilus_tag_manager_file_is_favorite (tag_manager,
uri_1);
file_2_is_favorite = nautilus_tag_manager_file_is_favorite (tag_manager,
uri_2);
if (!!file_1_is_favorite == !!file_2_is_favorite)
{
return 0;
}
else if (file_1_is_favorite && !file_2_is_favorite)
{
return -1;
}
else
{
return 1;
}
}
static Knowledge
get_search_relevance (NautilusFile *file,
gdouble *relevance_out)
@ -3863,6 +3898,16 @@ nautilus_file_compare_for_sort (NautilusFile *file_1,
}
break;
case NAUTILUS_FILE_SORT_BY_FAVORITE:
{
result = compare_by_favorite (file_1, file_2);
if (result == 0)
{
result = compare_by_full_path (file_1, file_2);
}
}
break;
case NAUTILUS_FILE_SORT_BY_MTIME:
{
result = compare_by_time (file_1, file_2, NAUTILUS_DATE_TYPE_MODIFIED);
@ -3967,6 +4012,13 @@ nautilus_file_compare_for_sort_by_attribute_q (NautilusFile *file_1,
directories_first,
reversed);
}
else if (attribute == attribute_favorite_q)
{
return nautilus_file_compare_for_sort (file_1, file_2,
NAUTILUS_FILE_SORT_BY_FAVORITE,
directories_first,
reversed);
}
else if (attribute == attribute_modification_date_q || attribute == attribute_date_modified_q || attribute == attribute_date_modified_with_time_q || attribute == attribute_date_modified_full_q)
{
return nautilus_file_compare_for_sort (file_1, file_2,
@ -4576,6 +4628,11 @@ nautilus_file_peek_display_name (NautilusFile *file)
char *
nautilus_file_get_display_name (NautilusFile *file)
{
if (nautilus_file_is_other_locations (file))
return g_strdup (_("Other Locations"));
if (nautilus_file_is_favorite_location (file))
return g_strdup (_("Starred"));
return g_strdup (nautilus_file_peek_display_name (file));
}
@ -7608,6 +7665,11 @@ nautilus_file_get_string_attribute_with_default_q (NautilusFile *file,
/* If n/a */
return g_strdup ("");
}
if (attribute_q == attribute_favorite_q)
{
/* If n/a */
return g_strdup ("");
}
/* Fallback, use for both unknown attributes and attributes
* for which we have no more appropriate default.
@ -8298,6 +8360,23 @@ nautilus_file_is_in_recent (NautilusFile *file)
return nautilus_directory_is_in_recent (file->details->directory);
}
/**
* nautilus_file_is_in_starred
*
* Check if this file is a file in Starred.
* @file: NautilusFile representing the file in question.
*
* Returns: TRUE if @file is in Starred.
*
**/
gboolean
nautilus_file_is_in_starred (NautilusFile *file)
{
g_assert (NAUTILUS_IS_FILE (file));
return nautilus_directory_is_in_starred (file->details->directory);
}
static const gchar * const remote_types[] =
{
"afp",
@ -8356,6 +8435,27 @@ nautilus_file_is_other_locations (NautilusFile *file)
return is_other_locations;
}
/**
* nautilus_file_is_favorite_location
*
* Check if this file is the Favorite location.
* @file: NautilusFile representing the file in question.
*
* Returns: TRUE if @file is the Favorite location.
*
**/
gboolean
nautilus_file_is_favorite_location (NautilusFile *file)
{
g_autofree gchar *uri = NULL;
g_assert (NAUTILUS_IS_FILE (file));
uri = nautilus_file_get_uri (file);
return eel_uri_is_favorites (uri);
}
/**
* nautilus_file_is_in_admin
*
@ -9371,6 +9471,7 @@ nautilus_file_class_init (NautilusFileClass *class)
attribute_link_target_q = g_quark_from_static_string ("link_target");
attribute_volume_q = g_quark_from_static_string ("volume");
attribute_free_space_q = g_quark_from_static_string ("free_space");
attribute_favorite_q = g_quark_from_static_string ("favorite");
G_OBJECT_CLASS (class)->finalize = finalize;
G_OBJECT_CLASS (class)->constructor = nautilus_file_constructor;

View file

@ -55,6 +55,7 @@ typedef enum {
NAUTILUS_FILE_SORT_BY_DISPLAY_NAME,
NAUTILUS_FILE_SORT_BY_SIZE,
NAUTILUS_FILE_SORT_BY_TYPE,
NAUTILUS_FILE_SORT_BY_FAVORITE,
NAUTILUS_FILE_SORT_BY_MTIME,
NAUTILUS_FILE_SORT_BY_ATIME,
NAUTILUS_FILE_SORT_BY_TRASHED_TIME,
@ -215,9 +216,11 @@ gboolean nautilus_file_is_archive (NautilusFile *file);
gboolean nautilus_file_is_in_search (NautilusFile *file);
gboolean nautilus_file_is_in_trash (NautilusFile *file);
gboolean nautilus_file_is_in_recent (NautilusFile *file);
gboolean nautilus_file_is_in_starred (NautilusFile *file);
gboolean nautilus_file_is_in_admin (NautilusFile *file);
gboolean nautilus_file_is_remote (NautilusFile *file);
gboolean nautilus_file_is_other_locations (NautilusFile *file);
gboolean nautilus_file_is_favorite_location (NautilusFile *file);
gboolean nautilus_file_is_home (NautilusFile *file);
gboolean nautilus_file_is_desktop_directory (NautilusFile *file);
gboolean nautilus_file_is_child_of_desktop_directory (NautilusFile *file);

View file

@ -42,6 +42,7 @@
#include "nautilus-window.h"
#include "nautilus-toolbar.h"
#include "nautilus-view.h"
#include "nautilus-tag-manager.h"
#ifdef HAVE_X11_XF86KEYSYM_H
#include <X11/XF86keysym.h>
@ -70,6 +71,7 @@
#include <libnautilus-extension/nautilus-menu-provider.h>
#include "nautilus-clipboard.h"
#include "nautilus-search-directory.h"
#include "nautilus-favorite-directory.h"
#include "nautilus-directory.h"
#include "nautilus-dnd.h"
#include "nautilus-file-attributes.h"
@ -254,6 +256,7 @@ typedef struct
GtkWidget *folder_is_empty_widget;
GtkWidget *trash_is_empty_widget;
GtkWidget *no_search_results_widget;
GtkWidget *starred_is_empty_widget;
/* Floating bar */
guint floating_bar_set_status_timeout_id;
@ -273,6 +276,9 @@ typedef struct
gulong stop_signal_handler;
gulong reload_signal_handler;
GCancellable *favorite_cancellable;
NautilusTagManager *tag_manager;
} NautilusFilesViewPrivate;
typedef struct
@ -747,6 +753,19 @@ showing_recent_directory (NautilusFilesView *view)
return FALSE;
}
static gboolean
showing_starred_directory (NautilusFilesView *view)
{
NautilusFile *file;
file = nautilus_files_view_get_directory_as_file (view);
if (file != NULL)
{
return nautilus_file_is_in_starred (file);
}
return FALSE;
}
static gboolean
nautilus_files_view_supports_creating_files (NautilusFilesView *view)
{
@ -754,7 +773,8 @@ nautilus_files_view_supports_creating_files (NautilusFilesView *view)
return !nautilus_files_view_is_read_only (view)
&& !showing_trash_directory (view)
&& !showing_recent_directory (view);
&& !showing_recent_directory (view)
&& !showing_starred_directory (view);
}
static gboolean
@ -1561,6 +1581,46 @@ action_delete (GSimpleAction *action,
delete_selected_files (NAUTILUS_FILES_VIEW (user_data));
}
static void
action_star (GSimpleAction *action,
GVariant *state,
gpointer user_data)
{
NautilusFilesView *view;
GList *selection;
NautilusFilesViewPrivate *priv;
view = NAUTILUS_FILES_VIEW (user_data);
priv = nautilus_files_view_get_instance_private (view);
selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
nautilus_tag_manager_star_files (priv->tag_manager,
G_OBJECT (view),
selection,
NULL,
priv->favorite_cancellable);
}
static void
action_unstar (GSimpleAction *action,
GVariant *state,
gpointer user_data)
{
NautilusFilesView *view;
GList *selection;
NautilusFilesViewPrivate *priv;
view = NAUTILUS_FILES_VIEW (user_data);
priv = nautilus_files_view_get_instance_private (view);
selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
nautilus_tag_manager_unstar_files (priv->tag_manager,
G_OBJECT (view),
selection,
NULL,
priv->favorite_cancellable);
}
static void
action_restore_from_trash (GSimpleAction *action,
GVariant *state,
@ -3226,6 +3286,9 @@ nautilus_files_view_finalize (GObject *object)
g_hash_table_destroy (priv->non_ready_files);
g_hash_table_destroy (priv->pending_reveal);
g_cancellable_cancel (priv->favorite_cancellable);
g_clear_object (&priv->favorite_cancellable);
G_OBJECT_CLASS (nautilus_files_view_parent_class)->finalize (object);
}
@ -3474,6 +3537,10 @@ nautilus_files_view_set_location (NautilusView *view,
set_search_query_internal (files_view, previous_query, base_model);
g_object_unref (previous_query);
}
else if (NAUTILUS_IS_FAVORITE_DIRECTORY (directory))
{
load_directory (NAUTILUS_FILES_VIEW (view), directory);
}
else
{
load_directory (NAUTILUS_FILES_VIEW (view), directory);
@ -3514,6 +3581,7 @@ real_check_empty_states (NautilusFilesView *view)
gtk_widget_hide (priv->no_search_results_widget);
gtk_widget_hide (priv->folder_is_empty_widget);
gtk_widget_hide (priv->trash_is_empty_widget);
gtk_widget_hide (priv->starred_is_empty_widget);
if (!priv->loading &&
nautilus_files_view_is_empty (view))
@ -3528,6 +3596,10 @@ real_check_empty_states (NautilusFilesView *view)
{
gtk_widget_show (priv->trash_is_empty_widget);
}
else if (eel_uri_is_favorites (uri))
{
gtk_widget_show (priv->starred_is_empty_widget);
}
else
{
gtk_widget_show (priv->folder_is_empty_widget);
@ -7014,6 +7086,8 @@ const GActionEntry view_entries[] =
{ "copy-to", action_copy_to},
{ "move-to-trash", action_move_to_trash},
{ "delete-from-trash", action_delete },
{ "star", action_star},
{ "unstar", action_unstar},
/* We separate the shortcut and the menu item since we want the shortcut
* to always be available, but we don't want the menu item shown if not
* completely necesary. Since the visibility of the menu item is based on
@ -7093,6 +7167,7 @@ on_clipboard_contents_received (GtkClipboard *clipboard,
gboolean settings_show_create_link;
gboolean is_read_only;
gboolean selection_contains_recent;
gboolean selection_contains_starred;
GAction *action;
view = NAUTILUS_FILES_VIEW (user_data);
@ -7110,9 +7185,10 @@ on_clipboard_contents_received (GtkClipboard *clipboard,
NAUTILUS_PREFERENCES_SHOW_CREATE_LINK);
is_read_only = nautilus_files_view_is_read_only (view);
selection_contains_recent = showing_recent_directory (view);
selection_contains_starred = showing_starred_directory (view);
can_link_from_copied_files = !nautilus_clipboard_is_cut_from_selection_data (selection_data) &&
!selection_contains_recent && !is_read_only &&
gtk_selection_data_get_length (selection_data) > 0;
!selection_contains_recent && !selection_contains_starred &&
!is_read_only && gtk_selection_data_get_length (selection_data) > 0;
action = g_action_map_lookup_action (G_ACTION_MAP (priv->view_action_group),
"create-link");
@ -7399,6 +7475,7 @@ real_update_actions_state (NautilusFilesView *view)
gboolean selection_contains_desktop_or_home_dir;
gboolean selection_contains_recent;
gboolean selection_contains_search;
gboolean selection_contains_starred;
gboolean selection_all_in_trash;
gboolean selection_is_read_only;
gboolean can_create_files;
@ -7423,6 +7500,9 @@ real_update_actions_state (NautilusFilesView *view)
gboolean settings_show_delete_permanently;
gboolean settings_show_create_link;
GDriveStartStopType start_stop_type;
gboolean show_star;
gboolean show_unstar;
gchar *uri;
priv = nautilus_files_view_get_instance_private (view);
@ -7433,6 +7513,7 @@ real_update_actions_state (NautilusFilesView *view)
selection_contains_special_link = nautilus_files_view_special_link_in_selection (view, selection);
selection_contains_desktop_or_home_dir = desktop_or_home_dir_in_selection (selection);
selection_contains_recent = showing_recent_directory (view);
selection_contains_starred = showing_starred_directory (view);
selection_contains_search = nautilus_view_is_searching (NAUTILUS_VIEW (view));
selection_is_read_only = selection_count == 1 &&
(!nautilus_file_can_write (NAUTILUS_FILE (selection->data)) &&
@ -7454,8 +7535,10 @@ real_update_actions_state (NautilusFilesView *view)
!selection_contains_desktop_or_home_dir;
can_copy_files = selection_count != 0
&& !selection_contains_special_link;
can_move_files = can_delete_files && !selection_contains_recent;
can_move_files = can_delete_files && !selection_contains_recent &&
!selection_contains_starred;
can_paste_files_into = (!selection_contains_recent &&
!selection_contains_starred &&
selection_count == 1 &&
can_paste_into_file (NAUTILUS_FILE (selection->data)));
can_extract_files = selection_count != 0 &&
@ -7471,7 +7554,8 @@ real_update_actions_state (NautilusFilesView *view)
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
"new-folder-with-selection");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
can_create_files && can_delete_files && (selection_count > 1) && !selection_contains_recent);
can_create_files && can_delete_files && (selection_count > 1) && !selection_contains_recent
&& !selection_contains_starred);
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
"rename");
@ -7519,7 +7603,8 @@ real_update_actions_state (NautilusFilesView *view)
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
selection_count == 1 &&
(selection_contains_recent || selection_contains_search));
(selection_contains_recent || selection_contains_search ||
selection_contains_starred));
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
"new-folder");
@ -7585,14 +7670,16 @@ real_update_actions_state (NautilusFilesView *view)
"delete-permanently-menu-item");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
can_delete_files && !can_trash_files &&
!selection_all_in_trash && !selection_contains_recent);
!selection_all_in_trash && !selection_contains_recent &&
!selection_contains_starred);
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
"permanent-delete-permanently-menu-item");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
can_delete_files && can_trash_files &&
settings_show_delete_permanently &&
!selection_all_in_trash && !selection_contains_recent);
!selection_all_in_trash && !selection_contains_recent &&
!selection_contains_starred);
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
"remove-from-recent");
@ -7602,7 +7689,8 @@ real_update_actions_state (NautilusFilesView *view)
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
"cut");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
can_move_files && !selection_contains_recent);
can_move_files && !selection_contains_recent &&
!selection_contains_starred);
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
"copy");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
@ -7620,7 +7708,8 @@ real_update_actions_state (NautilusFilesView *view)
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
"move-to");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
can_move_files && !selection_contains_recent);
can_move_files && !selection_contains_recent &&
!selection_contains_starred);
/* Drive menu */
show_mount = (selection != NULL);
@ -7697,13 +7786,14 @@ real_update_actions_state (NautilusFilesView *view)
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
"paste");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
!is_read_only && !selection_contains_recent);
!is_read_only && !selection_contains_recent &&
!selection_contains_starred);
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
"paste-into");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
!selection_is_read_only && !selection_contains_recent &&
can_paste_files_into);
can_paste_files_into && !selection_contains_starred);
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
"properties");
@ -7714,6 +7804,7 @@ real_update_actions_state (NautilusFilesView *view)
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
can_create_files &&
!selection_contains_recent &&
!selection_contains_starred &&
priv->templates_present);
/* Actions that are related to the clipboard need request, request the data
@ -7757,6 +7848,38 @@ real_update_actions_state (NautilusFilesView *view)
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
!nautilus_files_view_is_empty (view));
show_star = (selection != NULL);
show_unstar = (selection != NULL);
for (l = selection; l != NULL; l = l->next)
{
file = NAUTILUS_FILE (l->data);
uri = nautilus_file_get_uri (file);
if (!show_star && !show_unstar)
{
break;
}
if (nautilus_tag_manager_file_is_favorite (priv->tag_manager, uri))
{
show_star = FALSE;
}
else
{
show_unstar = FALSE;
}
g_free (uri);
}
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
"star");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), show_star);
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
"unstar");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), show_unstar);
nautilus_file_list_free (selection);
}
@ -8031,7 +8154,8 @@ static void
update_background_menu (NautilusFilesView *view)
{
if (nautilus_files_view_supports_creating_files (view) &&
!showing_recent_directory (view))
!showing_recent_directory (view) &&
!showing_starred_directory (view))
{
update_templates_menu (view);
}
@ -9601,6 +9725,14 @@ nautilus_files_view_init (NautilusFilesView *view)
TRUE);
g_object_unref (builder);
builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/ui/nautilus-starred-is-empty.ui");
priv->starred_is_empty_widget = GTK_WIDGET (gtk_builder_get_object (builder, "starred_is_empty"));
gtk_overlay_add_overlay (GTK_OVERLAY (priv->overlay), priv->starred_is_empty_widget);
gtk_overlay_set_overlay_pass_through (GTK_OVERLAY (priv->overlay),
priv->starred_is_empty_widget,
TRUE);
g_object_unref (builder);
builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/ui/nautilus-trash-is-empty.ui");
priv->trash_is_empty_widget = GTK_WIDGET (gtk_builder_get_object (builder, "trash_is_empty"));
gtk_overlay_add_overlay (GTK_OVERLAY (priv->overlay), priv->trash_is_empty_widget);
@ -9742,6 +9874,9 @@ nautilus_files_view_init (NautilusFilesView *view)
* changed */
nautilus_application_set_accelerator (app, "view.show-move-to-trash-shortcut-changed-dialog", "<control>Delete");
priv->favorite_cancellable = g_cancellable_new ();
priv->tag_manager = nautilus_tag_manager_get ();
nautilus_profile_end (NULL);
}

View file

@ -21,6 +21,7 @@
#include "nautilus-list-model.h"
#include "nautilus-tree-view-drag-dest.h"
#include "nautilus-dnd.h"
#include "nautilus-tag-manager.h"
struct NautilusListViewDetails {
GtkTreeView *tree_view;
@ -66,5 +67,8 @@ struct NautilusListViewDetails {
GQuark last_sort_attr;
GRegex *regex;
NautilusTagManager *tag_manager;
GCancellable *favorite_cancellable;
};

View file

@ -32,6 +32,7 @@
#include "nautilus-toolbar.h"
#include "nautilus-list-view-dnd.h"
#include "nautilus-view.h"
#include "nautilus-tag-manager.h"
#include <string.h>
#include <eel/eel-vfs-extensions.h>
@ -457,6 +458,90 @@ row_activated_callback (GtkTreeView *treeview,
activate_selected_items (view);
}
gboolean
check_starred_status (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
gpointer data)
{
NautilusFile *file;
GList *l;
GList *changed_files;
changed_files = data;
gtk_tree_model_get (GTK_TREE_MODEL (model),
iter,
NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
-1);
if (!file)
{
return FALSE;
}
for (l = changed_files; l != NULL; l = l->next)
{
if (nautilus_file_compare_location (NAUTILUS_FILE (l->data), file) == 0)
{
gtk_tree_model_row_changed (model, path, iter);
}
}
nautilus_file_unref (file);
return FALSE;
}
static void
on_favorites_files_changed (NautilusTagManager *tag_manager,
GList *changed_files,
gpointer user_data)
{
NautilusListView *list_view;
list_view = NAUTILUS_LIST_VIEW (user_data);
gtk_tree_model_foreach (GTK_TREE_MODEL (list_view->details->model),
check_starred_status,
changed_files);
}
static void
on_star_cell_renderer_clicked (GtkTreePath *path,
NautilusListView *list_view)
{
NautilusListModel *list_model;
NautilusFile *file;
g_autofree gchar *uri = NULL;
GList *selection;
list_model = list_view->details->model;
file = nautilus_list_model_file_for_path (list_model, path);
uri = nautilus_file_get_uri (file);
selection = g_list_prepend (NULL, file);
if (nautilus_tag_manager_file_is_favorite (list_view->details->tag_manager, uri))
{
nautilus_tag_manager_unstar_files (list_view->details->tag_manager,
G_OBJECT (list_view),
selection,
NULL,
list_view->details->favorite_cancellable);
}
else
{
nautilus_tag_manager_star_files (list_view->details->tag_manager,
G_OBJECT (list_view),
selection,
NULL,
list_view->details->favorite_cancellable);
}
nautilus_file_list_free (selection);
}
static gboolean
button_press_callback (GtkWidget *widget,
GdkEventButton *event,
@ -703,6 +788,32 @@ button_press_callback (GtkWidget *widget,
}
}
if (is_simple_click)
{
GtkTreeViewColumn *column = NULL;
gdouble cell_middle_x;
gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (view->details->tree_view),
event->x,
event->y,
NULL,
&column,
NULL,
NULL);
if (g_strcmp0 (gtk_tree_view_column_get_title (column), "Star") == 0)
{
cell_middle_x = gtk_tree_view_column_get_width (column) / 2 +
gtk_tree_view_column_get_x_offset (column);
if (event->x > cell_middle_x - 10 &&
event->x < cell_middle_x + 10)
{
on_star_cell_renderer_clicked (path, view);
}
}
}
gtk_tree_path_free (path);
/* We chained to the default handler in this method, so never
@ -1546,6 +1657,45 @@ apply_columns_settings (NautilusListView *list_view,
g_list_free (view_columns);
}
static void
favorite_cell_data_func (GtkTreeViewColumn *column,
GtkCellRenderer *renderer,
GtkTreeModel *model,
GtkTreeIter *iter,
NautilusListView *view)
{
g_autofree gchar *text = NULL;
g_autofree gchar *uri = NULL;
NautilusFile *file;
gtk_tree_model_get (model, iter,
view->details->file_name_column_num, &text,
-1);
gtk_tree_model_get (GTK_TREE_MODEL (model),
iter,
NAUTILUS_LIST_MODEL_FILE_COLUMN, &file,
-1);
uri = nautilus_file_get_uri (file);
if (nautilus_tag_manager_file_is_favorite (view->details->tag_manager, uri))
{
g_object_set (renderer,
"icon-name", "starred-symbolic",
NULL);
}
else
{
g_object_set (renderer,
"icon-name", "non-starred-symbolic",
NULL);
}
nautilus_file_unref (file);
}
static void
filename_cell_data_func (GtkTreeViewColumn *column,
GtkCellRenderer *renderer,
@ -2040,13 +2190,34 @@ create_and_set_up_tree_view (NautilusListView *view)
}
else
{
/* We need to use libgd */
cell = gd_styled_text_renderer_new ();
/* FIXME: should be just dim-label.
* See https://bugzilla.gnome.org/show_bug.cgi?id=744397
*/
gd_styled_text_renderer_add_class (GD_STYLED_TEXT_RENDERER (cell),
"nautilus-list-dim-label");
if (g_strcmp0 (name, "favorite") == 0)
{
cell = gtk_cell_renderer_pixbuf_new ();
g_object_set (cell,
"icon-name", "non-starred-symbolic",
"mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE,
NULL);
column = gtk_tree_view_column_new_with_attributes (label,
cell,
NULL);
}
else
{
/* We need to use libgd */
cell = gd_styled_text_renderer_new ();
/* FIXME: should be just dim-label.
* See https://bugzilla.gnome.org/show_bug.cgi?id=744397
*/
gd_styled_text_renderer_add_class (GD_STYLED_TEXT_RENDERER (cell),
"nautilus-list-dim-label");
column = gtk_tree_view_column_new_with_attributes (label,
cell,
"text", column_num,
NULL);
}
g_object_set (cell,
"xalign", xalign,
@ -2060,10 +2231,7 @@ create_and_set_up_tree_view (NautilusListView *view)
}
view->details->cells = g_list_append (view->details->cells,
cell);
column = gtk_tree_view_column_new_with_attributes (label,
cell,
"text", column_num,
NULL);
gtk_tree_view_append_column (view->details->tree_view, column);
gtk_tree_view_column_set_sort_column_id (column, column_num);
g_hash_table_insert (view->details->columns,
@ -2090,6 +2258,12 @@ create_and_set_up_tree_view (NautilusListView *view)
(GtkTreeCellDataFunc) trash_orig_path_cell_data_func,
view, NULL);
}
else if (!strcmp (name, "favorite"))
{
gtk_tree_view_column_set_cell_data_func (column, cell,
(GtkTreeCellDataFunc) favorite_cell_data_func,
view, NULL);
}
}
g_free (name);
g_free (label);
@ -3378,6 +3552,13 @@ nautilus_list_view_finalize (GObject *object)
g_regex_unref (list_view->details->regex);
g_cancellable_cancel (list_view->details->favorite_cancellable);
g_clear_object (&list_view->details->favorite_cancellable);
g_signal_handlers_disconnect_by_func (list_view->details->tag_manager,
on_favorites_files_changed,
list_view);
g_free (list_view->details);
G_OBJECT_CLASS (nautilus_list_view_parent_class)->finalize (object);
@ -3664,6 +3845,14 @@ nautilus_list_view_init (NautilusListView *list_view)
"zoom-to-level", g_variant_new_int32 (get_default_zoom_level ()));
list_view->details->regex = g_regex_new ("\\R+", 0, G_REGEX_MATCH_NEWLINE_ANY, NULL);
list_view->details->tag_manager = nautilus_tag_manager_get ();
list_view->details->favorite_cancellable = g_cancellable_new ();
g_signal_connect (list_view->details->tag_manager,
"favorites-changed",
(GCallback) on_favorites_files_changed,
list_view);
}
NautilusFilesView *

View file

@ -47,7 +47,8 @@ typedef enum
OTHER_LOCATIONS_BUTTON,
ROOT_BUTTON,
HOME_BUTTON,
MOUNT_BUTTON
MOUNT_BUTTON,
FAVORITE_LOCATION_BUTTON
} ButtonType;
#define BUTTON_DATA(x) ((ButtonData *) (x))
@ -454,6 +455,11 @@ get_dir_name (ButtonData *button_data)
return _("Other Locations");
}
case FAVORITE_LOCATION_BUTTON:
{
return _("Starred");
}
default:
return button_data->dir_name;
}
@ -1924,6 +1930,10 @@ setup_button_type (ButtonData *button_data,
g_object_unref (mount);
}
else if (nautilus_is_favorite_directory (location))
{
button_data->type = FAVORITE_LOCATION_BUTTON;
}
else
{
button_data->type = NORMAL_BUTTON;

View file

@ -46,6 +46,7 @@ struct _NautilusQuery
GPtrArray *date_range;
NautilusQuerySearchType search_type;
NautilusQuerySearchContent search_content;
gboolean search_favorite;
gboolean searching;
gboolean recursive;
@ -343,6 +344,7 @@ nautilus_query_init (NautilusQuery *query)
query->location = g_file_new_for_path (g_get_home_dir ());
query->search_type = g_settings_get_enum (nautilus_preferences, "search-filter-time-type");
query->search_content = NAUTILUS_QUERY_SEARCH_CONTENT_SIMPLE;
query->search_favorite = FALSE;
g_mutex_init (&query->prepared_words_mutex);
}
@ -550,6 +552,23 @@ nautilus_query_set_search_content (NautilusQuery *query,
}
}
gboolean
nautilus_query_get_search_favorite (NautilusQuery *query)
{
g_return_val_if_fail (NAUTILUS_IS_QUERY (query), FALSE);
return query->search_favorite;
}
void
nautilus_query_set_search_favorite (NautilusQuery *query,
gboolean search_favorite)
{
g_return_if_fail (NAUTILUS_IS_QUERY (query));
query->search_favorite = search_favorite;
}
NautilusQuerySearchType
nautilus_query_get_search_type (NautilusQuery *query)
{

View file

@ -59,6 +59,10 @@ NautilusQuerySearchContent nautilus_query_get_search_content (NautilusQuery *que
void nautilus_query_set_search_content (NautilusQuery *query,
NautilusQuerySearchContent content);
gboolean nautilus_query_get_search_favorite (NautilusQuery *query);
void nautilus_query_set_search_favorite (NautilusQuery *query,
gboolean search_favorite);
NautilusQuerySearchType nautilus_query_get_search_type (NautilusQuery *query);
void nautilus_query_set_search_type (NautilusQuery *query,
NautilusQuerySearchType type);

View file

@ -27,6 +27,7 @@
#include "nautilus-directory-private.h"
#include "nautilus-file.h"
#include "nautilus-ui-utilities.h"
#include "nautilus-tag-manager.h"
#define DEBUG_FLAG NAUTILUS_DEBUG_SEARCH
#include "nautilus-debug.h"
@ -139,6 +140,7 @@ model_directory_ready_cb (NautilusDirectory *directory,
GDateTime *initial_date;
GDateTime *end_date;
GPtrArray *date_range;
NautilusTagManager *tag_manager;
files = nautilus_directory_get_file_list (directory);
mime_types = nautilus_query_get_mime_types (model->query);
@ -191,12 +193,27 @@ model_directory_ready_cb (NautilusDirectory *directory,
g_ptr_array_unref (date_range);
}
if (nautilus_query_get_search_favorite (model->query))
{
tag_manager = nautilus_tag_manager_get ();
uri = nautilus_file_get_uri (file);
if (!nautilus_tag_manager_file_is_favorite (tag_manager, uri))
{
found = FALSE;
}
g_free (uri);
}
if (found)
{
uri = nautilus_file_get_uri (file);
hit = nautilus_search_hit_new (uri);
nautilus_search_hit_set_fts_rank (hit, match);
hits = g_list_prepend (hits, hit);
g_free (uri);
}

View file

@ -24,6 +24,7 @@
#include "nautilus-search-provider.h"
#include "nautilus-search-engine-simple.h"
#include "nautilus-ui-utilities.h"
#include "nautilus-tag-manager.h"
#define DEBUG_FLAG NAUTILUS_DEBUG_SEARCH
#include "nautilus-debug.h"
@ -222,7 +223,8 @@ visit_directory (GFile *dir,
GPtrArray *date_range;
GDateTime *initial_date;
GDateTime *end_date;
NautilusTagManager *tag_manager;
gchar *uri;
enumerator = g_file_enumerate_children (dir,
data->mime_types != NULL ?
@ -299,11 +301,24 @@ visit_directory (GFile *dir,
g_ptr_array_unref (date_range);
}
if (nautilus_query_get_search_favorite (data->query))
{
tag_manager = nautilus_tag_manager_get ();
uri = g_file_get_uri (child);
if (!nautilus_tag_manager_file_is_favorite (tag_manager, uri))
{
found = FALSE;
}
g_free (uri);
}
if (found)
{
NautilusSearchHit *hit;
GDateTime *date;
char *uri;
uri = g_file_get_uri (child);
hit = nautilus_search_hit_new (uri);

View file

@ -353,6 +353,11 @@ nautilus_search_engine_tracker_start (NautilusSearchProvider *provider)
g_string_append_printf (sparql, "; fts:match '\"%s\"*'", search_text);
}
if (nautilus_query_get_search_favorite (tracker->query))
{
g_string_append_printf (sparql, "; nao:hasTag nao:predefined-tag-favorite");
}
if (mime_count > 0)
{
g_string_append (sparql, "; nie:mimeType ?mime");

View file

@ -95,17 +95,17 @@ search_engine_start_real (NautilusSearchEngine *engine)
g_object_ref (engine);
nautilus_search_provider_start (NAUTILUS_SEARCH_PROVIDER (priv->tracker));
priv->providers_running++;
nautilus_search_provider_start (NAUTILUS_SEARCH_PROVIDER (priv->tracker));
if (nautilus_search_engine_model_get_model (priv->model))
{
nautilus_search_provider_start (NAUTILUS_SEARCH_PROVIDER (priv->model));
priv->providers_running++;
nautilus_search_provider_start (NAUTILUS_SEARCH_PROVIDER (priv->model));
}
nautilus_search_provider_start (NAUTILUS_SEARCH_PROVIDER (priv->simple));
priv->providers_running++;
nautilus_search_provider_start (NAUTILUS_SEARCH_PROVIDER (priv->simple));
}
static void

884
src/nautilus-tag-manager.c Normal file
View file

@ -0,0 +1,884 @@
/* nautilus-tag-manager.c
*
* Copyright (C) 2017 Alexandru Pandelea <alexandru.pandelea@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 2 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-tag-manager.h"
#include "nautilus-file.h"
#include "nautilus-file-undo-operations.h"
#include "nautilus-file-undo-manager.h"
#include <tracker-sparql.h>
struct _NautilusTagManager
{
GObject object;
TrackerNotifier *notifier;
GError *notifier_error;
GHashTable *favorite_files;
GCancellable *cancellable;
};
G_DEFINE_TYPE (NautilusTagManager, nautilus_tag_manager, G_TYPE_OBJECT);
static NautilusTagManager *tag_manager = NULL;
typedef enum
{
GET_FAVORITE_FILES,
GET_IDS_FOR_URLS
} OperationType;
typedef struct
{
GTask *task;
GList *selection;
GHashTable *ids;
GObject *object;
GAsyncReadyCallback callback;
GCancellable *cancellable;
} InsertTaskData;
typedef struct
{
NautilusTagManager *tag_manager;
GTask *task;
GList *selection;
gboolean star;
GHashTable *ids;
} UpdateData;
enum
{
FAVORITES_CHANGED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
static const gchar*
nautilus_tag_manager_file_with_id_changed_url (GHashTable *hash_table,
gint64 id,
const gchar *url)
{
GHashTableIter iter;
gpointer key, value;
g_hash_table_iter_init (&iter, hash_table);
while (g_hash_table_iter_next (&iter, &key, &value))
{
if ((gint64) value == id && g_strcmp0 (url, key) != 0)
{
return key;
}
}
return NULL;
}
void
destroy_insert_task_data (gpointer data)
{
InsertTaskData *task_data;
task_data = data;
nautilus_file_list_free (task_data->selection);
g_free (data);
}
static GString*
add_selection_filter (GList *selection,
GString *query)
{
NautilusFile *file;
GList *l;
gchar *uri;
g_string_append (query, " FILTER(?url IN (");
for (l = selection; l != NULL; l = l->next)
{
file = l->data;
uri = nautilus_file_get_uri (file);
g_string_append_printf (query, "'%s'", uri);
if (l->next != NULL)
{
g_string_append (query, ", ");
}
g_free (uri);
}
g_string_append (query, "))");
return query;
}
static void
start_query_or_update (GString *query,
GAsyncReadyCallback callback,
gpointer user_data,
gboolean is_query,
GCancellable *cancellable)
{
g_autoptr (GError) error = NULL;
TrackerSparqlConnection *connection;
connection = tracker_sparql_connection_get (cancellable, &error);
if (!connection)
{
if (error)
{
g_warning ("Error on getting connection: %s", error->message);
}
return;
}
if (is_query)
{
tracker_sparql_connection_query_async (connection,
query->str,
cancellable,
callback,
user_data);
}
else
{
tracker_sparql_connection_update_async (connection,
query->str,
G_PRIORITY_DEFAULT,
cancellable,
callback,
user_data);
}
g_object_unref (connection);
}
static void
on_query_callback (GObject *object,
GAsyncResult *result,
gpointer user_data,
GAsyncReadyCallback callback,
OperationType op_type,
GCancellable *cancellable)
{
TrackerSparqlCursor *cursor;
g_autoptr (GError) error = NULL;
TrackerSparqlConnection *connection;
GTask *task;
task = user_data;
connection = TRACKER_SPARQL_CONNECTION (object);
cursor = tracker_sparql_connection_query_finish (connection,
result,
&error);
if (error != NULL)
{
if (error->code != G_IO_ERROR_CANCELLED)
{
if (op_type == GET_FAVORITE_FILES)
{
g_warning ("Error on getting favorite files: %s", error->message);
}
else if (op_type == GET_IDS_FOR_URLS)
{
g_warning ("Error on getting id for url: %s", error->message);
g_task_return_pointer (task, g_task_get_task_data (task), NULL);
g_object_unref (task);
}
else
{
g_warning ("Error on getting query callback: %s", error->message);
}
}
}
else
{
tracker_sparql_cursor_next_async (cursor,
cancellable,
callback,
user_data);
}
}
static void
on_update_callback (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
TrackerSparqlConnection *connection;
GError *error;
UpdateData *data;
gint64 *id;
GList *l;
gchar *uri;
data = user_data;
error = NULL;
connection = TRACKER_SPARQL_CONNECTION (object);
tracker_sparql_connection_update_finish (connection, result, &error);
if (error == NULL ||
(error != NULL && error->code != G_IO_ERROR_CANCELLED))
{
for (l = data->selection; l != NULL; l = l->next)
{
uri = nautilus_file_get_uri (NAUTILUS_FILE (l->data));
if (data->star)
{
if (g_hash_table_contains (data->ids, uri))
{
id = g_new0 (gint64, 1);
*id = (gint64) g_hash_table_lookup (data->ids, uri);
g_hash_table_insert (data->tag_manager->favorite_files,
nautilus_file_get_uri (NAUTILUS_FILE (l->data)),
id);
}
}
else
{
g_hash_table_remove (data->tag_manager->favorite_files, uri);
}
g_free (uri);
}
if (!nautilus_file_undo_manager_is_operating ())
{
NautilusFileUndoInfo *undo_info;
undo_info = nautilus_file_undo_info_favorites_new (data->selection, data->star);
nautilus_file_undo_manager_set_action (undo_info);
g_object_unref (undo_info);
}
g_signal_emit_by_name (data->tag_manager, "favorites-changed", nautilus_file_list_copy (data->selection));
g_task_return_boolean (data->task, TRUE);
g_object_unref (data->task);
}
else if (error && error->code == G_IO_ERROR_CANCELLED)
{
g_error_free (error);
}
else
{
g_task_return_error (data->task, error);
g_object_unref (data->task);
g_warning ("error updating tags: %s", error->message);
}
if (data->ids)
{
g_hash_table_destroy (data->ids);
}
nautilus_file_list_free (data->selection);
g_free (data);
}
static gboolean
get_query_status (TrackerSparqlCursor *cursor,
GAsyncResult *result,
OperationType op_type,
gpointer user_data)
{
gboolean success;
GTask *task;
g_autoptr (GError) error = NULL;
task = user_data;
success = tracker_sparql_cursor_next_finish (cursor, result, &error);
if (!success)
{
if (error)
{
g_warning ("Error on getting all tags cursor callback: %s", error->message);
}
g_clear_object (&cursor);
if (error == NULL ||
(error != NULL && error->code != G_IO_ERROR_CANCELLED))
{
if (op_type == GET_IDS_FOR_URLS)
{
g_task_return_pointer (task, g_task_get_task_data (task), NULL);
g_object_unref (task);
}
}
}
return success;
}
GList*
nautilus_tag_manager_get_favorite_files (NautilusTagManager *self)
{
return g_hash_table_get_keys (self->favorite_files);
}
static void
on_get_favorite_files_cursor_callback (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
TrackerSparqlCursor *cursor;
const gchar *url;
gint64 *id;
gboolean success;
NautilusTagManager *self;
GList *changed_files;
NautilusFile *file;
cursor = TRACKER_SPARQL_CURSOR (object);
self = NAUTILUS_TAG_MANAGER (user_data);
success = get_query_status (cursor, result, GET_FAVORITE_FILES, NULL);
if (!success)
{
return;
}
id = g_new0 (gint64, 1);
url = tracker_sparql_cursor_get_string (cursor, 0, NULL);
*id = tracker_sparql_cursor_get_integer (cursor, 1);
g_hash_table_insert (self->favorite_files,
g_strdup (url),
id);
file = nautilus_file_get_by_uri (url);
changed_files = g_list_prepend (NULL, file);
g_signal_emit_by_name (self, "favorites-changed", changed_files);
nautilus_file_list_free (changed_files);
tracker_sparql_cursor_next_async (cursor,
self->cancellable,
on_get_favorite_files_cursor_callback,
self);
}
static void
on_get_favorite_files_query_callback (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
NautilusTagManager *self;
self = NAUTILUS_TAG_MANAGER (user_data);
on_query_callback (object,
result,
user_data,
on_get_favorite_files_cursor_callback,
GET_FAVORITE_FILES,
self->cancellable);
}
static void
nautilus_tag_manager_query_favorite_files (NautilusTagManager *self,
GCancellable *cancellable)
{
GString *query;
self->cancellable = cancellable;
query = g_string_new ("SELECT ?url tracker:id(?urn) WHERE { ?urn nie:url ?url ; nao:hasTag nao:predefined-tag-favorite}");
start_query_or_update (query,
on_get_favorite_files_query_callback,
self,
TRUE,
cancellable);
g_string_free (query, TRUE);
}
static gpointer
nautilus_tag_manager_gpointer_task_finish (GObject *source_object,
GAsyncResult *res,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (res, source_object), FALSE);
return g_task_propagate_pointer (G_TASK (res), error);
}
static GString*
nautilus_tag_manager_delete_tag (NautilusTagManager *self,
GList *selection,
GString *query)
{
g_string_append (query,
"DELETE { ?urn nao:hasTag nao:predefined-tag-favorite }"
"WHERE { ?urn a nfo:FileDataObject ; nie:url ?url .");
query = add_selection_filter (selection, query);
g_string_append (query, "}\n");
return query;
}
static GString*
nautilus_tag_manager_insert_tag (NautilusTagManager *self,
GList *selection,
GString *query)
{
g_string_append (query,
"INSERT { ?urn nao:hasTag nao:predefined-tag-favorite }"
"WHERE { ?urn a nfo:FileDataObject ; nie:url ?url .");
query = add_selection_filter (selection, query);
g_string_append (query, "}\n");
return query;
}
gboolean
nautilus_tag_manager_file_is_favorite (NautilusTagManager *self,
const gchar *file_name)
{
return g_hash_table_contains (self->favorite_files, file_name);
}
static void
on_get_file_ids_for_urls_cursor_callback (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
TrackerSparqlCursor *cursor;
GTask *task;
gint64 *id;
const gchar *url;
gboolean success;
GList *l;
gchar *file_url;
InsertTaskData *data;
task = user_data;
data = g_task_get_task_data (task);
cursor = TRACKER_SPARQL_CURSOR (object);
success = get_query_status (cursor, result, GET_IDS_FOR_URLS, task);
if (!success)
{
return;
}
id = g_new0 (gint64, 1);
url = tracker_sparql_cursor_get_string (cursor, 0, NULL);
*id = tracker_sparql_cursor_get_integer (cursor, 1);
for (l = data->selection; l != NULL; l = l->next)
{
file_url = nautilus_file_get_uri (NAUTILUS_FILE (l->data));
if (g_strcmp0 (file_url, url) == 0)
{
g_hash_table_insert (data->ids,
g_strdup (url),
id);
g_free (file_url);
break;
}
g_free (file_url);
}
tracker_sparql_cursor_next_async (cursor,
g_task_get_cancellable (task),
on_get_file_ids_for_urls_cursor_callback,
task);
}
static void
on_get_file_ids_for_urls_query_callback (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GTask *task;
task = user_data;
on_query_callback (object,
result,
user_data,
on_get_file_ids_for_urls_cursor_callback,
GET_IDS_FOR_URLS,
g_task_get_cancellable (task));
}
static void
nautilus_tag_manager_get_file_ids_for_urls (GObject *object,
GList *selection,
GTask *task)
{
GString *query;
query = g_string_new ("SELECT ?url tracker:id(?urn) WHERE { ?urn nie:url ?url; .");
query = add_selection_filter (selection, query);
g_string_append (query, "}\n");
start_query_or_update (query,
on_get_file_ids_for_urls_query_callback,
task,
TRUE,
g_task_get_cancellable (task));
g_string_free (query, TRUE);
}
static void
on_star_files_callback (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
NautilusTagManager *self;
GString *query;
InsertTaskData *data;
g_autoptr (GError) error = NULL;
GTask *task;
UpdateData *update_data;
self = NAUTILUS_TAG_MANAGER (object);
data = nautilus_tag_manager_gpointer_task_finish (object, res, &error);
task = g_task_new (data->object, data->cancellable, data->callback, NULL);
query = g_string_new ("");
query = nautilus_tag_manager_insert_tag (self,
data->selection,
query);
update_data = g_new0 (UpdateData, 1);
update_data->task = task;
update_data->tag_manager = self;
update_data->selection = nautilus_file_list_copy (data->selection);
update_data->star = TRUE;
update_data->ids = data->ids;
/* the ids hash table is now owned by the update_data,
* so it will be freed by it.
*/
destroy_insert_task_data (data);
start_query_or_update (query,
on_update_callback,
update_data,
FALSE,
g_task_get_cancellable (task));
g_string_free (query, TRUE);
}
void
nautilus_tag_manager_star_files (NautilusTagManager *self,
GObject *object,
GList *selection,
GAsyncReadyCallback callback,
GCancellable *cancellable)
{
GTask *task;
InsertTaskData *data;
data = g_new0 (InsertTaskData, 1);
data->selection = nautilus_file_list_copy (selection);
data->ids = g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) g_free);
data->callback = callback;
data->object = object;
data->cancellable = cancellable;
task = g_task_new (self, cancellable, on_star_files_callback, NULL);
g_task_set_task_data (task,
data,
NULL);
nautilus_tag_manager_get_file_ids_for_urls (G_OBJECT (self), selection, task);
}
void
nautilus_tag_manager_unstar_files (NautilusTagManager *self,
GObject *object,
GList *selection,
GAsyncReadyCallback callback,
GCancellable *cancellable)
{
GString *query;
GTask *task;
UpdateData *update_data;
task = g_task_new (object, cancellable, callback, NULL);
query = g_string_new ("");
query = nautilus_tag_manager_delete_tag (self,
selection,
query);
update_data = g_new0 (UpdateData, 1);
update_data->task = task;
update_data->tag_manager = self;
update_data->selection = nautilus_file_list_copy (selection);
update_data->star = FALSE;
start_query_or_update (query,
on_update_callback,
update_data,
FALSE,
cancellable);
g_string_free (query, TRUE);
}
void
on_tracker_notifier_events(TrackerNotifier *notifier,
GPtrArray *events,
gpointer user_data)
{
TrackerNotifierEvent *event;
NautilusTagManager *self;
int i;
const gchar *location_uri;
const gchar *new_location_uri;
GError *error = NULL;
TrackerSparqlConnection *connection;
TrackerSparqlCursor *cursor;
GString *query;
gboolean query_has_results;
gint64 *id;
GList *changed_files;
NautilusFile *file;
self = NAUTILUS_TAG_MANAGER (user_data);
for (i = 0; i < events->len; i++)
{
event = g_ptr_array_index (events, i);
location_uri = tracker_notifier_event_get_location (event);
query = g_string_new ("");
g_string_append_printf (query,
"SELECT ?url WHERE { ?urn nie:url ?url; nao:hasTag nao:predefined-tag-favorite . FILTER (tracker:id(?urn) = %ld)}",
tracker_notifier_event_get_id (event));
/* check if the file changed it's location and update hash table if so */
new_location_uri = nautilus_tag_manager_file_with_id_changed_url (self->favorite_files,
tracker_notifier_event_get_id (event),
location_uri);
if (new_location_uri)
{
id = g_new0 (gint64, 1);
*id = tracker_notifier_event_get_id (event);
g_hash_table_remove (self->favorite_files, new_location_uri);
g_hash_table_insert (self->favorite_files,
g_strdup (location_uri),
id);
file = nautilus_file_get_by_uri (location_uri);
changed_files = g_list_prepend (NULL, file);
g_signal_emit_by_name (self, "favorites-changed", changed_files);
nautilus_file_list_free (changed_files);
}
connection = tracker_sparql_connection_get (NULL, &error);
if (!connection)
{
g_printerr ("Couldn't obtain a direct connection to the Tracker store: %s",
error ? error->message : "unknown error");
g_clear_error (&error);
return;
}
cursor = tracker_sparql_connection_query (connection,
query->str,
NULL,
&error);
if (error)
{
g_printerr ("Couldn't query the Tracker Store: '%s'", error->message);
g_clear_error (&error);
return;
}
if (cursor)
{
query_has_results = tracker_sparql_cursor_next (cursor, NULL, &error);
/* if no results are found, then the file isn't marked as favorite.
* If needed, update the hashtable.
*/
if (!query_has_results && location_uri && g_hash_table_contains (self->favorite_files, location_uri))
{
g_hash_table_remove (self->favorite_files, location_uri);
file = nautilus_file_get_by_uri (location_uri);
changed_files = g_list_prepend (NULL, file);
g_signal_emit_by_name (self, "favorites-changed", changed_files);
nautilus_file_list_free (changed_files);
}
else if (query_has_results && location_uri && !g_hash_table_contains (self->favorite_files, location_uri))
{
id = g_new0 (gint64, 1);
*id = tracker_notifier_event_get_id (event);
g_hash_table_insert (self->favorite_files,
g_strdup (location_uri),
id);
file = nautilus_file_get_by_uri (location_uri);
changed_files = g_list_prepend (NULL, file);
g_signal_emit_by_name (self, "favorites-changed", changed_files);
nautilus_file_list_free (changed_files);
}
g_object_unref (cursor);
}
g_object_unref (connection);
g_string_free (query, TRUE);
}
}
static void
nautilus_tag_manager_finalize (GObject *object)
{
NautilusTagManager *self;
self = NAUTILUS_TAG_MANAGER (object);
g_signal_handlers_disconnect_by_func (self->notifier,
G_CALLBACK (on_tracker_notifier_events),
self);
g_clear_object (&self->notifier);
g_hash_table_destroy (self->favorite_files);
G_OBJECT_CLASS (nautilus_tag_manager_parent_class)->finalize (object);
}
static void
nautilus_tag_manager_class_init (NautilusTagManagerClass *klass)
{
GObjectClass *oclass;
oclass = G_OBJECT_CLASS (klass);
oclass->finalize = nautilus_tag_manager_finalize;
signals[FAVORITES_CHANGED] = g_signal_new ("favorites-changed",
NAUTILUS_TYPE_TAG_MANAGER,
G_SIGNAL_RUN_LAST,
0,
NULL,
NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE,
1,
G_TYPE_POINTER);
}
NautilusTagManager* nautilus_tag_manager_get ()
{
if (tag_manager != NULL)
{
return g_object_ref (tag_manager);
}
tag_manager = g_object_new (NAUTILUS_TYPE_TAG_MANAGER, NULL);
g_object_add_weak_pointer (G_OBJECT (tag_manager), (gpointer)&tag_manager);
return tag_manager;
}
void nautilus_tag_manager_set_cancellable (NautilusTagManager *tag_manager,
GCancellable *cancellable)
{
nautilus_tag_manager_query_favorite_files (tag_manager, cancellable);
tag_manager->notifier = tracker_notifier_new (NULL,
TRACKER_NOTIFIER_FLAG_QUERY_LOCATION,
cancellable,
&tag_manager->notifier_error);
g_signal_connect (tag_manager->notifier,
"events",
G_CALLBACK (on_tracker_notifier_events),
tag_manager);
}
static void
nautilus_tag_manager_init (NautilusTagManager *self)
{
self->favorite_files = g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) g_free);
}

View file

@ -0,0 +1,57 @@
/* nautilus-tag-manager.h
*
* Copyright (C) 2017 Alexandru Pandelea <alexandru.pandelea@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 2 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_TAG_MANAGER_H
#define NAUTILUS_TAG_MANAGER_H
#include <glib.h>
#include <glib-object.h>
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define NAUTILUS_TYPE_TAG_MANAGER (nautilus_tag_manager_get_type ())
G_DECLARE_FINAL_TYPE (NautilusTagManager, nautilus_tag_manager, NAUTILUS, TAG_MANAGER, GObject);
NautilusTagManager* nautilus_tag_manager_get ();
void nautilus_tag_manager_set_cancellable (NautilusTagManager *tag_manager,
GCancellable *cancellable);
GList* nautilus_tag_manager_get_favorite_files (NautilusTagManager *self);
void nautilus_tag_manager_star_files (NautilusTagManager *self,
GObject *object,
GList *selection,
GAsyncReadyCallback callback,
GCancellable *cancellable);
void nautilus_tag_manager_unstar_files (NautilusTagManager *self,
GObject *object,
GList *selection,
GAsyncReadyCallback callback,
GCancellable *cancellable);
gboolean nautilus_tag_manager_file_is_favorite (NautilusTagManager *self,
const gchar *file_name);
G_END_DECLS
#endif

View file

@ -1140,6 +1140,19 @@ places_sidebar_show_other_locations_with_flags (NautilusWindow *window,
g_object_unref (location);
}
static void
places_sidebar_show_starred_location (NautilusWindow *window,
GtkPlacesOpenFlags open_flags)
{
GFile *location;
location = g_file_new_for_uri ("favorites:///");
open_location_cb (window, location, open_flags);
g_object_unref (location);
}
static GList *
build_selection_list_from_gfile_list (GList *gfile_list)
{
@ -2947,6 +2960,7 @@ nautilus_window_class_init (NautilusWindowClass *class)
gtk_widget_class_bind_template_child_private (wclass, NautilusWindow, notification_operation_close);
gtk_widget_class_bind_template_callback (wclass, places_sidebar_show_other_locations_with_flags);
gtk_widget_class_bind_template_callback (wclass, places_sidebar_show_starred_location);
properties[PROP_DISABLE_CHROME] =
g_param_spec_boolean ("disable-chrome",

View file

@ -18,6 +18,7 @@
<file>ui/nautilus-no-search-results.ui</file>
<file>ui/nautilus-folder-is-empty.ui</file>
<file>ui/nautilus-trash-is-empty.ui</file>
<file>ui/nautilus-starred-is-empty.ui</file>
<file>gtk/help-overlay.ui</file>
<file>ui/nautilus-batch-rename-dialog.ui</file>
<file alias="gtk/ui/nautilusgtkplacesview.ui">../gtk/nautilusgtkplacesview.ui</file>

View file

@ -251,6 +251,23 @@
<attribute name="hidden-when">action-disabled</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">Tags</attribute>
<attribute name="action">view.edit-tags</attribute>
<attribute name="hidden-when">action-disabled</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Star</attribute>
<attribute name="action">view.star</attribute>
<attribute name="hidden-when">action-disabled</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Unstar</attribute>
<attribute name="action">view.unstar</attribute>
<attribute name="hidden-when">action-disabled</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">P_roperties</attribute>

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkGrid" id="starred_is_empty">
<property name="visible">False</property>
<property name="row_spacing">12</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
<style>
<class name="dim-label"/>
</style>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon-name">starred-symbolic</property>
<property name="pixel-size">72</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Starred files will appear here</property>
<attributes>
<attribute name="weight" value="bold"/>
<attribute name="scale" value="1.44"/>
</attributes>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
</interface>

View file

@ -34,7 +34,9 @@
<property name="visible">True</property>
<property name="populate-all">True</property>
<property name="show-other-locations">True</property>
<property name="show-starred-location">True</property>
<signal name="show-other-locations-with-flags" handler="places_sidebar_show_other_locations_with_flags" object="NautilusWindow" swapped="yes" />
<signal name="show-starred-location" handler="places_sidebar_show_starred_location" object="NautilusWindow" swapped="yes" />
</object>
<packing>
<property name="pack_type">start</property>