00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00042 #include "select_handlers.h"
00043
00044 #include <string.h>
00045 #include <gtk/gtk.h>
00046
00047 #include "frontend.h"
00048 #include "question.h"
00049
00050 #include "fe_gtk.h"
00051 #include "fe_data.h"
00052 #include "descriptions.h"
00053 #include "choice_model.h"
00054 #include "ui.h"
00055
00061 static void set_value_from_combo(struct question * question,
00062 GtkComboBox * combo_box)
00063 {
00064 GtkTreeModel * model;
00065 GtkTreeIter iter;
00066 char * value;
00067
00068 if (gtk_combo_box_get_active_iter(combo_box, &iter)) {
00069 model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo_box));
00070 gtk_tree_model_get(model, &iter,
00071 CHOICE_MODEL_VALUE, &value,
00072 -1 );
00073 question_setvalue(question, value);
00074 g_free(value);
00075 } else {
00076 question_setvalue(question, "");
00077 }
00078 }
00079
00085 static void set_value_from_select(struct question * question,
00086 GtkTreeView * view)
00087 {
00088 GtkTreeSelection * selection;
00089 GtkTreeModel * model;
00090 GtkTreeIter iter;
00091 char * value;
00092
00093 selection = gtk_tree_view_get_selection(view);
00094 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
00095 gtk_tree_model_get(model, &iter,
00096 CHOICE_MODEL_VALUE, &value,
00097 -1 );
00098 question_setvalue(question, value);
00099 g_free(value);
00100 } else {
00101 question_setvalue(question, "");
00102 }
00103 }
00104
00112 static gboolean is_country(int index, const char * choice,
00113 const char * choice_translated)
00114 {
00115 return '-' == choice_translated[0] && '-' == choice_translated[1];
00116 }
00117
00125 static gboolean is_disk(int index, const char * choice,
00126 const char * choice_translated)
00127 {
00128 return NULL == strstr(choice_translated, " ");
00129 }
00130
00132 static const struct {
00134 const char * tag;
00136 parent_predicate parent_predicate;
00137 } special_questions[] = {
00138 { "countrychooser/country-name", is_country },
00139 { "partman/choose_partition", is_disk },
00140 { NULL, NULL }
00141 };
00142
00149 static parent_predicate get_special_predicate(const char * tag) {
00150 int i;
00151
00152 for (i = 0; NULL != special_questions[i].tag; i++) {
00153 if (0 == strcmp(tag, special_questions[i].tag)) {
00154 return special_questions[i].parent_predicate;
00155 }
00156 }
00157 return NULL;
00158 }
00159
00170 static int create_select_list(struct frontend * fe, struct question * question,
00171 GtkWidget * question_box, GtkTreeModel * model)
00172 {
00173 GtkTreePath * path = NULL;
00174 GtkWidget * view;
00175 GtkWidget * scroll;
00176 GtkWidget * frame;
00177 GtkCellRenderer * text_renderer;
00178 char * description;
00179
00180 model = fe_gtk_choice_model_create_full(
00181 fe, question, get_special_predicate(question->tag));
00182 if (NULL == model) {
00183 g_warning("create_model_from_choices failed.");
00184 return DC_NOTOK;
00185 }
00186
00187
00188
00189
00190 view = gtk_tree_view_new_with_model(model);
00191
00192 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view),
00193 FALSE );
00194 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(view),
00195 TRUE );
00196 gtk_tree_selection_set_mode(
00197 gtk_tree_view_get_selection(GTK_TREE_VIEW(view)),
00198 GTK_SELECTION_BROWSE);
00199
00200 description = q_get_description(question);
00201 text_renderer = gtk_cell_renderer_text_new();
00202 gtk_tree_view_insert_column_with_attributes(
00203 GTK_TREE_VIEW(view), -1 ,
00204 description , text_renderer,
00205 "text", CHOICE_MODEL_TRANSLATED_VALUE,
00206 NULL );
00207 g_free(description);
00208
00209 g_signal_connect_swapped(G_OBJECT(view), "row-activated",
00210 G_CALLBACK(fe_gtk_set_answer_ok), fe);
00211
00212 path = fe_gtk_choice_model_get_first_selected(model);
00213
00214 if (NULL == path) {
00215 path = gtk_tree_path_new_first();
00216 } else {
00217
00218 gtk_tree_view_expand_to_path(GTK_TREE_VIEW(view), path);
00219 }
00220
00221 gtk_tree_view_scroll_to_cell(
00222 GTK_TREE_VIEW(view), path,
00223 NULL ,
00224 TRUE ,
00225 0.5 ,
00226 0 );
00227 gtk_tree_view_set_cursor(GTK_TREE_VIEW(view), path,
00228 NULL ,
00229 FALSE );
00230 gtk_tree_path_free(path);
00231
00232 scroll = gtk_scrolled_window_new(NULL ,
00233 NULL );
00234 gtk_container_add(GTK_CONTAINER(scroll), view);
00235 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
00236 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
00237 frame = gtk_frame_new(NULL);
00238 gtk_container_add(GTK_CONTAINER(frame), scroll);
00239
00240 fe_gtk_add_common_layout(fe, question, question_box, frame);
00241
00242 gtk_widget_grab_focus(view);
00243
00244 fe_gtk_register_setter(fe, SETTER_FUNCTION(set_value_from_select),
00245 question, view);
00246
00247 return DC_OK;
00248 }
00249
00256 static void update_selection_for_toggle(GtkCellRendererToggle * cell,
00257 const gchar * path_string,
00258 GtkTreeModel * model)
00259 {
00260 GtkTreeIter iter;
00261 gboolean value;
00262
00263 if (gtk_tree_model_get_iter_from_string(model, &iter, path_string)) {
00264 gtk_tree_model_get(model, &iter,
00265 CHOICE_MODEL_SELECTED, &value,
00266 -1 );
00267 value ^= TRUE;
00268 fe_gtk_choice_model_set(model, &iter,
00269 CHOICE_MODEL_SELECTED, value,
00270 -1 );
00271 }
00272 }
00273
00282 static void set_value_from_multiselect(struct question * question,
00283 GtkTreeModel * model)
00284 {
00285 GtkTreeIter iter;
00286 gboolean valid;
00287 gboolean selected;
00288 gchar ** selected_values;
00289 guint selected_index;
00290 gchar * result;
00291
00292
00293 selected_values = g_malloc0(
00294 sizeof (char *) * (1 +
00295 fe_gtk_choice_model_get_length(model)));
00296 selected_index = 0;
00297 valid = gtk_tree_model_get_iter_first(model, &iter);
00298 while (valid) {
00299 gtk_tree_model_get(model, &iter,
00300 CHOICE_MODEL_SELECTED, &selected,
00301 -1 );
00302 if (selected) {
00303 gtk_tree_model_get(model, &iter,
00304 CHOICE_MODEL_VALUE,
00305 &selected_values[selected_index],
00306 -1 );
00307 selected_index++;
00308 }
00309 valid = gtk_tree_model_iter_next(model, &iter);
00310 }
00311 if (0 < selected_index) {
00312 result = g_strjoinv(", ", selected_values);
00313 } else {
00314
00315 result = g_strdup("");
00316 }
00317 question_setvalue(question, result);
00318 g_free(result);
00319
00320 for (selected_index = 0; NULL != selected_values[selected_index];
00321 selected_index++) {
00322 g_free(selected_values[selected_index]);
00323 }
00324 g_free(selected_values);
00325 }
00326
00332 static void update_model_from_toggle_button(
00333 GtkToggleButton * toggle_button, GtkTreeRowReference * row_reference)
00334 {
00335 GtkTreeModel * model = gtk_tree_row_reference_get_model(row_reference);
00336 GtkTreePath * path = gtk_tree_row_reference_get_path(row_reference);
00337 GtkTreeIter iter;
00338
00339 g_assert(NULL != model);
00340 g_assert(NULL != path);
00341
00342 if (gtk_tree_model_get_iter(model, &iter, path)) {
00343 gtk_list_store_set(
00344 GTK_LIST_STORE(model), &iter,
00345 CHOICE_MODEL_SELECTED,
00346 gtk_toggle_button_get_active(toggle_button),
00347 -1 );
00348 }
00349 }
00350
00360 static gulong connect_signal_to_row(GObject * object, const gchar * signal,
00361 GtkTreeModel * model, GtkTreeIter * iter,
00362 GCallback handler)
00363 {
00364 GtkTreePath * path;
00365 GtkTreeRowReference * row_reference;
00366
00367 path = gtk_tree_model_get_path(model, iter);
00368 row_reference = gtk_tree_row_reference_new(model, path);
00369 gtk_tree_path_free(path);
00370 return g_signal_connect_data(object, "toggled", handler, row_reference,
00371 (GClosureNotify) gtk_tree_row_reference_free,
00372 0 );
00373 }
00374
00385 static int create_multiselect_list(struct frontend * fe,
00386 struct question * question,
00387 GtkWidget * question_box,
00388 GtkTreeModel * model)
00389 {
00390 GtkTreeIter iter;
00391 GtkWidget * view;
00392 GtkWidget * scroll;
00393 GtkWidget * frame;
00394 GtkCellRenderer * toggle_renderer;
00395 GtkCellRenderer * text_renderer;
00396 GtkTreePath * path;
00397
00398 view = gtk_tree_view_new_with_model(model);
00399
00400 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
00401
00402 toggle_renderer = gtk_cell_renderer_toggle_new();
00403 g_signal_connect(G_OBJECT(toggle_renderer), "toggled",
00404 G_CALLBACK(update_selection_for_toggle), model);
00405 gtk_tree_view_insert_column_with_attributes(
00406 GTK_TREE_VIEW(view), -1 ,
00407 NULL , toggle_renderer,
00408 "active", CHOICE_MODEL_SELECTED,
00409 NULL );
00410
00411 text_renderer = gtk_cell_renderer_text_new();
00412 gtk_tree_view_insert_column_with_attributes(
00413 GTK_TREE_VIEW(view), -1 ,
00414 NULL , text_renderer,
00415 "text", CHOICE_MODEL_TRANSLATED_VALUE,
00416 NULL );
00417
00418
00419 gtk_tree_model_get_iter_first(model, &iter);
00420 path = gtk_tree_model_get_path(model, &iter);
00421 gtk_tree_view_set_cursor(GTK_TREE_VIEW(view), path,
00422 NULL ,
00423 FALSE );
00424 gtk_tree_path_free(path);
00425
00426 scroll = gtk_scrolled_window_new(NULL ,
00427 NULL );
00428 gtk_container_add(GTK_CONTAINER(scroll), view);
00429 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
00430 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
00431 frame = gtk_frame_new(NULL );
00432 gtk_container_add(GTK_CONTAINER(frame), scroll);
00433
00434 fe_gtk_add_common_layout(fe, question, question_box, frame);
00435 gtk_widget_grab_focus(view);
00436
00437 fe_gtk_register_setter(fe, SETTER_FUNCTION(set_value_from_multiselect),
00438 question, model);
00439 return DC_OK;
00440 }
00441
00446 static void focus_first_child(GtkContainer * container)
00447 {
00448 GList * children;
00449
00450 children = gtk_container_get_children(container);
00451 gtk_widget_grab_focus(GTK_WIDGET(children->data));
00452 g_list_free(children);
00453 }
00454
00465 static int create_multiselect_checkboxes(struct frontend * fe,
00466 struct question * question,
00467 GtkWidget * question_box,
00468 GtkTreeModel * model)
00469 {
00470 GtkWidget * check_container;
00471 GtkWidget * check;
00472 GtkTreeIter iter;
00473 gboolean valid;
00474 gchar * label;
00475 gboolean selected;
00476
00477
00478 g_assert(0 < fe_gtk_choice_model_get_length(model));
00479
00480 check_container = gtk_vbox_new(FALSE ,
00481 0 );
00482
00483 valid = gtk_tree_model_get_iter_first(model, &iter);
00484 while (valid) {
00485 gtk_tree_model_get(model, &iter,
00486 CHOICE_MODEL_TRANSLATED_VALUE, &label,
00487 CHOICE_MODEL_SELECTED, &selected,
00488 -1 );
00489
00490 check = gtk_check_button_new_with_label(label);
00491 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), selected);
00492
00493 connect_signal_to_row(G_OBJECT(check), "toggled", model, &iter,
00494 G_CALLBACK(update_model_from_toggle_button));
00495
00496 gtk_box_pack_start(GTK_BOX(check_container), check,
00497 FALSE , FALSE ,
00498 0 );
00499
00500 g_free(label);
00501 valid = gtk_tree_model_iter_next(model, &iter);
00502 }
00503
00504 fe_gtk_add_common_layout(fe, question, question_box, check_container);
00505
00506 if (fe_gtk_is_first_question(question)) {
00507 focus_first_child(GTK_CONTAINER(check_container));
00508 }
00509
00510 fe_gtk_register_setter(fe, SETTER_FUNCTION(set_value_from_multiselect),
00511 question, model);
00512
00513 return DC_OK;
00514 }
00515
00521 static void set_selected_active(GtkWidget * combo_box, GtkTreeModel * model)
00522 {
00523 GtkTreePath * path;
00524 GtkTreeIter iter;
00525 gboolean valid;
00526
00527 path = fe_gtk_choice_model_get_first_selected(model);
00528 if (NULL != path) {
00529 valid = gtk_tree_model_get_iter(model, &iter, path);
00530 if (valid) {
00531 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo_box), &iter);
00532 }
00533 gtk_tree_path_free(path);
00534 }
00535 }
00536
00547 static int create_select_combo(struct frontend * fe,
00548 struct question * question,
00549 GtkWidget * question_box,
00550 GtkTreeModel * model)
00551 {
00552 GtkWidget * combo_box;
00553 GtkCellRenderer * text_renderer;
00554
00555
00556 combo_box = gtk_combo_box_new_with_model(model);
00557
00558 text_renderer = gtk_cell_renderer_text_new();
00559 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_box), text_renderer,
00560 TRUE );
00561 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box), text_renderer,
00562 "text", CHOICE_MODEL_TRANSLATED_VALUE,
00563 NULL );
00564 set_selected_active(combo_box, model);
00565
00566 fe_gtk_add_common_layout(fe, question, question_box, combo_box);
00567
00568 if (fe_gtk_is_first_question(question)) {
00569 gtk_widget_grab_focus(combo_box);
00570 }
00571
00572 fe_gtk_register_setter(fe, SETTER_FUNCTION(set_value_from_combo),
00573 question, combo_box);
00574
00575 return DC_OK;
00576 }
00577
00588 static int handle_all(struct frontend * fe, struct question * question,
00589 GtkWidget * question_box, gboolean multiselect)
00590 {
00591 GtkTreeModel * model;
00592
00593 if (NULL == (model = fe_gtk_choice_model_create(fe, question))) {
00594 g_warning("create_model_from_choices failed.");
00595 return DC_NOTOK;
00596 }
00597
00598 if (multiselect && IS_QUESTION_SINGLE(question)) {
00599 return create_multiselect_list(fe, question, question_box, model);
00600 }
00601 if (multiselect) {
00602 return create_multiselect_checkboxes(fe, question, question_box,
00603 model);
00604 }
00605 if (IS_QUESTION_SINGLE(question)) {
00606 return create_select_list(fe, question, question_box, model);
00607 }
00608 return create_select_combo(fe, question, question_box, model);
00609 }
00610
00618 int fe_gtk_handle_select(struct frontend * fe, struct question * question,
00619 GtkWidget * question_box)
00620 {
00621 return handle_all(fe, question, question_box, FALSE );
00622 }
00623
00631 int fe_gtk_handle_multiselect(struct frontend * fe, struct question * question,
00632 GtkWidget * question_box)
00633 {
00634 return handle_all(fe, question, question_box, TRUE );
00635 }
00636
00637
00638