gimpfileentry.c 11.8 KB
Newer Older
1
/* LIBGIMP - The GIMP Library
2
 * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
3
 *
Michael Natterer's avatar
Michael Natterer committed
4
 * gimpfileentry.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.
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
#include "config.h"
Tor Lillqvist's avatar
Tor Lillqvist committed
24

25 26
#include <string.h>

27 28
#include <gtk/gtk.h>

29 30
#include "gimpwidgetstypes.h"

31
#undef GIMP_DISABLE_DEPRECATED
Michael Natterer's avatar
Michael Natterer committed
32
#include "gimpfileentry.h"
33

34
#include "gimphelpui.h"
35

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

38

39 40
enum
{
41
  FILENAME_CHANGED,
42 43 44
  LAST_SIGNAL
};

45

46
static void   gimp_file_entry_destroy         (GtkObject     *object);
47

48 49 50 51 52 53 54 55
static void   gimp_file_entry_entry_activate  (GtkWidget     *widget,
                                               GimpFileEntry *entry);
static gint   gimp_file_entry_entry_focus_out (GtkWidget     *widget,
                                               GdkEvent      *event,
                                               GimpFileEntry *entry);
static void   gimp_file_entry_browse_clicked  (GtkWidget     *widget,
                                               GimpFileEntry *entry);
static void   gimp_file_entry_check_filename  (GimpFileEntry *entry);
56 57


58
G_DEFINE_TYPE (GimpFileEntry, gimp_file_entry, GTK_TYPE_HBOX)
59

60
#define parent_class gimp_file_entry_parent_class
61

62
static guint gimp_file_entry_signals[LAST_SIGNAL] = { 0 };
63

64

65
static void
Michael Natterer's avatar
Michael Natterer committed
66
gimp_file_entry_class_init (GimpFileEntryClass *klass)
67
{
68
  GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
69

70 71 72 73 74
  /**
   * GimpFileEntry::filename-changed:
   *
   * This signal is emitted whenever the user changes the filename.
   **/
Michael Natterer's avatar
Michael Natterer committed
75
  gimp_file_entry_signals[FILENAME_CHANGED] =
76
    g_signal_new ("filename-changed",
Sven Neumann's avatar
Sven Neumann committed
77 78 79 80 81 82
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GimpFileEntryClass, filename_changed),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);
83

Michael Natterer's avatar
Michael Natterer committed
84
  object_class->destroy   = gimp_file_entry_destroy;
85

86
  klass->filename_changed = NULL;
87 88 89
}

static void
Michael Natterer's avatar
Michael Natterer committed
90
gimp_file_entry_init (GimpFileEntry *entry)
91
{
92 93
  GtkWidget *image;

94 95 96 97
  entry->title       = NULL;
  entry->file_dialog = NULL;
  entry->check_valid = FALSE;
  entry->file_exists = NULL;
Michael Natterer's avatar
Michael Natterer committed
98 99 100 101

  gtk_box_set_spacing (GTK_BOX (entry), 4);
  gtk_box_set_homogeneous (GTK_BOX (entry), FALSE);

102
  entry->browse_button = gtk_button_new ();
Michael Natterer's avatar
Michael Natterer committed
103 104 105
  gtk_box_pack_end (GTK_BOX (entry), entry->browse_button, FALSE, FALSE, 0);
  gtk_widget_show (entry->browse_button);

106 107 108 109
  image = gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_BUTTON);
  gtk_container_add (GTK_CONTAINER (entry->browse_button), image);
  gtk_widget_show (image);

Michael Natterer's avatar
Michael Natterer committed
110 111 112 113 114 115 116 117 118 119 120
  g_signal_connect (entry->browse_button, "clicked",
                    G_CALLBACK (gimp_file_entry_browse_clicked),
                    entry);

  entry->entry = gtk_entry_new ();
  gtk_box_pack_end (GTK_BOX (entry), entry->entry, TRUE, TRUE, 0);
  gtk_widget_show (entry->entry);

  g_signal_connect (entry->entry, "activate",
                    G_CALLBACK (gimp_file_entry_entry_activate),
                    entry);
121
  g_signal_connect (entry->entry, "focus-out-event",
Michael Natterer's avatar
Michael Natterer committed
122 123
                    G_CALLBACK (gimp_file_entry_entry_focus_out),
                    entry);
124 125
}

126
static void
Michael Natterer's avatar
Michael Natterer committed
127
gimp_file_entry_destroy (GtkObject *object)
128
{
Michael Natterer's avatar
Michael Natterer committed
129
  GimpFileEntry *entry = GIMP_FILE_ENTRY (object);
130

131
  if (entry->file_dialog)
132
    {
133 134
      gtk_widget_destroy (entry->file_dialog);
      entry->file_dialog = NULL;
135
    }
136

Michael Natterer's avatar
Michael Natterer committed
137
  if (entry->title)
138
    {
Michael Natterer's avatar
Michael Natterer committed
139 140
      g_free (entry->title);
      entry->title = NULL;
141
    }
142

143
  GTK_OBJECT_CLASS (parent_class)->destroy (object);
144 145
}

146
/**
Michael Natterer's avatar
Michael Natterer committed
147 148 149 150
 * gimp_file_entry_new:
 * @title:       The title of the #GtkFileEntry dialog.
 * @filename:    The initial filename.
 * @dir_only:    %TRUE if the file entry should accept directories only.
151
 * @check_valid: %TRUE if the widget should check if the entered file
152 153
 *               really exists.
 *
154
 * You should use #GtkFileChooserButton instead.
155
 *
Michael Natterer's avatar
Michael Natterer committed
156
 * Returns: A pointer to the new #GimpFileEntry widget.
157
 **/
158
GtkWidget *
Michael Natterer's avatar
Michael Natterer committed
159 160 161 162
gimp_file_entry_new (const gchar *title,
                     const gchar *filename,
                     gboolean     dir_only,
                     gboolean     check_valid)
163
{
Michael Natterer's avatar
Michael Natterer committed
164
  GimpFileEntry *entry;
165

Michael Natterer's avatar
Michael Natterer committed
166
  entry = g_object_new (GIMP_TYPE_FILE_ENTRY, NULL);
167

Michael Natterer's avatar
Michael Natterer committed
168 169 170
  entry->title       = g_strdup (title);
  entry->dir_only    = dir_only;
  entry->check_valid = check_valid;
171

172 173 174 175 176 177
  gimp_help_set_help_data (entry->browse_button,
                           dir_only ?
                           _("Open a file selector to browse your folders") :
                           _("Open a file selector to browse your files"),
                           NULL);

178 179
  if (check_valid)
    {
Michael Natterer's avatar
Michael Natterer committed
180 181 182 183
      entry->file_exists = gtk_image_new_from_stock (GTK_STOCK_NO,
                                                     GTK_ICON_SIZE_BUTTON);
      gtk_box_pack_start (GTK_BOX (entry), entry->file_exists, FALSE, FALSE, 0);
      gtk_widget_show (entry->file_exists);
184 185
    }

Michael Natterer's avatar
Michael Natterer committed
186
  gimp_file_entry_set_filename (entry, filename);
187

Michael Natterer's avatar
Michael Natterer committed
188
  return GTK_WIDGET (entry);
189 190
}

191
/**
Michael Natterer's avatar
Michael Natterer committed
192 193
 * gimp_file_entry_get_filename:
 * @entry: The file entry you want to know the filename from.
194 195 196 197
 *
 * Note that you have to g_free() the returned string.
 *
 * Returns: The file or directory the user has entered.
198
 **/
199
gchar *
Michael Natterer's avatar
Michael Natterer committed
200
gimp_file_entry_get_filename (GimpFileEntry *entry)
201
{
202 203 204
  gchar *utf8;
  gchar *filename;

Michael Natterer's avatar
Michael Natterer committed
205
  g_return_val_if_fail (GIMP_IS_FILE_ENTRY (entry), NULL);
206

207 208 209 210 211 212 213
  utf8 = gtk_editable_get_chars (GTK_EDITABLE (entry->entry), 0, -1);

  filename = g_filename_from_utf8 (utf8, -1, NULL, NULL, NULL);

  g_free (utf8);

  return filename;
214 215
}

216
/**
Michael Natterer's avatar
Michael Natterer committed
217 218
 * gimp_file_entry_set_filename:
 * @entry:    The file entry you want to set the filename for.
219 220
 * @filename: The new filename.
 *
Michael Natterer's avatar
Michael Natterer committed
221 222
 * If you specified @check_valid as %TRUE in gimp_file_entry_new()
 * the #GimpFileEntry will immediately check the validity of the file
223
 * name.
Michael Natterer's avatar
Michael Natterer committed
224
 **/
225
void
Michael Natterer's avatar
Michael Natterer committed
226 227
gimp_file_entry_set_filename (GimpFileEntry *entry,
                              const gchar   *filename)
228
{
229 230
  gchar *utf8;

Michael Natterer's avatar
Michael Natterer committed
231
  g_return_if_fail (GIMP_IS_FILE_ENTRY (entry));
232

233 234 235 236 237 238 239
  if (filename)
    utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
  else
    utf8 = g_strdup ("");

  gtk_entry_set_text (GTK_ENTRY (entry->entry), utf8);
  g_free (utf8);
240 241 242

  /*  update everything
   */
Michael Natterer's avatar
Michael Natterer committed
243
  gimp_file_entry_entry_activate (entry->entry, entry);
244 245 246
}

static void
Michael Natterer's avatar
Michael Natterer committed
247 248
gimp_file_entry_entry_activate (GtkWidget     *widget,
                                GimpFileEntry *entry)
249
{
250
  gchar *utf8;
251 252
  gchar *filename;
  gint   len;
253 254 255 256

  /*  filenames still need more sanity checking
   *  (erase double G_DIR_SEPARATORS, ...)
   */
257 258
  utf8 = gtk_editable_get_chars (GTK_EDITABLE (widget), 0, -1);
  utf8 = g_strstrip (utf8);
259

260
  while (((len = strlen (utf8)) > 1) &&
Sven Neumann's avatar
Sven Neumann committed
261
         (utf8[len - 1] == G_DIR_SEPARATOR))
262 263 264
    utf8[len - 1] = '\0';

  filename = g_filename_from_utf8 (utf8, -1, NULL, NULL, NULL);
265

Michael Natterer's avatar
Michael Natterer committed
266 267 268
  g_signal_handlers_block_by_func (entry->entry,
                                   gimp_file_entry_entry_activate,
                                   entry);
269
  gtk_entry_set_text (GTK_ENTRY (entry->entry), utf8);
Michael Natterer's avatar
Michael Natterer committed
270 271 272
  g_signal_handlers_unblock_by_func (entry->entry,
                                     gimp_file_entry_entry_activate,
                                     entry);
273

274
  if (entry->file_dialog)
275 276
    gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (entry->file_dialog),
                                   filename);
277

278
  g_free (filename);
279
  g_free (utf8);
280

Michael Natterer's avatar
Michael Natterer committed
281
  gimp_file_entry_check_filename (entry);
282

Michael Natterer's avatar
Michael Natterer committed
283
  gtk_editable_set_position (GTK_EDITABLE (entry->entry), -1);
284

Michael Natterer's avatar
Michael Natterer committed
285
  g_signal_emit (entry, gimp_file_entry_signals[FILENAME_CHANGED], 0);
286 287
}

288
static gboolean
Michael Natterer's avatar
Michael Natterer committed
289 290 291
gimp_file_entry_entry_focus_out (GtkWidget     *widget,
                                 GdkEvent      *event,
                                 GimpFileEntry *entry)
292
{
Michael Natterer's avatar
Michael Natterer committed
293
  gimp_file_entry_entry_activate (widget, entry);
294

295
  return FALSE;
296 297
}

Michael Natterer's avatar
Michael Natterer committed
298
/*  local callback of gimp_file_entry_browse_clicked()  */
299
static void
300
gimp_file_entry_chooser_response (GtkWidget     *dialog,
Michael Natterer's avatar
Michael Natterer committed
301 302
                                  gint           response_id,
                                  GimpFileEntry *entry)
303
{
304 305
  if (response_id == GTK_RESPONSE_OK)
    {
306
      gchar *filename;
307

308
      filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
Michael Natterer's avatar
Michael Natterer committed
309
      gimp_file_entry_set_filename (entry, filename);
310
      g_free (filename);
311
    }
312

Michael Natterer's avatar
Michael Natterer committed
313
  gtk_widget_hide (dialog);
314 315 316
}

static void
Michael Natterer's avatar
Michael Natterer committed
317 318
gimp_file_entry_browse_clicked (GtkWidget     *widget,
                                GimpFileEntry *entry)
319
{
320 321 322
  GtkFileChooser *chooser;
  gchar          *utf8;
  gchar          *filename;
323

324 325 326
  utf8 = gtk_editable_get_chars (GTK_EDITABLE (entry->entry), 0, -1);
  filename = g_filename_from_utf8 (utf8, -1, NULL, NULL, NULL);
  g_free (utf8);
327

328
  if (! entry->file_dialog)
329
    {
330 331 332
      const gchar *title = entry->title;

      if (! title)
333
        {
334 335 336 337
          if (entry->dir_only)
            title = _("Select Folder");
          else
            title = _("Select File");
338
        }
339

340 341 342 343 344
      entry->file_dialog =
        gtk_file_chooser_dialog_new (title, NULL,
                                     entry->dir_only ?
                                     GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER :
                                     GTK_FILE_CHOOSER_ACTION_OPEN,
345

346 347 348 349
                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                     GTK_STOCK_OK,     GTK_RESPONSE_OK,

                                     NULL);
350

Sven Neumann's avatar
Sven Neumann committed
351
        gtk_dialog_set_alternative_button_order (GTK_DIALOG (entry->file_dialog),
352 353 354 355
                                                GTK_RESPONSE_OK,
                                                GTK_RESPONSE_CANCEL,
                                                -1);

356
      chooser = GTK_FILE_CHOOSER (entry->file_dialog);
357

358 359 360 361 362 363
      gtk_window_set_position (GTK_WINDOW (chooser), GTK_WIN_POS_MOUSE);
      gtk_window_set_role (GTK_WINDOW (chooser),
                           "gimp-file-entry-file-dialog");

      g_signal_connect (chooser, "response",
                        G_CALLBACK (gimp_file_entry_chooser_response),
Michael Natterer's avatar
Michael Natterer committed
364
                        entry);
365
      g_signal_connect (chooser, "delete-event",
366 367 368
                        G_CALLBACK (gtk_true),
                        NULL);

Michael Natterer's avatar
Michael Natterer committed
369
      g_signal_connect_swapped (entry, "unmap",
370
                                G_CALLBACK (gtk_widget_hide),
371 372 373 374 375
                                chooser);
    }
  else
    {
      chooser = GTK_FILE_CHOOSER (entry->file_dialog);
376 377
    }

378
  gtk_file_chooser_set_filename (chooser, filename);
379

380
  g_free (filename);
381

382 383
  gtk_window_set_screen (GTK_WINDOW (chooser), gtk_widget_get_screen (widget));
  gtk_window_present (GTK_WINDOW (chooser));
384 385 386
}

static void
Michael Natterer's avatar
Michael Natterer committed
387
gimp_file_entry_check_filename (GimpFileEntry *entry)
388
{
389
  gchar    *utf8;
390 391
  gchar    *filename;
  gboolean  exists;
392

Michael Natterer's avatar
Michael Natterer committed
393
  if (! entry->check_valid || ! entry->file_exists)
394 395
    return;

396 397 398
  utf8 = gtk_editable_get_chars (GTK_EDITABLE (entry->entry), 0, -1);
  filename = g_filename_from_utf8 (utf8, -1, NULL, NULL, NULL);
  g_free (utf8);
399

Michael Natterer's avatar
Michael Natterer committed
400
  if (entry->dir_only)
401
    exists = g_file_test (filename, G_FILE_TEST_IS_DIR);
402
  else
403
    exists = g_file_test (filename, G_FILE_TEST_IS_REGULAR);
404

Sven Neumann's avatar
Sven Neumann committed
405
  g_free (filename);
406

Michael Natterer's avatar
Michael Natterer committed
407
  gtk_image_set_from_stock (GTK_IMAGE (entry->file_exists),
408
                            exists ? GTK_STOCK_YES : GTK_STOCK_NO,
409
                            GTK_ICON_SIZE_BUTTON);
410
}