/*
 *  previews.c:		Pixmap preview browser	
 *
 *  Written by:		Ullrich Hafner
 *		
 *  Copyright (C) 1998 Ullrich Hafner <hafner@bigfoot.de>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 */

/*
 *  $Date: 1999/10/23 17:44:29 $
 *  $Author: hafner $
 *  $Revision: 1.30 $
 *  $State: Exp $
 */

#include "config.h"

#ifdef HAVE_SYS_TYPES_H
#	include <sys/types.h>
#endif
#ifdef HAVE_UNISTD_H
#	include <unistd.h>
#endif /* HAVE_UNISTD_H */
/* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */
#if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION)
#   include <dirent.h>
#   define NLENGTH(dirent) (strlen ((dirent)->d_name))
#else
#   define dirent direct
#   define NLENGTH(dirent) ((dirent)->d_namlen)
#   ifdef HAVE_SYS_NDIR_H
#       include <sys/ndir.h>
#   endif /* HAVE_SYS_NDIR_H */
#   ifdef HAVE_SYS_DIR_H
#       include <sys/dir.h>
#   endif /* HAVE_SYS_DIR_H */
#   ifdef HAVE_NDIR_H
#       include <ndir.h>
#   endif /* HAVE_NDIR_H */
#endif /* not (HAVE_DIRENT_H or _POSIX_VERSION) */

#include <gtk/gtk.h>
#include "proplist_t.h"

#include "previews.h"
#include "window.h"
#include "misc.h"
#include "dialog.h"
#include "texture.h"

#include "error.h"

/*******************************************************************************

			     global variables
  
*******************************************************************************/

extern GtkTooltips *tooltips;
extern proplist_t  windowmaker;	/* window.c */

/*******************************************************************************

			     local variables
  
*******************************************************************************/

static GList	 *file_list        = NULL;
static GtkWidget *table         = NULL;
static GtkWidget *entry         = NULL;
static GtkWidget *main_vbox     = NULL;
static GtkWidget *scrolled      = NULL;
static GtkWidget *ok_button     = NULL;
static wtexture_t *wtexture     = NULL;
static GtkWidget *pathomenu     = NULL;
static GtkWidget *previewbutton = NULL;

/*******************************************************************************

				prototypes
  
*******************************************************************************/

static void
unlock_filelist (GtkWidget *widget, gpointer ptr);
static void
lock_filelist (GtkWidget *widget, gpointer ptr);
static void
new_scrolled_and_table (void);
static void
destroy_data (gpointer data, gpointer user_data);
static void
preview_new_path (GtkWidget *widget, gpointer ptr);
static void
image_list (const char *path);
static void
make_preview (GtkWidget *entry, char *name);
static gint
set_selection (GtkWidget *widget, GdkEventButton *event, gpointer ptr);
static void
accept_selection (GtkWidget *widget, gpointer ptr);
static void
show_previews (GtkWidget *table);

/*******************************************************************************

				public code
  
*******************************************************************************/

void
preview_browser (GtkWidget *widget, gpointer ptr)
/*
 *  Open or close pixmap preview image browser dialog window.
 *  If the window is visible then hide the window and vice versa.
 *
 *  No return value.
 */
{
   static GtkWidget *window= NULL;

   wtexture = (wtexture_t *) ptr;
   if (!window)				/* window already created */
   {
      entry = gtk_entry_new ();
      
      /*
       *  Make new dialog window
       */
      window = gtk_dialog_new ();
      gtk_window_set_title (GTK_WINDOW (window), _("Pixmap Browser"));
      gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
      gtk_signal_connect (GTK_OBJECT (window), "delete_event",
			  GTK_SIGNAL_FUNC (gtk_true), NULL);
      gtk_signal_connect_object (GTK_OBJECT (window), "delete_event",
				 GTK_SIGNAL_FUNC (gtk_widget_hide),
				 GTK_OBJECT (window));

      /*
       *  Optionmenu pixmap path and update button
       */
      {
	 const char	**pathlist;
	 unsigned	n;
	 GtkWidget	*box;
	 GtkWidget	*button = gtk_button_new_with_label (_("Update previews"));
	 GtkWidget	*bbox   = gtk_hbutton_box_new ();
	 GtkWidget	*hbox   = gtk_hbox_new (FALSE, 0);
	 proplist_t	plpath      = WMCreatePLString ("PixmapPath");
	 proplist_t	pixmap_path = WMGetFromPLDictionary (windowmaker, plpath);

	 gtk_signal_connect (GTK_OBJECT (button), "clicked",
			     GTK_SIGNAL_FUNC (lock_filelist), &file_list);
	 gtk_signal_connect (GTK_OBJECT (button), "clicked",
			     GTK_SIGNAL_FUNC (generate_previews), &file_list);
	 gtk_signal_connect (GTK_OBJECT (button), "clicked",
			     GTK_SIGNAL_FUNC (unlock_filelist), &file_list);

	 WMReleasePropList (plpath);
	 pathlist = Calloc (WMGetPropListItemCount (pixmap_path) + 1,
			    sizeof (char *));

	 for (n = 0; n < WMGetPropListItemCount (pixmap_path); n++)
	    pathlist [n] = WMGetFromPLString (WMGetFromPLArray (pixmap_path, n));
	 pathlist [n] = NULL;
	 
	 box = generate_option_menu (NULL, tooltips,
				     _("Window Maker's searchpath for pixmaps"),
				     pathlist, pathlist [0], NULL,
				     preview_new_path, NULL);
	 image_list (pathlist [0]);
	 Free (pathlist);

	 pathomenu     = box;
	 previewbutton = button;
	 
	 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
			     hbox, FALSE, TRUE, 5);
	 gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new ("PixmapPath:"),
			     FALSE, TRUE, 5);
	 gtk_box_pack_start (GTK_BOX (hbox), box, FALSE, TRUE, 5);
	 gtk_box_pack_start (GTK_BOX (hbox), bbox, FALSE, TRUE, 5);
	 gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, TRUE, 0);
      }
      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
			  main_vbox = gtk_vbox_new (FALSE, 0), TRUE, TRUE, 5);
      new_scrolled_and_table ();
      /*
       *  Confirm arean (at bottom)
       */
      {
	 GtkWidget *confirm_area;
	 GtkWidget *button;
	 GtkWidget *hbox;

	 hbox = gtk_hbox_new (FALSE, 5);
	 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), hbox,
			     FALSE, TRUE, 0);

	 gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (_("Filename:")),
			     FALSE, TRUE, 0);

	 gtk_widget_set_usize (entry, 200, 0);
	 gtk_entry_set_editable (GTK_ENTRY (entry), FALSE);
	 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 10);

	 confirm_area = gtk_hbutton_box_new ();
	 gtk_box_pack_end (GTK_BOX (hbox), confirm_area, FALSE, TRUE, 10);
	 gtk_button_box_set_spacing (GTK_BUTTON_BOX (confirm_area), 5);
	 gtk_button_box_set_layout (GTK_BUTTON_BOX (confirm_area),
				    GTK_BUTTONBOX_END);

	 ok_button = gtk_button_new_with_label (_("OK"));
	 gtk_box_pack_start (GTK_BOX (confirm_area), ok_button, TRUE, TRUE, 0);
	 gtk_signal_connect (GTK_OBJECT (ok_button), "clicked",
			     GTK_SIGNAL_FUNC (accept_selection), NULL);
	 gtk_entry_set_text (GTK_ENTRY (entry), PKGDATADIR "/black.xpm");
	 GTK_WIDGET_SET_FLAGS (ok_button, GTK_CAN_DEFAULT);
	 gtk_signal_connect_object (GTK_OBJECT (ok_button), "clicked",
				    GTK_SIGNAL_FUNC (gtk_widget_hide),
				    GTK_OBJECT (window));

	 button = gtk_button_new_with_label (_("Cancel"));
	 gtk_box_pack_start (GTK_BOX (confirm_area), button, TRUE, TRUE, 0);
	 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
				    GTK_SIGNAL_FUNC (gtk_widget_hide),
				    GTK_OBJECT (window));
	 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
	 gtk_widget_grab_default (button);
      }
      show_previews (table);
   }

   if (!GTK_WIDGET_VISIBLE (window))
      gtk_widget_show_all (window);
   else
      gtk_widget_hide (window);
}

static void
image_list (const char *path)
{
   DIR			*dir;
   struct dirent	*file;
   char			*realpath = expand_tilde (path);

   dir = opendir (realpath);
   if (!dir)
      return;
   while ((file = readdir (dir)))
   {
      if (streq (file->d_name, ".") || streq (file->d_name, ".."))
	 continue;
      /*
       *  Check whether file is a directory
       */
      {
	 char	*subdir = g_strconcat (realpath, "/", file->d_name, NULL);
	 DIR	*tmpdir = opendir (subdir);

	 if (tmpdir)
	 {
	    closedir (tmpdir);
	    Free (subdir);
	    continue;
	 }
	 make_preview (entry, subdir);
      }
   }
   Free (realpath);
   closedir (dir);
}

static void
make_preview (GtkWidget *entry, char *name)
/*
 *  Make button widget displaying a pixmap with tooltips showing the
 *  pixmap filename.
 *  'image' is the filename of the preview.
 *
 *  Return value:
 *	button widget
 */
{
   previewdata_t *data = Calloc (1, sizeof (previewdata_t));
   GtkWidget	 *pixmap;

   data->name   = name;
   data->button = gtk_button_new ();

   gtk_signal_connect (GTK_OBJECT (data->button), "button_press_event",
		       GTK_SIGNAL_FUNC (set_selection), data);
   file_list = g_list_append (file_list, data);

   {
      char *fname = expand_tilde (name);
      char *pname = preview_name (fname);
      char *path  = get_pixmap_path (pname);

      if (path)
      {
	 pixmap = make_pixmap (path, 64, 64, NULL);
	 Free (path);
      }
      else
      {
	 pixmap = make_pixmap (PKGDATADIR "/black.xpm", 64, 64, NULL);
	 make_pixmap (WMAKERDATADIR "/Icons/defaultAppIcon.xpm", 64, 64, pixmap);
      }
      
      Free (fname);
      Free (pname);
   }
   
   gtk_tooltips_set_tip (tooltips, data->button, g_basename (name), NULL);
   gtk_container_set_border_width (GTK_CONTAINER (data->button), 2);
   gtk_container_add (GTK_CONTAINER (data->button), pixmap);
   gtk_widget_show_all (data->button);
   gtk_object_set_user_data (GTK_OBJECT (data->button), pixmap);
   gtk_object_set_user_data (GTK_OBJECT (pixmap), entry);
}

static gint
set_selection (GtkWidget *widget, GdkEventButton *event, gpointer ptr)
/*
 *  Change text entry if pixmap button is pressed.
 */
{
   GtkWidget	 *pixmap = gtk_object_get_user_data (GTK_OBJECT (widget));
   GtkWidget	 *entry  = gtk_object_get_user_data (GTK_OBJECT (pixmap));
   previewdata_t *data   = (previewdata_t *) ptr;

   gtk_entry_set_text (GTK_ENTRY (entry), g_basename (data->name));

   if (event->type == GDK_2BUTTON_PRESS)
     gtk_signal_emit_by_name (GTK_OBJECT (ok_button), "clicked");

   return TRUE;
}

static void
accept_selection (GtkWidget *widget, gpointer ptr)
/*
 *  OK button is activated: set pixmap and text entry of texture dialog.
 *
 *  No return value.
 */
{
   gtk_entry_set_text (GTK_ENTRY (wtexture->wpixmap [PIXMAP_NAME]),
		       gtk_entry_get_text (GTK_ENTRY (entry)));
   verify_pixmap_name (entry, wtexture);
}

static void
show_previews (GtkWidget *table)
{
   unsigned n = 0;
   unsigned x = 0;
   unsigned y = 0;

   for (n = 0; n < g_list_length (file_list); n++)
   {
      previewdata_t *data = g_list_nth_data (file_list, n);

      gtk_table_attach (GTK_TABLE (table), data->button, x, x + 1, y, y + 1,
			GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
      x++;
      if (x == 8)
      {
	 x = 0;
	 y++;
      }
   }
}

static void
preview_new_path (GtkWidget *widget, gpointer ptr)
{
   char *text = gtk_object_get_user_data (GTK_OBJECT (widget));

   g_list_foreach (file_list, destroy_data, NULL);
   g_list_free (file_list);
   file_list = NULL;
   new_scrolled_and_table ();
   image_list (text);
   show_previews (table);
}

static void
destroy_data (gpointer data, gpointer user_data)
{
   previewdata_t *pd = (previewdata_t *) data;

   Free (pd->name);
   Free (pd);
}

static void
new_scrolled_and_table (void)
{
   if (scrolled)
      gtk_widget_destroy (scrolled);
   scrolled = gtk_scrolled_window_new (NULL, NULL);
   gtk_box_pack_start (GTK_BOX (main_vbox), scrolled, TRUE, TRUE, 5);

   table = gtk_table_new (1, 1, TRUE);
   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
				   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
   gtk_widget_set_usize (scrolled, 660, 430);
   gtk_container_set_border_width (GTK_CONTAINER (scrolled), 5);

   gtk_container_set_border_width (GTK_CONTAINER (table), 5);
   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
   gtk_table_set_col_spacings (GTK_TABLE (table), 2);
   gtk_widget_show (table);
   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
					  table);
   gtk_widget_show_all (scrolled);
}

static void
lock_filelist (GtkWidget *widget, gpointer ptr)
{
   gtk_widget_set_sensitive (pathomenu, FALSE);
   gtk_widget_set_sensitive (previewbutton, FALSE);
}

static void
unlock_filelist (GtkWidget *widget, gpointer ptr)
{
   gtk_widget_set_sensitive (pathomenu, TRUE);
   gtk_widget_set_sensitive (previewbutton, TRUE);
}

