1 /*
2  *  path.c:		Path selection widget
3  *
4  *  Written by:		Ullrich Hafner
5  *
6  *  Copyright (C) 1998-2000 Ullrich Hafner <hafner@bigfoot.de>
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
21  */
22 
23 
24 /*
25  *  $Date: 2000/09/03 19:22:04 $
26  *  $Author: hafner $
27  *  $Revision: 1.19 $
28  *  $State: Exp $
29  */
30 
31 #include "config.h"
32 
33 #include <gtk/gtk.h>
34 #include "proplist_t.h"
35 
36 #include "misc.h"
37 #include "path.h"
38 #include "themebrowser.h"
39 #include "menu.h"
40 #include "error.h"
41 
42 extern proplist_t windowmaker;
43 extern proplist_t wmconfig;
44 extern bool_t	   changed;
45 
46 /*****************************************************************************
47 
48 			       prototypes
49 
50 *****************************************************************************/
51 
52 static void
53 remove_dir (GtkWidget *button, gpointer data);
54 static void
55 update_proplist (GtkWidget *button, gpointer data);
56 static void
57 open_dirbrowser (GtkWidget *button, gpointer data);
58 static void
59 insert_dir (GtkWidget *button, gpointer data);
60 static void
61 row_moved (GtkWidget *clist, gint source_row, gint dest_row, gpointer data);
62 static void
63 update_entry (GtkCList *clist, gint row, gint column,
64 	      GdkEvent *event, gpointer data);
65 static void
66 change_dir (GtkWidget *entry, gpointer data);
67 static void
68 update_path (proplist_t key, gpointer ptr, proplist_t value,
69 	     const char *path);
70 static void
71 init_dir_list (GtkCList *clist, proplist_t value);
72 
73 /*****************************************************************************
74 
75 			       public code
76 
77 *****************************************************************************/
78 
79 void
path_dialog(GtkWidget * page,proplist_t key,proplist_t array,GtkTooltips * tooltips,proplist_t info)80 path_dialog (GtkWidget *page, proplist_t key, proplist_t array,
81 	     GtkTooltips *tooltips, proplist_t info)
82 /*
83  *  Generate path dialog widget.
84  *  Associated wmaker attribute name is given by 'key'.
85  *
86  *  Return value:
87  *	container box
88  */
89 {
90    GtkWidget *hbox;
91    GtkWidget *vbox;
92    GtkWidget *entry;
93    GtkWidget *clist;
94    GtkWidget *frame;
95    guint      entry_sig_handler;
96 
97    /*
98     *  Error handling
99     */
100    if (array && !WMIsPLArray (array))	/* uups */
101    {
102       WMReleasePropList (array);
103       array = NULL;
104    }
105    if (!array)
106    {
107       array = WMCreatePLArray (WMCreatePLString ("/"), NULL);
108       WMPutInPLDictionary (windowmaker, key, array);
109    }
110 
111    {
112       proplist_t pltitle    = WMCreatePLString ("Title");
113       proplist_t keydef     = WMGetFromPLDictionary (wmconfig, key);
114       proplist_t title_text = WMGetFromPLDictionary (keydef, pltitle);
115 
116       frame = gtk_frame_new (D_(WMGetFromPLString (title_text ? title_text : key)));
117       gtk_frame_set_label_align (GTK_FRAME (frame), 0.5, 0.5);
118       gtk_container_set_border_width (GTK_CONTAINER (frame), 5);
119 
120       WMReleasePropList (pltitle);
121    }
122 
123    hbox = gtk_hbox_new (FALSE, 0);
124    gtk_container_add (GTK_CONTAINER (frame), hbox);
125 
126    vbox = gtk_vbox_new (FALSE, 5);
127    gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
128 
129    clist = gtk_clist_new (1);
130    gtk_object_set_user_data (GTK_OBJECT (clist), key);
131 
132    gtk_clist_set_reorderable (GTK_CLIST (clist), TRUE);
133    gtk_clist_set_use_drag_icons (GTK_CLIST (clist), TRUE);
134    gtk_clist_set_column_auto_resize (GTK_CLIST (clist), 0, YES);
135    {
136       GtkWidget *scrolled = gtk_scrolled_window_new (NULL, NULL);
137       gtk_container_set_border_width (GTK_CONTAINER (scrolled), 5);
138       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
139 				      GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
140       gtk_widget_set_usize (scrolled, -1, 120);
141       gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
142       gtk_container_add (GTK_CONTAINER (scrolled), clist);
143    }
144    gtk_clist_column_titles_passive (GTK_CLIST (clist));
145    gtk_clist_set_selection_mode (GTK_CLIST (clist), GTK_SELECTION_BROWSE);
146 
147    {
148       GtkWidget *button;
149       GtkWidget *bbox = gtk_vbutton_box_new ();
150 
151       gtk_box_pack_start (GTK_BOX (hbox), bbox, FALSE, TRUE, 5);
152       gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox),
153 				 GTK_BUTTONBOX_SPREAD);
154 
155       button = gtk_button_new_with_label (_("Insert..."));
156       gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, TRUE, 5);
157       gtk_tooltips_set_tip (tooltips, button,
158 			    _("Insert new directory."), NULL);
159       gtk_object_set_user_data (GTK_OBJECT (button), NULL);
160       gtk_signal_connect (GTK_OBJECT (button), "clicked",
161 			  GTK_SIGNAL_FUNC (open_dirbrowser), clist);
162 
163       button = gtk_button_new_with_label (_("Remove"));
164       gtk_object_set_data (GTK_OBJECT (clist), "remove", button);
165       gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, TRUE, 5);
166       gtk_tooltips_set_tip (tooltips, button,
167 			    _("Remove selected directory."), NULL);
168       gtk_signal_connect (GTK_OBJECT (button), "clicked",
169 			  GTK_SIGNAL_FUNC (remove_dir), clist);
170    }
171 
172    hbox = gtk_hbox_new (FALSE, 5);
173    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
174    gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
175 
176    entry = gtk_entry_new ();
177    gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
178    if (info)
179       gtk_tooltips_set_tip (tooltips, entry, D_(WMGetFromPLString (info)), NULL);
180 
181    entry_sig_handler = gtk_signal_connect (GTK_OBJECT (entry), "changed",
182 		                           GTK_SIGNAL_FUNC (change_dir), clist);
183    gtk_object_set_user_data (GTK_OBJECT (entry),
184 		             GINT_TO_POINTER (entry_sig_handler));
185 
186    gtk_signal_connect (GTK_OBJECT (clist), "select_row",
187 		       GTK_SIGNAL_FUNC (update_entry), entry);
188 
189    gtk_signal_connect_after (GTK_OBJECT (clist), "row_move",
190 			     GTK_SIGNAL_FUNC (row_moved), clist);
191 
192    init_dir_list (GTK_CLIST (clist), WMGetFromPLDictionary (windowmaker, key));
193 
194    gtk_widget_show_all (frame);
195    gtk_box_pack_start (GTK_BOX (page), frame, TRUE, TRUE, 0);
196 
197    connect_update_function (key, clist, update_path);
198 }
199 
200 /*******************************************************************************
201 
202 			       private code
203 
204 *******************************************************************************/
205 
206 static void
init_dir_list(GtkCList * clist,proplist_t value)207 init_dir_list (GtkCList *clist, proplist_t value)
208 {
209    unsigned	i;
210 
211    gtk_clist_clear (GTK_CLIST (clist));
212    for (i = 0; i < WMGetPropListItemCount (value); i++)
213    {
214       char *text = WMGetFromPLString (WMGetFromPLArray (value, i));
215 
216       gtk_clist_insert (GTK_CLIST (clist), i, &text);
217    }
218    gtk_clist_select_row (GTK_CLIST (clist), 0, 0);
219 }
220 
221 static void
remove_dir(GtkWidget * button,gpointer data)222 remove_dir (GtkWidget *button, gpointer data)
223 /*
224  *  Remove selected directory.
225  */
226 {
227    GtkWidget	*clist = (GtkWidget *) data;
228 
229    if (GTK_CLIST (clist)->rows > 1)
230    {
231       gint row = GPOINTER_TO_INT (GTK_CLIST (clist)->selection->data);
232 
233       if (row == GTK_CLIST (clist)->rows - 1) /* last row */
234 	 gtk_clist_select_row (GTK_CLIST (clist), row - 1, 0);
235       else
236 	 gtk_clist_select_row (GTK_CLIST (clist), row + 1, 0);
237       gtk_clist_remove (GTK_CLIST (clist), row);
238       if (GTK_CLIST (clist)->rows <= 1)
239 	 gtk_widget_set_sensitive (button, FALSE);
240       update_proplist (button, data);
241    }
242 }
243 
244 static void
open_dirbrowser(GtkWidget * button,gpointer data)245 open_dirbrowser (GtkWidget *button, gpointer data)
246 /*
247  *  Open pixmap browser to select new directory.
248  */
249 {
250    static GtkWidget	*filesel = NULL;
251    GtkWidget		*clist = (GtkWidget *) data;
252 
253    if (!filesel)
254    {
255       GtkFileSelection *fs;
256 
257       /*
258        *  Fileselection dialog window
259        */
260       filesel = gtk_file_selection_new (_("Choose directory"));
261       fs      = GTK_FILE_SELECTION (filesel);
262       gtk_widget_set_sensitive (fs->file_list, FALSE);
263       gtk_file_selection_hide_fileop_buttons (fs);
264       gtk_window_set_position (GTK_WINDOW (filesel), GTK_WIN_POS_MOUSE);
265       gtk_signal_connect (GTK_OBJECT (filesel), "destroy",
266                           GTK_SIGNAL_FUNC (gtk_widget_destroyed),
267                           &filesel);
268       gtk_signal_connect (GTK_OBJECT (fs->ok_button), "clicked",
269 			  GTK_SIGNAL_FUNC (insert_dir), data);
270       gtk_object_set_user_data (GTK_OBJECT (fs->ok_button), filesel);
271 
272       gtk_signal_connect_object (GTK_OBJECT (fs->cancel_button), "clicked",
273 				 GTK_SIGNAL_FUNC (gtk_widget_destroy),
274 				 GTK_OBJECT (filesel));
275       gtk_signal_connect_object (GTK_OBJECT (fs->ok_button), "clicked",
276 				 GTK_SIGNAL_FUNC (gtk_widget_destroy),
277 				 GTK_OBJECT (filesel));
278       {
279 	 char *filename;
280 
281 	 if (GTK_CLIST (clist)->rows > 0)
282 	    gtk_clist_get_text (GTK_CLIST (clist),
283 				GPOINTER_TO_INT (GTK_CLIST (clist)->selection->data),
284 				0, &filename);
285 	 else
286 	    filename = "";
287 
288 	 if (streq (filename, ""))
289 	    gtk_file_selection_set_filename (fs, WMAKERDATADIR "/");
290 	 else
291 	    gtk_file_selection_set_filename (fs, filename);
292       }
293    }
294 
295    if (!GTK_WIDGET_VISIBLE (filesel))
296       gtk_widget_show (filesel);
297    else
298       gtk_widget_destroy (filesel);
299 }
300 
301 static void
insert_dir(GtkWidget * button,gpointer data)302 insert_dir (GtkWidget *button, gpointer data)
303 /*
304  *  Insert directory selected with pixmap browser into the directory list.
305  */
306 {
307    GtkWidget		*clist  = (GtkWidget *) data;
308    GtkFileSelection	*fs;
309    char			*text;
310 
311    fs 	= GTK_FILE_SELECTION (gtk_object_get_user_data (GTK_OBJECT (button)));
312    text = g_strdup (gtk_file_selection_get_filename (fs));
313 
314    if (strlen (text) > 1 && text [strlen (text) - 1] == '/')
315       text [strlen (text) - 1] = 0;
316 
317    if (GTK_CLIST (clist)->rows > 0)
318       gtk_clist_insert (GTK_CLIST (clist),
319 			GPOINTER_TO_INT (GTK_CLIST (clist)->selection->data),
320 			&text);
321    else
322       gtk_clist_insert (GTK_CLIST (clist), 0, &text);
323 
324    Free (text);
325 
326    if (GTK_CLIST (clist)->rows > 1)
327    {
328       GtkWidget *remove = (GtkWidget *) gtk_object_get_data (GTK_OBJECT (clist),
329 							     "remove");
330       gtk_widget_set_sensitive (remove, TRUE);
331    }
332    update_proplist (button, data);
333 }
334 
335 static void
update_proplist(GtkWidget * button,gpointer data)336 update_proplist (GtkWidget *button, gpointer data)
337 /*
338  *  Update value of WindowMaker array.
339  */
340 {
341    GtkWidget	*clist = (GtkWidget *) data;
342    proplist_t	key   = gtk_object_get_user_data (GTK_OBJECT (clist));
343    proplist_t	array = WMGetFromPLDictionary (windowmaker, key);
344    int		n;
345 
346    for (n = WMGetPropListItemCount (array); n; n--)
347       WMDeleteFromPLArray (array, 0);
348 
349    for (n = 0; n < GTK_CLIST (clist)->rows; n++)
350    {
351       char *text;
352 
353       gtk_clist_get_text (GTK_CLIST (clist), n, 0, &text);
354       WMInsertInPLArray (array, n, WMCreatePLString (text));
355    }
356    toggle_save (changed = YES, key);
357 }
358 
359 static void
update_entry(GtkCList * clist,gint row,gint column,GdkEvent * event,gpointer data)360 update_entry (GtkCList *clist, gint row, gint column,
361 	      GdkEvent *event, gpointer data)
362 /*
363  *  Update entry if new directory has been selected in the dir list.
364  */
365 {
366    GtkWidget	*entry = (GtkWidget *) data;
367    guint         entry_sig_handler = GPOINTER_TO_INT (gtk_object_get_user_data
368 						      (GTK_OBJECT (entry)));
369    char		*text;
370 
371    gtk_clist_get_text (GTK_CLIST (clist), row, 0, &text);
372    g_signal_handler_block (entry, entry_sig_handler);
373    gtk_entry_set_text (GTK_ENTRY (entry), text);
374    g_signal_handler_unblock (entry, entry_sig_handler);
375 }
376 
377 static void
row_moved(GtkWidget * clist,gint source_row,gint dest_row,gpointer data)378 row_moved (GtkWidget *clist, gint source_row, gint dest_row, gpointer data)
379 /*
380  *  Update directory array if row has been moved with DND.
381  */
382 {
383    update_proplist (clist, clist);
384 }
385 
386 static void
change_dir(GtkWidget * entry,gpointer data)387 change_dir (GtkWidget *entry, gpointer data)
388 /*
389  *  Update directory name changed via entry
390  */
391 {
392    GtkWidget	*clist = (GtkWidget *) data;
393    const char	*new_text;
394    char         *text;
395    gint		 row = GPOINTER_TO_INT (GTK_CLIST (clist)->selection->data);
396 
397    new_text = gtk_entry_get_text (GTK_ENTRY (entry));
398    gtk_clist_get_text (GTK_CLIST (clist), row, 0, &text);
399    if (strcmp (text, new_text)) {
400       gtk_clist_set_text (GTK_CLIST (clist), row, 0, new_text);
401       update_proplist (clist, clist);
402    }
403 }
404 
405 static void
update_path(proplist_t key,gpointer ptr,proplist_t value,const char * path)406 update_path (proplist_t key, gpointer ptr, proplist_t value,
407 	     const char *path)
408 {
409    if (WMIsPLArray (value))
410       init_dir_list (GTK_CLIST (ptr), value);
411 }
412