NautilusExtension.c 9.49 KB
Newer Older
1 2
/* -*- Mode: C; indent-tabs-mode: nil; tab-width: 2 -*- */
/*
3
    This file is part of Déjà Dup.
4
    © 2004–2005 Free Software Foundation, Inc.
5
    © 2009–2011 Michael Terry <mike@mterry.name>
6

7
    Déjà Dup is free software: you can redistribute it and/or modify
8 9 10 11
    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.

12
    Déjà Dup is distributed in the hope that it will be useful,
13 14 15 16 17
    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
18
    along with Déjà Dup.  If not, see <http://www.gnu.org/licenses/>.
19 20
*/

Michael Terry's avatar
Michael Terry committed
21
#include "dirhandling.h"
22 23
#include "NautilusExtension.h"
#include <libnautilus-extension/nautilus-menu-provider.h>
24 25
#include <glib/gi18n-lib.h>

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
GList *dirs = NULL;
GSettings *settings = NULL;

// This will treat a < b iff a is 'lower' in the file tree than b
static int
cmp_prefix(GFile *a, GFile *b)
{
  if (a == NULL && b == NULL)
    return 0;
  else if (b == NULL || g_file_has_prefix(a, b))
    return -1;
  else if (a == NULL || g_file_has_prefix(b, a))
    return 1;
  else
    return 0;
}

/* Do the include/exclude processing up front so that when
   we query to see if a file is included, it will be fast. */
static void
update_include_excludes ()
{
  /* Clear any existing dirs */
  if (dirs != NULL) {
    g_list_foreach(dirs, (GFunc)g_object_unref, NULL);
    g_list_free(dirs);
    dirs = NULL;
  }

  if (settings == NULL)
    return;

58 59
  gchar **includes_strv = g_settings_get_strv(settings, "include-list");
  gchar **excludes_strv = g_settings_get_strv(settings, "exclude-list");
60 61

  gchar **p;
62
  for (p = includes_strv; p && *p; p++) {
63
    GFile *file = deja_dup_parse_dir(*p);
64 65 66 67
    if (file != NULL) {
      g_object_set_data(G_OBJECT(file), "included", GINT_TO_POINTER(TRUE));
      dirs = g_list_insert_sorted(dirs, file, (GCompareFunc)cmp_prefix);
    }
68
  }
69
  for (p = excludes_strv; p && *p; p++) {
70
    GFile *file = deja_dup_parse_dir(*p);
71 72 73 74
    if (file != NULL) {
      g_object_set_data(G_OBJECT(file), "included", GINT_TO_POINTER(FALSE));
      dirs = g_list_insert_sorted(dirs, file, (GCompareFunc)cmp_prefix);
    }
75 76 77 78 79 80 81
  }


  g_strfreev(includes_strv);
  g_strfreev(excludes_strv);
}

82 83 84 85 86 87 88
static gboolean
update_include_excludes_idle_cb ()
{
  update_include_excludes ();
  return FALSE;
}

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
static gboolean
is_dir_included(GFile *file)
{
  GList *p;
  for (p = dirs; p; p = p->next) {
    if (g_file_equal(file, (GFile *)p->data) ||
        g_file_has_prefix(file, (GFile *)p->data)) {
      gboolean included;
      included = GPOINTER_TO_INT(g_object_get_data(p->data, "included"));
      return included;
    }
  }
  return FALSE;
}

104 105 106
static void
make_file_list(NautilusFileInfo *info, GString *str)
{
107
  gchar *uri = nautilus_file_info_get_uri(info);
108
  if (!str->len)
109
    g_string_printf(str, "\"%s\"", uri);
110
  else
111
    g_string_append_printf(str, " \"%s\"", uri);
112 113 114
  g_free(uri);
}

115 116 117 118 119 120 121 122
static void
restore_missing_files_callback(NautilusMenuItem *item)
{
  gchar *cmd;
  NautilusFileInfo *info;

  info = g_object_get_data(G_OBJECT(item), "deja_dup_extension_file");

123
  cmd = g_strdup_printf("deja-dup --restore-missing \"%s\"",
124 125 126 127 128 129 130
                        nautilus_file_info_get_uri(info));

  g_spawn_command_line_async(cmd, NULL);

  g_free(cmd);
}

131
static void
132
restore_files_callback(NautilusMenuItem *item)
133 134 135
{
  GString *str = g_string_new("");
  gchar *cmd;
136 137 138
  GList *files;

  files = g_object_get_data(G_OBJECT(item), "deja_dup_extension_files");
139 140

  g_list_foreach(files, (GFunc)make_file_list, str);
141
  cmd = g_strdup_printf("deja-dup --restore %s", 
142
                        str->str);
143 144 145 146 147 148

  g_spawn_command_line_async(cmd, NULL);

  g_free(cmd);
  g_string_free(str, TRUE);
}
149 150 151 152 153 154

static GList *
deja_dup_nautilus_extension_get_background_items(NautilusMenuProvider *provider,
                                                 GtkWidget *window,
                                                 NautilusFileInfo *file)
{
155 156 157
  NautilusMenuItem *item;
  guint length;
  GList *file_copies;
158
  gchar *path;
159 160 161 162

  if (file == NULL)
    return NULL;

Michael Terry's avatar
Michael Terry committed
163
  path = g_find_program_in_path("deja-dup");
164
  if (!path)
165
    return NULL;
166
  g_free(path);
167

168 169 170
  if (!is_dir_included(nautilus_file_info_get_location(file)))
    return NULL;

171
  item = nautilus_menu_item_new("DejaDupNautilusExtension::restore_missing_item",
172
                                dgettext(GETTEXT_PACKAGE, "Restore Missing Files…"),
173
                                dgettext(GETTEXT_PACKAGE, "Restore deleted files from backup"),
174
                                ICON_NAME);
175 176 177 178 179 180 181

  g_signal_connect(item, "activate", G_CALLBACK(restore_missing_files_callback), NULL);
  g_object_set_data_full (G_OBJECT(item), "deja_dup_extension_file",
                          g_object_ref(file),
                          (GDestroyNotify)g_object_unref);

  return g_list_append(NULL, item);
182 183 184 185 186 187 188
}

static GList *
deja_dup_nautilus_extension_get_file_items(NautilusMenuProvider *provider,
                                           GtkWidget *window,
                                           GList *files)
{
189 190 191
  NautilusMenuItem *item;
  guint length;
  GList *file_copies;
192
  gchar *path;
193 194 195 196

  if (files == NULL)
    return NULL;

Michael Terry's avatar
Michael Terry committed
197
  path = g_find_program_in_path("deja-dup");
198
  if (!path)
199
    return NULL;
200
  g_free(path);
201

202 203 204 205 206 207 208 209 210 211
  gboolean is_one_included = FALSE;
  GList *p;
  for (p = files; p; p = p->next) {
    GFile *gfile = nautilus_file_info_get_location((NautilusFileInfo *)p->data);
    if (is_dir_included(gfile))
      is_one_included = TRUE;
  }
  if (!is_one_included)
    return NULL;

212 213 214
  length = g_list_length(files);
  item = nautilus_menu_item_new("DejaDupNautilusExtension::restore_item",
                                dngettext(GETTEXT_PACKAGE,
215 216
                                          "Revert to Previous Version…",
                                          "Revert to Previous Versions…",
217 218 219 220 221
                                          length),
                                dngettext(GETTEXT_PACKAGE,
                                          "Restore file from backup",
                                          "Restore files from backup",
                                          length),
222
                                ICON_NAME);
223

224 225 226 227
  g_signal_connect(item, "activate", G_CALLBACK(restore_files_callback), NULL);
  g_object_set_data_full (G_OBJECT(item), "deja_dup_extension_files", 
                          nautilus_file_info_list_copy(files),
                          (GDestroyNotify)nautilus_file_info_list_free);
228 229

  return g_list_append(NULL, item);
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
}


enum  {
  DEJA_DUP_NAUTILUS_EXTENSION_DUMMY_PROPERTY
};
static gpointer deja_dup_nautilus_extension_parent_class = NULL;


static GType deja_dup_nautilus_extension_type = 0;


DejaDupNautilusExtension* deja_dup_nautilus_extension_construct (GType object_type) {
  DejaDupNautilusExtension * self;
  self = g_object_newv (object_type, 0, NULL);
  return self;
}


DejaDupNautilusExtension* deja_dup_nautilus_extension_new (void) {
  return deja_dup_nautilus_extension_construct (TYPE_DEJA_DUP_NAUTILUS_EXTENSION);
}


static void deja_dup_nautilus_extension_class_init (DejaDupNautilusExtensionClass * klass) {
  deja_dup_nautilus_extension_parent_class = g_type_class_peek_parent (klass);
}


static void deja_dup_nautilus_extension_instance_init (DejaDupNautilusExtension * self) {
}


GType deja_dup_nautilus_extension_get_type (void) {
  return deja_dup_nautilus_extension_type;
}


static void
deja_dup_nautilus_extension_menu_provider_iface_init (NautilusMenuProviderIface *iface)
{
  iface->get_background_items = deja_dup_nautilus_extension_get_background_items;
  iface->get_file_items = deja_dup_nautilus_extension_get_file_items;
}

void deja_dup_nautilus_extension_register_type (GTypeModule *module)
{
277
  const GTypeInfo info = {
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
    sizeof (DejaDupNautilusExtensionClass),
    (GBaseInitFunc) NULL,
    (GBaseFinalizeFunc) NULL,
    (GClassInitFunc) deja_dup_nautilus_extension_class_init,
    NULL,
    NULL,
    sizeof (DejaDupNautilusExtension),
    0,
    (GInstanceInitFunc) deja_dup_nautilus_extension_instance_init,
  };

  deja_dup_nautilus_extension_type = g_type_module_register_type (module,
    G_TYPE_OBJECT,
    "DejaDupNautilusExtension",
    &info, 0);

294
  const GInterfaceInfo menu_provider_iface_info =
295 296 297 298 299 300 301 302 303 304 305 306 307 308
  {
    (GInterfaceInitFunc)deja_dup_nautilus_extension_menu_provider_iface_init,
     NULL,
     NULL
  };

  g_type_module_add_interface (module, deja_dup_nautilus_extension_type,
    NAUTILUS_TYPE_MENU_PROVIDER, &menu_provider_iface_info);
}

static GType type_list[1];

void nautilus_module_initialize(GTypeModule *module)
{
309
  /*g_print("Initializing Déjà Dup extension\n");*/
310 311
  deja_dup_nautilus_extension_register_type(module);
  type_list[0] = TYPE_DEJA_DUP_NAUTILUS_EXTENSION;
312 313 314

  bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR);
  bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
315 316

  settings = g_settings_new("org.gnome.DejaDup");
317
  g_signal_connect(settings, "changed::include-list",
318
                   update_include_excludes, NULL);
319
  g_signal_connect(settings, "changed::exclude-list",
320
                   update_include_excludes, NULL);
321
  g_idle_add(update_include_excludes_idle_cb, NULL);
322 323 324 325 326 327 328 329 330 331
}

void nautilus_module_list_types (const GType **types, int *num_types)
{
  *types = type_list;
  *num_types = G_N_ELEMENTS (type_list);
}

void nautilus_module_shutdown(void)
{
332 333 334 335
  g_object_unref(settings);
  settings = NULL;

  update_include_excludes(); /* will clear it now that settings is NULL */
336 337
}