source: branches/profile/WINDOW/AW_question.cxx

Last change on this file was 10877, checked in by westram, 11 years ago
  • eliminate all deprecated callback-installer-calls(!) from WINDOW
    • mostly useless work (code only exists in motif version)
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.6 KB
Line 
1//  ==================================================================== //
2//                                                                       //
3//    File      : AW_question.cxx                                        //
4//    Purpose   :                                                        //
5//                                                                       //
6//  Coded by Ralf Westram (coder@reallysoft.de) in January 2002          //
7//  Copyright Department of Microbiology (Technical University Munich)   //
8//                                                                       //
9//  Visit our web site at: http://www.arb-home.de/                       //
10//  ==================================================================== //
11
12#include <arbdb.h>
13#include <aw_msg.hxx>
14#include <aw_question.hxx>
15#include "aw_root.hxx"
16#include "aw_awar.hxx"
17#include "aw_global.hxx"
18#include "aw_window.hxx"
19#include "aw_window_Xm.hxx"
20#include "aw_advice.hxx"
21
22using namespace std;
23
24#define AWAR_QUESTION "tmp/question"
25
26int aw_question(const char *uniqueID, const char *question, const char *buttons, bool fixedSizeButtons, const char *helpfile) {
27    // return 0 for first button, 1 for second button, 2 for third button, ...
28    //
29    // the single buttons are separated by commas (e.g. "YES,NO")
30    // If the button-name starts with ^ it starts a new row of buttons
31    // (if a button named 'EXIT' is pressed the program terminates using exit(EXIT_FAILURE))
32    //
33    // The remaining arguments only apply if 'buttons' is non-zero:
34    //
35    // If fixedSizeButtons is true all buttons have the same size
36    // otherwise the size for every button is set depending on the text length
37    //
38    // If 'helpfile' is non-zero a HELP button is added.
39
40    aw_assert(buttons);
41
42    AW_root *root = AW_root::SINGLETON;
43
44    char *awar_name_neverAskAgain = NULL;
45    int   have_auto_answer        = 0;
46
47    if (uniqueID) {
48        GB_ERROR error = GB_check_key(uniqueID);
49        if (error) {
50            aw_message(error);
51            uniqueID = NULL;
52        }
53        else {
54            awar_name_neverAskAgain     = GBS_global_string_copy("answers/%s", uniqueID);
55            AW_awar *awar_neverAskAgain = root->awar_int(awar_name_neverAskAgain, 0, AW_ROOT_DEFAULT);
56            have_auto_answer            = awar_neverAskAgain->read_int();
57        }
58    }
59
60    if (have_auto_answer>0) {
61        aw_message_cb_result = have_auto_answer-1;
62    }
63    else {
64        char *button_list = strdup(buttons ? buttons : "OK");
65        if (button_list[0] == 0) {
66            freedup(button_list, "Maybe ok,EXIT");
67            GBK_dump_backtrace(stderr, "Empty buttonlist");
68            question = GBS_global_string_copy("%s\n"
69                                              "(Program error - Unsure what happens when you click ok\n"
70                                              " Check console for backtrace and report error)",
71                                              question);
72        }
73
74        AW_awar *awar_quest     = root->awar_string(AWAR_QUESTION);
75        if (!question) question = "<oops - no question?!>";
76        awar_quest->write_string(question);
77
78        size_t question_length, question_lines;
79        aw_detect_text_size(question, question_length, question_lines);
80
81        // hash key to find matching window
82        char *hindex = GBS_global_string_copy("%s$%s$%zu$%zu$%i$%s",
83                                              button_list, uniqueID ? uniqueID : "<NOID>",
84                                              question_length, question_lines, int(fixedSizeButtons),
85                                              helpfile ? helpfile : "");
86
87        static GB_HASH    *hash_windows = 0;
88        if (!hash_windows) hash_windows = GBS_create_hash(256, GB_MIND_CASE);
89        AW_window_message *aw_msg       = (AW_window_message *)GBS_read_hash(hash_windows, hindex);
90
91#if defined(DEBUG)
92        printf("hindex='%s'\n", hindex);
93#endif // DEBUG
94
95        if (!aw_msg) {
96            aw_msg = new AW_window_message;
97            GBS_write_hash(hash_windows, hindex, (long)aw_msg);
98
99            aw_msg->init(root, "QUESTION BOX", false);
100            aw_msg->recalc_size_atShow(AW_RESIZE_DEFAULT); // force size recalc (ignores user size)
101
102            aw_msg->label_length(10);
103
104            aw_msg->at(10, 10);
105            aw_msg->auto_space(10, 10);
106
107            aw_msg->button_length(question_length+3);
108            aw_msg->button_height(question_lines+1);
109
110            aw_msg->create_button(0, AWAR_QUESTION);
111
112            aw_msg->button_height(0);
113
114            aw_msg->at_newline();
115
116            if (fixedSizeButtons) {
117                size_t  max_button_length = helpfile ? 4 : 0;
118                char   *pos               = button_list;
119
120                while (1) {
121                    char *comma       = strchr(pos, ',');
122                    if (!comma) comma = strchr(pos, 0);
123
124                    size_t len                                   = comma-pos;
125                    if (len>max_button_length) max_button_length = len;
126
127                    if (!comma[0]) break;
128                    pos = comma+1;
129                }
130
131                aw_msg->button_length(max_button_length+2);
132            }
133            else {
134                aw_msg->button_length(0);
135            }
136
137            // insert the buttons:
138            char *ret              = strtok(button_list, ",");
139            bool  help_button_done = false;
140            int   counter          = 0;
141
142            while (ret) {
143                if (ret[0] == '^') {
144                    if (helpfile && !help_button_done) {
145                        aw_msg->callback(makeHelpCallback(helpfile));
146                        aw_msg->create_button("HELP", "HELP", "H");
147                        help_button_done = true;
148                    }
149                    aw_msg->at_newline();
150                    ++ret;
151                }
152                if (strcmp(ret, "EXIT") == 0) {
153                    aw_msg->callback(makeWindowCallback(message_cb, -1));
154                }
155                else {
156                    aw_msg->callback(makeWindowCallback(message_cb, counter++));
157                }
158
159                if (fixedSizeButtons) {
160                    aw_msg->create_button(0, ret);
161                }
162                else {
163                    aw_msg->create_autosize_button(0, ret);
164                }
165                ret = strtok(NULL, ",");
166            }
167
168            if (helpfile && !help_button_done) { // if not done above
169                aw_msg->callback(makeHelpCallback(helpfile));
170                aw_msg->create_button("HELP", "HELP", "H");
171                help_button_done = true;
172            }
173
174            if (uniqueID) {
175                aw_msg->at_newline();
176                const char *label = counter>1 ? "Never ask again" : "Never notify me again";
177                aw_msg->label_length(strlen(label));
178                aw_msg->label(label);
179                aw_msg->create_toggle(awar_name_neverAskAgain);
180            }
181
182            aw_msg->window_fit();
183        }
184        else {
185#if defined(DEBUG)
186            printf("[Reusing existing aw_question-window]\n");
187#endif
188        }
189        free(hindex);
190        aw_msg->show_modal();
191
192        free(button_list);
193        aw_message_cb_result = -13;
194
195#if defined(TRACE_STATUS_MORE)
196        fprintf(stderr, "add aw_message_timer_listen_event with delay = %i\n", AW_MESSAGE_LISTEN_DELAY); fflush(stdout);
197#endif // TRACE_STATUS_MORE
198        root->add_timed_callback_never_disabled(AW_MESSAGE_LISTEN_DELAY, makeTimedCallback(aw_message_timer_listen_event, static_cast<AW_window*>(aw_msg)));
199
200        {
201            LocallyModify<bool> flag(root->disable_callbacks, true);
202            while (aw_message_cb_result == -13) {
203                root->process_events();
204            }
205        }
206        aw_msg->hide();
207
208        if (awar_name_neverAskAgain) {
209            AW_awar *awar_neverAskAgain = root->awar(awar_name_neverAskAgain);
210
211            if (awar_neverAskAgain->read_int()) { // user checked "Never ask again"
212                int givenAnswer = aw_message_cb_result >= 0 ? aw_message_cb_result+1 : 0;
213                awar_neverAskAgain->write_int(givenAnswer); // store given answer for "never asking again"
214
215                if (givenAnswer && strchr(buttons, ',') != 0) {
216                    const char *appname = root->program_name;
217                    char       *advice  = GBS_global_string_copy("You will not be asked that question again in this session.\n"
218                                                                 "%s will always assume the answer you just gave.\n"
219                                                                 "\n"
220                                                                 "When you restart %s that question will be asked again.\n"
221                                                                 "To disable that question permanently for future sessions,\n"
222                                                                 "you need to save properties.\n"
223                                                                 "\n"
224                                                                 "Depending on the type of question doing that might be\n"
225                                                                 "helpful or obstructive.\n"
226                                                                 "Disabled questions can be reactivated from the properties menu.\n",
227                                                                 appname, appname);
228                    AW_advice(advice, AW_ADVICE_TOGGLE, "Disabling questions", NULL);
229                    free(advice);
230                }
231            }
232        }
233    }
234
235    free(awar_name_neverAskAgain);
236
237    switch (aw_message_cb_result) {
238        case -1:                // exit with core
239            fprintf(stderr, "Core dump requested\n");
240            ARB_SIGSEGV(1);
241            break;
242        case -2:                // exit without core
243            exit(-1);
244            break;
245    }
246    return aw_message_cb_result;
247}
248
249bool aw_ask_sure(const char *uniqueID, const char *msg) {
250    return aw_question(uniqueID, msg, "Yes,No", true, NULL) == 0;
251}
252void aw_popup_ok(const char *msg) {
253    aw_question(NULL, msg, "Ok", true, NULL);
254}
255void aw_popup_exit(const char *msg) {
256    aw_question(NULL, msg, "EXIT", true, NULL);
257    aw_assert(0); // should not be reached
258    exit(EXIT_FAILURE);
259}
260
261void AW_reactivate_all_questions(AW_window*) {
262    GB_transaction  ta(AW_ROOT_DEFAULT);
263    GBDATA         *gb_neverAskedAgain = GB_search(AW_ROOT_DEFAULT, "answers", GB_FIND);
264    const char     *msg                = "No questions were disabled yet.";
265
266    if (gb_neverAskedAgain) {
267        int reactivated = 0;
268        for (GBDATA *gb_q = GB_child(gb_neverAskedAgain); gb_q; gb_q = GB_nextChild(gb_q)) {
269            if (GB_read_int(gb_q)) {
270                GB_write_int(gb_q, 0);
271                reactivated++;
272            }
273        }
274        if (reactivated) {
275            msg = GBS_global_string("Reactivated %i questions (for this session)\n"
276                                    "To reactivate them for future sessions, save properties.",
277                                    reactivated);
278        }
279    }
280    aw_message(msg);
281}
282
283
284void AW_repeated_question::add_help(const char *help_file) {
285    freedup(helpfile, help_file);
286}
287
288int AW_repeated_question::get_answer(const char *uniqueID, const char *question, const char *buttons, const char *to_all, bool add_abort)
289{
290    if (!buttons_used) {
291        buttons_used = strdup(buttons);
292    }
293    else {
294        // do not use the same instance of AW_repeated_question with different buttons!
295        assert_or_exit(strcmp(buttons_used, buttons) == 0);
296    }
297
298    if (answer == -1 || !dont_ask_again) {
299
300        char   *all             = GBS_global_string_copy(" (%s)", to_all);
301        int     all_len         = strlen(all);
302        size_t  but_len         = strlen(buttons);
303        size_t  new_buttons_len = but_len*3+1+(add_abort ? 6 : 0)+all_len*3;
304        char   *new_buttons     = (char*)malloc(new_buttons_len);
305        int     button_count    = 0; // number of buttons in 'buttons'
306
307        { // transform "YES,NO"  ->   "YES,YES (to_all),^NO,NO (to_all)" or "YES (to_all),NO (to_all)"
308            char       *w       = new_buttons;
309            const char *r       = buttons;
310
311            while (1) {
312                const char *comma = strchr(r, ',');
313                if (!comma) comma = strchr(r, 0);
314                int         len   = comma-r;
315
316                if (!dont_ask_again) {
317                    if (w>new_buttons) *w++ = '^'; // not in front of first button
318                    memcpy(w, r, len); w += len;
319                    *w++ = ',';
320                }
321                memcpy(w, r, len); w       += len;
322                memcpy(w, all, all_len); w += all_len;
323                *w++ = ',';
324
325                button_count++;
326
327                if (!comma[0]) break;
328                r = comma+1;
329            }
330            if (add_abort) {
331                const char *abort      = "^ABORT";
332                strcpy(w, abort); w += strlen(abort);
333            }
334            else {
335                --w; // delete comma at end
336            }
337            w[0] = 0;
338
339            aw_assert(size_t(w-new_buttons) < new_buttons_len); // oops buffer overflow
340
341            free(all);
342        }
343
344        int user_answer = aw_question(uniqueID, question, new_buttons, true, helpfile);
345
346        if (dont_ask_again) {   // ask question as normal when called first (dont_ask_again later)
347            answer = user_answer;
348        }
349        else {
350            answer         = user_answer/2;
351            dont_ask_again = (user_answer%2) || (user_answer == (button_count*2));
352        }
353
354        free(new_buttons);
355
356        aw_assert(answer<(button_count+(add_abort ? 1 : 0)));
357    }
358
359    aw_assert(answer != -1);
360
361    return answer;
362}
363
Note: See TracBrowser for help on using the repository browser.