source: trunk/WINDOW/AW_advice.cxx

Last change on this file was 19363, checked in by westram, 18 months ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.5 KB
Line 
1//  ==================================================================== //
2//                                                                       //
3//    File      : aw_advice.cpp                                          //
4//    Purpose   :                                                        //
5//                                                                       //
6//                                                                       //
7//  Coded by Ralf Westram (coder@reallysoft.de) in May 2002              //
8//  Copyright Department of Microbiology (Technical University Munich)   //
9//                                                                       //
10//  Visit our web site at: http://www.arb-home.de/                       //
11//                                                                       //
12//                                                                       //
13//  ==================================================================== //
14
15#include "aw_advice.hxx"
16#include "aw_window.hxx"
17#include "aw_awar.hxx"
18#include "aw_msg.hxx"
19#include "aw_root.hxx"
20
21#include <arbdb.h>
22
23using namespace std;
24
25#define AWAR_ADVICE_TMP "/tmp/advices/"
26
27#define AWAR_ADVICE_TEXT       AWAR_ADVICE_TMP "text"
28#define AWAR_ADVICE_UNDERSTOOD AWAR_ADVICE_TMP "understood"
29
30#define AWAR_ADVICE_DISABLED "/advices/disabled"
31#define AWAR_ADVICE_SHOWN    "/tmp/advices/shown"
32
33// -------------------------
34//      internal data :
35
36static bool     initialized = false;
37static AW_root *advice_root = NULp;
38
39// --------------------------------------------------------
40
41void init_Advisor(AW_root *awr) {
42    if (!initialized) {
43        advice_root  = awr;
44
45        advice_root->awar_string(AWAR_ADVICE_TEXT, "<no advice>");
46        advice_root->awar_int(AWAR_ADVICE_UNDERSTOOD, 0);
47
48        initialized = true;
49    }
50}
51
52// ----------------------------
53//      disabled advices :
54
55inline AW_awar *get_disabled_advices() { return advice_root->awar_string(AWAR_ADVICE_DISABLED, ""); }
56inline AW_awar *get_shown_advices()    { return advice_root->awar_string(AWAR_ADVICE_SHOWN, ""); }
57
58inline int advice_id_offset(const char* id, const char *idlist) {
59    const char *found = strstr(idlist, GBS_global_string(";%s;", id));
60    return found ? found-idlist : -1;
61}
62
63inline bool advice_id_is_set(const char* id, const char *idlist) { return advice_id_offset(id, idlist) >= 0; }
64
65inline void set_advice_id(const char* id, AW_awar *var) {
66    const char *idlist = var->read_char_pntr();
67    if (!advice_id_is_set(id, idlist)) {
68        if (idlist[0]) var->write_string(GBS_global_string("%s%s;", idlist, id));
69        else var->write_string(GBS_global_string(";%s;", id));
70    }
71}
72inline void remove_advice_id(const char* id, AW_awar *var) {
73    const char *idlist = var->read_char_pntr();
74    if (advice_id_is_set(id, idlist)) {
75        int offset = advice_id_offset(id, idlist);
76        if (offset >= 0) {
77            char *newList = NULp;
78            if (offset == 0) {
79                newList = strdup(idlist+strlen(id)+1);
80            }
81            else {
82                newList     = strdup(idlist);
83                char *idPos = newList+offset;
84                strcpy(idPos, idPos+strlen(id)+1);
85            }
86            var->write_string(newList);
87            free(newList);
88        }
89    }
90}
91inline void toggle_advice_id(const char* id, AW_awar *var) {
92    if (advice_id_is_set(id, var->read_char_pntr())) {
93        remove_advice_id(id, var);
94    }
95    else {
96        set_advice_id(id, var);
97    }
98}
99
100inline bool advice_disabled(const char* id) { return advice_id_is_set(id, get_disabled_advices()->read_char_pntr()); }
101inline void disable_advice(const char* id)  { set_advice_id(id, get_disabled_advices()); }
102
103inline bool advice_currently_shown(const char *id) { return advice_id_is_set(id, get_shown_advices()->read_char_pntr()); }
104inline void toggle_advice_shown(const char *id)    { toggle_advice_id(id, get_shown_advices()); }
105
106// -------------------------------------------
107
108static void advice_close_cb(AW_window *aww, const char *id, AW_Advice_Type type) {
109    int understood = advice_root->awar(AWAR_ADVICE_UNDERSTOOD)->read_int();
110
111    // switch to 'not understood'. Has to be checked by user for each advice.
112    advice_root->awar(AWAR_ADVICE_UNDERSTOOD)->write_int(0);
113    aww->hide();
114
115    toggle_advice_shown(id);
116
117    if (understood) {
118        disable_advice(id);
119        if (type & AW_ADVICE_TOGGLE) {
120            static bool in_advice = false;
121            if (!in_advice) {
122                in_advice = true;
123                AW_advice("You have disabled an advice.\n"
124                          "In order to disable it PERMANENTLY, save properties.", AW_ADVICE_TOGGLE, "Advice disabled", "advice.hlp");
125                in_advice = false;
126            }
127        }
128    }
129}
130static void advice_hide_and_close_cb(AW_window *aww, const char *id, AW_Advice_Type type) {
131    advice_root->awar(AWAR_ADVICE_UNDERSTOOD)->write_int(1);
132    advice_close_cb(aww, id, type);
133}
134
135// -------------------------------------------
136
137void AW_reactivate_all_advices(AW_window*) {
138    AW_awar *awar_disabled = get_disabled_advices();
139
140    char       *disabled = awar_disabled->read_string();
141    char       *nosemi   = GBS_string_eval(disabled, ";=");
142    int         entries  = strlen(disabled)-strlen(nosemi);
143    const char *msg      = "No advices were disabled yet.";
144
145    if (entries>0) {
146        aw_assert(entries>1);
147        entries--;
148        msg = GBS_global_string("Reactivated %i advices (for this session)\n"
149                                "To reactivate them for future sessions, save properties.",
150                                entries);
151    }
152    aw_message(msg);
153
154    free(nosemi);
155    free(disabled);
156
157    awar_disabled->write_string("");
158}
159
160void AW_advice(const char *message, AW_Advice_Type type, const char *title, const char *corresponding_help) {
161    aw_assert(initialized);
162    size_t  message_len = strlen(message); aw_assert(message_len>0);
163    long    crc32       = GB_checksum(message, message_len, true, " .,-!"); // checksum is used to test if advice was shown
164    char   *advice_id   = GBS_global_string_copy("%lx", crc32); // do not delete (bound to cbs)
165
166    bool show_advice = !advice_disabled(advice_id) && !advice_currently_shown(advice_id);
167
168    if (show_advice) {
169        AW_awar *understood = advice_root->awar(AWAR_ADVICE_UNDERSTOOD);
170        understood->write_int(0);
171
172        if (corresponding_help) type = AW_Advice_Type(type|AW_ADVICE_HELP);
173#if defined(ASSERTION_USED)
174        else aw_assert((type & AW_ADVICE_HELP) == 0);
175#endif // ASSERTION_USED
176
177        AW_window_simple *aws = new AW_window_simple; // do not delete (ARB will crash) -- maybe reuse window for all advices?
178
179        if (!title) title = "Please read carefully";
180        aws->init(advice_root, "advice", GBS_global_string("ARB: %s", title));
181        aws->load_xfig("window/advice.fig");
182
183        bool has_help     = type & AW_ADVICE_HELP;
184        bool help_pops_up = false;
185
186        if (has_help) {
187            aws->callback(makeHelpCallback(corresponding_help));
188            aws->at("help");
189            aws->create_button(NULp, "HELP", "H");
190
191            if (type & AW_ADVICE_HELP_POPUP) help_pops_up = true;
192        }
193
194        aws->at("advice");
195        aws->create_text_field(AWAR_ADVICE_TEXT);
196
197        advice_root->awar(AWAR_ADVICE_TEXT)
198            ->write_string(has_help && !help_pops_up
199                           ? GBS_global_string("%s\n\nPlease refer to 'HELP' for more info.", message)
200                           : message);
201
202        if (help_pops_up) AW_help_popup(NULp, corresponding_help);
203
204        if (type & AW_ADVICE_TOGGLE) {
205            aws->label("Do not advice me again");
206            aws->at("understood");
207            aws->create_toggle(AWAR_ADVICE_UNDERSTOOD);
208        }
209
210        aws->at("ok");
211        if (type & AW_ADVICE_TOGGLE) {
212            aws->callback(makeWindowCallback(advice_close_cb, advice_id, type));
213            aws->create_button(NULp, "OK", "O");
214        }
215        else {
216            aws->callback(makeWindowCallback(advice_hide_and_close_cb, advice_id, type));
217            aws->create_autosize_button(NULp, "I understand", "O", 2);
218        }
219
220        aws->window_fit();
221        aws->allow_delete_window(false); // disable closing the window via 'X'-button
222        aws->show();
223        toggle_advice_shown(advice_id);
224    }
225}
226
227// --------------------------------------------------------------------------------
228
229#ifdef UNIT_TESTS
230#include <test_unit.h>
231
232void TEST_advice_id_awar_handling() {
233    GB_shell  shell;
234    AW_root  root("min_ascii.arb", UNITTEST_MOCK);
235    init_Advisor(&root);
236
237    const char *one = "one";
238    const char *two = "second";
239
240    TEST_REJECT(advice_disabled(one));
241    TEST_REJECT(advice_disabled(two));
242
243    disable_advice(one);
244    TEST_EXPECT(advice_disabled(one));
245    TEST_REJECT(advice_disabled(two));
246
247    disable_advice(two);
248    TEST_EXPECT(advice_disabled(one));
249    TEST_EXPECT(advice_disabled(two));
250
251
252    TEST_REJECT(advice_currently_shown(one));
253    TEST_REJECT(advice_currently_shown(two));
254
255    toggle_advice_shown(two);
256    TEST_REJECT(advice_currently_shown(one));
257    TEST_EXPECT(advice_currently_shown(two));
258
259    toggle_advice_shown(one);
260    TEST_EXPECT(advice_currently_shown(one));
261    TEST_EXPECT(advice_currently_shown(two));
262
263    toggle_advice_shown(two);
264    TEST_EXPECT(advice_currently_shown(one));
265    TEST_REJECT(advice_currently_shown(two));
266
267    toggle_advice_shown(one);
268    TEST_REJECT(advice_currently_shown(one));
269    TEST_REJECT(advice_currently_shown(two));
270}
271
272void TEST_another_AW_root() {
273    GB_shell  shell;
274    AW_root("min_ascii.arb", UNITTEST_MOCK);
275}
276TEST_PUBLISH(TEST_another_AW_root);
277
278#endif // UNIT_TESTS
Note: See TracBrowser for help on using the repository browser.