gimppatheditor.c 24.9 KB
Newer Older
Michael Natterer's avatar
Michael Natterer committed
1
/* LIBGIMP - The GIMP Library
2
 * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
3 4
 *
 * gimppatheditor.c
5
 * Copyright (C) 1999-2004 Michael Natterer <mitch@gimp.org>
6 7
 *
 * This library is free software; you can redistribute it and/or
Marc Lehmann's avatar
Marc Lehmann committed
8
 * modify it under the terms of the GNU Lesser General Public
9 10
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
Michael Natterer's avatar
Michael Natterer committed
11 12 13 14
 *
 * This library 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
15 16
 * Library General Public License for more details.
 *
Marc Lehmann's avatar
Marc Lehmann committed
17
 * You should have received a copy of the GNU Lesser General Public
18 19 20 21
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
22

23 24
#include "config.h"

25 26
#include <string.h>

27 28
#include <gtk/gtk.h>

29 30
#include "libgimpbase/gimpbase.h"

31
#include "gimpwidgetstypes.h"
32

33
#include "gimppatheditor.h"
Michael Natterer's avatar
Michael Natterer committed
34
#include "gimpfileentry.h"
35

36 37
#include "libgimp/libgimp-intl.h"

38

39 40
enum
{
41
  PATH_CHANGED,
42
  WRITABLE_CHANGED,
43 44 45
  LAST_SIGNAL
};

46 47 48 49 50 51 52 53
enum
{
  COLUMN_UTF8,
  COLUMN_DIRECTORY,
  COLUMN_WRITABLE,
  NUM_COLUMNS
};

54

Michael Natterer's avatar
Michael Natterer committed
55
static void     gimp_path_editor_class_init         (GimpPathEditorClass *klass);
56
static void     gimp_path_editor_init               (GimpPathEditor      *editor);
57

Michael Natterer's avatar
Michael Natterer committed
58
static void     gimp_path_editor_new_clicked        (GtkWidget           *widget,
59
                                                     GimpPathEditor      *editor);
Michael Natterer's avatar
Michael Natterer committed
60
static void     gimp_path_editor_move_clicked       (GtkWidget           *widget,
61
                                                     GimpPathEditor      *editor);
Michael Natterer's avatar
Michael Natterer committed
62
static void     gimp_path_editor_delete_clicked     (GtkWidget           *widget,
63
                                                     GimpPathEditor      *editor);
Michael Natterer's avatar
Michael Natterer committed
64
static void     gimp_path_editor_file_entry_changed (GtkWidget           *widget,
65
                                                     GimpPathEditor      *editor);
Michael Natterer's avatar
Michael Natterer committed
66
static void     gimp_path_editor_selection_changed  (GtkTreeSelection    *sel,
67
                                                     GimpPathEditor      *editor);
68 69 70
static void     gimp_path_editor_writable_toggled   (GtkCellRendererToggle *toggle,
                                                     gchar               *path_str,
                                                     GimpPathEditor      *editor);
71 72


Sven Neumann's avatar
Sven Neumann committed
73
static guint gimp_path_editor_signals[LAST_SIGNAL] = { 0 };
74 75 76

static GtkVBoxClass *parent_class = NULL;

77 78 79 80

GType
gimp_path_editor_get_type (void)
{
81
  static GType type = 0;
82

83
  if (! type)
84
    {
85
      static const GTypeInfo info =
86
      {
87 88 89 90 91 92
        sizeof (GimpPathEditorClass),
	(GBaseInitFunc) NULL,
	(GBaseFinalizeFunc) NULL,
	(GClassInitFunc) gimp_path_editor_class_init,
	NULL,		/* class_finalize */
	NULL,		/* class_data     */
93
	sizeof (GimpPathEditor),
94 95
	0,              /* n_preallocs    */
	(GInstanceInitFunc) gimp_path_editor_init,
96 97
      };

98 99 100
      type = g_type_register_static (GTK_TYPE_VBOX,
                                     "GimpPathEditor",
                                     &info, 0);
101
    }
102

103
  return type;
104 105
}

106
static void
107
gimp_path_editor_class_init (GimpPathEditorClass *klass)
108
{
109
  parent_class = g_type_class_peek_parent (klass);
110

111 112 113 114 115 116
  /**
   * GimpPathEditor::path-changed:
   *
   * This signal is emitted whenever the user adds, deletes, modifies
   * or reorders an element of the search path.
   **/
Michael Natterer's avatar
Michael Natterer committed
117
  gimp_path_editor_signals[PATH_CHANGED] =
118 119 120 121 122 123 124 125
    g_signal_new ("path_changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpPathEditorClass, path_changed),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);

126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
  /**
   * GimpPathEditor::writable-changed:
   *
   * This signal is emitted whenever the "writable" column of a directory
   * is changed, either by the user clicking on it or by calling
   * gimp_path_editor_set_dir_writable().
   **/
  gimp_path_editor_signals[WRITABLE_CHANGED] =
    g_signal_new ("writable_changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpPathEditorClass, writable_changed),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);

  klass->path_changed     = NULL;
  klass->writable_changed = NULL;
144 145 146
}

static void
147
gimp_path_editor_init (GimpPathEditor *editor)
148
{
149 150 151 152 153 154 155
  GtkWidget         *button_box;
  GtkWidget         *button;
  GtkWidget         *image;
  GtkWidget         *scrolled_window;
  GtkWidget         *tv;
  GtkTreeViewColumn *col;
  GtkCellRenderer   *renderer;
156

157 158 159
  editor->file_entry = NULL;
  editor->sel_path   = NULL;
  editor->num_items  = 0;
160

161 162 163
  editor->upper_hbox = gtk_hbox_new (FALSE, 2);
  gtk_box_pack_start (GTK_BOX (editor), editor->upper_hbox, FALSE, TRUE, 0);
  gtk_widget_show (editor->upper_hbox);
164 165

  button_box = gtk_hbox_new (TRUE, 0);
166
  gtk_box_pack_start (GTK_BOX (editor->upper_hbox), button_box, FALSE, TRUE, 0);
167 168
  gtk_widget_show (button_box);

169
  editor->new_button = button = gtk_button_new ();
170
  gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0);
171 172
  gtk_widget_show (button);

173
  image = gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_BUTTON);
174 175 176
  gtk_container_add (GTK_CONTAINER (button), image);
  gtk_widget_show (image);

177
  g_signal_connect (button, "clicked",
Michael Natterer's avatar
Michael Natterer committed
178
                    G_CALLBACK (gimp_path_editor_new_clicked),
179
		    editor);
180

181
  editor->up_button = button = gtk_button_new ();
182 183
  gtk_widget_set_sensitive (button, FALSE);
  gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0);
184 185
  gtk_widget_show (button);

186
  image = gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_BUTTON);
187 188 189
  gtk_container_add (GTK_CONTAINER (button), image);
  gtk_widget_show (image);

190
  g_signal_connect (button, "clicked",
Michael Natterer's avatar
Michael Natterer committed
191
                    G_CALLBACK (gimp_path_editor_move_clicked),
192
		    editor);
193

194
  editor->down_button = button = gtk_button_new ();
195 196
  gtk_widget_set_sensitive (button, FALSE);
  gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0);
197 198
  gtk_widget_show (button);

199
  image = gtk_image_new_from_stock (GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_BUTTON);
200 201 202
  gtk_container_add (GTK_CONTAINER (button), image);
  gtk_widget_show (image);

203
  g_signal_connect (button, "clicked",
Michael Natterer's avatar
Michael Natterer committed
204
                    G_CALLBACK (gimp_path_editor_move_clicked),
205
		    editor);
206

207
  editor->delete_button = button = gtk_button_new ();
208 209
  gtk_widget_set_sensitive (button, FALSE);
  gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0);
210 211
  gtk_widget_show (button);

212
  image = gtk_image_new_from_stock (GTK_STOCK_DELETE, GTK_ICON_SIZE_BUTTON);
213 214 215
  gtk_container_add (GTK_CONTAINER (button), image);
  gtk_widget_show (image);

216
  g_signal_connect (button, "clicked",
Michael Natterer's avatar
Michael Natterer committed
217
                    G_CALLBACK (gimp_path_editor_delete_clicked),
218
		    editor);
219 220

  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
Manish Singh's avatar
Manish Singh committed
221 222
  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
				       GTK_SHADOW_IN);
223 224 225
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
                                  GTK_POLICY_AUTOMATIC,
                                  GTK_POLICY_ALWAYS);
226
  gtk_box_pack_start (GTK_BOX (editor), scrolled_window, TRUE, TRUE, 2);
227
  gtk_widget_show (scrolled_window);
Michael Natterer's avatar
Michael Natterer committed
228

229 230 231 232
  editor->dir_list = gtk_list_store_new (NUM_COLUMNS,
                                         G_TYPE_STRING,
                                         G_TYPE_STRING,
                                         G_TYPE_BOOLEAN);
233 234
  tv = gtk_tree_view_new_with_model (GTK_TREE_MODEL (editor->dir_list));
  g_object_unref (editor->dir_list);
Manish Singh's avatar
Manish Singh committed
235

236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
  renderer = gtk_cell_renderer_toggle_new ();

  g_signal_connect (renderer, "toggled",
                    G_CALLBACK (gimp_path_editor_writable_toggled),
                    editor);

  editor->writable_column = col = gtk_tree_view_column_new ();
  gtk_tree_view_column_set_title (col, _("Writable"));
  gtk_tree_view_column_pack_start (col, renderer, FALSE);
  gtk_tree_view_column_add_attribute (col, renderer, "active", COLUMN_WRITABLE);

  gtk_tree_view_append_column (GTK_TREE_VIEW (tv), col);

  gtk_tree_view_column_set_visible (col, FALSE);

Manish Singh's avatar
Manish Singh committed
251
  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tv),
252
					       -1, _("Folder"),
Manish Singh's avatar
Manish Singh committed
253
					       gtk_cell_renderer_text_new (),
254
					       "text", COLUMN_UTF8,
Manish Singh's avatar
Manish Singh committed
255 256
					       NULL);

257
  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tv), TRUE);
Manish Singh's avatar
Manish Singh committed
258 259 260 261

  gtk_container_add (GTK_CONTAINER (scrolled_window), tv);
  gtk_widget_show (tv);

262 263
  editor->sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv));
  g_signal_connect (editor->sel, "changed",
Michael Natterer's avatar
Michael Natterer committed
264
		    G_CALLBACK (gimp_path_editor_selection_changed),
265
		    editor);
266 267
}

268 269 270 271
/**
 * gimp_path_editor_new:
 * @filesel_title: The title of the #GtkFileSelection dialog which can be
 *                 popped up by the attached #GimpFileSelection.
272
 * @path:          The initial search path.
273 274 275 276 277 278 279
 *
 * Creates a new #GimpPathEditor widget.
 *
 * The elements of the initial search path must be separated with the
 * #G_SEARCHPATH_SEPARATOR character.
 *
 * Returns: A pointer to the new #GimpPathEditor widget.
280
 **/
281
GtkWidget *
282 283
gimp_path_editor_new (const gchar *filesel_title,
		      const gchar *path)
284
{
285
  GimpPathEditor *editor;
286

287
  g_return_val_if_fail (filesel_title != NULL, NULL);
288

289
  editor = g_object_new (GIMP_TYPE_PATH_EDITOR, NULL);
290

291 292 293
  editor->file_entry = gimp_file_entry_new (filesel_title, "", TRUE, TRUE);
  gtk_widget_set_sensitive (editor->file_entry, FALSE);
  gtk_box_pack_start (GTK_BOX (editor->upper_hbox), editor->file_entry,
Michael Natterer's avatar
Michael Natterer committed
294
                      TRUE, TRUE, 0);
295
  gtk_widget_show (editor->file_entry);
296

297
  g_signal_connect (editor->file_entry, "filename_changed",
Michael Natterer's avatar
Michael Natterer committed
298
                    G_CALLBACK (gimp_path_editor_file_entry_changed),
299
		    editor);
300

301
  if (path)
302
    gimp_path_editor_set_path (editor, path);
303

304
  return GTK_WIDGET (editor);
305 306
}

307 308
/**
 * gimp_path_editor_get_path:
309
 * @editor: The path editor you want to get the search path from.
310 311 312 313 314 315 316
 *
 * The elements of the returned search path string are separated with the
 * #G_SEARCHPATH_SEPARATOR character.
 *
 * Note that you have to g_free() the returned string.
 *
 * Returns: The search path the user has selected in the path editor.
317
 **/
318
gchar *
319
gimp_path_editor_get_path (GimpPathEditor *editor)
320
{
321 322 323 324
  GtkTreeModel *model;
  GString      *path;
  GtkTreeIter   iter;
  gboolean      iter_valid;
325

326
  g_return_val_if_fail (GIMP_IS_PATH_EDITOR (editor), g_strdup (""));
327

328 329
  model = GTK_TREE_MODEL (editor->dir_list);

Manish Singh's avatar
Manish Singh committed
330
  path = g_string_new ("");
331

332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
  for (iter_valid = gtk_tree_model_get_iter_first (model, &iter);
       iter_valid;
       iter_valid = gtk_tree_model_iter_next (model, &iter))
    {
      gchar *dir;

      gtk_tree_model_get (model, &iter,
                          COLUMN_DIRECTORY, &dir,
                          -1);

      if (path->len > 0)
        g_string_append_c (path, G_SEARCHPATH_SEPARATOR);

      g_string_append (path, dir);

      g_free (dir);
    }
Manish Singh's avatar
Manish Singh committed
349 350

  return g_string_free (path, FALSE);
351 352
}

353 354
/**
 * gimp_path_editor_set_path:
355 356
 * @editor: The path editor you want to set the search path from.
 * @path:   The new path to set.
357 358 359 360 361
 *
 * The elements of the initial search path must be separated with the
 * #G_SEARCHPATH_SEPARATOR character.
 **/
void
362
gimp_path_editor_set_path (GimpPathEditor *editor,
363 364
                           const gchar    *path)
{
365 366 367
  gchar *old_path;
  GList *path_list;
  GList *list;
368

369
  g_return_if_fail (GIMP_IS_PATH_EDITOR (editor));
370

371 372 373 374 375 376 377 378 379
  old_path = gimp_path_editor_get_path (editor);

  if (old_path == path || (old_path && path && ! strcmp (old_path, path)))
    {
      g_free (old_path);
      return;
    }

  path_list = gimp_path_parse (path, 16, TRUE, NULL);
380

381
  gtk_list_store_clear (editor->dir_list);
382

383
  for (list = path_list; list; list = g_list_next (list))
384
    {
385 386 387
      gchar       *directory = list->data;
      gchar       *utf8;
      GtkTreeIter  iter;
388

389
      utf8 = g_filename_to_utf8 (directory, -1, NULL, NULL, NULL);
390

391
      gtk_list_store_append (editor->dir_list, &iter);
392 393 394 395 396
      gtk_list_store_set (editor->dir_list, &iter,
                          COLUMN_UTF8,      utf8,
                          COLUMN_DIRECTORY, directory,
                          COLUMN_WRITABLE,  FALSE,
                          -1);
397

398 399
      g_free (utf8);

400
      editor->num_items++;
401 402
    }

403
  gimp_path_free (path_list);
404 405

  g_signal_emit (editor, gimp_path_editor_signals[PATH_CHANGED], 0);
406 407
}

408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
gchar *
gimp_path_editor_get_writable_path (GimpPathEditor *editor)
{
  GtkTreeModel *model;
  GString      *path;
  GtkTreeIter   iter;
  gboolean      iter_valid;

  g_return_val_if_fail (GIMP_IS_PATH_EDITOR (editor), g_strdup (""));

  model = GTK_TREE_MODEL (editor->dir_list);

  path = g_string_new ("");

  for (iter_valid = gtk_tree_model_get_iter_first (model, &iter);
       iter_valid;
       iter_valid = gtk_tree_model_iter_next (model, &iter))
    {
      gchar    *dir;
      gboolean  dir_writable;

      gtk_tree_model_get (model, &iter,
                          COLUMN_DIRECTORY, &dir,
                          COLUMN_WRITABLE,  &dir_writable,
                          -1);

      if (dir_writable)
        {
          if (path->len > 0)
            g_string_append_c (path, G_SEARCHPATH_SEPARATOR);

          g_string_append (path, dir);
        }

      g_free (dir);
    }

  return g_string_free (path, FALSE);
}

void
gimp_path_editor_set_writable_path (GimpPathEditor *editor,
                                    const gchar    *path)
{
  GtkTreeModel *model;
  GtkTreeIter   iter;
  gboolean      iter_valid;
  GList        *path_list;
  gboolean      writable_changed = FALSE;

  g_return_if_fail (GIMP_IS_PATH_EDITOR (editor));

  gtk_tree_view_column_set_visible (editor->writable_column, TRUE);

  path_list = gimp_path_parse (path, 16, TRUE, NULL);

  model = GTK_TREE_MODEL (editor->dir_list);

  for (iter_valid = gtk_tree_model_get_iter_first (model, &iter);
       iter_valid;
       iter_valid = gtk_tree_model_iter_next (model, &iter))
    {
      gchar    *dir;
      gboolean  dir_writable;
      gboolean  new_writable = FALSE;

      gtk_tree_model_get (model, &iter,
                          COLUMN_DIRECTORY, &dir,
                          COLUMN_WRITABLE,  &dir_writable,
                          -1);

      if (g_list_find_custom (path_list, dir, (GCompareFunc) strcmp))
        new_writable = TRUE;

      g_free (dir);

      if (dir_writable != new_writable)
        {
          gtk_list_store_set (editor->dir_list, &iter,
                              COLUMN_WRITABLE, new_writable,
                              -1);

          writable_changed = TRUE;
        }
    }

  gimp_path_free (path_list);

  if (writable_changed)
    g_signal_emit (editor, gimp_path_editor_signals[WRITABLE_CHANGED], 0);
}

gboolean
gimp_path_editor_get_dir_writable (GimpPathEditor *editor,
                                   const gchar    *directory)
{
  GtkTreeModel *model;
  GtkTreeIter   iter;
  gboolean      iter_valid;

  g_return_val_if_fail (GIMP_IS_PATH_EDITOR (editor), FALSE);
  g_return_val_if_fail (directory != NULL, FALSE);

  model = GTK_TREE_MODEL (editor->dir_list);

  for (iter_valid = gtk_tree_model_get_iter_first (model, &iter);
       iter_valid;
       iter_valid = gtk_tree_model_iter_next (model, &iter))
    {
      gchar    *dir;
      gboolean  dir_writable;

      gtk_tree_model_get (model, &iter,
                          COLUMN_DIRECTORY, &dir,
                          COLUMN_WRITABLE,  &dir_writable,
                          -1);

      if (! strcmp (dir, directory))
        {
          g_free (dir);

          return dir_writable;
        }

      g_free (dir);
    }

  return FALSE;
}

void
gimp_path_editor_set_dir_writable (GimpPathEditor *editor,
                                   const gchar    *directory,
                                   gboolean        writable)
{
  GtkTreeModel *model;
  GtkTreeIter   iter;
  gboolean      iter_valid;

  g_return_if_fail (GIMP_IS_PATH_EDITOR (editor));
  g_return_if_fail (directory != NULL);

  model = GTK_TREE_MODEL (editor->dir_list);

  for (iter_valid = gtk_tree_model_get_iter_first (model, &iter);
       iter_valid;
       iter_valid = gtk_tree_model_iter_next (model, &iter))
    {
      gchar    *dir;
      gboolean  dir_writable;

      gtk_tree_model_get (model, &iter,
                          COLUMN_DIRECTORY, &dir,
                          COLUMN_WRITABLE,  &dir_writable,
                          -1);

      if (! strcmp (dir, directory) && dir_writable != writable)
        {
          gtk_list_store_set (editor->dir_list, &iter,
                              COLUMN_WRITABLE, writable ? TRUE : FALSE,
                              -1);

          g_signal_emit (editor, gimp_path_editor_signals[WRITABLE_CHANGED], 0);

          g_free (dir);
          break;
        }

      g_free (dir);
    }
}

580

Michael Natterer's avatar
Michael Natterer committed
581
/*  private functions  */
582 583

static void
Michael Natterer's avatar
Michael Natterer committed
584
gimp_path_editor_new_clicked (GtkWidget      *widget,
585
                              GimpPathEditor *editor)
586
{
587
  if (editor->sel_path)
588
    {
589
      g_signal_handlers_block_by_func (editor->sel,
Michael Natterer's avatar
Michael Natterer committed
590
				       gimp_path_editor_selection_changed,
591
                                       editor);
Michael Natterer's avatar
Michael Natterer committed
592

593
      gtk_tree_selection_unselect_path (editor->sel, editor->sel_path);
Michael Natterer's avatar
Michael Natterer committed
594

595
      g_signal_handlers_unblock_by_func (editor->sel,
Michael Natterer's avatar
Michael Natterer committed
596
					 gimp_path_editor_selection_changed,
597
                                         editor);
Manish Singh's avatar
Manish Singh committed
598

599 600
      gtk_tree_path_free (editor->sel_path);
      editor->sel_path = NULL;
601 602
    }

603 604 605 606
  gtk_widget_set_sensitive (editor->delete_button, FALSE);
  gtk_widget_set_sensitive (editor->up_button, FALSE);
  gtk_widget_set_sensitive (editor->down_button, FALSE);
  gtk_widget_set_sensitive (editor->file_entry, TRUE);
607

608
  gtk_editable_set_position
609
    (GTK_EDITABLE (GIMP_FILE_ENTRY (editor->file_entry)->entry), -1);
610
  gtk_widget_grab_focus
611
    (GTK_WIDGET (GIMP_FILE_ENTRY (editor->file_entry)->entry));
612 613
}

614
static void
Michael Natterer's avatar
Michael Natterer committed
615
gimp_path_editor_move_clicked (GtkWidget      *widget,
616
                               GimpPathEditor *editor)
617
{
Michael Natterer's avatar
Michael Natterer committed
618 619 620
  GtkTreePath  *path;
  GtkTreeModel *model;
  GtkTreeIter   iter1, iter2;
621
  gchar        *utf81, *utf82;
Michael Natterer's avatar
Michael Natterer committed
622
  gchar        *dir1, *dir2;
623
  gboolean      writable1, writable2;
624

625
  if (editor->sel_path == NULL)
626 627
    return;

628
  path = gtk_tree_path_copy (editor->sel_path);
Manish Singh's avatar
Manish Singh committed
629

630
  if (widget == editor->up_button)
Manish Singh's avatar
Manish Singh committed
631 632 633 634
    gtk_tree_path_prev (path);
  else
    gtk_tree_path_next (path);

635
  model = GTK_TREE_MODEL (editor->dir_list);
636

637
  gtk_tree_model_get_iter (model, &iter1, editor->sel_path);
Manish Singh's avatar
Manish Singh committed
638 639
  gtk_tree_model_get_iter (model, &iter2, path);

640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
  gtk_tree_model_get (model, &iter1,
                      COLUMN_UTF8,      &utf81,
                      COLUMN_DIRECTORY, &dir1,
                      COLUMN_WRITABLE,  &writable1,
                      -1);
  gtk_tree_model_get (model, &iter2,
                      COLUMN_UTF8,      &utf82,
                      COLUMN_DIRECTORY, &dir2,
                      COLUMN_WRITABLE,  &writable2,
                      -1);

  gtk_list_store_set (editor->dir_list, &iter1,
                      COLUMN_UTF8,      utf82,
                      COLUMN_DIRECTORY, dir2,
                      COLUMN_WRITABLE,  writable2,
                      -1);
  gtk_list_store_set (editor->dir_list, &iter2,
                      COLUMN_UTF8,      utf81,
                      COLUMN_DIRECTORY, dir1,
                      COLUMN_WRITABLE,  writable1,
                      -1);

  g_free (utf81);
  g_free (utf82);
Manish Singh's avatar
Manish Singh committed
664 665 666 667

  g_free (dir2);
  g_free (dir1);

668
  gtk_tree_selection_select_iter (editor->sel, &iter2);
669

670
  g_signal_emit (editor, gimp_path_editor_signals[PATH_CHANGED], 0);
671 672
}

673
static void
Michael Natterer's avatar
Michael Natterer committed
674
gimp_path_editor_delete_clicked (GtkWidget      *widget,
675
                                 GimpPathEditor *editor)
676
{
677 678
  GtkTreeIter iter;
  gboolean    dir_writable;
679

680
  if (editor->sel_path == NULL)
681 682
    return;

683 684
  gtk_tree_model_get_iter (GTK_TREE_MODEL (editor->dir_list), &iter,
			   editor->sel_path);
685 686 687 688 689

  gtk_tree_model_get (GTK_TREE_MODEL (editor->dir_list), &iter,
                      COLUMN_WRITABLE, &dir_writable,
                      -1);

690
  gtk_list_store_remove (editor->dir_list, &iter);
691

692
  editor->num_items--;
693

694
  if (editor->num_items == 0)
695
    {
696 697
      gtk_tree_path_free (editor->sel_path);
      editor->sel_path = NULL;
Manish Singh's avatar
Manish Singh committed
698

699
      g_signal_handlers_block_by_func (editor->file_entry,
Michael Natterer's avatar
Michael Natterer committed
700
                                       gimp_path_editor_file_entry_changed,
701
                                       editor);
Michael Natterer's avatar
Michael Natterer committed
702

703
      gimp_file_entry_set_filename (GIMP_FILE_ENTRY (editor->file_entry), "");
Michael Natterer's avatar
Michael Natterer committed
704

705
      g_signal_handlers_unblock_by_func (editor->file_entry,
Michael Natterer's avatar
Michael Natterer committed
706
                                         gimp_path_editor_file_entry_changed,
707
                                         editor);
Manish Singh's avatar
Manish Singh committed
708

709 710 711 712
      gtk_widget_set_sensitive (editor->delete_button, FALSE);
      gtk_widget_set_sensitive (editor->up_button,     FALSE);
      gtk_widget_set_sensitive (editor->down_button,   FALSE);
      gtk_widget_set_sensitive (editor->file_entry,    FALSE);
713
    }
714 715 716
  else
    {
      gint *indices;
717

718 719 720
      indices = gtk_tree_path_get_indices (editor->sel_path);
      if ((indices[0] == editor->num_items) && (indices[0] > 0))
        gtk_tree_path_prev (editor->sel_path);
Manish Singh's avatar
Manish Singh committed
721

722 723
      gtk_tree_selection_select_path (editor->sel, editor->sel_path);
    }
724

725
  g_signal_emit (editor, gimp_path_editor_signals[PATH_CHANGED], 0);
726 727 728

  if (dir_writable)
    g_signal_emit (editor, gimp_path_editor_signals[WRITABLE_CHANGED], 0);
729 730 731
}

static void
Michael Natterer's avatar
Michael Natterer committed
732
gimp_path_editor_file_entry_changed (GtkWidget      *widget,
733
                                     GimpPathEditor *editor)
734
{
735 736
  gchar       *dir;
  gchar       *utf8;
Michael Natterer's avatar
Michael Natterer committed
737
  GtkTreeIter  iter;
738

739 740
  dir = gimp_file_entry_get_filename (GIMP_FILE_ENTRY (widget));
  if (strcmp (dir, "") == 0)
Manish Singh's avatar
Manish Singh committed
741
    {
742
      g_free (dir);
Manish Singh's avatar
Manish Singh committed
743 744
      return;
    }
745

746 747
  utf8 = g_filename_to_utf8 (dir, -1, NULL, NULL, NULL);

748
  if (editor->sel_path == NULL)
749
    {
750
      gtk_list_store_append (editor->dir_list, &iter);
751 752 753 754 755
      gtk_list_store_set (editor->dir_list, &iter,
                          COLUMN_UTF8,      utf8,
                          COLUMN_DIRECTORY, dir,
                          COLUMN_WRITABLE,  FALSE,
                          -1);
756
      editor->num_items++;
Manish Singh's avatar
Manish Singh committed
757

758
      gtk_tree_selection_select_iter (editor->sel, &iter);
759 760 761
    }
  else
    {
762 763
      gtk_tree_model_get_iter (GTK_TREE_MODEL (editor->dir_list), &iter,
			       editor->sel_path);
764 765 766 767
      gtk_list_store_set (editor->dir_list, &iter,
                          COLUMN_UTF8,      utf8,
                          COLUMN_DIRECTORY, dir,
                          -1);
768 769
    }

770 771
  g_free (dir);
  g_free (utf8);
Manish Singh's avatar
Manish Singh committed
772

773
  g_signal_emit (editor, gimp_path_editor_signals[PATH_CHANGED], 0);
774
}
Michael Natterer's avatar
Michael Natterer committed
775 776 777

static void
gimp_path_editor_selection_changed (GtkTreeSelection *sel,
778
                                    GimpPathEditor   *editor)
Michael Natterer's avatar
Michael Natterer committed
779 780 781 782 783 784 785
{
  GtkTreeIter  iter;
  gchar       *directory;
  gint        *indices;

  if (gtk_tree_selection_get_selected (sel, NULL, &iter))
    {
786
      gtk_tree_model_get (GTK_TREE_MODEL (editor->dir_list), &iter,
787 788
                          0, &directory,
                          -1);
Michael Natterer's avatar
Michael Natterer committed
789

790
      g_signal_handlers_block_by_func (editor->file_entry,
791 792
                                       gimp_path_editor_file_entry_changed,
                                       editor);
Michael Natterer's avatar
Michael Natterer committed
793

794
      gimp_file_entry_set_filename (GIMP_FILE_ENTRY (editor->file_entry),
Michael Natterer's avatar
Michael Natterer committed
795 796
                                    directory);

797
      g_signal_handlers_unblock_by_func (editor->file_entry,
798 799
                                         gimp_path_editor_file_entry_changed,
                                         editor);
Michael Natterer's avatar
Michael Natterer committed
800 801 802

      g_free (directory);

803 804
      if (editor->sel_path)
	gtk_tree_path_free (editor->sel_path);
Michael Natterer's avatar
Michael Natterer committed
805

806 807
      editor->sel_path =
        gtk_tree_model_get_path (GTK_TREE_MODEL (editor->dir_list), &iter);
Michael Natterer's avatar
Michael Natterer committed
808

809
      indices = gtk_tree_path_get_indices (editor->sel_path);
Michael Natterer's avatar
Michael Natterer committed
810

811 812 813
      gtk_widget_set_sensitive (editor->delete_button, TRUE);
      gtk_widget_set_sensitive (editor->up_button, (indices[0] > 0));
      gtk_widget_set_sensitive (editor->down_button,
814
                                (indices[0] < (editor->num_items - 1)));
815
      gtk_widget_set_sensitive (editor->file_entry, TRUE);
Michael Natterer's avatar
Michael Natterer committed
816 817 818 819
    }
  else
    {
      g_signal_handlers_block_by_func (sel,
820 821
                                       gimp_path_editor_selection_changed,
                                       editor);
Michael Natterer's avatar
Michael Natterer committed
822

823
      gtk_tree_selection_select_path (editor->sel, editor->sel_path);
Michael Natterer's avatar
Michael Natterer committed
824 825

      g_signal_handlers_unblock_by_func (sel,
826 827
                                         gimp_path_editor_selection_changed,
                                         editor);
Michael Natterer's avatar
Michael Natterer committed
828 829 830
    }
}

831 832 833 834
static void
gimp_path_editor_writable_toggled (GtkCellRendererToggle *toggle,
                                   gchar                 *path_str,
                                   GimpPathEditor        *editor)
Michael Natterer's avatar
Michael Natterer committed
835
{
836 837
  GtkTreePath *path;
  GtkTreeIter  iter;
Michael Natterer's avatar
Michael Natterer committed
838

839
  path = gtk_tree_path_new_from_string (path_str);
Michael Natterer's avatar
Michael Natterer committed
840

841 842 843
  if (gtk_tree_model_get_iter (GTK_TREE_MODEL (editor->dir_list), &iter, path))
    {
      gboolean dir_writable;
Michael Natterer's avatar
Michael Natterer committed
844

845 846 847
      gtk_tree_model_get (GTK_TREE_MODEL (editor->dir_list), &iter,
                          COLUMN_WRITABLE,  &dir_writable,
                          -1);
Michael Natterer's avatar
Michael Natterer committed
848

849 850 851
      gtk_list_store_set (editor->dir_list, &iter,
                          COLUMN_WRITABLE, ! dir_writable,
                          -1);
Michael Natterer's avatar
Michael Natterer committed
852

853 854 855 856
      g_signal_emit (editor, gimp_path_editor_signals[WRITABLE_CHANGED], 0);
    }

  gtk_tree_path_free (path);
Michael Natterer's avatar
Michael Natterer committed
857
}