ARB
AW_advice.cxx
Go to the documentation of this file.
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 
23 using 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 
36 static bool initialized = false;
38 
39 // --------------------------------------------------------
40 
41 void 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 
55 inline AW_awar *get_disabled_advices() { return advice_root->awar_string(AWAR_ADVICE_DISABLED, ""); }
56 inline AW_awar *get_shown_advices() { return advice_root->awar_string(AWAR_ADVICE_SHOWN, ""); }
57 
58 inline 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 
63 inline bool advice_id_is_set(const char* id, const char *idlist) { return advice_id_offset(id, idlist) >= 0; }
64 
65 inline 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 }
72 inline 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 }
91 inline 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 
100 inline bool advice_disabled(const char* id) { return advice_id_is_set(id, get_disabled_advices()->read_char_pntr()); }
101 inline void disable_advice(const char* id) { set_advice_id(id, get_disabled_advices()); }
102 
103 inline bool advice_currently_shown(const char *id) { return advice_id_is_set(id, get_shown_advices()->read_char_pntr()); }
104 inline void toggle_advice_shown(const char *id) { toggle_advice_id(id, get_shown_advices()); }
105 
106 // -------------------------------------------
107 
108 static 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 
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 }
130 static 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 
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 
160 void AW_advice(const char *message, AW_Advice_Type type, const char *title, const char *corresponding_help) {
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 
232 void 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 
242 
243  disable_advice(one);
246 
247  disable_advice(two);
250 
251 
254 
255  toggle_advice_shown(two);
258 
259  toggle_advice_shown(one);
262 
263  toggle_advice_shown(two);
266 
267  toggle_advice_shown(one);
270 }
271 
272 void TEST_another_AW_root() {
273  GB_shell shell;
274  AW_root("min_ascii.arb", UNITTEST_MOCK);
275 }
276 TEST_PUBLISH(TEST_another_AW_root);
277 
278 #endif // UNIT_TESTS
void toggle_advice_shown(const char *id)
Definition: AW_advice.cxx:104
int advice_id_offset(const char *id, const char *idlist)
Definition: AW_advice.cxx:58
GB_TYPES type
bool advice_disabled(const char *id)
Definition: AW_advice.cxx:100
void init_Advisor(AW_root *awr)
has to be called one time (before calling AW_advice)
Definition: AW_advice.cxx:41
void remove_advice_id(const char *id, AW_awar *var)
Definition: AW_advice.cxx:72
void AW_reactivate_all_advices(AW_window *)
reactivates all advices which were disabled by the user
Definition: AW_advice.cxx:137
#define AWAR_ADVICE_UNDERSTOOD
Definition: AW_advice.cxx:28
long read_int() const
Definition: AW_awar.cxx:184
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:203
const char * title
Definition: readseq.c:22
void AW_advice(const char *message, AW_Advice_Type type, const char *title, const char *corresponding_help)
Show a message box with an advice for the user.
Definition: AW_advice.cxx:160
STL namespace.
char * GBS_string_eval(const char *insource, const char *icommand)
Definition: admatch.cxx:699
uint32_t GB_checksum(const char *seq, long length, int ignore_case, const char *exclude)
Definition: adstring.cxx:319
bool advice_id_is_set(const char *id, const char *idlist)
Definition: AW_advice.cxx:63
static AW_root * advice_root
Definition: AW_advice.cxx:37
static bool initialized
Definition: AW_advice.cxx:36
#define TEST_PUBLISH(testfunction)
Definition: test_unit.h:1517
const char * read_char_pntr() const
Definition: AW_awar.cxx:168
WindowCallback makeHelpCallback(const char *helpfile)
Definition: aw_window.hxx:106
#define TEST_EXPECT(cond)
Definition: test_unit.h:1328
bool advice_currently_shown(const char *id)
Definition: AW_advice.cxx:103
#define AWAR_ADVICE_SHOWN
Definition: AW_advice.cxx:31
#define aw_assert(bed)
Definition: aw_position.hxx:29
void message(char *errortext)
#define TEST_REJECT(cond)
Definition: test_unit.h:1330
void toggle_advice_id(const char *id, AW_awar *var)
Definition: AW_advice.cxx:91
char * read_string() const
Definition: AW_awar.cxx:198
AW_awar * awar(const char *awar)
Definition: AW_root.cxx:554
static void advice_hide_and_close_cb(AW_window *aww, const char *id, AW_Advice_Type type)
Definition: AW_advice.cxx:130
#define AWAR_ADVICE_DISABLED
Definition: AW_advice.cxx:30
AW_Advice_Type
define type of AW_advice by or-ing values
Definition: aw_advice.hxx:24
void disable_advice(const char *id)
Definition: AW_advice.cxx:101
AW_awar * awar_int(const char *var_name, long default_value=0, AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:580
void set_advice_id(const char *id, AW_awar *var)
Definition: AW_advice.cxx:65
AW_awar * get_disabled_advices()
Definition: AW_advice.cxx:55
void aw_message(const char *msg)
Definition: AW_status.cxx:1142
void hide()
Definition: AW_window.cxx:1835
#define NULp
Definition: cxxforward.h:116
void AW_help_popup(UNFIXED, const char *help_file)
Definition: AW_help.cxx:628
GB_ERROR write_string(const char *aw_string)
#define offset(field)
Definition: GLwDrawA.c:73
AW_awar * awar_string(const char *var_name, const char *default_value="", AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:570
static void advice_close_cb(AW_window *aww, const char *id, AW_Advice_Type type)
Definition: AW_advice.cxx:108
GB_ERROR write_int(long aw_int)
AW_awar * get_shown_advices()
Definition: AW_advice.cxx:56
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:194
#define AWAR_ADVICE_TEXT
Definition: AW_advice.cxx:27