home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / libgimp / gimpfileselection.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  13.0 KB  |  460 lines

  1. /* LIBGIMP - The GIMP Library 
  2.  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
  3.  *
  4.  * gimpfileselection.c
  5.  * Copyright (C) 1999-2000 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. #include "config.h"
  23.  
  24. #include <glib.h>         /* Needed here by Win32 gcc compilation */
  25.  
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #ifdef HAVE_UNISTD_H
  29. #include <unistd.h>
  30. #endif
  31. #include <string.h>
  32.  
  33. #include <gtk/gtk.h>
  34.  
  35. #include "gimpfileselection.h"
  36.  
  37. #include "libgimp-intl.h"
  38.  
  39. #include "pixmaps/yes.xpm"
  40. #include "pixmaps/no.xpm"
  41.  
  42.  
  43. #ifdef G_OS_WIN32
  44. # ifndef S_ISDIR
  45. #  define S_ISDIR(m) ((m) & _S_IFDIR)
  46. # endif
  47. # ifndef S_ISREG
  48. #  define S_ISREG(m) ((m) & _S_IFREG)
  49. # endif
  50. #endif
  51.  
  52. /*  callbacks  */
  53. static void gimp_file_selection_realize                  (GtkWidget *widget);
  54. static void gimp_file_selection_entry_callback           (GtkWidget *widget,
  55.                               gpointer   data);
  56. static gint gimp_file_selection_entry_focus_out_callback (GtkWidget *widget,
  57.                               GdkEvent  *event,
  58.                               gpointer   data);
  59. static void gimp_file_selection_browse_callback          (GtkWidget *widget,
  60.                               gpointer   data);
  61.  
  62. /*  private functions  */
  63. static void gimp_file_selection_check_filename (GimpFileSelection *gfs);
  64.  
  65. enum
  66. {
  67.   FILENAME_CHANGED,
  68.   LAST_SIGNAL
  69. };
  70.  
  71. static guint gimp_file_selection_signals[LAST_SIGNAL] = { 0 };
  72.  
  73. static GtkHBoxClass *parent_class = NULL;
  74.  
  75. static void
  76. gimp_file_selection_destroy (GtkObject *object)
  77. {
  78.   GimpFileSelection *gfs;
  79.  
  80.   g_return_if_fail (object != NULL);
  81.   g_return_if_fail (GIMP_IS_FILE_SELECTION (object));
  82.  
  83.   gfs = GIMP_FILE_SELECTION (object);
  84.  
  85.   if (gfs->file_selection)
  86.     gtk_widget_destroy (gfs->file_selection);
  87.  
  88.   if (gfs->title)
  89.     g_free (gfs->title);
  90.  
  91.   if (gfs->yes_pixmap)
  92.     gdk_pixmap_unref (gfs->yes_pixmap);
  93.   if (gfs->yes_mask)
  94.     gdk_bitmap_unref (gfs->yes_mask);
  95.  
  96.   if (gfs->no_pixmap)
  97.     gdk_pixmap_unref (gfs->no_pixmap);
  98.   if (gfs->no_mask)
  99.     gdk_bitmap_unref (gfs->no_mask);
  100.  
  101.   if (GTK_OBJECT_CLASS (parent_class)->destroy)
  102.     GTK_OBJECT_CLASS (parent_class)->destroy (object);
  103. }
  104.  
  105. static void
  106. gimp_file_selection_class_init (GimpFileSelectionClass *class)
  107. {
  108.   GtkObjectClass *object_class;
  109.   GtkWidgetClass *widget_class;
  110.  
  111.   object_class = (GtkObjectClass *) class;
  112.   widget_class = (GtkWidgetClass *) class;
  113.  
  114.   parent_class = gtk_type_class (gtk_hbox_get_type ());
  115.  
  116.   gimp_file_selection_signals[FILENAME_CHANGED] = 
  117.     gtk_signal_new ("filename_changed",
  118.             GTK_RUN_FIRST,
  119.             object_class->type,
  120.             GTK_SIGNAL_OFFSET (GimpFileSelectionClass,
  121.                        filename_changed),
  122.             gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
  123.  
  124.   gtk_object_class_add_signals (object_class, gimp_file_selection_signals, 
  125.                 LAST_SIGNAL);
  126.  
  127.   class->filename_changed = NULL;
  128.  
  129.   object_class->destroy = gimp_file_selection_destroy;
  130.   widget_class->realize = gimp_file_selection_realize;
  131. }
  132.  
  133. static void
  134. gimp_file_selection_init (GimpFileSelection *gfs)
  135. {
  136.   gfs->title          = NULL;
  137.   gfs->file_selection = NULL;
  138.   gfs->check_valid    = FALSE;
  139.  
  140.   gfs->file_exists    = NULL;
  141.   gfs->yes_pixmap     = NULL;
  142.   gfs->yes_mask       = NULL;
  143.   gfs->no_pixmap      = NULL;
  144.   gfs->no_mask        = NULL;
  145.  
  146.   gtk_box_set_spacing (GTK_BOX (gfs), 2);
  147.   gtk_box_set_homogeneous (GTK_BOX (gfs), FALSE);
  148.  
  149.   gfs->browse_button = gtk_button_new_with_label (" ... ");
  150.   gtk_box_pack_end (GTK_BOX (gfs), gfs->browse_button, FALSE, FALSE, 0);
  151.   gtk_signal_connect (GTK_OBJECT(gfs->browse_button), "clicked",
  152.               GTK_SIGNAL_FUNC (gimp_file_selection_browse_callback),
  153.               gfs);
  154.   gtk_widget_show (gfs->browse_button);
  155.  
  156.   gfs->entry = gtk_entry_new ();
  157.   gtk_box_pack_end (GTK_BOX (gfs), gfs->entry, TRUE, TRUE, 0);
  158.   gtk_signal_connect (GTK_OBJECT (gfs->entry), "activate",
  159.               GTK_SIGNAL_FUNC (gimp_file_selection_entry_callback),
  160.               gfs);
  161.   gtk_signal_connect (GTK_OBJECT (gfs->entry), "focus_out_event",
  162.               GTK_SIGNAL_FUNC (gimp_file_selection_entry_focus_out_callback),
  163.               gfs);
  164.   gtk_widget_show (gfs->entry);
  165. }
  166.  
  167. GtkType
  168. gimp_file_selection_get_type (void)
  169. {
  170.   static GtkType gfs_type = 0;
  171.  
  172.   if (!gfs_type)
  173.     {
  174.       GtkTypeInfo gfs_info =
  175.       {
  176.     "GimpFileSelection",
  177.     sizeof (GimpFileSelection),
  178.     sizeof (GimpFileSelectionClass),
  179.     (GtkClassInitFunc) gimp_file_selection_class_init,
  180.     (GtkObjectInitFunc) gimp_file_selection_init,
  181.     /* reserved_1 */ NULL,
  182.     /* reserved_2 */ NULL,
  183.         (GtkClassInitFunc) NULL
  184.       };
  185.  
  186.       gfs_type = gtk_type_unique (gtk_hbox_get_type (), &gfs_info);
  187.     }
  188.   
  189.   return gfs_type;
  190. }
  191.  
  192. /**
  193.  * gimp_file_selection_new:
  194.  * @title: The title of the #GtkFileSelection dialog.
  195.  * @filename: The initial filename.
  196.  * @dir_only: #TRUE if the file selection should accept directories only.
  197.  * @check_valid: #TRUE if the widget should check if the entered file
  198.  *               really exists.
  199.  *
  200.  * Creates a new #GimpFileSelection widget.
  201.  *
  202.  * Returns: A pointer to the new #GimpFileSelection widget.
  203.  **/
  204. GtkWidget *
  205. gimp_file_selection_new (const gchar *title,
  206.              const gchar *filename,
  207.              gboolean     dir_only,
  208.              gboolean     check_valid)
  209. {
  210.   GimpFileSelection *gfs;
  211.  
  212.   gfs = gtk_type_new (gimp_file_selection_get_type ());
  213.  
  214.   gfs->title       = g_strdup (title);
  215.   gfs->dir_only    = dir_only;
  216.   gfs->check_valid = check_valid;
  217.  
  218.   gimp_file_selection_set_filename (gfs, filename);
  219.  
  220.   return GTK_WIDGET (gfs);
  221. }
  222.  
  223. /**
  224.  * gimp_file_selection_get_filename:
  225.  * @gfs: The file selection you want to know the filename from.
  226.  *
  227.  * Note that you have to g_free() the returned string.
  228.  *
  229.  * Returns: The file or directory the user has entered.
  230.  **/
  231. gchar *
  232. gimp_file_selection_get_filename (GimpFileSelection *gfs)
  233. {
  234.   g_return_val_if_fail (gfs != NULL, g_strdup (""));
  235.   g_return_val_if_fail (GIMP_IS_FILE_SELECTION (gfs), g_strdup (""));
  236.  
  237.   return gtk_editable_get_chars (GTK_EDITABLE (gfs->entry), 0, -1);
  238. }
  239.  
  240. /**
  241.  * gimp_file_selection_set_filename:
  242.  * @gfs: The file selection you want to set the filename for.
  243.  * @filename: The new filename.
  244.  *
  245.  * If you specified @check_valid as #TRUE in gimp_file_selection_new()
  246.  * the #GimpFileSelection will immediately check the validity of the file
  247.  * name.
  248.  *
  249.  */
  250. void
  251. gimp_file_selection_set_filename (GimpFileSelection *gfs,
  252.                   const gchar       *filename)
  253. {
  254.   g_return_if_fail (gfs != NULL);
  255.   g_return_if_fail (GIMP_IS_FILE_SELECTION (gfs));
  256.  
  257.   gtk_entry_set_text (GTK_ENTRY (gfs->entry), filename ? filename : "");
  258.  
  259.   /*  update everything
  260.    */
  261.   gimp_file_selection_entry_callback (gfs->entry, (gpointer) gfs);
  262. }
  263.  
  264. static void
  265. gimp_file_selection_realize (GtkWidget *widget)
  266. {
  267.   GimpFileSelection *gfs;
  268.   GtkStyle          *style;
  269.  
  270.   gfs = GIMP_FILE_SELECTION (widget);
  271.   if (! gfs->check_valid)
  272.     return;
  273.  
  274.   if (GTK_WIDGET_CLASS (parent_class)->realize)
  275.     (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
  276.  
  277.   style = gtk_widget_get_style (widget);
  278.  
  279.   gfs->yes_pixmap = gdk_pixmap_create_from_xpm_d (widget->window,
  280.                           &gfs->yes_mask,
  281.                           &style->bg[GTK_STATE_NORMAL],
  282.                           yes_xpm);
  283.   gfs->no_pixmap = gdk_pixmap_create_from_xpm_d (widget->window,
  284.                          &gfs->no_mask,
  285.                          &style->bg[GTK_STATE_NORMAL],
  286.                          no_xpm);
  287.  
  288.   gfs->file_exists = gtk_pixmap_new (gfs->no_pixmap, gfs->no_mask);
  289.   gtk_box_pack_start (GTK_BOX (gfs), gfs->file_exists, FALSE, FALSE, 0);
  290.  
  291.   gimp_file_selection_check_filename (gfs);
  292.   gtk_widget_show (gfs->file_exists);
  293. }
  294.  
  295. static void
  296. gimp_file_selection_entry_callback (GtkWidget *widget,
  297.                     gpointer   data)
  298. {
  299.   GimpFileSelection *gfs;
  300.   gchar             *filename;
  301.   gint               len;
  302.  
  303.   gfs = GIMP_FILE_SELECTION (data);
  304.  
  305.   /*  filenames still need more sanity checking
  306.    *  (erase double G_DIR_SEPARATORS, ...)
  307.    */
  308.   filename = gtk_editable_get_chars (GTK_EDITABLE (widget), 0, -1);
  309.   filename = g_strstrip (filename);
  310.  
  311.   while (((len = strlen (filename)) > 1) &&
  312.      (filename[len - 1] == G_DIR_SEPARATOR))
  313.     filename[len - 1] = '\0';
  314.  
  315.   gtk_signal_handler_block_by_data (GTK_OBJECT (gfs->entry), gfs);
  316.   gtk_entry_set_text (GTK_ENTRY (gfs->entry), filename);
  317.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (gfs->entry), gfs);
  318.  
  319.   if (gfs->file_selection)
  320.     gtk_file_selection_set_filename (GTK_FILE_SELECTION (gfs->file_selection),
  321.                      filename);
  322.   g_free (filename);
  323.  
  324.   gimp_file_selection_check_filename (gfs);
  325.  
  326.   gtk_entry_set_position (GTK_ENTRY (gfs->entry), -1);
  327.  
  328.   gtk_signal_emit (GTK_OBJECT (gfs),
  329.            gimp_file_selection_signals[FILENAME_CHANGED]);
  330. }
  331.  
  332. static gboolean
  333. gimp_file_selection_entry_focus_out_callback (GtkWidget *widget,
  334.                           GdkEvent  *event,
  335.                           gpointer   data)
  336. {
  337.   gimp_file_selection_entry_callback (widget, data);
  338.  
  339.   return TRUE;
  340. }
  341.  
  342. /*  local callbacks of gimp_file_selection_browse_callback()  */
  343. static void
  344. gimp_file_selection_filesel_ok_callback (GtkWidget *widget,
  345.                      gpointer   data)
  346. {
  347.   GimpFileSelection *gfs;
  348.   gchar             *filename;
  349.  
  350.   gfs = GIMP_FILE_SELECTION (data);
  351.   filename =
  352.     gtk_file_selection_get_filename (GTK_FILE_SELECTION (gfs->file_selection));
  353.  
  354.   gtk_entry_set_text (GTK_ENTRY (gfs->entry), filename);
  355.  
  356.   gtk_widget_hide (gfs->file_selection);
  357.  
  358.   /*  update everything  */
  359.   gimp_file_selection_entry_callback (gfs->entry, data);
  360. }
  361.  
  362. static void
  363. gimp_file_selection_browse_callback (GtkWidget *widget,
  364.                      gpointer   data)
  365. {
  366.   GimpFileSelection *gfs;
  367.   gchar             *filename;
  368.  
  369.   gfs = GIMP_FILE_SELECTION (data);
  370.   filename = gtk_editable_get_chars (GTK_EDITABLE (gfs->entry), 0, -1);
  371.   
  372.   if (gfs->file_selection == NULL)
  373.     {
  374.       if (gfs->dir_only)
  375.     {
  376.       gfs->file_selection = gtk_file_selection_new (gfs->title);
  377.  
  378.       /*  hiding these widgets uses internal gtk+ knowledge, but it's
  379.        *  easier than creating my own directory browser -- michael
  380.        */
  381.       gtk_widget_hide
  382.         (GTK_FILE_SELECTION (gfs->file_selection)->fileop_del_file);
  383.       gtk_widget_hide
  384.         (GTK_FILE_SELECTION (gfs->file_selection)->file_list->parent);
  385.     }
  386.       else
  387.     {
  388.       gfs->file_selection = gtk_file_selection_new (_("Select File"));
  389.     }
  390.  
  391.       gtk_window_set_position (GTK_WINDOW (gfs->file_selection),
  392.                    GTK_WIN_POS_MOUSE);
  393.       gtk_window_set_wmclass (GTK_WINDOW (gfs->file_selection),
  394.                   "file_select", "Gimp");
  395.  
  396.       /* slightly compress the dialog */
  397.       gtk_container_set_border_width (GTK_CONTAINER (gfs->file_selection), 2);
  398.       gtk_container_set_border_width (GTK_CONTAINER (GTK_FILE_SELECTION (gfs->file_selection)->button_area), 2);
  399.  
  400.       gtk_signal_connect 
  401.     (GTK_OBJECT (GTK_FILE_SELECTION (gfs->file_selection)->ok_button),
  402.      "clicked",
  403.      GTK_SIGNAL_FUNC (gimp_file_selection_filesel_ok_callback),
  404.      gfs);
  405.       gtk_signal_connect
  406.     (GTK_OBJECT (GTK_FILE_SELECTION (gfs->file_selection)->selection_entry),
  407.      "activate",
  408.      GTK_SIGNAL_FUNC (gimp_file_selection_filesel_ok_callback),
  409.      gfs);
  410.  
  411.       gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (gfs->file_selection)->cancel_button),
  412.                  "clicked",
  413.                  GTK_SIGNAL_FUNC (gtk_widget_hide),
  414.                  GTK_OBJECT (gfs->file_selection));
  415.       gtk_signal_connect_object (GTK_OBJECT (gfs), "unmap",
  416.                  GTK_SIGNAL_FUNC (gtk_widget_hide),
  417.                  GTK_OBJECT (gfs->file_selection));
  418.       gtk_signal_connect_object (GTK_OBJECT (gfs->file_selection),
  419.                  "delete_event",
  420.                  GTK_SIGNAL_FUNC (gtk_widget_hide),
  421.                  GTK_OBJECT (gfs->file_selection));
  422.     }
  423.  
  424.   gtk_file_selection_set_filename (GTK_FILE_SELECTION (gfs->file_selection),
  425.                    filename);
  426.  
  427.   if (! GTK_WIDGET_VISIBLE (gfs->file_selection))
  428.     gtk_widget_show (gfs->file_selection);
  429.   else
  430.     gdk_window_raise (gfs->file_selection->window);
  431. }
  432.  
  433. static void
  434. gimp_file_selection_check_filename (GimpFileSelection *gfs)
  435. {
  436.   static struct stat  statbuf;
  437.   gchar              *filename;
  438.  
  439.   if (! gfs->check_valid)
  440.     return;
  441.  
  442.   if (gfs->file_exists == NULL)
  443.     return;
  444.  
  445.   filename = gtk_editable_get_chars (GTK_EDITABLE (gfs->entry), 0, -1);
  446.   if ((stat (filename, &statbuf) == 0) &&
  447.       (gfs->dir_only ? S_ISDIR (statbuf.st_mode) : S_ISREG (statbuf.st_mode)))
  448.     {
  449.       gtk_pixmap_set (GTK_PIXMAP (gfs->file_exists),
  450.               gfs->yes_pixmap, gfs->yes_mask);
  451.     }
  452.   else
  453.     {
  454.       gtk_pixmap_set (GTK_PIXMAP (gfs->file_exists),
  455.               gfs->no_pixmap, gfs->no_mask);
  456.     }
  457.  
  458.   g_free (filename);
  459. }
  460.