home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 February / CMCD0205.ISO / Linux / gimp-2.2.0.tar.gz / gimp-2.2.0.tar / gimp-2.2.0 / libgimpwidgets / gimpfileentry.c < prev    next >
C/C++ Source or Header  |  2004-04-15  |  12KB  |  422 lines

  1. /* LIBGIMP - The GIMP Library
  2.  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
  3.  *
  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
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2 of the License, or (at your option) any later version.
  11.  *
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Library General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the
  19.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20.  * Boston, MA 02111-1307, USA.
  21.  */
  22.  
  23. #include "config.h"
  24.  
  25. #include <string.h>
  26.  
  27. #include <gtk/gtk.h>
  28.  
  29. #include "gimpwidgetstypes.h"
  30.  
  31. #include "gimpfileentry.h"
  32.  
  33. #include "libgimp/libgimp-intl.h"
  34.  
  35.  
  36. enum
  37. {
  38.   FILENAME_CHANGED,
  39.   LAST_SIGNAL
  40. };
  41.  
  42.  
  43. static void   gimp_file_entry_class_init      (GimpFileEntryClass *klass);
  44. static void   gimp_file_entry_init            (GimpFileEntry      *entry);
  45.  
  46. static void   gimp_file_entry_destroy         (GtkObject          *object);
  47.  
  48. static void   gimp_file_entry_entry_activate  (GtkWidget          *widget,
  49.                                                GimpFileEntry      *entry);
  50. static gint   gimp_file_entry_entry_focus_out (GtkWidget          *widget,
  51.                                                GdkEvent           *event,
  52.                                                GimpFileEntry      *entry);
  53. static void   gimp_file_entry_browse_clicked  (GtkWidget          *widget,
  54.                                                GimpFileEntry      *entry);
  55. static void   gimp_file_entry_check_filename  (GimpFileEntry      *entry);
  56.  
  57.  
  58. static guint gimp_file_entry_signals[LAST_SIGNAL] = { 0 };
  59.  
  60. static GtkHBoxClass *parent_class = NULL;
  61.  
  62.  
  63. GType
  64. gimp_file_entry_get_type (void)
  65. {
  66.   static GType entry_type = 0;
  67.  
  68.   if (! entry_type)
  69.     {
  70.       static const GTypeInfo entry_info =
  71.       {
  72.         sizeof (GimpFileEntryClass),
  73.         (GBaseInitFunc) NULL,
  74.         (GBaseFinalizeFunc) NULL,
  75.         (GClassInitFunc) gimp_file_entry_class_init,
  76.         NULL,        /* class_finalize */
  77.         NULL,        /* class_data     */
  78.         sizeof (GimpFileEntry),
  79.         0,              /* n_preallocs    */
  80.         (GInstanceInitFunc) gimp_file_entry_init,
  81.       };
  82.  
  83.       entry_type = g_type_register_static (GTK_TYPE_HBOX,
  84.                                            "GimpFileEntry",
  85.                                            &entry_info, 0);
  86.     }
  87.  
  88.   return entry_type;
  89. }
  90.  
  91. static void
  92. gimp_file_entry_class_init (GimpFileEntryClass *klass)
  93. {
  94.   GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
  95.  
  96.   parent_class = g_type_class_peek_parent (klass);
  97.  
  98.   /**
  99.    * GimpFileEntry::filename-changed:
  100.    *
  101.    * This signal is emitted whenever the user changes the filename.
  102.    **/
  103.   gimp_file_entry_signals[FILENAME_CHANGED] =
  104.     g_signal_new ("filename_changed",
  105.           G_TYPE_FROM_CLASS (klass),
  106.           G_SIGNAL_RUN_FIRST,
  107.           G_STRUCT_OFFSET (GimpFileEntryClass, filename_changed),
  108.           NULL, NULL,
  109.           g_cclosure_marshal_VOID__VOID,
  110.           G_TYPE_NONE, 0);
  111.  
  112.   object_class->destroy   = gimp_file_entry_destroy;
  113.  
  114.   klass->filename_changed = NULL;
  115. }
  116.  
  117. static void
  118. gimp_file_entry_init (GimpFileEntry *entry)
  119. {
  120.   entry->title       = NULL;
  121.   entry->file_dialog = NULL;
  122.   entry->check_valid = FALSE;
  123.   entry->file_exists = NULL;
  124.  
  125.   gtk_box_set_spacing (GTK_BOX (entry), 4);
  126.   gtk_box_set_homogeneous (GTK_BOX (entry), FALSE);
  127.  
  128.   entry->browse_button = gtk_button_new_with_label (" ... ");
  129.   gtk_box_pack_end (GTK_BOX (entry), entry->browse_button, FALSE, FALSE, 0);
  130.   gtk_widget_show (entry->browse_button);
  131.  
  132.   g_signal_connect (entry->browse_button, "clicked",
  133.                     G_CALLBACK (gimp_file_entry_browse_clicked),
  134.                     entry);
  135.  
  136.   entry->entry = gtk_entry_new ();
  137.   gtk_box_pack_end (GTK_BOX (entry), entry->entry, TRUE, TRUE, 0);
  138.   gtk_widget_show (entry->entry);
  139.  
  140.   g_signal_connect (entry->entry, "activate",
  141.                     G_CALLBACK (gimp_file_entry_entry_activate),
  142.                     entry);
  143.   g_signal_connect (entry->entry, "focus_out_event",
  144.                     G_CALLBACK (gimp_file_entry_entry_focus_out),
  145.                     entry);
  146. }
  147.  
  148. static void
  149. gimp_file_entry_destroy (GtkObject *object)
  150. {
  151.   GimpFileEntry *entry = GIMP_FILE_ENTRY (object);
  152.  
  153.   if (entry->file_dialog)
  154.     {
  155.       gtk_widget_destroy (entry->file_dialog);
  156.       entry->file_dialog = NULL;
  157.     }
  158.  
  159.   if (entry->title)
  160.     {
  161.       g_free (entry->title);
  162.       entry->title = NULL;
  163.     }
  164.  
  165.   GTK_OBJECT_CLASS (parent_class)->destroy (object);
  166. }
  167.  
  168. /**
  169.  * gimp_file_entry_new:
  170.  * @title:       The title of the #GtkFileEntry dialog.
  171.  * @filename:    The initial filename.
  172.  * @dir_only:    %TRUE if the file entry should accept directories only.
  173.  * @check_valid: %TRUE if the widget should check if the entered file
  174.  *               really exists.
  175.  *
  176.  * Creates a new #GimpFileEntry widget.
  177.  *
  178.  * Returns: A pointer to the new #GimpFileEntry widget.
  179.  **/
  180. GtkWidget *
  181. gimp_file_entry_new (const gchar *title,
  182.                      const gchar *filename,
  183.                      gboolean     dir_only,
  184.                      gboolean     check_valid)
  185. {
  186.   GimpFileEntry *entry;
  187.  
  188.   entry = g_object_new (GIMP_TYPE_FILE_ENTRY, NULL);
  189.  
  190.   entry->title       = g_strdup (title);
  191.   entry->dir_only    = dir_only;
  192.   entry->check_valid = check_valid;
  193.  
  194.   if (check_valid)
  195.     {
  196.       entry->file_exists = gtk_image_new_from_stock (GTK_STOCK_NO,
  197.                                                      GTK_ICON_SIZE_BUTTON);
  198.       gtk_box_pack_start (GTK_BOX (entry), entry->file_exists, FALSE, FALSE, 0);
  199.       gtk_widget_show (entry->file_exists);
  200.     }
  201.  
  202.   gimp_file_entry_set_filename (entry, filename);
  203.  
  204.   return GTK_WIDGET (entry);
  205. }
  206.  
  207. /**
  208.  * gimp_file_entry_get_filename:
  209.  * @entry: The file entry you want to know the filename from.
  210.  *
  211.  * Note that you have to g_free() the returned string.
  212.  *
  213.  * Returns: The file or directory the user has entered.
  214.  **/
  215. gchar *
  216. gimp_file_entry_get_filename (GimpFileEntry *entry)
  217. {
  218.   gchar *utf8;
  219.   gchar *filename;
  220.  
  221.   g_return_val_if_fail (GIMP_IS_FILE_ENTRY (entry), NULL);
  222.  
  223.   utf8 = gtk_editable_get_chars (GTK_EDITABLE (entry->entry), 0, -1);
  224.  
  225.   filename = g_filename_from_utf8 (utf8, -1, NULL, NULL, NULL);
  226.  
  227.   g_free (utf8);
  228.  
  229.   return filename;
  230. }
  231.  
  232. /**
  233.  * gimp_file_entry_set_filename:
  234.  * @entry:    The file entry you want to set the filename for.
  235.  * @filename: The new filename.
  236.  *
  237.  * If you specified @check_valid as %TRUE in gimp_file_entry_new()
  238.  * the #GimpFileEntry will immediately check the validity of the file
  239.  * name.
  240.  **/
  241. void
  242. gimp_file_entry_set_filename (GimpFileEntry *entry,
  243.                               const gchar   *filename)
  244. {
  245.   gchar *utf8;
  246.  
  247.   g_return_if_fail (GIMP_IS_FILE_ENTRY (entry));
  248.  
  249.   if (filename)
  250.     utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
  251.   else
  252.     utf8 = g_strdup ("");
  253.  
  254.   gtk_entry_set_text (GTK_ENTRY (entry->entry), utf8);
  255.   g_free (utf8);
  256.  
  257.   /*  update everything
  258.    */
  259.   gimp_file_entry_entry_activate (entry->entry, entry);
  260. }
  261.  
  262. static void
  263. gimp_file_entry_entry_activate (GtkWidget     *widget,
  264.                                 GimpFileEntry *entry)
  265. {
  266.   gchar *utf8;
  267.   gchar *filename;
  268.   gint   len;
  269.  
  270.   /*  filenames still need more sanity checking
  271.    *  (erase double G_DIR_SEPARATORS, ...)
  272.    */
  273.   utf8 = gtk_editable_get_chars (GTK_EDITABLE (widget), 0, -1);
  274.   utf8 = g_strstrip (utf8);
  275.  
  276.   while (((len = strlen (utf8)) > 1) &&
  277.      (utf8[len - 1] == G_DIR_SEPARATOR))
  278.     utf8[len - 1] = '\0';
  279.  
  280.   filename = g_filename_from_utf8 (utf8, -1, NULL, NULL, NULL);
  281.  
  282.   g_signal_handlers_block_by_func (entry->entry,
  283.                                    gimp_file_entry_entry_activate,
  284.                                    entry);
  285.   gtk_entry_set_text (GTK_ENTRY (entry->entry), utf8);
  286.   g_signal_handlers_unblock_by_func (entry->entry,
  287.                                      gimp_file_entry_entry_activate,
  288.                                      entry);
  289.  
  290.   if (entry->file_dialog)
  291.     gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (entry->file_dialog),
  292.                                    filename);
  293.  
  294.   g_free (filename);
  295.   g_free (utf8);
  296.  
  297.   gimp_file_entry_check_filename (entry);
  298.  
  299.   gtk_editable_set_position (GTK_EDITABLE (entry->entry), -1);
  300.  
  301.   g_signal_emit (entry, gimp_file_entry_signals[FILENAME_CHANGED], 0);
  302. }
  303.  
  304. static gboolean
  305. gimp_file_entry_entry_focus_out (GtkWidget     *widget,
  306.                                  GdkEvent      *event,
  307.                                  GimpFileEntry *entry)
  308. {
  309.   gimp_file_entry_entry_activate (widget, entry);
  310.  
  311.   return FALSE;
  312. }
  313.  
  314. /*  local callback of gimp_file_entry_browse_clicked()  */
  315. static void
  316. gimp_file_entry_chooser_response (GtkWidget     *dialog,
  317.                                   gint           response_id,
  318.                                   GimpFileEntry *entry)
  319. {
  320.   if (response_id == GTK_RESPONSE_OK)
  321.     {
  322.       gchar *filename;
  323.  
  324.       filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
  325.       gimp_file_entry_set_filename (entry, filename);
  326.       g_free (filename);
  327.     }
  328.  
  329.   gtk_widget_hide (dialog);
  330. }
  331.  
  332. static void
  333. gimp_file_entry_browse_clicked (GtkWidget     *widget,
  334.                                 GimpFileEntry *entry)
  335. {
  336.   GtkFileChooser *chooser;
  337.   gchar          *utf8;
  338.   gchar          *filename;
  339.  
  340.   utf8 = gtk_editable_get_chars (GTK_EDITABLE (entry->entry), 0, -1);
  341.   filename = g_filename_from_utf8 (utf8, -1, NULL, NULL, NULL);
  342.   g_free (utf8);
  343.  
  344.   if (! entry->file_dialog)
  345.     {
  346.       const gchar *title = entry->title;
  347.  
  348.       if (! title)
  349.         {
  350.           if (entry->dir_only)
  351.             title = _("Select Folder");
  352.           else
  353.             title = _("Select File");
  354.         }
  355.  
  356.       entry->file_dialog =
  357.         gtk_file_chooser_dialog_new (title, NULL,
  358.                                      entry->dir_only ?
  359.                                      GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER :
  360.                                      GTK_FILE_CHOOSER_ACTION_OPEN,
  361.  
  362.                                      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
  363.                                      GTK_STOCK_OK,     GTK_RESPONSE_OK,
  364.  
  365.                                      NULL);
  366.  
  367.       chooser = GTK_FILE_CHOOSER (entry->file_dialog);
  368.  
  369.       gtk_window_set_position (GTK_WINDOW (chooser), GTK_WIN_POS_MOUSE);
  370.       gtk_window_set_role (GTK_WINDOW (chooser),
  371.                            "gimp-file-entry-file-dialog");
  372.  
  373.       g_signal_connect (chooser, "response",
  374.                         G_CALLBACK (gimp_file_entry_chooser_response),
  375.                         entry);
  376.       g_signal_connect (chooser, "delete_event",
  377.                         G_CALLBACK (gtk_true),
  378.                         NULL);
  379.  
  380.       g_signal_connect_swapped (entry, "unmap",
  381.                                 G_CALLBACK (gtk_widget_hide),
  382.                                 chooser);
  383.     }
  384.   else
  385.     {
  386.       chooser = GTK_FILE_CHOOSER (entry->file_dialog);
  387.     }
  388.  
  389.   gtk_file_chooser_set_filename (chooser, filename);
  390.  
  391.   g_free (filename);
  392.  
  393.   gtk_window_set_screen (GTK_WINDOW (chooser), gtk_widget_get_screen (widget));
  394.   gtk_window_present (GTK_WINDOW (chooser));
  395. }
  396.  
  397. static void
  398. gimp_file_entry_check_filename (GimpFileEntry *entry)
  399. {
  400.   gchar    *utf8;
  401.   gchar    *filename;
  402.   gboolean  exists;
  403.  
  404.   if (! entry->check_valid || ! entry->file_exists)
  405.     return;
  406.  
  407.   utf8 = gtk_editable_get_chars (GTK_EDITABLE (entry->entry), 0, -1);
  408.   filename = g_filename_from_utf8 (utf8, -1, NULL, NULL, NULL);
  409.   g_free (utf8);
  410.  
  411.   if (entry->dir_only)
  412.     exists = g_file_test (filename, G_FILE_TEST_IS_DIR);
  413.   else
  414.     exists = g_file_test (filename, G_FILE_TEST_IS_REGULAR);
  415.  
  416.   g_free (filename);
  417.  
  418.   gtk_image_set_from_stock (GTK_IMAGE (entry->file_exists),
  419.                             exists ? GTK_STOCK_YES : GTK_STOCK_NO,
  420.                             GTK_ICON_SIZE_BUTTON);
  421. }
  422.