1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3 * arch-tag: Implementation of RhythmDB query creation dialog
5 * Copyright (C) 2003, 2004 Colin Walters <walters@gnome.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program 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
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include <glib/gi18n.h>
31 #include "rb-query-creator.h"
32 #include "rb-query-creator-private.h"
33 #include "rb-dialog.h"
35 #include "rb-preferences.h"
36 #include "rb-glade-helpers.h"
39 static void rb_query_creator_class_init (RBQueryCreatorClass
*klass
);
40 static GObject
*rb_query_creator_constructor (GType type
, guint n_construct_properties
,
41 GObjectConstructParam
*construct_properties
);
42 static void rb_query_creator_dispose (GObject
*object
);
43 static void rb_query_creator_set_property (GObject
*object
,
47 static void rb_query_creator_get_property (GObject
*object
,
51 static void select_criteria_from_value (RBQueryCreator
*creator
,
52 GtkWidget
*option_menu
,
53 RhythmDBPropType prop
,
54 RhythmDBQueryType qtype
);
55 static GtkWidget
* create_property_option_menu (RBQueryCreator
*creator
,
56 const RBQueryCreatorPropertyOption
*options
,
58 static GtkWidget
* create_criteria_option_menu (const RBQueryCreatorCriteriaOption
*options
,
60 static void setup_sort_option_menu (RBQueryCreator
*creator
,
61 GtkWidget
*option_menu
,
62 const RBQueryCreatorSortOption
*options
,
65 static GtkWidget
* append_row (RBQueryCreator
*creator
);
66 static void add_button_click_cb (GtkWidget
*button
, RBQueryCreator
*creator
);
67 static void remove_button_click_cb (GtkWidget
*button
, RBQueryCreator
*creator
);
68 static void limit_toggled_cb (GtkWidget
*limit
, RBQueryCreator
*creator
);
70 static int get_property_index_from_proptype (const RBQueryCreatorPropertyOption
*options
,
71 int length
, RhythmDBPropType prop
);
72 static void sort_option_menu_changed (GtkOptionMenu
*propmenu
, RBQueryCreator
*creator
);
80 GtkSizeGroup
*property_size_group
;
81 GtkSizeGroup
*criteria_size_group
;
82 GtkSizeGroup
*entry_size_group
;
83 GtkSizeGroup
*button_size_group
;
89 GtkWidget
*disjunction_check
;
90 GtkWidget
*limit_check
;
91 GtkWidget
*limit_entry
;
92 GtkWidget
*limit_option
;
93 GtkWidget
*sort_label
;
96 } RBQueryCreatorPrivate
;
98 G_DEFINE_TYPE (RBQueryCreator
, rb_query_creator
, GTK_TYPE_DIALOG
)
99 #define QUERY_CREATOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), rb_query_creator_get_type(), RBQueryCreatorPrivate))
109 rb_query_creator_class_init (RBQueryCreatorClass
*klass
)
111 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
113 object_class
->dispose
= rb_query_creator_dispose
;
114 object_class
->constructor
= rb_query_creator_constructor
;
115 object_class
->set_property
= rb_query_creator_set_property
;
116 object_class
->get_property
= rb_query_creator_get_property
;
118 g_object_class_install_property (object_class
,
120 g_param_spec_object ("db",
124 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
126 g_object_class_install_property (object_class
,
128 g_param_spec_boolean ("creating",
130 "Whether or not we're creating a new playlist",
132 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
134 g_type_class_add_private (klass
, sizeof (RBQueryCreatorPrivate
));
138 rb_query_creator_init (RBQueryCreator
*creator
)
144 rb_query_creator_constructor (GType type
,
145 guint n_construct_properties
,
146 GObjectConstructParam
*construct_properties
)
148 RBQueryCreatorPrivate
*priv
;
149 RBQueryCreator
*creator
;
153 creator
= RB_QUERY_CREATOR (G_OBJECT_CLASS (rb_query_creator_parent_class
)
154 ->constructor (type
, n_construct_properties
, construct_properties
));
155 priv
= QUERY_CREATOR_GET_PRIVATE (creator
);
157 if (priv
->creating
) {
158 gtk_dialog_add_button (GTK_DIALOG (creator
),
161 gtk_dialog_add_button (GTK_DIALOG (creator
),
165 gtk_dialog_add_button (GTK_DIALOG (creator
),
169 gtk_dialog_set_default_response (GTK_DIALOG (creator
),
172 priv
->property_size_group
= gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL
);
173 priv
->criteria_size_group
= gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL
);
174 priv
->entry_size_group
= gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL
);
175 priv
->button_size_group
= gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL
);
178 gtk_window_set_title (GTK_WINDOW (creator
), _("Create Automatic Playlist"));
180 gtk_window_set_title (GTK_WINDOW (creator
), _("Edit Automatic Playlist"));
182 gtk_container_set_border_width (GTK_CONTAINER (creator
), 5);
183 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (creator
)->vbox
), 2);
184 gtk_dialog_set_has_separator (GTK_DIALOG (creator
), FALSE
);
186 xml
= rb_glade_xml_new ("create-playlist.glade",
190 priv
->disjunction_check
= GTK_WIDGET (glade_xml_get_widget (xml
, "disjunctionCheck"));
191 priv
->limit_check
= GTK_WIDGET (glade_xml_get_widget (xml
, "limitCheck"));
192 priv
->limit_entry
= GTK_WIDGET (glade_xml_get_widget (xml
, "limitEntry"));
193 priv
->limit_option
= GTK_WIDGET (glade_xml_get_widget (xml
, "limitOption"));
194 priv
->addbutton
= GTK_WIDGET (glade_xml_get_widget (xml
, "addButton"));
195 priv
->sort_label
= GTK_WIDGET (glade_xml_get_widget (xml
, "sortLabel"));
196 priv
->sort_menu
= GTK_WIDGET (glade_xml_get_widget (xml
, "sortMenu"));
197 priv
->sort_desc
= GTK_WIDGET (glade_xml_get_widget (xml
, "sortDesc"));
199 g_signal_connect_object (G_OBJECT (priv
->limit_check
), "toggled", G_CALLBACK (limit_toggled_cb
),
201 limit_toggled_cb (priv
->limit_check
, creator
);
203 gtk_size_group_add_widget (priv
->button_size_group
, priv
->addbutton
);
204 g_signal_connect_object (G_OBJECT (priv
->addbutton
), "clicked", G_CALLBACK (add_button_click_cb
),
207 setup_sort_option_menu (creator
, priv
->sort_menu
, sort_options
, num_sort_options
);
209 priv
->vbox
= GTK_BOX (glade_xml_get_widget (xml
, "sub_vbox"));
211 append_row (creator
);
213 mainbox
= glade_xml_get_widget (xml
, "main_vbox");
214 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (creator
)->vbox
), mainbox
, FALSE
, FALSE
, 0);
215 gtk_widget_show_all (GTK_WIDGET (creator
));
217 g_object_unref (xml
);
219 return G_OBJECT (creator
);
223 rb_query_creator_dispose (GObject
*object
)
225 RBQueryCreatorPrivate
*priv
;
227 g_return_if_fail (RB_IS_QUERY_CREATOR (object
));
229 priv
= QUERY_CREATOR_GET_PRIVATE (object
);
230 g_return_if_fail (priv
!= NULL
);
232 if (priv
->property_size_group
!= NULL
)
233 g_object_unref (G_OBJECT (priv
->property_size_group
));
234 priv
->property_size_group
= NULL
;
235 if (priv
->criteria_size_group
!= NULL
)
236 g_object_unref (G_OBJECT (priv
->criteria_size_group
));
237 priv
->criteria_size_group
= NULL
;
238 if (priv
->entry_size_group
!= NULL
)
239 g_object_unref (G_OBJECT (priv
->entry_size_group
));
240 priv
->entry_size_group
= NULL
;
241 if (priv
->button_size_group
!= NULL
)
242 g_object_unref (G_OBJECT (priv
->button_size_group
));
243 priv
->button_size_group
= NULL
;
246 g_list_free (priv
->rows
);
249 G_OBJECT_CLASS (rb_query_creator_parent_class
)->dispose (object
);
253 rb_query_creator_set_property (GObject
*object
,
258 RBQueryCreator
*creator
= RB_QUERY_CREATOR (object
);
259 RBQueryCreatorPrivate
*priv
= QUERY_CREATOR_GET_PRIVATE (creator
);
264 priv
->db
= g_value_get_object (value
);
267 priv
->creating
= g_value_get_boolean (value
);
270 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
276 rb_query_creator_get_property (GObject
*object
,
281 RBQueryCreator
*creator
= RB_QUERY_CREATOR (object
);
282 RBQueryCreatorPrivate
*priv
= QUERY_CREATOR_GET_PRIVATE (creator
);
287 g_value_set_object (value
, priv
->db
);
290 g_value_set_boolean (value
, priv
->creating
);
293 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
299 rb_query_creator_new (RhythmDB
*db
)
301 return g_object_new (RB_TYPE_QUERY_CREATOR
, "db", db
, NULL
);
305 rb_query_creator_load_query (RBQueryCreator
*creator
,
307 RhythmDBQueryModelLimitType limit_type
,
308 GValueArray
*limit_value
)
310 RBQueryCreatorPrivate
*priv
= QUERY_CREATOR_GET_PRIVATE (creator
);
313 gboolean disjunction
= FALSE
;
314 RhythmDBQueryData
*qdata
;
317 g_return_val_if_fail (query
->len
== 2, FALSE
);
319 qdata
= g_ptr_array_index (query
, 1);
320 g_return_val_if_fail (qdata
->type
== RHYTHMDB_QUERY_SUBQUERY
, FALSE
);
322 subquery
= qdata
->subquery
;
324 if (subquery
->len
> 0)
325 for (i
= 0; i
< subquery
->len
; i
++) {
326 RhythmDBQueryData
*data
= g_ptr_array_index (subquery
, i
);
327 if (data
->type
!= RHYTHMDB_QUERY_DISJUNCTION
)
328 append_row (creator
);
333 for (i
= 0; i
< subquery
->len
; i
++) {
334 RhythmDBQueryData
*data
= g_ptr_array_index (subquery
, i
);
335 GtkOptionMenu
*propmenu
;
336 GtkWidget
*criteria_menu
;
338 const RBQueryCreatorPropertyType
*property_type
;
340 if (data
->type
== RHYTHMDB_QUERY_DISJUNCTION
) {
345 propmenu
= GTK_OPTION_MENU (get_box_widget_at_pos (GTK_BOX (rows
->data
), 0));
346 index
= get_property_index_from_proptype (property_options
, num_property_options
, data
->propid
);
347 gtk_option_menu_set_history (propmenu
, index
);
349 criteria_menu
= get_box_widget_at_pos (GTK_BOX (rows
->data
), 1);
350 select_criteria_from_value (creator
, criteria_menu
, data
->propid
, data
->type
);
352 property_type
= property_options
[index
].property_type
;
353 g_assert (property_type
->criteria_set_widget_data
!= NULL
);
354 property_type
->criteria_set_widget_data (get_box_widget_at_pos (GTK_BOX (rows
->data
), 2),
360 /* setup the limits */
364 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv
->disjunction_check
),
366 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv
->limit_check
),
367 limit_type
!= RHYTHMDB_QUERY_MODEL_LIMIT_NONE
);
369 switch (limit_type
) {
370 case RHYTHMDB_QUERY_MODEL_LIMIT_NONE
:
374 case RHYTHMDB_QUERY_MODEL_LIMIT_COUNT
:
375 gtk_option_menu_set_history (GTK_OPTION_MENU (priv
->limit_option
), 0);
376 limit
= g_value_get_ulong (g_value_array_get_nth (limit_value
, 0));
379 case RHYTHMDB_QUERY_MODEL_LIMIT_TIME
:
380 gtk_option_menu_set_history (GTK_OPTION_MENU (priv
->limit_option
), 3);
381 /* convert to minutes */
382 limit
= g_value_get_ulong (g_value_array_get_nth (limit_value
, 0)) / 60;
385 case RHYTHMDB_QUERY_MODEL_LIMIT_SIZE
:
386 limit
= g_value_get_uint64 (g_value_array_get_nth (limit_value
, 0));
388 if (limit
% 1000 == 0) {
389 gtk_option_menu_set_history (GTK_OPTION_MENU (priv
->limit_option
), 2);
392 gtk_option_menu_set_history (GTK_OPTION_MENU (priv
->limit_option
), 1);
397 g_assert_not_reached ();
400 gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv
->limit_entry
), limit
);
407 rb_query_creator_set_sorting (RBQueryCreator
*creator
,
408 const char *sort_column
,
411 RBQueryCreatorPrivate
*priv
= QUERY_CREATOR_GET_PRIVATE (creator
);
414 if (!sort_column
|| ! *sort_column
) {
415 g_warning("No playlist sorting order");
417 sort_column
= sort_options
[DEFAULT_SORTING_COLUMN
].sort_key
;
418 sort_direction
= DEFAULT_SORTING_ORDER
;
421 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv
->sort_desc
), (sort_direction
== GTK_SORT_DESCENDING
));
423 for (i
= 0; i
< num_sort_options
; i
++)
424 if (strcmp (sort_options
[i
].sort_key
, sort_column
) == 0)
427 /* check that it is a valid sort option */
428 g_return_val_if_fail (i
< num_property_options
, FALSE
);
430 gtk_option_menu_set_history (GTK_OPTION_MENU (priv
->sort_menu
), i
);
431 sort_option_menu_changed (GTK_OPTION_MENU (priv
->sort_menu
), creator
); /* force the checkbox to change label */
437 rb_query_creator_new_from_query (RhythmDB
*db
,
439 RhythmDBQueryModelLimitType limit_type
,
440 GValueArray
*limit_value
,
441 const char *sort_column
,
444 RBQueryCreator
*creator
= g_object_new (RB_TYPE_QUERY_CREATOR
, "db", db
,
445 "creating", FALSE
, NULL
);
449 if ( !rb_query_creator_load_query (creator
, query
, limit_type
, limit_value
)
450 | !rb_query_creator_set_sorting (creator
, sort_column
, sort_direction
)) {
451 gtk_widget_destroy (GTK_WIDGET (creator
));
455 return GTK_WIDGET (creator
);
459 get_box_widget_at_pos (GtkBox
*box
, guint pos
)
461 GtkWidget
*ret
= NULL
;
462 GList
*children
= gtk_container_get_children (GTK_CONTAINER (box
));
464 for (tem
= children
; tem
; tem
= tem
->next
) {
465 GValue thispos
= { 0, };
466 g_value_init (&thispos
, G_TYPE_INT
);
467 gtk_container_child_get_property (GTK_CONTAINER (box
),
468 GTK_WIDGET (tem
->data
),
469 "position", &thispos
);
470 if (g_value_get_int (&thispos
) == pos
) {
475 g_list_free (children
);
476 return GTK_WIDGET (ret
);
480 get_entry_for_property (RBQueryCreator
*creator
,
481 RhythmDBPropType prop
,
484 const RBQueryCreatorPropertyType
*property_type
;
485 int index
= get_property_index_from_proptype (property_options
, num_property_options
, prop
);
487 property_type
= property_options
[index
].property_type
;
488 g_assert (property_type
->criteria_create_widget
!= NULL
);
491 return property_type
->criteria_create_widget (constrain
);
495 rb_query_creator_get_query (RBQueryCreator
*creator
)
497 RBQueryCreatorPrivate
*priv
;
499 GPtrArray
*sub_query
;
501 gboolean disjunction
;
503 g_return_val_if_fail (RB_IS_QUERY_CREATOR (creator
), NULL
);
505 priv
= QUERY_CREATOR_GET_PRIVATE (creator
);
507 disjunction
= gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv
->disjunction_check
));
508 sub_query
= g_ptr_array_new ();
511 for (row
= rows
; row
; row
= row
->next
) {
512 GtkOptionMenu
*propmenu
= GTK_OPTION_MENU (get_box_widget_at_pos (GTK_BOX (row
->data
),
514 GtkOptionMenu
*criteria_menu
= GTK_OPTION_MENU (get_box_widget_at_pos (GTK_BOX (row
->data
),
516 guint prop_position
= gtk_option_menu_get_history (propmenu
);
517 const RBQueryCreatorPropertyOption
*prop_option
= &property_options
[prop_position
];
518 const RBQueryCreatorCriteriaOption
*criteria_options
= prop_option
->property_type
->criteria_options
;
519 const RBQueryCreatorCriteriaOption
*criteria_option
= &criteria_options
[gtk_option_menu_get_history (criteria_menu
)];
521 g_assert (prop_option
->property_type
->criteria_get_widget_data
!= NULL
);
523 RhythmDBQueryData
*data
= g_new0 (RhythmDBQueryData
, 1);
524 GValue
*val
= g_new0 (GValue
, 1);
526 data
->type
= criteria_option
->val
;
527 data
->propid
= criteria_option
->strict
? prop_option
->strict_val
: prop_option
->fuzzy_val
;
529 prop_option
->property_type
->criteria_get_widget_data (get_box_widget_at_pos (GTK_BOX (row
->data
), 2), val
);
532 g_ptr_array_add (sub_query
, data
);
535 if (disjunction
&& row
->next
)
536 rhythmdb_query_append (priv
->db
,
538 RHYTHMDB_QUERY_DISJUNCTION
,
541 query
= rhythmdb_query_parse (priv
->db
,
543 RHYTHMDB_QUERY_PROP_EQUALS
,
545 RHYTHMDB_ENTRY_TYPE_SONG
,
546 /* the constructed query */
547 RHYTHMDB_QUERY_SUBQUERY
,
554 rb_query_creator_get_limit (RBQueryCreator
*creator
,
555 RhythmDBQueryModelLimitType
*type
,
558 RBQueryCreatorPrivate
*priv
;
560 g_return_if_fail (RB_IS_QUERY_CREATOR (creator
));
562 priv
= QUERY_CREATOR_GET_PRIVATE (creator
);
564 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv
->limit_check
))) {
567 l
= gtk_spin_button_get_value(GTK_SPIN_BUTTON (priv
->limit_entry
));
568 *limit
= g_value_array_new (0);
570 switch (gtk_option_menu_get_history (GTK_OPTION_MENU (priv
->limit_option
))) {
572 *type
= RHYTHMDB_QUERY_MODEL_LIMIT_COUNT
;
573 rb_value_array_append_data (*limit
, G_TYPE_ULONG
, (gulong
)l
);
576 *type
= RHYTHMDB_QUERY_MODEL_LIMIT_SIZE
;
577 rb_value_array_append_data (*limit
, G_TYPE_UINT64
, l
);
581 *type
= RHYTHMDB_QUERY_MODEL_LIMIT_SIZE
;
582 rb_value_array_append_data (*limit
, G_TYPE_ULONG
, (gulong
)l
);
586 *type
= RHYTHMDB_QUERY_MODEL_LIMIT_TIME
;
587 rb_value_array_append_data (*limit
, G_TYPE_ULONG
, (gulong
)l
* 60);
591 g_assert_not_reached ();
594 *type
= RHYTHMDB_QUERY_MODEL_LIMIT_NONE
;
600 rb_query_creator_get_sort_order (RBQueryCreator
*creator
,
601 const char **sort_column
,
602 gint
*sort_direction
)
604 RBQueryCreatorPrivate
*priv
;
606 g_return_if_fail (RB_IS_QUERY_CREATOR (creator
));
608 priv
= QUERY_CREATOR_GET_PRIVATE (creator
);
610 if (sort_direction
!= NULL
) {
611 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv
->sort_desc
)))
612 *sort_direction
= GTK_SORT_DESCENDING
;
614 *sort_direction
= GTK_SORT_ASCENDING
;
617 if (sort_column
!= NULL
) {
619 i
= gtk_option_menu_get_history (GTK_OPTION_MENU (priv
->sort_menu
));
620 *sort_column
= sort_options
[i
].sort_key
;
625 limit_toggled_cb (GtkWidget
*limit
,
626 RBQueryCreator
*creator
)
628 RBQueryCreatorPrivate
*priv
= QUERY_CREATOR_GET_PRIVATE (creator
);
629 gboolean active
= gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (limit
));
631 gtk_widget_set_sensitive (priv
->limit_entry
, active
);
632 gtk_widget_set_sensitive (priv
->limit_option
, active
);
633 gtk_widget_set_sensitive (priv
->sort_menu
, active
);
634 gtk_widget_set_sensitive (priv
->sort_label
, active
);
635 gtk_widget_set_sensitive (priv
->sort_desc
, active
);
639 lookup_row_by_widget (RBQueryCreator
*creator
,
642 RBQueryCreatorPrivate
*priv
= QUERY_CREATOR_GET_PRIVATE (creator
);
643 GList
*rows
= priv
->rows
;
645 GtkWidget
*ret
= NULL
;
648 for (row
= rows
, i
= 0; row
; row
= row
->next
, i
++) {
649 GList
*columns
= gtk_container_get_children (GTK_CONTAINER (row
->data
));
650 gboolean found
= g_list_find (columns
, widget
) != NULL
;
651 g_list_free (columns
);
661 remove_button_click_cb (GtkWidget
*button
,
662 RBQueryCreator
*creator
)
664 RBQueryCreatorPrivate
*priv
= QUERY_CREATOR_GET_PRIVATE (creator
);
667 row
= lookup_row_by_widget (creator
, button
);
669 gtk_container_remove (GTK_CONTAINER (priv
->vbox
),
671 priv
->rows
= g_list_remove (priv
->rows
, row
);
675 add_button_click_cb (GtkWidget
*button
,
676 RBQueryCreator
*creator
)
678 append_row (creator
);
682 append_row (RBQueryCreator
*creator
)
684 RBQueryCreatorPrivate
*priv
= QUERY_CREATOR_GET_PRIVATE (creator
);
688 GtkWidget
*remove_button
;
695 len
= g_list_length (rows
);
697 hbox
= GTK_BOX (gtk_hbox_new (FALSE
, 5));
698 gtk_box_pack_start_defaults (GTK_BOX (priv
->vbox
), GTK_WIDGET (hbox
));
699 priv
->rows
= g_list_prepend (priv
->rows
, hbox
);
700 gtk_box_reorder_child (priv
->vbox
, GTK_WIDGET (hbox
), -1);
702 /* This is the main (leftmost) GtkOptionMenu, for types. */
703 option
= create_property_option_menu (creator
, property_options
, num_property_options
);
704 gtk_size_group_add_widget (priv
->property_size_group
, option
);
705 gtk_box_pack_start_defaults (hbox
, GTK_WIDGET (option
));
706 gtk_option_menu_set_history (GTK_OPTION_MENU (option
), 0);
707 criteria
= create_criteria_option_menu (property_options
[0].property_type
->criteria_options
,
708 property_options
[0].property_type
->num_criteria_options
);
709 gtk_size_group_add_widget (priv
->criteria_size_group
, criteria
);
710 gtk_box_pack_start_defaults (hbox
, GTK_WIDGET (criteria
));
712 entry
= get_entry_for_property (creator
, property_options
[0].strict_val
, &constrain
);
714 gtk_size_group_add_widget (priv
->entry_size_group
, entry
);
715 gtk_box_pack_start_defaults (hbox
, GTK_WIDGET (entry
));
717 remove_button
= gtk_button_new_from_stock (GTK_STOCK_REMOVE
);
718 g_signal_connect_object (G_OBJECT (remove_button
), "clicked", G_CALLBACK (remove_button_click_cb
),
720 gtk_size_group_add_widget (priv
->button_size_group
, remove_button
);
721 gtk_box_pack_start_defaults (hbox
, GTK_WIDGET (remove_button
));
723 gtk_widget_show_all (GTK_WIDGET (priv
->vbox
));
724 return GTK_WIDGET (hbox
);
728 get_property_index_from_proptype (const RBQueryCreatorPropertyOption
*options
,
730 RhythmDBPropType prop
)
734 for (i
= 0; i
< length
; i
++)
735 if (prop
== options
[i
].strict_val
|| prop
== options
[i
].fuzzy_val
)
738 g_assert_not_reached ();
742 select_criteria_from_value (RBQueryCreator
*creator
,
743 GtkWidget
*option_menu
,
744 RhythmDBPropType prop
,
745 RhythmDBQueryType qtype
)
748 const RBQueryCreatorCriteriaOption
*options
;
751 i
= get_property_index_from_proptype (property_options
, num_property_options
, prop
);
752 length
= property_options
[i
].property_type
->num_criteria_options
;
753 options
= property_options
[i
].property_type
->criteria_options
;
755 for (i
= 0; i
< length
; i
++) {
756 if (qtype
== options
[i
].val
) {
757 gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu
), i
);
761 g_assert_not_reached ();
765 property_option_menu_changed (GtkOptionMenu
*propmenu
,
766 RBQueryCreator
*creator
)
768 RBQueryCreatorPrivate
*priv
= QUERY_CREATOR_GET_PRIVATE (creator
);
772 const RBQueryCreatorPropertyOption
*prop_option
;
773 const RBQueryCreatorCriteriaOption
*criteria_options
;
778 prop_option
= &property_options
[gtk_option_menu_get_history (propmenu
)];
779 old_value
= GPOINTER_TO_INT (g_object_get_data (G_OBJECT (propmenu
), "prop-menu old-value"));
781 /* don't recreate the criteria menu and entry if they will be the same*/
782 if (prop_option
->property_type
== property_options
[old_value
].property_type
)
785 g_object_set_data (G_OBJECT (propmenu
), "prop-menu old-value",
786 GINT_TO_POINTER (gtk_option_menu_get_history (propmenu
)));
788 row
= lookup_row_by_widget (creator
, GTK_WIDGET (propmenu
));
790 criteria
= get_box_widget_at_pos (GTK_BOX (row
), 1);
791 gtk_container_remove (GTK_CONTAINER (row
), criteria
);
793 criteria_options
= prop_option
->property_type
->criteria_options
;
794 length
= prop_option
->property_type
->num_criteria_options
;
796 criteria
= create_criteria_option_menu (criteria_options
, length
);
797 gtk_widget_show (criteria
);
798 gtk_size_group_add_widget (priv
->criteria_size_group
, criteria
);
799 gtk_box_pack_start_defaults (GTK_BOX (row
), GTK_WIDGET (criteria
));
800 gtk_box_reorder_child (GTK_BOX (row
), criteria
, 1);
802 entry
= get_box_widget_at_pos (GTK_BOX (row
), 2);
803 gtk_container_remove (GTK_CONTAINER (row
), entry
);
804 entry
= get_entry_for_property (creator
, prop_option
->strict_val
,
806 gtk_widget_show (entry
);
809 gtk_size_group_add_widget (priv
->entry_size_group
, entry
);
810 gtk_box_pack_start_defaults (GTK_BOX (row
), GTK_WIDGET (entry
));
811 gtk_box_reorder_child (GTK_BOX (row
), entry
, 2);
815 create_property_option_menu (RBQueryCreator
*creator
,
816 const RBQueryCreatorPropertyOption
*options
,
819 GtkWidget
*option_menu
;
821 GtkWidget
*menu_item
;
824 option_menu
= gtk_option_menu_new ();
825 menu
= gtk_menu_new ();
827 /* add the property options */
828 for (i
= 0; i
< length
; i
++) {
829 menu_item
= gtk_menu_item_new_with_label (_(options
[i
].name
));
830 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menu_item
);
831 gtk_widget_show (menu_item
);
834 gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu
), 0);
835 g_object_set_data (G_OBJECT (option_menu
), "prop-menu old-value", GINT_TO_POINTER (0));
837 gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu
), menu
);
838 gtk_widget_show (menu
);
840 g_signal_connect_object (G_OBJECT (option_menu
), "changed",
841 G_CALLBACK (property_option_menu_changed
), creator
, 0);
847 create_criteria_option_menu (const RBQueryCreatorCriteriaOption
*options
,
850 GtkWidget
*option_menu
;
852 GtkWidget
*menu_item
;
855 option_menu
= gtk_option_menu_new ();
856 menu
= gtk_menu_new ();
858 for (i
= 0; i
< length
; i
++) {
859 menu_item
= gtk_menu_item_new_with_label (_(options
[i
].name
));
860 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menu_item
);
861 gtk_widget_show (menu_item
);
864 gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu
), menu
);
865 gtk_widget_show (menu
);
871 sort_option_menu_changed (GtkOptionMenu
*propmenu
,
872 RBQueryCreator
*creator
)
874 RBQueryCreatorPrivate
*priv
= QUERY_CREATOR_GET_PRIVATE (creator
);
875 int index
= gtk_option_menu_get_history (propmenu
);
877 gtk_button_set_label (GTK_BUTTON (priv
->sort_desc
), _(sort_options
[index
].sort_descending_name
));
878 rb_debug("changing descending label to %s[%d]", sort_options
[index
].sort_descending_name
, index
);
882 setup_sort_option_menu (RBQueryCreator
*creator
,
883 GtkWidget
*option_menu
,
884 const RBQueryCreatorSortOption
*options
,
888 GtkWidget
*menu_item
;
891 menu
= gtk_menu_new ();
892 gtk_widget_show (menu
);
894 for (i
= 0; i
< length
; i
++) {
895 menu_item
= gtk_menu_item_new_with_label (_(options
[i
].name
));
896 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menu_item
);
897 gtk_widget_show (menu_item
);
900 g_signal_connect_object (G_OBJECT (option_menu
), "changed",
901 G_CALLBACK (sort_option_menu_changed
), creator
, 0);
903 gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu
), menu
);