1 /* Time-stamp: <2007-06-25 00:53:20 jcs>
2 |
3 |  Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net>
4 |  Part of the gtkpod project.
5 |
6 |  URL: http://www.gtkpod.org/
7 |  URL: http://gtkpod.sourceforge.net/
8 |
9 |  This program is free software; you can redistribute it and/or modify
10 |  it under the terms of the GNU General Public License as published by
11 |  the Free Software Foundation; either version 2 of the License, or
12 |  (at your option) any later version.
13 |
14 |  This program is distributed in the hope that it will be useful,
15 |  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 |  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 |  GNU General Public License for more details.
18 |
19 |  You should have received a copy of the GNU General Public License
20 |  along with this program; if not, write to the Free Software
21 |  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 |
23 |  iTunes and iPod are trademarks of Apple
24 |
25 |  This product is not supported/written/published by Apple!
26 |
27 |  $Id$
28 */
29 
30 #ifdef HAVE_CONFIG_H
31 #  include <config.h>
32 #endif
33 
34 #include <stdlib.h>
35 #include "charset.h"
36 #include "fileselection.h"
37 #include "info.h"
38 #include "misc.h"
39 #include "misc_track.h"
40 #include "prefs.h"
41 #include "sort_window.h"
42 
43 
44 #define DEBUG_MISC 0
45 
46 /* Concats @base_dir and @rel_dir if and only if @rel_dir is not
47  * absolute (does not start with '~' or '/'). Otherwise simply return
48  * a copy of @rel_dir. Must free return value after use */
concat_dir_if_relative(G_CONST_RETURN gchar * base_dir,G_CONST_RETURN gchar * rel_dir)49 gchar *concat_dir_if_relative (G_CONST_RETURN gchar *base_dir,
50 			       G_CONST_RETURN gchar *rel_dir)
51 {
52     /* sanity */
53     if (!rel_dir || !*rel_dir)
54 	return g_build_filename (base_dir, rel_dir, NULL);
55 				 /* this constellation is nonsense... */
56     if ((*rel_dir == '/') || (*rel_dir == '~'))
57 	return g_strdup (rel_dir);             /* rel_dir is absolute */
58 					       /* make absolute path */
59     return g_build_filename (base_dir, rel_dir, NULL);
60 }
61 
62 
63 /*------------------------------------------------------------------*\
64  *                                                                  *
65  *             Ask for User Input (String, SortTab Nr.)             *
66  *                                                                  *
67 \*------------------------------------------------------------------*/
68 
69 
70 /* Retrieves a string (and option) from the user using a dialog.
71    @title: title of the dialogue (may be NULL)
72    @message: text (question) to be displayed (may be NULL)
73    @dflt: default string to be returned (may be NULL)
74    @opt_msg: message for the option checkbox (or NULL)
75    @opt_state: original state of the checkbox. Will be updated
76    return value: the string entered by the user or NULL if the dialog
77    was cancelled. */
get_user_string(gchar * title,gchar * message,gchar * dflt,gchar * opt_msg,gboolean * opt_state,const gchar * accept_button)78 gchar *get_user_string (gchar *title, gchar *message, gchar *dflt,
79 			gchar *opt_msg, gboolean *opt_state, const gchar *accept_button)
80 {
81 	GladeXML *xml = gtkpod_xml_new (xml_file, "input_box");
82     GtkWidget *dialog = gtkpod_xml_get_widget (xml, "input_box");
83 	GtkWidget *label = gtkpod_xml_get_widget (xml, "input_box_label");
84     GtkWidget *entry = gtkpod_xml_get_widget (xml, "input_box_entry");
85 	GtkWidget *checkb = gtkpod_xml_get_widget (xml, "input_box_checkbox");
86     gint response;
87     gchar *result = NULL;
88 	gchar *temp;
89 
90     gtk_dialog_add_buttons (GTK_DIALOG (dialog),
91 								GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
92 								accept_button ? accept_button : GTK_STOCK_OK, GTK_RESPONSE_OK,
93 								NULL);
94 
95     temp = g_markup_printf_escaped ("<span weight='bold' size='larger'>%s</span>\n\n%s", title, message);
96 	gtk_label_set_markup (GTK_LABEL (label), temp);
97 	g_free (temp);
98 
99     if (dflt)
100     {
101 		gtk_entry_set_text (GTK_ENTRY (entry), dflt);
102 		gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
103     }
104 
105     /* Pressing enter should activate the default response (default
106        response set above */
107     gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
108 
109     /* create option checkbox */
110     if (opt_msg && opt_state)
111     {
112 		gtk_widget_show (checkb);
113 		gtk_button_set_label (GTK_BUTTON (checkb), opt_msg);
114 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkb), *opt_state);
115     }
116 
117 	response = gtk_dialog_run (GTK_DIALOG (dialog));
118 
119     if (response == GTK_RESPONSE_OK)
120     {
121 		result = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
122 
123 		/* get state of checkbox only if opt_msg was non NULL */
124 		if (opt_msg && checkb)
125 		{
126 			*opt_state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkb));
127 		}
128     }
129 
130     gtk_widget_destroy (dialog);
131 	g_object_unref (xml);
132     return result;
133 }
134 
135 
136 
137 /* Let the user select a sort tab number */
138 /* @text: text to be displayed */
139 /* return value: -1: user selected cancel
140    0...prefs_get_sort_tab_number()-1: selected tab */
get_sort_tab_number(gchar * text)141 gint get_sort_tab_number (gchar *text)
142 {
143     static gint last_nr = 1;
144     GtkWidget *mdialog;
145     GtkDialog *dialog;
146     GtkWidget *combo;
147     gint result;
148     gint i, nr, stn;
149     GList *list=NULL, *lnk;
150     gchar buf[20], *bufp;
151 
152     mdialog = gtk_message_dialog_new (
153 	GTK_WINDOW (gtkpod_window),
154 	GTK_DIALOG_DESTROY_WITH_PARENT,
155 	GTK_MESSAGE_QUESTION,
156 	GTK_BUTTONS_OK_CANCEL,
157 	"%s", text);
158 
159     dialog = GTK_DIALOG (mdialog);
160 
161     combo = gtk_combo_new ();
162     gtk_widget_show (combo);
163     gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), combo);
164 
165     stn = prefs_get_int("sort_tab_num");
166     /* Create list */
167     for (i=1; i<=stn; ++i)
168     {
169 	bufp = g_strdup_printf ("%d", i);
170 	list = g_list_append (list, bufp);
171     }
172 
173     /* set pull down items */
174     gtk_combo_set_popdown_strings (GTK_COMBO (combo), list);
175     /* set standard entry */
176     if (last_nr > stn) last_nr = 1;  /* maybe the stn has become
177 					smaller... */
178     snprintf (buf, 20, "%d", last_nr);
179     gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (combo)->entry), buf);
180 
181     result = gtk_dialog_run (GTK_DIALOG (mdialog));
182 
183     /* free the list */
184     for (lnk = list; lnk; lnk = lnk->next)
185     {
186 	C_FREE (lnk->data);
187     }
188     g_list_free (list);
189     list = NULL;
190 
191     if (result == GTK_RESPONSE_CANCEL)
192     {
193 	nr = -1;  /* no selection */
194     }
195     else
196     {
197 	bufp = gtk_editable_get_chars (GTK_EDITABLE (GTK_COMBO (combo)->entry),
198 				      0, -1);
199 	nr = atoi (bufp)-1;
200 	last_nr = nr+1;
201 	C_FREE (bufp);
202     }
203 
204     gtk_widget_destroy (mdialog);
205 
206     return nr;
207 }
208 
209 
210 
211 
212 /*------------------------------------------------------------------*\
213  *                                                                  *
214  *             Functions for blocking widgets (block input)         *
215  *                                                                  *
216 \*------------------------------------------------------------------*/
217 
218 /* --------------------------------------------------------------*/
219 /* are widgets blocked at the moment? */
220 gboolean widgets_blocked = FALSE;
221 struct blocked_widget { /* struct to be kept in blocked_widgets */
222     GtkWidget *widget;   /* widget that has been turned insensitive */
223     gboolean  sensitive; /* state of the widget before */
224 };
225 /* --------------------------------------------------------------*/
226 
227 
228 enum {
229     BR_BLOCK,
230     BR_RELEASE,
231     BR_UPDATE
232 };
233 
234 /* function to add one widget to the blocked_widgets list */
add_blocked_widget(GList * blocked_widgets,gchar * name)235 static GList *add_blocked_widget (GList *blocked_widgets, gchar *name)
236 {
237     GtkWidget *w;
238     struct blocked_widget *bw;
239 
240     if((w = gtkpod_xml_get_widget (main_window_xml,  name)))
241     {
242 	bw = g_malloc0 (sizeof (struct blocked_widget));
243 	bw->widget = w;
244 	/* we don't have to set the sensitive flag right now. It's
245 	 * done in "block_widgets ()" */
246 	blocked_widgets = g_list_append (blocked_widgets, bw);
247     }
248     return blocked_widgets;
249 }
250 
251 /* called by block_widgets() and release_widgets() */
252 /* "block": TRUE = block, FALSE = release */
block_release_widgets(gint action,GtkWidget * w,gboolean sens)253 static void block_release_widgets (gint action, GtkWidget *w, gboolean sens)
254 {
255     /* list with the widgets that are turned insensitive during
256        import/export...*/
257     static GList *bws = NULL;
258     static gint count = 0; /* how many times are the widgets blocked? */
259     GList *l;
260     struct blocked_widget *bw;
261 
262     /* Create a list of widgets that are to be turned insensitive when
263      * importing/exporting, adding tracks or directories etc. */
264     if (bws == NULL)
265     {
266 	bws = add_blocked_widget (bws, "menubar");
267 	bws = add_blocked_widget (bws, "load_ipods_button");
268 	bws = add_blocked_widget (bws, "save_changes_button");
269 	bws = add_blocked_widget (bws, "add_files_button");
270 	bws = add_blocked_widget (bws, "add_dirs_button");
271 	bws = add_blocked_widget (bws, "add_PL_button");
272 	bws = add_blocked_widget (bws, "new_PL_button");
273 	widgets_blocked = FALSE;
274     }
275 
276     switch (action)
277     {
278     case BR_BLOCK:
279 	/* we must block the widgets */
280 	++count;  /* increase number of locks */
281 	if (!widgets_blocked)
282 	{ /* only block widgets, if they are not already blocked */
283 	    for (l = bws; l; l = l->next)
284 	    {
285 			bw = (struct blocked_widget *)l->data;
286 			/* remember the state the widget was in before */
287 			bw->sensitive = GTK_WIDGET_SENSITIVE (bw->widget);
288 			gtk_widget_set_sensitive (bw->widget, FALSE);
289 	    }
290 	    sort_window_block ();
291 	    widgets_blocked = TRUE;
292 	}
293 	break;
294     case BR_RELEASE:
295 	/* release the widgets if --count == 0 */
296 	if (widgets_blocked)
297 	{ /* only release widgets, if they are blocked */
298 	    --count;
299 	    if (count == 0)
300 	    {
301 			for (l = bws; l; l = l->next)
302 			{
303 				bw = (struct blocked_widget *)l->data;
304 				gtk_widget_set_sensitive (bw->widget, bw->sensitive);
305 			}
306 
307 			sort_window_release ();
308 			widgets_blocked = FALSE;
309 	    }
310 	}
311 	break;
312     case BR_UPDATE:
313 	if (widgets_blocked)
314 	{ /* only update widgets, if they are blocked */
315 	    for (l = bws; l; l = l->next)
316 	    { /* find the required widget */
317 		bw = (struct blocked_widget *)l->data;
318 		if (bw->widget == w)
319 		{ /* found -> set to new desired state */
320 		    bw->sensitive = sens;
321 		    break;
322 		}
323 	    }
324 	}
325 	break;
326     }
327 }
328 
329 
330 /* Block widgets (turn insensitive) listed in "bws" */
block_widgets(void)331 void block_widgets (void)
332 {
333     block_release_widgets (BR_BLOCK, NULL, FALSE);
334 }
335 
336 /* Release widgets (i.e. return them to their state before
337    "block_widgets() was called */
release_widgets(void)338 void release_widgets (void)
339 {
340     block_release_widgets (BR_RELEASE, NULL, FALSE);
341 }
342 
update_blocked_widget(GtkWidget * w,gboolean sens)343 void update_blocked_widget (GtkWidget *w, gboolean sens)
344 {
345     block_release_widgets (BR_UPDATE, w, sens);
346 }
347