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