'smart qotes' now will replace '<', '>' and '&' inside 'pre' and 'code' tags
[k8lowj.git] / src / poll-questions.c
blobd543215294e79b915efa95297541871d99d75368
1 /* logjam - a GTK client for LiveJournal.
2 * Copyright (C) 2000-2004 Evan Martin <martine@danga.com>
4 * vim: tabstop=4 shiftwidth=4 noexpandtab :
5 */
7 #include "gtk-all.h"
8 #include "util-gtk.h"
9 #include "poll.h"
11 typedef struct {
12 GtkWidget *dlg;
14 GtkWidget *typemenu;
15 GtkWidget *question;
16 JamReorderable answers;
17 } PollMultiDlg;
19 typedef struct {
20 GtkWidget *dlg;
22 GtkWidget *question;
23 GtkWidget *size, *width;
24 } PollTextDlg;
26 typedef struct {
27 GtkWidget *dlg;
29 GtkWidget *question;
30 GtkWidget *from, *to, *by;
31 } PollScaleDlg;
33 static char*
34 pollmultidlg_option(GtkWindow *parent, const char *current) {
35 GtkWidget *dlg, *vbox, *label, *view;
36 GtkTextBuffer *buffer;
37 char *newtext = NULL;
39 dlg = gtk_dialog_new_with_buttons(_("Multi Poll Option"),
40 parent, GTK_DIALOG_MODAL,
41 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
42 GTK_STOCK_OK, GTK_RESPONSE_OK,
43 NULL);
44 jam_win_set_size(GTK_WINDOW(dlg), 300, -1);
46 vbox = gtk_vbox_new(FALSE, 6);
48 label = gtk_label_new_with_mnemonic(_("O_ption:"));
49 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
50 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
52 view = gtk_text_view_new();
53 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
54 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view), GTK_WRAP_WORD);
55 if (current)
56 gtk_text_buffer_insert_at_cursor(buffer, current, -1);
57 gtk_label_set_mnemonic_widget(GTK_LABEL(label), view);
58 gtk_box_pack_start(GTK_BOX(vbox), scroll_wrap(view), TRUE, TRUE, 0);
60 jam_dialog_set_contents(GTK_DIALOG(dlg), vbox);
62 if (gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_OK) {
63 GtkTextIter start, end;
64 gtk_text_buffer_get_bounds(buffer, &start, &end);
65 newtext = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
67 gtk_widget_destroy(dlg);
68 return newtext;
71 static void
72 add_option_cb(PollMultiDlg *pmdlg) {
73 char *newtext;
74 GtkTreeIter iter;
76 newtext = pollmultidlg_option(GTK_WINDOW(pmdlg->dlg), NULL);
77 if (!newtext) return;
78 gtk_list_store_append(pmdlg->answers.store, &iter);
79 gtk_list_store_set(pmdlg->answers.store, &iter, 0, newtext, -1);
80 g_free(newtext);
82 static void
83 edit_option_cb(PollMultiDlg *pmdlg) {
84 GtkTreeSelection *sel;
85 GtkTreeModel *model;
86 GtkTreeIter iter;
87 char *text, *newtext;
89 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(pmdlg->answers.view));
91 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
92 return;
93 gtk_tree_model_get(model, &iter, 0, &text, -1);
94 newtext = pollmultidlg_option(GTK_WINDOW(pmdlg->dlg), text);
95 if (newtext)
96 gtk_list_store_set(pmdlg->answers.store, &iter, 0, newtext, -1);
97 g_free(text);
98 g_free(newtext);
100 static void
101 remove_option_cb(PollMultiDlg *pmdlg) {
102 GtkTreeSelection *sel;
103 GtkTreeIter iter;
105 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(pmdlg->answers.view));
106 if (!gtk_tree_selection_get_selected(sel, NULL, &iter))
107 return;
108 gtk_list_store_remove(pmdlg->answers.store, &iter);
111 static void
112 pollmulti_make_list(PollMultiDlg *pmdlg) {
113 GtkCellRenderer *renderer;
114 GtkTreeViewColumn *column;
116 pmdlg->answers.store = gtk_list_store_new(1, G_TYPE_STRING);
118 jam_reorderable_make(&pmdlg->answers);
119 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(pmdlg->answers.view), FALSE);
120 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(pmdlg->answers.view), TRUE);
121 g_object_unref(pmdlg->answers.store);
123 renderer = gtk_cell_renderer_text_new();
124 column = gtk_tree_view_column_new();
125 gtk_tree_view_column_pack_start(column, renderer, TRUE);
126 gtk_tree_view_column_add_attribute(column, renderer, "text", 0);
127 gtk_tree_view_append_column(GTK_TREE_VIEW(pmdlg->answers.view), column);
129 g_signal_connect_swapped(G_OBJECT(pmdlg->answers.add), "clicked",
130 G_CALLBACK(add_option_cb), pmdlg);
131 g_signal_connect_swapped(G_OBJECT(pmdlg->answers.edit), "clicked",
132 G_CALLBACK(edit_option_cb), pmdlg);
133 g_signal_connect_swapped(G_OBJECT(pmdlg->answers.remove), "clicked",
134 G_CALLBACK(remove_option_cb), pmdlg);
137 static void
138 pollmultidlg_init(PollMultiDlg *pmdlg, GtkWindow *parent) {
139 GtkWidget *mainbox, *vbox, *paned;
140 GtkWidget *menu, *label;
142 pmdlg->dlg = gtk_dialog_new_with_buttons(_("Multi Poll Question"),
143 parent, GTK_DIALOG_MODAL,
144 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
145 GTK_STOCK_OK, GTK_RESPONSE_OK,
146 NULL);
147 jam_win_set_size(GTK_WINDOW(pmdlg->dlg), 500, -1);
149 mainbox = gtk_vbox_new(FALSE, 12);
151 menu = gtk_menu_new();
152 gtk_menu_shell_append(GTK_MENU_SHELL(menu),
153 gtk_menu_item_new_with_mnemonic(_("Choose best answer (_radio buttons)")));
154 gtk_menu_shell_append(GTK_MENU_SHELL(menu),
155 gtk_menu_item_new_with_mnemonic(_("Choose best answer (_drop-down menu)")));
156 gtk_menu_shell_append(GTK_MENU_SHELL(menu),
157 gtk_menu_item_new_with_mnemonic(_("Select _all that apply (checkboxes)")));
159 pmdlg->typemenu = gtk_option_menu_new();
160 gtk_option_menu_set_menu(GTK_OPTION_MENU(pmdlg->typemenu), menu);
161 gtk_box_pack_start(GTK_BOX(mainbox),
162 labelled_box_new_expand(_("Choice _Type:"), pmdlg->typemenu, TRUE),
163 FALSE, FALSE, 0);
165 paned = gtk_hpaned_new();
166 gtk_box_pack_start(GTK_BOX(mainbox), paned, TRUE, TRUE, 0);
168 vbox = gtk_vbox_new(FALSE, 6);
169 label = gtk_label_new_with_mnemonic(_("_Question:"));
170 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
171 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
173 pmdlg->question = gtk_text_view_new();
174 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(pmdlg->question), GTK_WRAP_WORD);
175 gtk_label_set_mnemonic_widget(GTK_LABEL(label), pmdlg->question);
176 gtk_box_pack_start(GTK_BOX(vbox),
177 scroll_wrap(pmdlg->question),
178 TRUE, TRUE, 0);
180 gtk_paned_pack1(GTK_PANED(paned), vbox, TRUE, FALSE);
182 vbox = gtk_vbox_new(FALSE, 6);
183 pollmulti_make_list(pmdlg);
184 label = gtk_label_new_with_mnemonic(_("O_ptions:"));
185 gtk_label_set_mnemonic_widget(GTK_LABEL(label), pmdlg->answers.view);
186 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
187 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
188 gtk_box_pack_start(GTK_BOX(vbox), pmdlg->answers.box, TRUE, TRUE, 0);
190 gtk_paned_pack2(GTK_PANED(paned), vbox, TRUE, FALSE);
192 jam_dialog_set_contents(GTK_DIALOG(pmdlg->dlg), mainbox);
195 PollQuestion*
196 pollmultidlg_run(GtkWindow *parent, PollQuestionMulti *qm) {
197 PollQuestion *q = NULL;
198 GtkTextBuffer *buffer;
199 STACK(PollMultiDlg, pmdlg);
201 pollmultidlg_init(pmdlg, parent);
203 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pmdlg->question));
204 if (qm) {
205 GSList *l;
206 GtkTreeIter iter;
207 q = (PollQuestion*)qm;
208 gtk_option_menu_set_history(GTK_OPTION_MENU(pmdlg->typemenu), q->type);
209 gtk_text_buffer_insert_at_cursor(buffer, q->question, -1);
210 for (l = qm->answers; l; l = l->next) {
211 gtk_list_store_append(pmdlg->answers.store, &iter);
212 gtk_list_store_set(pmdlg->answers.store, &iter, 0, l->data, -1);
216 if (gtk_dialog_run(GTK_DIALOG(pmdlg->dlg)) == GTK_RESPONSE_OK) {
217 GtkTextIter start, end;
218 GtkTreeModel *model = GTK_TREE_MODEL(pmdlg->answers.store);
219 GtkTreeIter iter;
221 if (qm == NULL)
222 qm = g_new0(PollQuestionMulti, 1);
223 q = (PollQuestion*)qm;
224 q->type = gtk_option_menu_get_history(GTK_OPTION_MENU(pmdlg->typemenu));
226 gtk_text_buffer_get_bounds(buffer, &start, &end);
227 g_free(q->question);
228 q->question = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
230 g_slist_foreach(qm->answers, (GFunc)g_free, NULL);
231 g_slist_free(qm->answers);
232 qm->answers = NULL;
233 if (gtk_tree_model_get_iter_first(model, &iter)) {
234 /* this is probably O(n^2) or something like that.
235 * but there hopefully won't be that many answers. */
236 do {
237 char *text;
238 gtk_tree_model_get(model, &iter, 0, &text, -1);
239 qm->answers = g_slist_append(qm->answers, text);
240 } while (gtk_tree_model_iter_next(model, &iter));
243 gtk_widget_destroy(GTK_WIDGET(pmdlg->dlg));
244 return q;
247 static void
248 polltextdlg_init(PollTextDlg *ptdlg, GtkWindow *parent) {
249 GtkWidget *mainbox, *vbox;
250 GtkWidget *label, *view;
252 ptdlg->dlg = gtk_dialog_new_with_buttons(_("Text Poll Question"),
253 parent, GTK_DIALOG_MODAL,
254 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
255 GTK_STOCK_OK, GTK_RESPONSE_OK,
256 NULL);
258 mainbox = gtk_vbox_new(FALSE, 12);
260 vbox = gtk_vbox_new(FALSE, 6);
262 label = gtk_label_new_with_mnemonic(_("_Question:"));
263 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
264 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
266 ptdlg->question = view = gtk_text_view_new();
267 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view), GTK_WRAP_WORD);
268 gtk_label_set_mnemonic_widget(GTK_LABEL(label), view);
269 gtk_box_pack_start(GTK_BOX(vbox), scroll_wrap(view), TRUE, TRUE, 0);
271 gtk_box_pack_start(GTK_BOX(mainbox), vbox, TRUE, TRUE, 0);
273 vbox = gtk_vbox_new(FALSE, 6);
275 ptdlg->size = gtk_entry_new();
276 gtk_entry_set_width_chars(GTK_ENTRY(ptdlg->size), 4);
277 ptdlg->width = gtk_entry_new();
278 gtk_entry_set_width_chars(GTK_ENTRY(ptdlg->width), 4);
280 gtk_box_pack_start(GTK_BOX(vbox),
281 labelled_box_new(_("_Text field size (optional): "),
282 ptdlg->size),
283 FALSE, FALSE, 0);
284 gtk_box_pack_start(GTK_BOX(vbox),
285 labelled_box_new(_("_Maximum text length (optional): "),
286 ptdlg->width),
287 FALSE, FALSE, 0);
289 gtk_box_pack_start(GTK_BOX(mainbox), vbox, FALSE, FALSE, 0);
291 jam_dialog_set_contents(GTK_DIALOG(ptdlg->dlg), mainbox);
294 PollQuestion*
295 polltextdlg_run(GtkWindow *parent, PollQuestionText *pqt) {
296 STACK(PollTextDlg, ptdlg);
297 PollQuestion *q = NULL;
298 GtkTextBuffer *buffer;
300 polltextdlg_init(ptdlg, parent);
302 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ptdlg->question));
303 if (pqt) {
304 char *text;
305 q = (PollQuestion*)pqt;
307 gtk_text_buffer_insert_at_cursor(buffer, q->question, -1);
309 if (pqt->size) {
310 text = g_strdup_printf("%d", pqt->size);
311 gtk_entry_set_text(GTK_ENTRY(ptdlg->size), text);
312 g_free(text);
314 if (pqt->width) {
315 text = g_strdup_printf("%d", pqt->width);
316 gtk_entry_set_text(GTK_ENTRY(ptdlg->width), text);
317 g_free(text);
321 if (gtk_dialog_run(GTK_DIALOG(ptdlg->dlg)) == GTK_RESPONSE_OK) {
322 GtkTextIter start, end;
323 const char *text;
325 if (!pqt)
326 pqt = g_new0(PollQuestionText, 1);
327 q = (PollQuestion*)pqt;
328 q->type = PQ_TEXT;
330 gtk_text_buffer_get_bounds(buffer, &start, &end);
331 g_free(q->question);
332 q->question = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
334 text = gtk_entry_get_text(GTK_ENTRY(ptdlg->size));
335 if (text && text[0])
336 pqt->size = atoi(text);
338 text = gtk_entry_get_text(GTK_ENTRY(ptdlg->width));
339 if (text && text[0])
340 pqt->width = atoi(text);
342 gtk_widget_destroy(GTK_WIDGET(ptdlg->dlg));
343 return q;
346 static void
347 pollscaledlg_init(PollScaleDlg *psdlg, GtkWindow *parent) {
348 GtkWidget *mainbox, *vbox;
349 GtkWidget *label;
350 GtkSizeGroup *sizegroup;
352 GtkAdjustment *adj1 = (GtkAdjustment*)gtk_adjustment_new(
353 1.0, -32000.0, 32000.0, 1.0, 5.0, 5.0);
354 GtkAdjustment *adj2 = (GtkAdjustment*)gtk_adjustment_new(
355 10.0, -32000.0, 32000.0, 1.0, 5.0, 5.0);
356 GtkAdjustment *adj3 = (GtkAdjustment*)gtk_adjustment_new(
357 1.0, -32000.0, 32000.0, 1.0, 5.0, 5.0);
359 psdlg->dlg = gtk_dialog_new_with_buttons(_("Scale Poll Question"),
360 parent, GTK_DIALOG_MODAL,
361 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
362 GTK_STOCK_OK, GTK_RESPONSE_OK,
363 NULL);
364 jam_win_set_size(GTK_WINDOW(psdlg->dlg), 400, -1);
366 mainbox = gtk_hbox_new(FALSE, 12);
368 vbox = gtk_vbox_new(FALSE, 6);
369 label = gtk_label_new_with_mnemonic(_("_Question:"));
370 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
371 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
373 psdlg->question = gtk_text_view_new();
374 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(psdlg->question), GTK_WRAP_WORD);
375 gtk_label_set_mnemonic_widget(GTK_LABEL(label), psdlg->question);
376 gtk_box_pack_start(GTK_BOX(vbox),
377 scroll_wrap(psdlg->question),
378 TRUE, TRUE, 0);
380 gtk_box_pack_start(GTK_BOX(mainbox), vbox, TRUE, TRUE, 0);
382 vbox = gtk_vbox_new(FALSE, 6);
383 sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
385 psdlg->from = gtk_spin_button_new(adj1, 1.0, 0);
386 gtk_box_pack_start(GTK_BOX(vbox),
387 labelled_box_new_sg(_("_From:"), psdlg->from, sizegroup),
388 FALSE, FALSE, 0);
389 psdlg->to = gtk_spin_button_new(adj2, 1.0, 0);
390 gtk_box_pack_start(GTK_BOX(vbox),
391 labelled_box_new_sg(_("_To:"), psdlg->to, sizegroup),
392 FALSE, FALSE, 0);
393 psdlg->by = gtk_spin_button_new(adj3, 1.0, 0);
394 gtk_box_pack_start(GTK_BOX(vbox),
395 labelled_box_new_sg(_("_By:"), psdlg->by, sizegroup),
396 FALSE, FALSE, 0);
398 gtk_box_pack_start(GTK_BOX(mainbox), vbox, FALSE, FALSE, 0);
400 jam_dialog_set_contents(GTK_DIALOG(psdlg->dlg), mainbox);
403 PollQuestion*
404 pollscaledlg_run(GtkWindow *parent, PollQuestionScale *pqs) {
405 STACK(PollScaleDlg, psdlg);
406 PollQuestion *q = NULL;
407 GtkTextBuffer *buffer;
409 pollscaledlg_init(psdlg, parent);
410 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(psdlg->question));
411 if (pqs) {
412 q = (PollQuestion*)pqs;
414 gtk_text_buffer_insert_at_cursor(buffer, q->question, -1);
416 gtk_spin_button_set_value(GTK_SPIN_BUTTON(psdlg->from),
417 (gdouble)pqs->from);
418 gtk_spin_button_set_value(GTK_SPIN_BUTTON(psdlg->to),
419 (gdouble)pqs->to);
420 gtk_spin_button_set_value(GTK_SPIN_BUTTON(psdlg->by),
421 (gdouble)pqs->by);
424 if (gtk_dialog_run(GTK_DIALOG(psdlg->dlg)) == GTK_RESPONSE_OK) {
425 GtkTextIter start, end;
427 if (!pqs)
428 pqs = g_new0(PollQuestionScale, 1);
429 q = (PollQuestion*)pqs;
430 q->type = PQ_SCALE;
432 gtk_text_buffer_get_bounds(buffer, &start, &end);
433 g_free(q->question);
434 q->question = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
436 pqs->from = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(psdlg->from));
437 pqs->to = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(psdlg->to));
438 pqs->by = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(psdlg->by));
440 gtk_widget_destroy(GTK_WIDGET(psdlg->dlg));
441 return q;
445 void
446 poll_question_free(PollQuestion *pq) {
447 switch (pq->type) {
448 case PQ_RADIO:
449 case PQ_COMBO:
450 case PQ_CHECK:
451 g_slist_foreach(((PollQuestionMulti*)pq)->answers,
452 (GFunc)g_free, NULL);
453 g_slist_free(((PollQuestionMulti*)pq)->answers);
454 break;
455 case PQ_TEXT:
456 case PQ_SCALE:
457 break;
459 g_free(pq);