ARB
AWT_input_mask.cxx
Go to the documentation of this file.
1 // ==================================================================== //
2 // //
3 // File : AWT_input_mask.cxx //
4 // Purpose : General input masks //
5 // //
6 // //
7 // Coded by Ralf Westram (coder@reallysoft.de) in August 2001 //
8 // Copyright Department of Microbiology (Technical University Munich) //
9 // //
10 // Visit our web site at: http://www.arb-home.de/ //
11 // //
12 // //
13 // ==================================================================== //
14 
16 
17 #include <awt_www.hxx>
18 
19 #include <aw_edit.hxx>
20 #include <aw_file.hxx>
21 #include <aw_msg.hxx>
22 #include <aw_question.hxx>
23 
24 #include <arbdbt.h>
25 #include <gb_aci.h>
26 #include <ad_cb.h>
27 
28 #include <arb_file.h>
29 
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <dirent.h>
33 #include <climits>
34 #include <set>
35 
36 using namespace std;
37 
38 static const char *awt_itemtype_names[AWT_IT_TYPES+1] = {
39  "Unknown",
40  "Species", "Organism", "Gene", "Experiment",
41  "<overflow>"
42 };
43 
44 #define SEC_XBORDER 3 // space left/right of NEW_SECTION line
45 #define SEC_YBORDER 4 // space above/below
46 #define SEC_LINE_WIDTH 1 // line width
47 
48 #define MIN_TEXTFIELD_SIZE 1
49 #define MAX_TEXTFIELD_SIZE 1000
50 
51 #define AWT_SCOPE_LOCAL 0
52 #define AWT_SCOPE_GLOBAL 1
53 
54 awt_input_mask_id_list awt_input_mask_global::global_ids; // stores global ids
55 
56 // ---------------------
57 // global awars
58 
59 #define AWAR_INPUT_MASK_BASE "tmp/inputMask"
60 #define AWAR_INPUT_MASK_NAME AWAR_INPUT_MASK_BASE"/name"
61 #define AWAR_INPUT_MASK_ITEM AWAR_INPUT_MASK_BASE"/item"
62 #define AWAR_INPUT_MASK_SCOPE AWAR_INPUT_MASK_BASE"/scope"
63 #define AWAR_INPUT_MASK_HIDDEN AWAR_INPUT_MASK_BASE"/hidden"
64 
65 #define AWAR_INPUT_MASKS_EDIT_ENABLED AWAR_INPUT_MASK_BASE"/edit_enabled"
66 
67 static bool global_awars_created = false;
68 
69 static void create_global_awars(AW_root *awr) {
71  awr->awar_string(AWAR_INPUT_MASK_NAME, "new");
72  awr->awar_string(AWAR_INPUT_MASK_ITEM, awt_itemtype_names[AWT_IT_SPECIES]);
76  global_awars_created = true;
77 }
78 
79 // ------------------------------------------
80 // Callbacks from database and awars
81 
82 static bool in_item_changed_callback = false;
83 static bool in_field_changed_callback = false;
84 static bool in_awar_changed_callback = false;
85 
87  if (!in_item_changed_callback) { // avoid deadlock
89  if (type&GB_CB_DELETE) { // handled child was deleted
90  item_link->relink();
91  }
92  else if ((type&GB_CB_CHANGED_OR_SON_CREATED) == GB_CB_CHANGED_OR_SON_CREATED) {
93  // child was created (not only changed)
94  item_link->relink();
95  }
96  else if (type&GB_CB_CHANGED) { // only changed
97  item_link->general_item_change();
98  }
99  }
100 }
101 
103  if (!in_field_changed_callback) { // avoid deadlock
105  if (type&GB_CB_DELETE) { // field was deleted from db -> relink this item
106  handler->relink();
107  }
108  else if (type&GB_CB_CHANGED) {
109  handler->db_changed(); // database entry was changed
110  }
111  }
112 }
113 
115  if (!in_awar_changed_callback) { // avoid deadlock
117  awt_assert(item);
118  if (item) item->awar_changed();
119  }
120 }
121 
122 string awt_input_mask_global::generate_id(const string& mask_name_) {
123  string result;
124  result.reserve(mask_name_.length());
125  for (string::const_iterator p = mask_name_.begin(); p != mask_name_.end(); ++p) {
126  if (isalnum(*p)) result.append(1, *p);
127  else result.append(1, '_');
128  }
129  return result;
130 }
131 
133  return !test_edit_enabled ||
134  get_root()->awar(AWAR_INPUT_MASKS_EDIT_ENABLED)->read_int() == 1;
135 }
136 
138  aw_message(GBS_global_string("This had no effect, because no %s is selected",
139  awt_itemtype_names[get_itemtype()]));
140 }
141 
143  awt_mask_item *existing = lookup(name);
144  if (existing) return GBS_global_string("ID '%s' already exists", name.c_str());
145 
146  id[name] = item;
147  return NULp;
148 }
150  if (!lookup(name)) return GBS_global_string("ID '%s' does not exist", name.c_str());
151  id.erase(name);
152  return NULp;
153 }
154 
156  : global(global_)
157 {}
158 
160  awt_assert(!has_name()); // you forgot to call remove_name()
161 }
162 
163 GB_ERROR awt_mask_item::set_name(const string& name_, bool is_global) {
164  GB_ERROR error = NULp;
165  if (has_name()) {
166  error = GBS_global_string("Element already has name (%s)", get_name().c_str());
167  }
168  else {
169  name = new string(name_);
170  if (is_global) {
171  if (!mask_global().has_global_id(*name)) { // do not add if variable already defined elsewhere
172  error = mask_global().add_global_id(*name, this);
173  }
174  }
175  else {
176  error = mask_global().add_local_id(*name, this);
177  }
178  }
179  return error;
180 }
181 
183  GB_ERROR error = NULp;
184  if (has_name()) {
185  error = mask_global().remove_id(*name);
186  name.setNull();
187  }
188  return error;
189 }
190 
191 awt_mask_awar_item::awt_mask_awar_item(awt_input_mask_global& global_, const string& awar_base, const string& default_value, bool saved_with_properties)
192  : awt_mask_item(global_)
193 {
194  const char *root_name;
195 
196  if (saved_with_properties) root_name = "/input_masks";
197  else root_name = "/tmp/input_masks"; // awars starting with /tmp are not saved
198 
199  awarName = GBS_global_string("%s/%s", root_name, awar_base.c_str());
200 #if defined(DEBUG)
201  printf("awarName='%s'\n", awarName.c_str());
202 #endif // DEBUG
203  mask_global().get_root()->awar_string(awarName.c_str(), default_value.c_str()); // create the awar
205 }
206 
208  AW_awar *var = awar();
209  awt_assert(var);
210  if (var) var->add_callback(makeRootCallback(awar_changed_cb, this));
211 }
213  AW_awar *var = awar();
214  awt_assert(var);
215  if (var) var->remove_callback(makeRootCallback(awar_changed_cb, this));
216 }
217 
218 awt_variable::awt_variable(awt_input_mask_global& global_, const string& id, bool is_global_, const string& default_value, GB_ERROR& error) :
219  awt_mask_awar_item(global_, generate_baseName(global_, id, is_global_), default_value, true),
220  is_global(is_global_)
221 {
222  error = set_name(id, is_global);
223 }
224 
226 
227 string awt_script::get_value() const {
228  string result;
229  AW_root *root = mask_global().get_root();
230  const awt_item_type_selector *selector = mask_global().get_selector();
231  GBDATA *gb_main = mask_global().get_gb_main();
232  GBDATA *gbd = selector->current(root, gb_main);
233 
234  if (gbd) {
235  char *species_name = root->awar(selector->get_self_awar())->read_string();
236  GB_transaction tscope(gb_main);
237 
238  char *val = GB_command_interpreter_in_env(species_name, script.c_str(), GBL_maybe_itemless_call_env(gb_main, gbd));
239  if (!val) {
241  result = "<error>";
242  }
243  else {
244  result = val;
245  free(val);
246  }
247  free(species_name);
248  }
249  else {
250  result = "<undefined>";
251  }
252 
253 
254  return result;
255 }
256 
257 GB_ERROR awt_script::set_value(const string& /* new_value */) {
258  return GBS_global_string("You cannot assign a value to script '%s'", has_name() ? get_name().c_str() : "<unnamed>");
259 }
260 
262  GB_ERROR error = NULp;
263  if (gb_item) error = GB_add_callback(gb_item, GB_CB_CHANGED_OR_DELETED, makeDatabaseCallback(item_changed_cb, this));
264  return error;
265 }
266 
268  if (!GB_inside_callback(gb_item, GB_CB_DELETE)) {
269  GB_remove_callback(gb_item, GB_CB_CHANGED_OR_DELETED, makeDatabaseCallback(item_changed_cb, this));
270  }
271 }
272 
273 awt_script_viewport::awt_script_viewport(awt_input_mask_global& global_, const awt_script *script_, const string& label_, long field_width_) :
274  awt_viewport(global_, generate_baseName(global_), "", false, label_),
275  script(script_),
276  field_width(field_width_)
277 {}
278 
279 awt_script_viewport::~awt_script_viewport() {
280  unlink();
281 }
282 
283 GB_ERROR awt_script_viewport::link_to(GBDATA *gb_new_item) {
284  GB_ERROR error = NULp;
285  GB_transaction ta(mask_global().get_gb_main());
286 
287  remove_awarItem_callbacks(); // unbind awar callbacks temporarily
288 
289  if (item()) {
290  remove_db_callbacks(); // ignore result (if handled db-entry was deleted, it returns an error)
291  set_item(NULp);
292  }
293 
294  if (gb_new_item) {
295  set_item(gb_new_item);
296  db_changed();
297  error = add_db_callbacks();
298  }
299 
300  add_awarItem_callbacks(); // rebind awar callbacks
301 
302  return error;
303 }
304 
305 void awt_script_viewport::build_widget(AW_window *aws) {
306  const string& lab = get_label();
307  if (lab.length()) aws->label(lab.c_str());
308 
309  aws->create_input_field(awar_name().c_str(), field_width);
310 }
311 
312 void awt_script_viewport::db_changed() {
313  awt_assert(script);
314  string current_value = script->get_value();
315  GB_ERROR error = awt_mask_awar_item::set_value(current_value);
316 
317  if (error) aw_message(error);
318 }
319 
320 void awt_script_viewport::awar_changed() {
321  aw_message("It makes no sense to change the result of a script");
322 }
323 
324 GB_ERROR awt_input_handler::add_db_callbacks() {
326  if (item() && gbd) error = GB_add_callback(gbd, GB_CB_CHANGED_OR_DELETED, makeDatabaseCallback(field_changed_cb, this));
327  return error;
328 }
329 void awt_input_handler::remove_db_callbacks() {
331  if (item() && gbd && !GB_inside_callback(gbd, GB_CB_DELETE)) {
332  GB_remove_callback(gbd, GB_CB_CHANGED_OR_DELETED, makeDatabaseCallback(field_changed_cb, this));
333  }
334 }
335 
336 awt_input_handler::awt_input_handler(awt_input_mask_global& global_, const string& child_path_, GB_TYPES type_, const string& label_) :
337  awt_viewport(global_, generate_baseName(global_, child_path_), "", false, label_),
338  gbd(NULp),
339  child_path(child_path_),
340  db_type(type_),
341  in_destructor(false)
342 {}
343 
345  in_destructor = true;
346  unlink();
347 }
348 
350  GB_ERROR error = NULp;
352 
353  remove_awarItem_callbacks(); // unbind awar callbacks temporarily
354 
355  if (item()) {
356  remove_db_callbacks(); // ignore result (if handled db-entry was deleted, it returns an error)
357  set_item(NULp);
358  gbd = NULp;
359  }
360  else {
361  awt_assert(!gbd);
362  }
363 
364  if (!gb_new_item && !in_destructor) { // crashes if we are in ~awt_input_handler
365  db_changed();
366  }
367 
368  if (!error && gb_new_item) {
369  set_item(gb_new_item);
370  gbd = GB_search(item(), child_path.c_str(), GB_FIND);
371 
372  db_changed(); // synchronize AWAR with DB-entry
373 
374  error = add_db_callbacks();
375  }
376 
377  add_awarItem_callbacks(); // rebind awar callbacks
378 
379  return error;
380 }
381 
383  GBDATA *gbdata = data();
384  GBDATA *gb_main = mask_global().get_gb_main();
385  bool relink_me = false;
386  GB_ERROR error = NULp;
387 
388  GB_push_transaction(gb_main);
389 
390  if (!mask_global().edit_allowed()) error = "Editing is disabled. Check the 'Enable edit' switch!";
391 
392  if (!error && !gbdata) {
393  const char *child = get_child_path().c_str();
394  const char *keypath = mask_global().get_selector()->getKeyPath();
395 
396  if (item()) {
397  gbdata = GB_search(item(), child, GB_FIND);
398 
399  if (!gbdata) {
400  GB_TYPES found_typ = GBT_get_type_of_changekey(gb_main, child, keypath);
401  if (found_typ != GB_NONE) set_type(found_typ); // fix type if different
402 
403  gbdata = GB_search(item(), child, type()); // here new items are created
404  if (found_typ == GB_NONE) GBT_add_new_changekey_to_keypath(gb_main, child, type(), keypath);
405  relink_me = true; // @@@ only if child was created!!
406  }
407  }
408  else {
410  aw_message(GBS_global_string("This had no effect, because no %s is selected",
411  awt_itemtype_names[mask_global().get_itemtype()]));
412  }
413  }
414 
415  if (!error && gbdata) {
416  char *content = awar()->read_string();
417  GB_TYPES found_typ = GB_read_type(gbdata);
418  if (found_typ != type()) set_type(found_typ); // fix type if different
419 
420  error = GB_write_autoconv_string(gbdata, awar2db(content).c_str());
421 
422  free(content);
423  }
424 
425  if (error) {
426  aw_message(error);
427  GB_abort_transaction(gb_main);
428  db_changed(); // write back old value
429  }
430  else {
431  GB_pop_transaction(gb_main);
432  }
433 
434  if (relink_me) relink();
435 }
436 
438  GBDATA *gbdata = data();
439  if (gbdata) { // gbdata may be zero, if field does not exist
441  char *content = GB_read_as_string(gbdata);
442  awar()->write_string(db2awar(content).c_str());
443  free(content);
444  }
445  else {
446  awar()->write_string(default_value.c_str());
447  }
448 }
449 
450 // ----------------
451 // Widgets
452 
454  const string& lab = get_label();
455  if (lab.length()) aws->label(lab.c_str());
456 
457  aws->create_input_field(awar_name().c_str(), field_width);
458 }
459 
461  const string& lab = get_label();
462  if (lab.length()) aws->label(lab.c_str());
463 
464  aws->create_input_field(awar_name().c_str(), field_width);
465 }
466 
468  const string& lab = get_label();
469  if (lab.length()) aws->label(lab.c_str());
470 
471  aws->create_toggle(awar_name().c_str());
472 }
474  const string& lab = get_label();
475  if (lab.length()) aws->label(lab.c_str());
476 
477  aws->create_toggle_field(awar_name().c_str(), vertical ? 0 : 1);
478 
479  vector<string>::const_iterator b = buttons.begin();
480  vector<string>::const_iterator v = values.begin();
481  int pos = 0;
482 
483  for (; b != buttons.end() && v != values.end(); ++b, ++v, ++pos) {
484  void (AW_window::*ins_togg)(const char*, const char*, const char*);
485 
486  if (pos == default_position) ins_togg = &AW_window::insert_default_toggle;
487  else ins_togg = &AW_window::insert_toggle;
488 
489  (aws->*ins_togg)(b->c_str(), mask_global().hotkey(*b), b->c_str());
490  }
491 
492  awt_assert(b == buttons.end() && v == values.end());
493 
494  aws->update_toggle_field();
495 }
496 
497 // -----------------------------------------
498 // Special AWAR <-> DB translations
499 
500 string awt_check_box::awar2db(const string& awar_content) const {
501  GB_TYPES typ = type();
502 
503  if (awar_content == "yes") {
504  if (typ == GB_STRING) return "yes";
505  return "1";
506  }
507  else {
508  if (typ == GB_STRING) return "no";
509  return "0";
510  }
511 }
512 string awt_check_box::db2awar(const string& db_content) const {
513  if (db_content == "yes" || db_content == "1") return "yes";
514  if (db_content == "no" || db_content == "0") return "no";
515  return atoi(db_content.c_str()) ? "yes" : "no";
516 }
517 
518 string awt_radio_button::awar2db(const string& awar_content) const {
519  vector<string>::const_iterator b = buttons.begin();
520  vector<string>::const_iterator v = values.begin();
521  for (; b != buttons.end() && v != values.end(); ++b, ++v) {
522  if (*b == awar_content) {
523  return *v;
524  }
525  }
526 
527  return string("Unknown awar_content '")+awar_content+"'";
528 }
529 
530 string awt_radio_button::db2awar(const string& db_content) const {
531  vector<string>::const_iterator b = buttons.begin();
532  vector<string>::const_iterator v = values.begin();
533  for (; b != buttons.end() && v != values.end(); ++b, ++v) {
534  if (*v == db_content) {
535  return *b;
536  }
537  }
538  return buttons[default_position];
539 }
540 
541 string awt_numeric_input_field::awar2db(const string& awar_content) const {
542  long val = strtol(awar_content.c_str(), NULp, 10);
543 
544  // correct numeric value :
545  if (val<min) val = min;
546  if (val>max) val = max;
547 
548  return GBS_global_string("%li", val);
549 }
550 
551 // -----------------------------------------
552 // Routines to parse user-mask file
553 
554 static GB_ERROR readLine(FILE *in, string& line, size_t& lineNo) {
555  const int BUFSIZE = 8000;
556  char buffer[BUFSIZE];
557  char *res = fgets(&buffer[0], BUFSIZE-1, in);
558  GB_ERROR error = NULp;
559 
560  if (int err = ferror(in)) {
561  error = strerror(err);
562  }
563  else if (!res) {
564  error = "Unexpected end of file (@MASK_BEGIN or @MASK_END missing?)";
565  }
566  else {
567  awt_assert(res == buffer);
568  res += strlen(buffer);
569  if (res>buffer) {
570  size_t last = res-buffer;
571  if (buffer[last-1] == '\n') {
572  buffer[last-1] = 0;
573  }
574  }
575  line = buffer;
576  lineNo++; // increment lineNo
577 
578  size_t last = line.find_last_not_of(" \t");
579  if (last != string::npos && line[last] == '\\') {
580  string next;
581  error = readLine(in, next, lineNo);
582  line = line.substr(0, last)+' '+next;
583  }
584  }
585 
586  if (error) line = "";
587 
588  return error;
589 }
590 
591 inline size_t next_non_white(const string& line, size_t start) {
592  if (start == string::npos) return string::npos;
593  return line.find_first_not_of(" \t", start);
594 }
595 
596 static bool was_last_parameter = false;
597 
598 inline size_t eat_para_separator(const string& line, size_t start, GB_ERROR& error) {
599  size_t para_sep = next_non_white(line, start);
600 
601  if (para_sep == string::npos) {
602  error = "',' or ')' expected after parameter";
603  }
604  else {
605  switch (line[para_sep]) {
606  case ')':
607  was_last_parameter = true;
608  break;
609 
610  case ',':
611  break;
612 
613  default:
614  error = "',' or ')' expected after parameter";
615  break;
616  }
617  if (!error) para_sep++;
618  }
619 
620  return para_sep;
621 }
622 
623 static void check_last_parameter(GB_ERROR& error, const string& command) {
624  if (!error && !was_last_parameter) {
625  error = GBS_global_string("Superfluous arguments to '%s'", command.c_str());
626  }
627 }
628 
629 static void check_no_parameter(const string& line, size_t& scan_pos, GB_ERROR& error, const string& command) {
630  size_t start = next_non_white(line, scan_pos);
631  scan_pos = start;
632 
633  if (start == string::npos) {
634  error = "')' expected";
635  }
636  else if (line[start] != ')') {
637  was_last_parameter = false;
638  check_last_parameter(error, command);
639  }
640  else { // ok
641  scan_pos++;
642  }
643 }
644 
645 inline GB_ERROR decodeEscapes(string& s) {
646  string::iterator f = s.begin();
647  string::iterator t = s.begin();
648 
649  for (; f != s.end(); ++f, ++t) {
650  if (*f == '\\') {
651  ++f;
652  if (f == s.end()) return GBS_global_string("Trailing \\ in '%s'", s.c_str());
653  }
654  *t = *f;
655  }
656 
657  s.erase(t, f);
658 
659  return NULp;
660 }
661 
662 static string check_data_path(const string& path, GB_ERROR& error) {
663  if (!error) error = GB_check_hkey(path.c_str());
664  return path;
665 }
666 
667 static string scan_string_parameter(const string& line, size_t& scan_pos, GB_ERROR& error, bool allow_escaped = false) {
668  string result;
669  size_t open_quote = next_non_white(line, scan_pos);
670  scan_pos = open_quote;
671 
672  if (open_quote == string::npos || line[open_quote] != '\"') {
673  error = "string parameter expected";
674  }
675  else {
676  size_t close_quote = string::npos;
677 
678  if (allow_escaped) {
679  size_t start = open_quote+1;
680 
681  while (1) {
682  close_quote = line.find_first_of("\\\"", start);
683 
684  if (close_quote == string::npos) break; // error
685  if (line[close_quote] == '\"') break; // found closing quote
686 
687  if (line[close_quote] == '\\') { // escape next char
688  close_quote++;
689  }
690  start = close_quote+1;
691  }
692  }
693  else {
694  close_quote = line.find('\"', open_quote+1);
695  }
696 
697  if (close_quote == string::npos) {
698  error = "string parameter missing closing '\"'";
699  }
700  else {
701  result = line.substr(open_quote+1, close_quote-open_quote-1);
702  if (allow_escaped) {
703  awt_assert(!error);
704  error = decodeEscapes(result);
705  }
706  if (!error) scan_pos = eat_para_separator(line, close_quote+1, error);
707  }
708  }
709 
710  return result;
711 }
712 
713 #if (GCC_VERSION_CODE == 901) || (GCC_VERSION_CODE == 902) // (please do not activate for all future versions, test each of them)
714 # define GCC_ARRAY_BOUNDS_FALSE_POSITIVE
715 #endif
716 
717 #ifdef GCC_ARRAY_BOUNDS_FALSE_POSITIVE
718 # pragma GCC diagnostic push
719 # pragma GCC diagnostic ignored "-Warray-bounds"
720 #endif
721 
722 static string list_keywords(const char **allowed_keywords) {
723  // it is required that 'allowed_keywords' has a NULp sentinel.
724  string result;
725  for (int i = 0; allowed_keywords[i]; ++i) {
726  if (i) {
727  if (allowed_keywords[i+1]) result += ", "; // (false positive "-Warray-bounds"; i+1 always inside array bounds if has sentinel)
728  else result += " or ";
729  }
730  result += allowed_keywords[i];
731  }
732  return result;
733 }
734 
735 #ifdef GCC_ARRAY_BOUNDS_FALSE_POSITIVE
736 # pragma GCC diagnostic pop
737 #endif
738 
739 inline int isKeyword(const char *current, const char *keyword) {
740  int pos = 0;
741  for (; keyword[pos]; ++pos) {
742  if (!current[pos] || std::tolower(current[pos]) != std::tolower(keyword[pos])) {
743  return 0;
744  }
745  }
746  return pos;
747 }
748 
749 static int scan_keyword_parameter(const string& line, size_t& scan_pos, GB_ERROR& error, const char **allowed_keywords) {
750  // return index of keyword (or -1)
751  // allowed_keywords has to be 0-terminated
752  int result = -1;
753  size_t start = next_non_white(line, scan_pos);
754  scan_pos = start;
755 
756  awt_assert(!error);
757 
758  if (start == string::npos) {
759 EXPECTED :
760  string keywords = list_keywords(allowed_keywords);
761  error = GBS_global_string("%s expected", keywords.c_str());
762  }
763  else {
764  const char *current = line.c_str()+start;
765 
766  int i = 0;
767  for (; allowed_keywords[i]; ++i) {
768  int found_keyword_size = isKeyword(current, allowed_keywords[i]);
769  if (found_keyword_size) {
770  result = i;
771  scan_pos += found_keyword_size;
772  break;
773  }
774  }
775  if (!allowed_keywords[i]) goto EXPECTED;
776  awt_assert(!error);
777  scan_pos = eat_para_separator(line, scan_pos, error);
778  }
779  return result;
780 }
781 
782 static void scan_string_or_keyword_parameter(const string& line, size_t& scan_pos, GB_ERROR& error,
783  string& string_para, int& keyword_index, // result parameters
784  const char **allowed_keywords) {
785  // if keyword_index != -1 -> keyword found
786  // == -1 -> string_para contains string-parameter
787 
788  awt_assert(!error);
789 
790  string_para = scan_string_parameter(line, scan_pos, error);
791  if (!error) {
792  keyword_index = -1;
793  }
794  else { // no string
795  error = NULp; // ignore error - test for keywords
796  keyword_index = scan_keyword_parameter(line, scan_pos, error, allowed_keywords);
797  if (keyword_index == -1) { // no keyword
798  error = GBS_global_string("string parameter or %s", error);
799  }
800  }
801 }
802 
803 static long scan_long_parameter(const string& line, size_t& scan_pos, GB_ERROR& error) {
804  int result = 0;
805  size_t start = next_non_white(line, scan_pos);
806  bool neg = false;
807 
808  awt_assert(!error);
809 
810  while (start != string::npos) {
811  char c = line[start];
812  if (c != '+' && c != '-') break;
813 
814  start = next_non_white(line, start+1);
815  if (c == '-') neg = !neg;
816  continue;
817  }
818 
819  if (start == string::npos || !isdigit(line[start])) {
820  scan_pos = start;
821  error = "digits (or+-) expected";
822  }
823  else {
824  size_t end = line.find_first_not_of("0123456789", start);
825  scan_pos = eat_para_separator(line, end, error);
826  if (!error) {
827  awt_assert(end != string::npos);
828  result = atoi(line.substr(start, end-start+1).c_str());
829  }
830  }
831 
832  return neg ? -result : result;
833 }
834 static long scan_long_parameter(const string& line, size_t& scan_pos, GB_ERROR& error, long min, long max) {
835  // with range-check
836  awt_assert(!error);
837  size_t old_scan_pos = scan_pos;
838  long result = scan_long_parameter(line, scan_pos, error);
839  if (!error) {
840  if (result<min || result>max) {
841  scan_pos = old_scan_pos;
842  error = GBS_global_string("value %li is outside allowed range (%li-%li)", result, min, max);
843  }
844  }
845  return result;
846 }
847 
848 static long scan_optional_parameter(const string& line, size_t& scan_pos, GB_ERROR& error, long if_empty) {
849  awt_assert(!error);
850  size_t old_scan_pos = scan_pos;
851  long result = scan_long_parameter(line, scan_pos, error);
852  if (error) {
853  error = NULp; // ignore and test for empty parameter
854  scan_pos = old_scan_pos;
855  scan_pos = eat_para_separator(line, scan_pos, error);
856 
857  if (error) {
858  error = "expected number or empty parameter";
859  scan_pos = old_scan_pos;
860  }
861  else {
862  result = if_empty;
863  }
864  }
865  return result;
866 }
867 
868 static int scan_flag_parameter(const string& line, size_t& scan_pos, GB_ERROR& error, const string& allowed_flags) {
869  // return 0..n-1 ( = position in 'allowed_flags')
870  // or error is set
871  awt_assert(!error);
872  int result = 0;
873  size_t start = next_non_white(line, scan_pos);
874  scan_pos = start;
875 
876  if (start == string::npos) {
877  error = GBS_global_string("One of '%s' expected", allowed_flags.c_str());
878  }
879  else {
880  char found = line[start];
881  char upper_found = std::toupper(found);
882  size_t pos = allowed_flags.find(upper_found);
883 
884  if (pos != string::npos) {
885  result = pos;
886  scan_pos = eat_para_separator(line, start+1, error);
887  }
888  else {
889  error = GBS_global_string("One of '%s' expected (found '%c')", allowed_flags.c_str(), found);
890  }
891  }
892  return result;
893 }
894 static bool scan_bool_parameter(const string& line, size_t& scan_pos, GB_ERROR& error) {
895  awt_assert(!error);
896  size_t old_scan_pos = scan_pos;
897  long result = scan_long_parameter(line, scan_pos, error);
898 
899  if (!error && (result != 0) && (result != 1)) {
900  scan_pos = old_scan_pos;
901  error = "'0' or '1' expected";
902  }
903  return result != 0;
904 }
905 
906 static string scan_identifier(const string& line, size_t& scan_pos, GB_ERROR& error) {
907  string id;
908  size_t start = next_non_white(line, scan_pos);
909  if (start == string::npos) {
910  error = "identifier expected";
911  }
912  else {
913  size_t end = start;
914  while (end<line.length()) {
915  char c = line[end];
916  if (!(isalnum(c) || c == '_')) break;
917  ++end;
918  }
919  id = line.substr(start, end-start);
920  scan_pos = eat_para_separator(line, end, error);
921  }
922  return id;
923 }
924 
925 inline const char *inputMaskDir(bool local) {
926  if (local) {
927  static char *local_mask_dir;
928  if (!local_mask_dir) local_mask_dir = ARB_strdup(GB_path_in_arbprop("inputMasks"));
929  return local_mask_dir;
930  }
931 
932  static char *global_mask_dir;
933  if (!global_mask_dir) global_mask_dir = ARB_strdup(GB_path_in_ARBLIB("inputMasks"));
934  return global_mask_dir;
935 }
936 
937 inline string inputMaskFullname(const string& mask_name, bool local) {
938  const char *dir = inputMaskDir(local);
939  return string(dir)+'/'+mask_name;
940 }
941 
942 #define ARB_INPUT_MASK_ID "ARB-Input-Mask"
943 
944 static awt_input_mask_descriptor *quick_scan_input_mask(const string& mask_name, const string& filename, bool local) {
945  awt_input_mask_descriptor *res = NULp;
946  FILE *in = fopen(filename.c_str(), "rt");
947  GB_ERROR error = NULp;
948 
949  if (in) {
950  string line;
951  size_t lineNo = 0;
952  error = readLine(in, line, lineNo);
953 
954  if (!error && line == ARB_INPUT_MASK_ID) {
955  bool done = false;
956  int hidden = 0; // 0 = 'not hidden'
957  string title;
958  string itemtype;
959 
960  while (!feof(in)) {
961  error = readLine(in, line, lineNo);
962  if (error) break;
963 
964  if (line[0] == '#') continue; // ignore comments
965  if (line == "@MASK_BEGIN") { done = true; break; }
966 
967  size_t at = line.find('@');
968  size_t eq = line.find('=', at);
969 
970  if (at == string::npos || eq == string::npos) {
971  continue; // ignore all other lines
972  }
973  else {
974  string parameter = line.substr(at+1, eq-at-1);
975  string value = line.substr(eq+1);
976 
977  if (parameter == "ITEMTYPE") itemtype = value;
978  else if (parameter == "TITLE") title = value;
979  else if (parameter == "HIDE") hidden = atoi(value.c_str());
980  }
981  }
982 
983  if (!error && done) {
984  if (itemtype == "") {
985  error = "No itemtype defined";
986  }
987  else {
988  if (title == "") title = mask_name;
989  res = new awt_input_mask_descriptor(title.c_str(), mask_name.c_str(), itemtype.c_str(), local, hidden);
990  }
991  }
992  }
993  fclose(in);
994  }
995 
996  if (error) {
997  aw_message(GBS_global_string("%s (while scanning user-mask '%s')", error, filename.c_str()));
998  }
999 
1000 #if defined(DEBUG)
1001  printf("Skipping '%s' (not a input mask)\n", filename.c_str());
1002 #endif // DEBUG
1003  return res;
1004 }
1005 
1006 static void AWT_edit_input_mask(AW_window *, const string *mask_name, bool local) {
1007  string fullmask = inputMaskFullname(*mask_name, local);
1008  AW_edit(fullmask.c_str()); // @@@ add callback and automatically reload input mask
1009 }
1010 
1011 // ---------------------------------
1012 // input mask container :
1013 
1015 typedef map<string, awt_input_mask_ptr> InputMaskList; // contains all active masks
1016 static InputMaskList input_mask_list;
1017 
1018 static void awt_input_mask_awar_changed_cb(AW_root*, awt_input_mask *mask) {
1019  mask->relink();
1020 }
1021 static void link_mask_to_database(awt_input_mask_ptr mask) {
1022  awt_input_mask_global& global = mask->mask_global();
1023  const awt_item_type_selector *sel = global.get_selector();
1024  AW_root *root = global.get_root();
1025 
1026  sel->add_awar_callbacks(root, makeRootCallback(awt_input_mask_awar_changed_cb, &*mask));
1027  awt_input_mask_awar_changed_cb(root, &*mask);
1028 }
1029 static void unlink_mask_from_database(awt_input_mask_ptr mask) {
1030  awt_input_mask_global& global = mask->mask_global();
1031  const awt_item_type_selector *sel = global.get_selector();
1032  AW_root *root = global.get_root();
1033 
1034  sel->remove_awar_callbacks(root, makeRootCallback(awt_input_mask_awar_changed_cb, &*mask));
1035 }
1036 
1037 inline bool isInternalMaskName(const string& s) {
1038  return s[0] == '0' || s[0] == '1';
1039 }
1040 
1041 static void awt_open_input_mask(AW_window *aww, const string *internal_mask_name, const string *mask_to_open, bool reload, bool hide_current) {
1042  InputMaskList::iterator mask_iter = input_mask_list.find(*internal_mask_name);
1043 
1044  awt_assert(internal_mask_name && isInternalMaskName(*internal_mask_name));
1045  awt_assert(mask_to_open && isInternalMaskName(*mask_to_open));
1046 
1047  if (mask_iter != input_mask_list.end()) {
1048  awt_input_mask_ptr mask = mask_iter->second;
1049  awt_input_mask_global& global = mask->mask_global();
1050 
1051  printf("aww=%p root=%p ; global=%p root=%p\n", aww, aww->get_root(), &global, global.get_root());
1052  awt_assert(aww->get_root() == global.get_root());
1053 
1054  if (reload) mask->set_reload_on_reinit(true);
1055  if (hide_current) mask->hide();
1056  // @@@ hier sollte nicht der Selector der alten Maske verwendet werden, sondern anhand des Typs ein
1057  // Selector ausgewaehlt werden. Dazu muessen jedoch alle Selectoren registriert werden.
1058  GB_ERROR error = AWT_initialize_input_mask(global.get_root(), global.get_gb_main(), global.get_selector(), mask_to_open->c_str(), global.is_local_mask());
1059  // CAUTION: AWT_initialize_input_mask invalidates mask and mask_iter
1060  if (error && hide_current) {
1061  mask_iter = input_mask_list.find(*internal_mask_name);
1062  awt_assert(mask_iter != input_mask_list.end());
1063  mask_iter->second->show();
1064  }
1065  }
1066 #if defined(DEBUG)
1067  else {
1068  string mask_name = internal_mask_name->substr(1);
1069  printf("'%s' (no such mask in input_mask_list)\n", mask_name.c_str());
1070  awt_assert(0);
1071  }
1072 #endif // DEBUG
1073 }
1074 
1075 static void AWT_reload_input_mask(AW_window *aww, const string *internal_mask_name) {
1076  awt_open_input_mask(aww, internal_mask_name, internal_mask_name, true, true);
1077 }
1078 static void AWT_open_input_mask(AW_window *aww, const string *internal_mask_name, const string *mask_to_open) {
1079  awt_open_input_mask(aww, internal_mask_name, mask_to_open, false, false);
1080 }
1081 static void AWT_change_input_mask(AW_window *aww, const string *internal_mask_name, const string *mask_to_open) {
1082  awt_open_input_mask(aww, internal_mask_name, mask_to_open, false, true);
1083 }
1084 
1085 // ------------------------------
1086 // class awt_mask_action
1087 
1089  // something that is performed i.e. when user pressed a mask button
1090  // used as callback parameter
1091 private:
1092  virtual GB_ERROR action() = 0;
1093 protected:
1094  awt_input_mask_ptr mask;
1095 public:
1096  awt_mask_action(awt_input_mask_ptr mask_) : mask(mask_) {}
1097  virtual ~awt_mask_action() {}
1098 
1100  GB_ERROR error = action();
1101  if (error) aw_message(error);
1102  }
1103 };
1104 
1105 
1106 // ------------------------------------------------------
1107 // class awt_assignment : public awt_mask_action
1108 
1110 private:
1111  string id_dest;
1112  string id_source;
1113 
1114  GB_ERROR action() OVERRIDE {
1115  GB_ERROR error = NULp;
1116  const awt_mask_item *item_source = mask->mask_global().get_identified_item(id_source, error);
1117  awt_mask_item *item_dest = mask->mask_global().get_identified_item(id_dest, error);
1118 
1119  if (!error) error = item_dest->set_value(item_source->get_value());
1120 
1121  return error;
1122  }
1123 public:
1124  awt_assignment(awt_input_mask_ptr mask_, const string& id_dest_, const string& id_source_) :
1125  awt_mask_action(mask_),
1126  id_dest(id_dest_),
1127  id_source(id_source_)
1128  {}
1130 };
1131 
1133  action->perform_action();
1134 }
1135 
1136 static void AWT_input_mask_browse_url(AW_window *aww, const string *url_aci, const awt_input_mask *mask) {
1137  const awt_input_mask_global& global = mask->mask_global();
1138  const awt_item_type_selector *selector = global.get_selector();
1139 
1140  AW_root *root = aww->get_root();
1141  GBDATA *gb_main = global.get_gb_main();
1142  GBDATA *gbd = selector->current(root, gb_main);
1143 
1144  if (!gbd) {
1145  aw_message(GBS_global_string("You have to select a %s first", awt_itemtype_names[selector->get_item_type()]));
1146  }
1147  else {
1148  GB_ERROR error = awt_open_ACI_URL_with_item(root, gb_main, gbd, url_aci->c_str());
1149  if (error) aw_message(error);
1150  }
1151 }
1152 
1153 
1154 // ---------------------------
1155 // User Mask Commands
1156 
1175 
1178 };
1179 
1181  const char *cmd_name;
1183 };
1184 
1186  { "TEXTFIELD", CMD_TEXTFIELD },
1187  { "NUMFIELD", CMD_NUMFIELD },
1188  { "CHECKBOX", CMD_CHECKBOX },
1189  { "RADIO", CMD_RADIO },
1190  { "OPENMASK", CMD_OPENMASK },
1191  { "CHANGEMASK", CMD_CHANGEMASK },
1192  { "TEXT", CMD_TEXT },
1193  { "SELF", CMD_SELF },
1194  { "NEW_LINE", CMD_NEW_LINE },
1195  { "NEW_SECTION", CMD_NEW_SECTION },
1196  { "WWW", CMD_WWW },
1197  { "ID", CMD_ID },
1198  { "GLOBAL", CMD_GLOBAL },
1199  { "LOCAL", CMD_LOCAL },
1200  { "SHOW", CMD_SHOW },
1201  { "ASSIGN", CMD_ASSIGN },
1202  { "SCRIPT", CMD_SCRIPT },
1203 
1204  { NULp, CMD_UNKNOWN }
1205 };
1206 
1207 inline MaskCommand findCommand(const string& cmd_name) {
1208  int mc = 0;
1209 
1210  for (; mask_command[mc].cmd != CMD_UNKNOWN; ++mc) {
1211  if (mask_command[mc].cmd_name == cmd_name) {
1212  return mask_command[mc].cmd;
1213  }
1214  }
1215  return CMD_UNKNOWN;
1216 }
1217 
1218 static void parse_CMD_RADIO(string& line, size_t& scan_pos, GB_ERROR& error, const string& command,
1219  awt_mask_item_ptr& handler1, awt_mask_item_ptr& handler2, awt_input_mask_global& global)
1220 {
1221  string label, data_path;
1222  int default_position = -1, orientation = -1;
1223  vector<string> buttons;
1224  vector<string> values;
1225  bool allow_edit = false;
1226  int width = -1;
1227  int edit_position = -1;
1228 
1229  label = scan_string_parameter(line, scan_pos, error);
1230  if (!error) data_path = check_data_path(scan_string_parameter(line, scan_pos, error), error);
1231  if (!error) default_position = scan_long_parameter(line, scan_pos, error);
1232  if (!error) {
1233  orientation = scan_flag_parameter(line, scan_pos, error, "HVXY");
1234  orientation = orientation&1;
1235  }
1236  while (!error && !was_last_parameter) {
1237  string but = scan_string_parameter(line, scan_pos, error);
1238  string val = "";
1239  if (!error) {
1240  int keyword_index;
1241  const char *allowed_keywords[] = { "ALLOW_EDIT", NULp };
1242  scan_string_or_keyword_parameter(line, scan_pos, error, val, keyword_index, allowed_keywords);
1243 
1244  if (!error) {
1245  if (keyword_index != -1) { // found keyword
1246  if (allow_edit) error = "ALLOW_EDIT is allowed only once for each RADIO";
1247 
1248  if (!error) width = scan_long_parameter(line, scan_pos, error, MIN_TEXTFIELD_SIZE, MAX_TEXTFIELD_SIZE);
1249  if (!error) val = scan_string_parameter(line, scan_pos, error);
1250 
1251  if (!error) {
1252  allow_edit = true;
1253  edit_position = buttons.size()+1; // positions are 1..n
1254  buttons.push_back(but);
1255  values.push_back(val);
1256  }
1257  }
1258  else { // found string
1259  buttons.push_back(but);
1260  values.push_back(val);
1261  }
1262  }
1263  }
1264  }
1265  check_last_parameter(error, command);
1266 
1267  if (!error && (buttons.size()<2)) error = "You have to define at least 2 buttons.";
1268 
1269  if (!error && allow_edit && edit_position != default_position) {
1270  error = GBS_global_string("Invalid default %i (must be index of ALLOW_EDIT: %i )", default_position, edit_position);
1271  }
1272  if (!error && (default_position<1 || size_t(default_position)>buttons.size())) {
1273  error = GBS_global_string("Invalid default %i (valid: 1..%zu)", default_position, buttons.size());
1274  }
1275 
1276  if (!error) {
1277  if (allow_edit) {
1278  // create radio-button + textfield
1279  handler1 = new awt_radio_button(global, data_path, label, default_position-1, orientation, buttons, values);
1280  handler2 = new awt_input_field(global, data_path, "", width, "", GB_STRING);
1281  }
1282  else {
1283  handler1 = new awt_radio_button(global, data_path, label, default_position-1, orientation, buttons, values);
1284  }
1285  }
1286 }
1287 
1288 static string find_internal_name(const string& mask_name, bool search_in_local) {
1289  const char *internal_local = NULp;
1290  const char *internal_global = NULp;
1291 
1292  for (int id = 0; ; ++id) {
1293  const awt_input_mask_descriptor *descriptor = AWT_look_input_mask(id);
1294  if (!descriptor) break;
1295 
1296  const char *internal_name = descriptor->get_internal_maskname();
1297 
1298  if (strcmp(internal_name+1, mask_name.c_str()) == 0) {
1299  if (descriptor->is_local_mask()) {
1300  awt_assert(!internal_local);
1301  internal_local = internal_name;
1302  }
1303  else {
1304  awt_assert(!internal_global);
1305  internal_global = internal_name;
1306  }
1307  }
1308  }
1309 
1310  return (search_in_local && internal_local) ? internal_local : null2empty(internal_global);
1311 }
1312 
1313 // ----------------------------------
1314 // class awt_marked_checkbox
1315 
1316 class awt_marked_checkbox FINAL_TYPE : public awt_viewport, public awt_linked_to_item {
1317 private:
1318 
1319  string generate_baseName(awt_input_mask_global& global_) {
1320  return GBS_global_string("%s/marked", global_.get_maskid().c_str());
1321  }
1322 
1323 public:
1325  awt_viewport(global_, generate_baseName(global_), "0", false, label_),
1327  {}
1329 
1330  GB_ERROR link_to(GBDATA *gb_new_item) OVERRIDE; // link to a new item
1331  GB_ERROR relink() OVERRIDE { return link_to(mask_global().get_selected_item()); }
1332  void awar_changed() OVERRIDE;
1333  void db_changed() OVERRIDE;
1334  void general_item_change() OVERRIDE { db_changed(); } // called if item was changed (somehow)
1335  void build_widget(AW_window *aws) OVERRIDE; // builds the widget at the current position
1336 };
1337 
1338 GB_ERROR awt_marked_checkbox::link_to(GBDATA *gb_new_item) { // link to a new item
1339  GB_ERROR error = NULp;
1340  GB_transaction ta(mask_global().get_gb_main());
1341 
1342  remove_awarItem_callbacks(); // unbind awar callbacks temporarily
1343 
1344  if (item()) {
1345  remove_db_callbacks(); // ignore result (if handled db-entry was deleted, it returns an error)
1346  set_item(NULp);
1347  }
1348 
1349  if (gb_new_item) {
1350  set_item(gb_new_item);
1351  db_changed();
1352  error = add_db_callbacks();
1353  }
1354 
1355  add_awarItem_callbacks(); // rebind awar callbacks
1356  return error;
1357 }
1358 
1359 void awt_marked_checkbox::awar_changed() { // called when awar changes
1360  if (item()) {
1361  string value = get_value();
1362  bool marked = value == "yes";
1363  GB_transaction ta(mask_global().get_gb_main());
1364  GB_write_flag(item(), marked);
1365  }
1366  else {
1367  mask_global().no_item_selected();
1368  }
1369 }
1370 
1371 void awt_marked_checkbox::db_changed() {
1372  if (item()) {
1373  GB_transaction ta(mask_global().get_gb_main());
1374  set_value(GB_read_flag(item()) ? "yes" : "no");
1375  }
1376 }
1377 
1378 void awt_marked_checkbox::build_widget(AW_window *aws) { // builds the widget at the current position
1379  const string& lab = get_label();
1380  if (lab.length()) aws->label(lab.c_str());
1381 
1382  aws->create_toggle(awar_name().c_str());
1383 }
1384 
1385 static GB_ERROR writeDefaultMaskfile(const string& fullname, const string& maskname, const string& itemtypename, bool hidden) {
1386  FILE *out = fopen(fullname.c_str(), "wt");
1387  if (!out) return GBS_global_string("Can't open '%s'", fullname.c_str());
1388 
1389  fprintf(out,
1390  "%s\n"
1391  "# New mask '%s'\n\n"
1392  "# What kind of item to edit:\n"
1393  "@ITEMTYPE=%s\n\n"
1394  "# Window title:\n"
1395  "@TITLE=%s\n\n", ARB_INPUT_MASK_ID, maskname.c_str(), itemtypename.c_str(), maskname.c_str());
1396 
1397  fprintf(out,
1398  "# Should mask appear in 'User mask' menu\n"
1399  "@HIDE=%i\n\n", int(hidden));
1400 
1401  fputs("# Spacing in window:\n"
1402  "@X_SPACING=5\n"
1403  "@Y_SPACING=3\n\n"
1404  "# Show edit/reload button?\n"
1405  "@EDIT=1\n"
1406  "# Show 'edit enable' toggle?\n"
1407  "@EDIT_ENABLE=1\n"
1408  "# Show 'marked' toggle?\n"
1409  "@SHOW_MARKED=1\n"
1410  "\n# ---------------------------\n"
1411  "# The definition of the mask:\n\n"
1412  "@MASK_BEGIN\n\n"
1413  " TEXT(\"You are editing\") SELF()\n"
1414  " NEW_SECTION()\n"
1415  " TEXTFIELD(\"Full name\", \"full_name\", 30)\n\n"
1416  "@MASK_END\n\n", out);
1417 
1418  fclose(out);
1419  return NULp;
1420 }
1421 
1422 class ID_checker {
1423  bool reloading;
1424  set<string> seen;
1425  set<string> dup;
1426  string curr_id;
1427 
1428  bool is_known(const string& id) { return seen.find(id) != seen.end(); }
1429 
1430  string makeUnique(string id) {
1431  if (is_known(id)) {
1432  dup.insert(id);
1433  for (int i = 0; ; ++i) {
1434  string undup = GBS_global_string("%s%i", id.c_str(), i);
1435  if (!is_known(undup)) {
1436  id = undup;
1437  break;
1438  }
1439  }
1440  }
1441  seen.insert(id);
1442  return id;
1443  }
1444 
1445 public:
1446  ID_checker(bool reloading_)
1447  : reloading(reloading_)
1448  {}
1449 
1450  const char *fromKey(const char *id) {
1451  curr_id = makeUnique(id);
1452  return reloading ? NULp : curr_id.c_str();
1453  }
1454  const char *fromText(const string& anystr) {
1455  SmartCharPtr key = GBS_string_2_key(anystr.c_str());
1456  return fromKey(&*key);
1457  }
1458 
1459  bool seenDups() const { return !dup.empty(); }
1460  const char *get_dup_error(const string& maskName) const {
1461  string dupList;
1462  for (set<string>::iterator d = dup.begin(); d != dup.end(); ++d) {
1463  dupList = dupList+" '"+*d+"'";
1464  }
1465  return GBS_global_string("Warning: duplicated IDs seen in '%s':\n"
1466  "%s\n"
1467  "(they need to be unique; change button texts etc. to change them)",
1468  maskName.c_str(), dupList.c_str());
1469  }
1470 };
1471 
1472 static awt_input_mask_ptr awt_create_input_mask(AW_root *root, GBDATA *gb_main, const awt_item_type_selector *sel,
1473  const string& mask_name, bool local, GB_ERROR& error, bool reloading) {
1474  awt_input_mask_ptr mask;
1475 
1476  error = NULp;
1477 
1478  FILE *in = NULp;
1479  {
1480  string fullfile = inputMaskFullname(mask_name, local);
1481  in = fopen(fullfile.c_str(), "rt");
1482  if (!in) error = GBS_global_string("Can't open '%s'", fullfile.c_str());
1483  }
1484 
1485  if (!error) {
1486  bool mask_began = false;
1487  bool mask_ended = false;
1488 
1489  // data to be scanned :
1490  string title;
1491  string itemtypename;
1492  int x_spacing = 5;
1493  int y_spacing = 3;
1494  bool edit_reload = false;
1495  bool edit_enable = true;
1496  bool show_marked = true;
1497 
1498  string line;
1499  size_t lineNo = 0;
1500  size_t err_pos = 0; // 0 = unknown; string::npos = at end of line; else position+1;
1501 
1502  error = readLine(in, line, lineNo);
1503 
1504  if (!error && line != ARB_INPUT_MASK_ID) {
1505  error = "'" ARB_INPUT_MASK_ID "' expected";
1506  }
1507 
1508  while (!error && !mask_began && !feof(in)) {
1509  error = readLine(in, line, lineNo);
1510  if (error) break;
1511 
1512  if (line[0] == '#') continue; // ignore comments
1513 
1514  if (line == "@MASK_BEGIN") mask_began = true;
1515  else {
1516  size_t at = line.find('@');
1517  size_t eq = line.find('=', at);
1518 
1519  if (at == string::npos || eq == string::npos) {
1520  continue;
1521  }
1522  else {
1523  string parameter = line.substr(at+1, eq-at-1);
1524  string value = line.substr(eq+1);
1525 
1526  if (parameter == "ITEMTYPE") itemtypename = value;
1527  else if (parameter == "TITLE") title = value;
1528  else if (parameter == "X_SPACING") x_spacing = atoi(value.c_str());
1529  else if (parameter == "Y_SPACING") y_spacing = atoi(value.c_str());
1530  else if (parameter == "EDIT") edit_reload = atoi(value.c_str()) != 0;
1531  else if (parameter == "EDIT_ENABLE") edit_enable = atoi(value.c_str()) != 0;
1532  else if (parameter == "SHOW_MARKED") show_marked = atoi(value.c_str()) != 0;
1533  else if (parameter == "HIDE") ; // ignore parameter here
1534  else {
1535  error = GBS_global_string("Unknown parameter '%s'", parameter.c_str());
1536  }
1537  }
1538  }
1539  }
1540 
1541  if (!error && !mask_began) error = "@MASK_BEGIN expected";
1542 
1543  // check data :
1544  if (!error) {
1545  if (title == "") title = string("Untitled (")+mask_name+")";
1546  awt_item_type itemtype = AWT_getItemType(itemtypename);
1547 
1548  if (itemtype == AWT_IT_UNKNOWN) error = GBS_global_string("Unknown @ITEMTYPE '%s'", itemtypename.c_str());
1549  if (itemtype != sel->get_item_type()) error = GBS_global_string("Mask is designed for @ITEMTYPE '%s' (current @ITEMTYPE '%s')",
1550  itemtypename.c_str(), awt_itemtype_names[sel->get_item_type()]);
1551 
1552  // create mask
1553  if (!error) mask = new awt_input_mask(root, gb_main, mask_name, itemtype, local, sel, edit_enable);
1554  }
1555 
1556  // create window
1557  if (!error) {
1558  awt_assert(!mask.isNull());
1559  AW_window_simple*& aws = mask->get_window();
1560  aws = new AW_window_simple;
1561 
1562  ID_checker ID(reloading);
1563 
1564  {
1565  char *window_id = GBS_global_string_copy("INPUT_MASK_%s", mask->mask_global().get_maskid().c_str()); // create a unique id for each mask
1566  aws->init(root, window_id, title.c_str());
1567  free(window_id);
1568  }
1569 
1570  aws->load_xfig(NULp, true);
1571  aws->recalc_size_atShow(AW_RESIZE_DEFAULT); // ignore user size!
1572 
1573  aws->auto_space(x_spacing, y_spacing);
1574  aws->at_newline();
1575 
1576  aws->callback(AW_POPDOWN); aws->create_button(ID.fromKey("CLOSE"), "CLOSE", "C");
1577  aws->callback(makeHelpCallback("input_mask.hlp")); aws->create_button(ID.fromKey("HELP"), "HELP", "H");
1578 
1579  if (edit_reload) {
1580  aws->callback(makeWindowCallback(AWT_edit_input_mask, &mask->mask_global().get_maskname(), mask->mask_global().is_local_mask()));
1581  aws->create_button(NULp, "!EDIT", "E");
1582 
1583  aws->callback(makeWindowCallback(AWT_reload_input_mask, &mask->mask_global().get_internal_maskname()));
1584  aws->create_button(NULp, "RELOAD", "R");
1585  }
1586 
1587  if (edit_reload && edit_enable && show_marked) aws->at_newline();
1588 
1589  if (edit_enable) {
1590  aws->label("Enable edit?");
1591  aws->create_toggle(AWAR_INPUT_MASKS_EDIT_ENABLED);
1592  }
1593 
1594  if (show_marked) {
1595  awt_mask_item_ptr handler = new awt_marked_checkbox(mask->mask_global(), "Marked");
1596  mask->add_handler(handler);
1597  if (handler->is_viewport()) handler->to_viewport()->build_widget(aws);
1598 
1599  }
1600 
1601  aws->at_newline();
1602 
1603  vector<int> horizontal_lines; // y-positions of horizontal lines
1604  map<string, size_t> referenced_ids; // all ids that where referenced by the script (size_t contains lineNo of last reference)
1605  map<string, size_t> declared_ids; // all ids that where declared by the script (size_t contains lineNo of declaration)
1606 
1607  awt_mask_item_ptr lasthandler;
1608 
1609  // read mask itself :
1610  while (!error && !mask_ended && !feof(in)) {
1611  error = readLine(in, line, lineNo);
1612  if (error) break;
1613 
1614  if (line.empty()) continue;
1615  if (line[0] == '#') continue;
1616 
1617  if (line == "@MASK_END") {
1618  mask_ended = true;
1619  }
1620  else {
1621  PARSE_REST_OF_LINE :
1622  was_last_parameter = false;
1623  size_t start = next_non_white(line, 0);
1624  if (start != string::npos) { // line contains sth
1625  size_t after_command = line.find_first_of(string(" \t("), start);
1626  if (after_command == string::npos) {
1627  string command = line.substr(start);
1628  error = GBS_global_string("arguments missing after '%s'", command.c_str());
1629  }
1630  else {
1631  string command = line.substr(start, after_command-start);
1632  size_t paren_open = line.find('(', after_command);
1633  if (paren_open == string::npos) {
1634  error = GBS_global_string("'(' expected after '%s'", command.c_str());
1635  }
1636  else {
1637  size_t scan_pos = paren_open+1;
1638  awt_mask_item_ptr handler;
1639  awt_mask_item_ptr radio_edit_handler;
1640  MaskCommand cmd = findCommand(command);
1641 
1642  // --------------------------------------
1643  // code for different commands :
1644 
1645  if (cmd == CMD_TEXTFIELD) {
1646  string label, data_path;
1647  long width = -1;
1648  label = scan_string_parameter(line, scan_pos, error);
1649  if (!error) data_path = check_data_path(scan_string_parameter(line, scan_pos, error), error);
1650  if (!error) width = scan_long_parameter(line, scan_pos, error, MIN_TEXTFIELD_SIZE, MAX_TEXTFIELD_SIZE);
1651  check_last_parameter(error, command);
1652 
1653  if (!error) handler = new awt_input_field(mask->mask_global(), data_path, label, width, "", GB_STRING);
1654  }
1655  else if (cmd == CMD_NUMFIELD) {
1656  string label, data_path;
1657  long width = -1;
1658 
1659  long min = LONG_MIN;
1660  long max = LONG_MAX;
1661 
1662  label = scan_string_parameter(line, scan_pos, error);
1663  if (!error) data_path = check_data_path(scan_string_parameter(line, scan_pos, error), error);
1664  if (!error) width = scan_long_parameter(line, scan_pos, error, MIN_TEXTFIELD_SIZE, MAX_TEXTFIELD_SIZE);
1665  if (!was_last_parameter) {
1666  if (!error) min = scan_optional_parameter(line, scan_pos, error, LONG_MIN);
1667  if (!error) max = scan_optional_parameter(line, scan_pos, error, LONG_MAX);
1668  }
1669  check_last_parameter(error, command);
1670 
1671  if (!error) handler = new awt_numeric_input_field(mask->mask_global(), data_path, label, width, 0, min, max);
1672  }
1673  else if (cmd == CMD_CHECKBOX) {
1674  string label, data_path;
1675  bool checked = false;
1676  label = scan_string_parameter(line, scan_pos, error);
1677  if (!error) data_path = check_data_path(scan_string_parameter(line, scan_pos, error), error);
1678  if (!error) checked = scan_bool_parameter(line, scan_pos, error);
1679  check_last_parameter(error, command);
1680 
1681  if (!error) handler = new awt_check_box(mask->mask_global(), data_path, label, checked);
1682  }
1683  else if (cmd == CMD_RADIO) {
1684  parse_CMD_RADIO(line, scan_pos, error, command, handler, radio_edit_handler, mask->mask_global());
1685  }
1686  else if (cmd == CMD_SCRIPT) {
1687  string id, script;
1688  id = scan_identifier(line, scan_pos, error);
1689  if (!error) script = scan_string_parameter(line, scan_pos, error, true);
1690  check_last_parameter(error, command);
1691 
1692  if (!error) {
1693  handler = new awt_script(mask->mask_global(), script);
1694  error = handler->set_name(id, false);
1695  declared_ids[id] = lineNo;
1696  }
1697  }
1698  else if (cmd == CMD_GLOBAL || cmd == CMD_LOCAL) {
1699  string id, def_value;
1700 
1701  id = scan_identifier(line, scan_pos, error);
1702  bool global_exists = mask->mask_global().has_global_id(id);
1703  bool local_exists = mask->mask_global().has_local_id(id);
1704 
1705  if ((cmd == CMD_GLOBAL && local_exists) || (cmd == CMD_LOCAL && global_exists)) {
1706  error = GBS_global_string("ID '%s' already declared as %s ID (rename your local id)",
1707  id.c_str(), cmd == CMD_LOCAL ? "global" : "local");
1708  }
1709  else if (cmd == CMD_LOCAL && local_exists) {
1710  error = GBS_global_string("ID '%s' declared twice", id.c_str());
1711  }
1712 
1713  if (!error) def_value = scan_string_parameter(line, scan_pos, error);
1714  if (!error) {
1715  if (cmd == CMD_GLOBAL) {
1716  if (!mask->mask_global().has_global_id(id)) { // do not create globals more than once
1717  // and never free them -> so we don't need pointer
1718  new awt_variable(mask->mask_global(), id, true, def_value, error);
1719  }
1720  awt_assert(handler.isNull());
1721  }
1722  else {
1723  handler = new awt_variable(mask->mask_global(), id, false, def_value, error);
1724  }
1725  declared_ids[id] = lineNo;
1726  }
1727  }
1728  else if (cmd == CMD_ID) {
1729  string id = scan_identifier(line, scan_pos, error);
1730  check_last_parameter(error, command);
1731 
1732  if (!error) {
1733  if (lasthandler.isNull()) {
1734  error = "ID() may only be used BEHIND another element";
1735  }
1736  else {
1737  error = lasthandler->set_name(id, false);
1738  declared_ids[id] = lineNo;
1739  }
1740  }
1741  }
1742  else if (cmd == CMD_SHOW) {
1743  string label, id;
1744  long width = -1;
1745  awt_mask_item *item = NULp;
1746 
1747  label = scan_string_parameter(line, scan_pos, error);
1748  if (!error) id = scan_identifier(line, scan_pos, error);
1749  if (!error) item = (awt_mask_item*)mask->mask_global().get_identified_item(id, error);
1750  if (!error) width = scan_long_parameter(line, scan_pos, error, MIN_TEXTFIELD_SIZE, MAX_TEXTFIELD_SIZE);
1751  check_last_parameter(error, command);
1752 
1753  if (!error) {
1754  awt_mask_awar_item *awar_item = dynamic_cast<awt_mask_awar_item*>(item);
1755 
1756  if (awar_item) { // item has an awar -> create a viewport using that awar
1757  handler = new awt_text_viewport(awar_item, label, width);
1758  }
1759  else { // item has no awar -> test if it's a script
1760  awt_script *script = dynamic_cast<awt_script*>(item);
1761  if (script) handler = new awt_script_viewport(mask->mask_global(), script, label, width);
1762  else error = "SHOW cannot be used on this ID-type";
1763  }
1764 
1765  referenced_ids[id] = lineNo;
1766  }
1767  }
1768  else if (cmd == CMD_OPENMASK || cmd == CMD_CHANGEMASK) {
1769  string label, mask_to_start;
1770  label = scan_string_parameter(line, scan_pos, error);
1771  if (!error) mask_to_start = scan_string_parameter(line, scan_pos, error);
1772  check_last_parameter(error, command);
1773 
1774  if (!error) {
1775  string mask_to_start_internal = find_internal_name(mask_to_start, local);
1776 
1777  if (mask_to_start_internal.length() == 0) {
1778  error = "Can't detect which mask to load";
1779  }
1780  else {
1781  const char *key = ID.fromText(label);
1782 
1783  string *const internal_mask_name = new string(mask->mask_global().get_internal_maskname());
1784  string *const mask_to_open = new string(mask_to_start_internal);
1785 
1786  awt_assert(internal_mask_name);
1787  awt_assert(mask_to_open);
1788 
1789  aws->callback(makeWindowCallback(cmd == CMD_OPENMASK ? AWT_open_input_mask : AWT_change_input_mask, internal_mask_name, mask_to_open));
1790 
1791  aws->button_length(label.length()+2);
1792  aws->create_button(key, label.c_str());
1793  }
1794  }
1795  }
1796  else if (cmd == CMD_WWW) {
1797  string button_text, url_aci;
1798  button_text = scan_string_parameter(line, scan_pos, error);
1799  if (!error) url_aci = scan_string_parameter(line, scan_pos, error, true);
1800  check_last_parameter(error, command);
1801 
1802  if (!error) {
1803  const char *key = ID.fromText(button_text);
1804  aws->callback(makeWindowCallback(AWT_input_mask_browse_url, new string(url_aci), &*mask));
1805  aws->button_length(button_text.length()+2);
1806  aws->create_button(key, button_text.c_str());
1807  }
1808  }
1809  else if (cmd == CMD_ASSIGN) {
1810  string id_dest, id_source, button_text;
1811 
1812  id_dest = scan_identifier(line, scan_pos, error);
1813  if (!error) id_source = scan_identifier(line, scan_pos, error);
1814  if (!error) button_text = scan_string_parameter(line, scan_pos, error);
1815 
1816  if (!error) {
1817  referenced_ids[id_source] = lineNo;
1818  referenced_ids[id_dest] = lineNo;
1819 
1820  const char *key = ID.fromText(button_text);
1821  aws->callback(makeWindowCallback(AWT_input_mask_perform_action, static_cast<awt_mask_action*>(new awt_assignment(mask, id_dest, id_source))));
1822  aws->button_length(button_text.length()+2);
1823  aws->create_button(key, button_text.c_str());
1824  }
1825  }
1826  else if (cmd == CMD_TEXT) {
1827  string text;
1828  text = scan_string_parameter(line, scan_pos, error);
1829  check_last_parameter(error, command);
1830 
1831  if (!error) {
1832  aws->button_length(text.length()+2);
1833  aws->create_button(NULp, text.c_str());
1834  }
1835  }
1836  else if (cmd == CMD_SELF) {
1837  check_no_parameter(line, scan_pos, error, command);
1838  if (!error) {
1839  const awt_item_type_selector *selector = mask->mask_global().get_selector();
1840  aws->button_length(selector->get_self_awar_content_length());
1841  aws->create_button(NULp, selector->get_self_awar());
1842  }
1843  }
1844  else if (cmd == CMD_NEW_LINE) {
1845  check_no_parameter(line, scan_pos, error, command);
1846  if (!error) {
1847  int width, height;
1848  aws->get_window_size(width, height);
1849  aws->at_shift(0, 2*SEC_YBORDER+SEC_LINE_WIDTH);
1850  }
1851  }
1852  else if (cmd == CMD_NEW_SECTION) {
1853  check_no_parameter(line, scan_pos, error, command);
1854  if (!error) {
1855  int width, height;
1856  aws->get_window_size(width, height);
1857  horizontal_lines.push_back(height);
1858  aws->at_shift(0, 2*SEC_YBORDER+SEC_LINE_WIDTH);
1859  }
1860  }
1861  else if (cmd == CMD_UNKNOWN) {
1862  error = GBS_global_string("Unknown command '%s'", command.c_str());
1863  }
1864  else {
1865  error = GBS_global_string("No handler for '%s'", command.c_str());
1866  awt_assert(0);
1867  }
1868 
1869  // --------------------------
1870  // insert handler(s)
1871 
1872  if (!handler.isNull() && !error) {
1873  if (!radio_edit_handler.isNull()) { // special radio handler
1874  const awt_radio_button *radio = dynamic_cast<const awt_radio_button*>(&*handler);
1875  awt_assert(radio);
1876 
1877  int x_start, y_start;
1878 
1879  aws->get_at_position(&x_start, &y_start);
1880 
1881  mask->add_handler(handler);
1882  handler->to_viewport()->build_widget(aws);
1883 
1884  int x_end, y_end, dummy;
1885  aws->get_at_position(&x_end, &dummy);
1886  aws->at_newline();
1887  aws->get_at_position(&dummy, &y_end);
1888 
1889  int height = y_end-y_start;
1890  int each_line = height/radio->no_of_toggles();
1891  int y_offset = each_line*(radio->default_toggle());
1892 
1893  aws->at(x_end+x_spacing, y_start+y_offset);
1894 
1895  mask->add_handler(radio_edit_handler);
1896  radio_edit_handler->to_viewport()->build_widget(aws);
1897 
1898  radio_edit_handler.setNull();
1899  }
1900  else {
1901  mask->add_handler(handler);
1902  if (handler->is_viewport()) handler->to_viewport()->build_widget(aws);
1903  }
1904  lasthandler = handler; // store handler (used by CMD_ID)
1905  }
1906 
1907  // parse rest of line or abort
1908  if (!error) {
1909  line = line.substr(scan_pos);
1910  goto PARSE_REST_OF_LINE;
1911  }
1912  err_pos = scan_pos;
1913  if (err_pos != string::npos) err_pos++; // because 0 means unknown
1914  }
1915  }
1916  }
1917  else { // reached the end of the current line
1918  aws->at_newline();
1919  }
1920  }
1921  }
1922 
1923  // check declarations and references
1924  if (!error) {
1925  for (map<string, size_t>::const_iterator r = referenced_ids.begin(); r != referenced_ids.end(); ++r) {
1926  if (declared_ids.find(r->first) == declared_ids.end()) {
1927  error = GBS_global_string("ID '%s' used in line #%zu was not declared", r->first.c_str(), r->second);
1928  aw_message(error);
1929  }
1930  }
1931 
1932  for (map<string, size_t>::const_iterator d = declared_ids.begin(); d != declared_ids.end(); ++d) {
1933  if (referenced_ids.find(d->first) == referenced_ids.end()) {
1934  const char *warning = GBS_global_string("ID '%s' declared in line #%zu is never used in %s",
1935  d->first.c_str(), d->second, mask_name.c_str());
1936  aw_message(warning);
1937  }
1938  }
1939 
1940  if (error) error = "Inconsistent IDs";
1941  }
1942 
1943  if (!error) {
1944  if (!horizontal_lines.empty()) { // draw all horizontal lines
1945  int width, height;
1946  aws->get_window_size(width, height);
1947  for (vector<int>::const_iterator yi = horizontal_lines.begin(); yi != horizontal_lines.end(); ++yi) {
1948  int y = (*yi)+SEC_YBORDER;
1949  aws->draw_line(SEC_XBORDER, y, width-SEC_XBORDER, y, SEC_LINE_WIDTH, true);
1950  }
1951  }
1952 
1953  // fit the window
1954  aws->window_fit();
1955  }
1956 
1957  if (!error) link_mask_to_database(mask);
1958  if (ID.seenDups()) aw_message(ID.get_dup_error(mask_name));
1959  }
1960 
1961  if (error) {
1962  if (lineNo == 0) {
1963  ; // do not change error
1964  }
1965  else if (err_pos == 0) { // don't knows exact error position
1966  error = GBS_global_string("%s in line #%zu", error, lineNo);
1967  }
1968  else if (err_pos == string::npos) {
1969  error = GBS_global_string("%s at end of line #%zu", error, lineNo);
1970  }
1971  else {
1972  int wanted = 35;
1973  size_t end = line.length();
1974  string context;
1975  context.reserve(wanted);
1976  bool last_was_space = false;
1977 
1978  for (size_t ex = err_pos-1; ex<end && wanted>0; ++ex) {
1979  char ch = line[ex];
1980  bool this_is_space = ch == ' ';
1981 
1982  if (!this_is_space || !last_was_space) {
1983  context.append(1, ch);
1984  --wanted;
1985  }
1986  last_was_space = this_is_space;
1987  }
1988 
1989  error = GBS_global_string("%s in line #%zu at '%s...'", error, lineNo, context.c_str());
1990  }
1991  }
1992 
1993  fclose(in);
1994  }
1995 
1996  if (error) mask.setNull();
1997 
1998  return mask;
1999 }
2000 
2001 GB_ERROR AWT_initialize_input_mask(AW_root *root, GBDATA *gb_main, const awt_item_type_selector *sel, const char* internal_mask_name, bool local) {
2002  const char *mask_name = internal_mask_name+1;
2003  InputMaskList::iterator mask_iter = input_mask_list.find(internal_mask_name);
2004  GB_ERROR error = NULp;
2005  awt_input_mask_ptr old_mask;
2006  bool unlink_old = false;
2007 
2008  if (mask_iter != input_mask_list.end() && mask_iter->second->reload_on_reinit()) { // reload wanted ?
2009  // erase mask (so it loads again from scratch)
2010  old_mask = mask_iter->second;
2011  input_mask_list.erase(mask_iter);
2012  mask_iter = input_mask_list.end();
2013 
2014  old_mask->hide();
2015  unlink_old = true;
2016  }
2017 
2018  if (mask_iter == input_mask_list.end()) { // mask not loaded yet
2019  awt_input_mask_ptr newMask = awt_create_input_mask(root, gb_main, sel, mask_name, local, error, unlink_old);
2020  if (error) {
2021  error = GBS_global_string("Error reading %s (%s)", mask_name, error);
2022  if (!old_mask.isNull()) { // are we doing a reload or changemask ?
2023  input_mask_list[internal_mask_name] = old_mask; // error loading modified mask -> put old one back to mask-list
2024  unlink_old = false;
2025  }
2026  }
2027  else { // new mask has been generated
2028  input_mask_list[internal_mask_name] = newMask;
2029  }
2030  mask_iter = input_mask_list.find(internal_mask_name);
2031  }
2032 
2033  if (!error) {
2034  awt_assert(mask_iter != input_mask_list.end());
2035  mask_iter->second->get_window()->activate();
2036  }
2037 
2038  if (unlink_old) {
2039  old_mask->unlink(); // unlink old mask from database ()
2040  unlink_mask_from_database(old_mask);
2041  }
2042 
2043  if (error) aw_message(error);
2044  return error;
2045 }
2046 
2047 // start of implementation of class awt_input_mask:
2048 
2049 awt_input_mask::~awt_input_mask() {
2050  unlink();
2051  for (awt_mask_item_list::iterator h = handlers.begin(); h != handlers.end(); ++h) {
2052  (*h)->remove_name();
2053  }
2054 }
2055 
2056 void awt_input_mask::link_to(GBDATA *gb_item) {
2057  // this functions links/unlinks all registered item handlers to/from the database
2058  for (awt_mask_item_list::iterator h = handlers.begin(); h != handlers.end(); ++h) {
2059  if ((*h)->is_linked_item()) (*h)->to_linked_item()->link_to(gb_item);
2060  }
2061 }
2062 
2063 // -end- of implementation of class awt_input_mask.
2064 
2065 
2066 awt_input_mask_descriptor::awt_input_mask_descriptor(const char *title_, const char *maskname_, const char *itemtypename_, bool local, bool hidden_) {
2067  title = ARB_strdup(title_);
2068  internal_maskname = ARB_alloc<char>(strlen(maskname_)+2);
2069  internal_maskname[0] = local ? '0' : '1';
2070  strcpy(internal_maskname+1, maskname_);
2071  itemtypename = ARB_strdup(itemtypename_);
2072  local_mask = local;
2073  hidden = hidden_;
2074 }
2075 awt_input_mask_descriptor::~awt_input_mask_descriptor() {
2076  free(itemtypename);
2077  free(internal_maskname);
2078  free(title);
2079 }
2080 
2081 awt_input_mask_descriptor::awt_input_mask_descriptor(const awt_input_mask_descriptor& other) {
2082  title = ARB_strdup(other.title);
2083  internal_maskname = ARB_strdup(other.internal_maskname);
2084  itemtypename = ARB_strdup(other.itemtypename);
2085  local_mask = other.local_mask;
2086  hidden = other.hidden;
2087 }
2088 awt_input_mask_descriptor& awt_input_mask_descriptor::operator = (const awt_input_mask_descriptor& other) {
2089  if (this != &other) {
2090  free(itemtypename);
2091  free(internal_maskname);
2092  free(title);
2093 
2094  title = ARB_strdup(other.title);
2095  internal_maskname = ARB_strdup(other.internal_maskname);
2096  itemtypename = ARB_strdup(other.itemtypename);
2097  local_mask = other.local_mask;
2098  hidden = other.hidden;
2099  }
2100 
2101  return *this;
2102 }
2103 
2104 static bool scanned_existing_input_masks = false;
2105 static vector<awt_input_mask_descriptor> existing_masks;
2106 
2107 static void add_new_input_mask(const string& maskname, const string& fullname, bool local) {
2108  awt_input_mask_descriptor *descriptor = quick_scan_input_mask(maskname, fullname, local);
2109  if (descriptor) {
2110  existing_masks.push_back(*descriptor);
2111  delete descriptor;
2112  }
2113 }
2115  awt_assert(!scanned_existing_input_masks);
2116 
2117  for (int scope = 0; scope <= 1; ++scope) {
2118  const char *dirname = inputMaskDir(scope == AWT_SCOPE_LOCAL);
2119 
2120  if (!GB_is_directory(dirname)) {
2121  if (scope == AWT_SCOPE_LOCAL) { // in local scope
2122  GB_ERROR warning = GB_create_directory(dirname); // try to create directory
2123  if (warning) GB_warning(warning);
2124  }
2125  }
2126 
2127  DIR *dirp = opendir(dirname);
2128  if (!dirp) {
2129  fprintf(stderr, "Warning: No such directory '%s'\n", dirname);
2130  }
2131  else {
2132  struct dirent *dp;
2133  for (dp = readdir(dirp); dp; dp = readdir(dirp)) {
2134  struct stat st;
2135  string maskname = dp->d_name;
2136  string fullname = inputMaskFullname(maskname, scope == AWT_SCOPE_LOCAL);
2137 
2138  if (stat(fullname.c_str(), &st)) continue;
2139  if (!S_ISREG(st.st_mode)) continue;
2140  // now we have a regular file
2141 
2142  size_t ext_pos = maskname.find(".mask");
2143 
2144  if (ext_pos != string::npos && maskname.substr(ext_pos) == ".mask") {
2145  awt_input_mask_descriptor *descriptor = quick_scan_input_mask(maskname, fullname, scope == AWT_SCOPE_LOCAL);
2146  if (descriptor) { // we found a input mask file
2147  existing_masks.push_back(*descriptor);
2148  delete descriptor;
2149  }
2150  }
2151  }
2152  closedir(dirp);
2153  }
2154  }
2155  scanned_existing_input_masks = true;
2156 }
2157 
2158 const awt_input_mask_descriptor *AWT_look_input_mask(int id) {
2159  if (!scanned_existing_input_masks) scan_existing_input_masks();
2160 
2161  if (id<0 || size_t(id) >= existing_masks.size()) return NULp;
2162 
2163  const awt_input_mask_descriptor *descriptor = &existing_masks[id];
2164  return descriptor;
2165 }
2166 
2167 awt_item_type AWT_getItemType(const string& itemtype_name) {
2169 
2170  for (int i = AWT_IT_UNKNOWN+1; i<AWT_IT_TYPES; ++i) {
2171  if (itemtype_name == awt_itemtype_names[i]) {
2172  type = awt_item_type(i);
2173  break;
2174  }
2175  }
2176 
2177  return type;
2178 }
2179 
2180 // -----------------------------
2181 // Registered Itemtypes
2182 
2184  // stores information about so-far-used item types
2185  RefPtr<AW_window_menu_modes> awm; // the main window responsible for opening windows
2186  AWT_OpenMaskWindowCallback open_window_cb; // callback to open the window
2187 
2188 public:
2190  awm(NULp),
2191  open_window_cb(NULp)
2192  {}
2194  awm(awm_),
2195  open_window_cb(open_window_cb_)
2196  {}
2197 
2198  AW_window_menu_modes *getWindow() const { return awm; }
2199  AWT_OpenMaskWindowCallback getOpenCb() const { return open_window_cb; }
2200 };
2201 
2202 typedef map<awt_item_type, AWT_registered_itemtype> TypeRegistry;
2203 typedef TypeRegistry::const_iterator TypeRegistryIter;
2204 
2205 static TypeRegistry registeredTypes;
2206 
2208  TypeRegistryIter registered = registeredTypes.find(type);
2209  GB_ERROR error = NULp;
2210 
2211  if (registered == registeredTypes.end()) error = GBS_global_string("Type '%s' not registered (yet)", awt_itemtype_names[type]);
2212  else registered->second.getOpenCb()(registered->second.getWindow(), mask_id, NULp);
2213 
2214  return error;
2215 }
2216 
2218  TypeRegistryIter alreadyRegistered = registeredTypes.find(type);
2219  if (alreadyRegistered == registeredTypes.end()) {
2220  registeredTypes[type] = AWT_registered_itemtype(awm, open_window_cb);
2221  }
2222 #if defined(DEBUG)
2223  else {
2224  awt_assert(alreadyRegistered->second.getOpenCb() == open_window_cb);
2225  }
2226 #endif // DEBUG
2227 }
2228 
2229 // ----------------------------------------------
2230 // Create a new input mask (interactive)
2231 
2232 static void create_new_mask_cb(AW_window *aww) {
2233  AW_root *awr = aww->get_root();
2234 
2235  string maskname = awr->awar(AWAR_INPUT_MASK_NAME)->read_char_pntr();
2236  {
2237  size_t ext = maskname.find(".mask");
2238 
2239  if (ext == string::npos) maskname = maskname+".mask";
2240  else maskname = maskname.substr(0, ext)+".mask";
2241 
2242  awr->awar(AWAR_INPUT_MASK_NAME)->write_string(maskname.c_str());
2243  }
2244 
2245 
2246  string itemname = awr->awar(AWAR_INPUT_MASK_ITEM)->read_char_pntr();
2247  int scope = awr->awar(AWAR_INPUT_MASK_SCOPE)->read_int();
2248  int hidden = awr->awar(AWAR_INPUT_MASK_HIDDEN)->read_int();
2249  bool local = scope == AWT_SCOPE_LOCAL;
2250  string maskfullname = inputMaskFullname(maskname, local);
2251  bool openMask = false;
2252 
2253  const char *error = NULp;
2254  struct stat st;
2255 
2256  if (stat(maskfullname.c_str(), &st) == 0) { // file exists
2257  int answer = aw_question("overwrite_mask", "File does already exist", "Overwrite mask,Cancel");
2258  switch (answer) {
2259  case 0:
2260  openMask = true;
2261  break;
2262  case 1: break;
2263  default: awt_assert(0); break;
2264  }
2265  }
2266  else { // file does not exist
2267  error = GB_create_directory(inputMaskDir(local));
2268  if (!error) {
2269  error = writeDefaultMaskfile(maskfullname, maskname, itemname, hidden);
2270  }
2271  if (!error) {
2272  add_new_input_mask(maskname, maskfullname, local);
2273  openMask = true;
2274  }
2275  }
2276 
2277  if (!error && openMask) {
2278  int mask_id;
2279  awt_item_type item_type = AWT_IT_UNKNOWN;
2280 
2281  for (mask_id = 0; ; ++mask_id) {
2282  const awt_input_mask_descriptor *descriptor = AWT_look_input_mask(mask_id);
2283  if (!descriptor) {
2284  error = GBS_global_string("Can't find descriptor for mask '%s'", maskname.c_str());
2285  break;
2286  }
2287 
2288  if (strcmp(descriptor->get_maskname(), maskname.c_str()) == 0 &&
2289  descriptor->is_local_mask() == local)
2290  {
2291  item_type = AWT_getItemType(descriptor->get_itemtypename());
2292  break; // found wanted mask id
2293  }
2294  }
2295 
2296  if (!error) {
2297  error = openMaskWindowByType(mask_id, item_type);
2298  }
2299  }
2300 
2301  if (error) aw_message(error);
2302 }
2303 
2304 static void create_new_input_mask(AW_window *aww, awt_item_type item_type) { // create new user mask (interactively)
2305  static AW_window_simple *aws = NULp;
2306 
2307  if (!aws) {
2308  aws = new AW_window_simple;
2309 
2310  aws->init(aww->get_root(), "CREATE_USER_MASK", "Create new input mask:");
2311 
2312  aws->auto_space(10, 10);
2313 
2314  aws->button_length(10);
2315  aws->callback(AW_POPDOWN);
2316  aws->create_button("CLOSE", "CLOSE");
2317  aws->callback(makeHelpCallback("input_mask_new.hlp"));
2318  aws->create_button("HELP", "HELP", "H");
2319 
2320  aws->at_newline();
2321 
2322  aws->label("Name of new input mask");
2323  aws->create_input_field(AWAR_INPUT_MASK_NAME, 20);
2324 
2325  aws->at_newline();
2326 
2327  aws->label("Item type");
2328  aws->create_option_menu(AWAR_INPUT_MASK_ITEM, true);
2329  for (int i = AWT_IT_UNKNOWN+1; i<AWT_IT_TYPES; ++i) {
2330  aws->insert_option(awt_itemtype_names[i], "", awt_itemtype_names[i]);
2331  }
2332  aws->update_option_menu();
2333 
2334  aws->at_newline();
2335 
2336  aws->label("Scope");
2337  aws->create_toggle_field(AWAR_INPUT_MASK_SCOPE, 1);
2338  aws->insert_toggle("Local", "L", AWT_SCOPE_LOCAL);
2339  aws->insert_toggle("Global", "G", AWT_SCOPE_GLOBAL);
2340  aws->update_toggle_field();
2341 
2342  aws->at_newline();
2343 
2344  aws->label("Visibility");
2345  aws->create_toggle_field(AWAR_INPUT_MASK_HIDDEN, 1);
2346  aws->insert_toggle("Normal", "N", 0);
2347  aws->insert_toggle("Hidden", "H", 1);
2348  aws->update_toggle_field();
2349 
2350  aws->at_newline();
2351 
2352  aws->callback(create_new_mask_cb);
2353  aws->create_button("CREATE", "CREATE", "C");
2354 
2355  aws->window_fit();
2356  }
2357 
2358  aws->activate();
2359  aww->get_root()->awar(AWAR_INPUT_MASK_ITEM)->write_string(awt_itemtype_names[item_type]);
2360 }
2361 
2362 // -----------------------------------------------------
2363 // Create User-Mask-Submenu for any application
2364 
2365 static bool hadMnemonic(char *availableMnemonics, char c) {
2366  // return true if 'c' occurs in 'availableMnemonics' (case ignored)
2367  // (in that case 'c' is removed from 'availableMnemonics').
2368  // returns false otherwise.
2369  char lc = tolower(c);
2370  char *cand = strchr(availableMnemonics, lc);
2371  if (cand) {
2372  char *last = strchr(cand+1, 0)-1;
2373  if (last>cand) {
2374  cand[0] = last[0];
2375  last[0] = 0;
2376  }
2377  else {
2378  awt_assert(last == cand);
2379  cand[0] = 0;
2380  }
2381  return true;
2382  }
2383  return false;
2384 }
2385 
2386 static char *selectMnemonic(const char *orgTitle, char *availableMnemonics, char& mnemonic) {
2387  // select (and remove) one from 'availableMnemonics' occurring in orgTitle
2388  // return selected in 'mnemonic'
2389  // return orgTitle (eventually modified if no matching mnemonic available)
2390 
2391  bool prevWasChar = false;
2392  for (int startOfWord = 1; startOfWord>=0; --startOfWord) {
2393  for (int i = 0; orgTitle[i]; ++i) {
2394  char c = orgTitle[i];
2395  if (isalnum(c)) {
2396  if (!prevWasChar || !startOfWord) {
2397  if (hadMnemonic(availableMnemonics, c)) {
2398  mnemonic = c;
2399  return ARB_strdup(orgTitle);
2400  }
2401  }
2402  prevWasChar = true;
2403  }
2404  else prevWasChar = false;
2405  }
2406  }
2407 
2408  for (int i = 0; i<2; ++i) {
2409  const char *takeAny = i ? availableMnemonics : "1234567890";
2410  for (int t = 0; takeAny[t]; ++t) {
2411  char c = takeAny[t];
2412  if (hadMnemonic(availableMnemonics, c)) {
2413  mnemonic = c;
2414  return GBS_global_string_copy("%s [%c]", orgTitle, c);
2415  }
2416  }
2417  }
2418 
2419  mnemonic = 0; // failed
2420  return ARB_strdup(orgTitle);
2421 }
2422 
2423 void AWT_create_mask_submenu(AW_window_menu_modes *awm, awt_item_type wanted_item_type, AWT_OpenMaskWindowCallback open_mask_window_cb, GBDATA *gb_main) {
2424  // add a user mask submenu at current position
2425  AW_root *awr = awm->get_root();
2426 
2428 
2429  awm->insert_sub_menu("User Masks", "k");
2430 
2431  char *availableMnemonics = ARB_strdup("abcdefghijklmopqrstuvwxyz0123456789"); // 'n' excluded!
2432 
2433  for (int scope = 0; scope <= 1; ++scope) {
2434  bool entries_made = false;
2435 
2436  for (int id = 0; ; ++id) {
2437  const awt_input_mask_descriptor *descriptor = AWT_look_input_mask(id);
2438 
2439  if (!descriptor) break;
2440  if (descriptor->is_local_mask() != (scope == AWT_SCOPE_LOCAL)) continue; // wrong scope type
2441 
2442  awt_item_type item_type = AWT_getItemType(descriptor->get_itemtypename());
2443 
2444  if (item_type == wanted_item_type) {
2445  if (!descriptor->is_hidden()) { // do not show masks with hidden-flag
2446  entries_made = true;
2447  char *macroname2key = GBS_string_2_key(descriptor->get_internal_maskname());
2448 #if defined(DEBUG) && 0
2449  printf("added user-mask '%s' with id=%i\n", descriptor->get_maskname(), id);
2450 #endif // DEBUG
2451  char mnemonic[2] = "x";
2452  char *mod_title = selectMnemonic(descriptor->get_title(), availableMnemonics, mnemonic[0]);
2453 
2454  awm->insert_menu_topic(macroname2key, mod_title, mnemonic, "input_mask.hlp", AWM_ALL, makeWindowCallback(open_mask_window_cb, id, gb_main));
2455  free(mod_title);
2456  free(macroname2key);
2457  }
2458  registerType(item_type, awm, open_mask_window_cb);
2459  }
2460  else if (item_type == AWT_IT_UNKNOWN) {
2461  aw_message(GBS_global_string("Unknown @ITEMTYPE '%s' in '%s'", descriptor->get_itemtypename(), descriptor->get_internal_maskname()));
2462  }
2463  }
2464  if (entries_made) awm->sep______________();
2465  }
2466 
2467  {
2468  const char *itemname = awt_itemtype_names[wanted_item_type];
2469  char *new_item_mask_id = GBS_global_string_copy("new_%s_mask", itemname);
2470  char *new_item_mask_label = GBS_global_string_copy("New %s mask..", itemname);
2471 
2472  awm->insert_menu_topic(new_item_mask_id, new_item_mask_label, "N", "input_mask_new.hlp", AWM_ALL, makeWindowCallback(create_new_input_mask, wanted_item_type));
2473 
2474  free(new_item_mask_label);
2475  free(new_item_mask_id);
2476  }
2477  free(availableMnemonics);
2478  awm->close_sub_menu();
2479 }
2480 
2482  // unlink from DB manually - there are too many smartptrs to
2483  // get rid of all of them before DB gets destroyed on exit
2484  for (InputMaskList::iterator i = input_mask_list.begin();
2485  i != input_mask_list.end();
2486  ++i)
2487  {
2488  i->second->unlink();
2489  }
2490  input_mask_list.clear();
2491 }
2492 
2493 
2494 void awt_item_type_selector::add_awar_callbacks(AW_root *root, const RootCallback& cb) const {
2495  root->awar(get_self_awar())->add_callback(cb);
2496 }
2497 
2498 void awt_item_type_selector::remove_awar_callbacks(AW_root *root, const RootCallback& cb) const {
2499  root->awar(get_self_awar())->remove_callback(cb);
2500 }
#define SEC_XBORDER
const awt_input_mask_global & mask_global() const
static bool hadMnemonic(char *availableMnemonics, char c)
std::string get_maskid() const
static InputMaskList input_mask_list
string inputMaskFullname(const string &mask_name, bool local)
const char * GB_ERROR
Definition: arb_core.h:25
virtual const char * get_self_awar() const =0
std::string awar2db(const std::string &awar_content) const OVERRIDE
string result
GB_TYPES type
void insert_toggle(AW_label toggle_label, const char *mnemonic, const char *var_value)
GB_ERROR relink() OVERRIDE
awt_item_type get_item_type() const
static GB_ERROR openMaskWindowByType(int mask_id, awt_item_type type)
#define AWT_SCOPE_LOCAL
void GB_warning(const char *message)
Definition: arb_msg.cxx:484
const char * id
Definition: AliAdmin.cxx:17
static void AWT_change_input_mask(AW_window *aww, const string *internal_mask_name, const string *mask_to_open)
void(* AWT_OpenMaskWindowCallback)(AW_window *aww, int id, GBDATA *gb_main)
GB_CSTR GB_path_in_arbprop(const char *relative_path)
Definition: adsocket.cxx:1109
virtual void db_changed()=0
GB_ERROR decodeEscapes(string &s)
virtual size_t get_self_awar_content_length() const =0
static void check_last_parameter(GB_ERROR &error, const string &command)
void build_widget(AW_window *aws) OVERRIDE
static bool in_field_changed_callback
static char * y[maxsp+1]
const std::string & get_name() const
return string(buffer, length)
void insert_menu_topic(const char *id, const char *name, const char *mnemonic, const char *help_text_, AW_active mask, const WindowCallback &wcb)
Definition: AW_window.cxx:592
static void field_changed_cb(GBDATA *, awt_input_handler *handler, GB_CB_TYPE type)
GB_ERROR GB_add_callback(GBDATA *gbd, GB_CB_TYPE type, const DatabaseCallback &dbcb)
Definition: ad_cb.cxx:356
size_t eat_para_separator(const string &line, size_t start, GB_ERROR &error)
virtual void build_widget(AW_window *aws)=0
void AW_edit(const char *path)
Definition: AW_edit.cxx:16
virtual GB_ERROR add_db_callbacks()
static string list_keywords(const char **allowed_keywords)
GB_ERROR link_to(GBDATA *gb_new_item) FINAL_OVERRIDE
const awt_item_type_selector * get_selector() const
ID_checker(bool reloading_)
static void item_changed_cb(GBDATA *, awt_linked_to_item *item_link, GB_CB_TYPE type)
#define awt_assert(cond)
Definition: awt.hxx:28
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
GB_ERROR awt_open_ACI_URL_with_item(AW_root *aw_root, GBDATA *gb_main, GBDATA *gb_item, const char *url_aci)
Definition: AWT_www.cxx:120
char * GB_read_as_string(GBDATA *gbd)
Definition: arbdb.cxx:1054
awt_item_type
static void create_new_mask_cb(AW_window *aww)
long read_int() const
Definition: AW_awar.cxx:187
awt_marked_checkbox(awt_input_mask_global &global_, const std::string &label_)
void set_item(GBDATA *new_item)
const char * inputMaskDir(bool local)
static void AWT_input_mask_browse_url(AW_window *aww, const string *url_aci, const awt_input_mask *mask)
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:204
void warning(int warning_num, const char *warning_message)
Definition: util.cxx:61
const char * title
Definition: readseq.c:22
static void AWT_edit_input_mask(AW_window *, const string *mask_name, bool local)
void AWT_create_mask_submenu(AW_window_menu_modes *awm, awt_item_type wanted_item_type, AWT_OpenMaskWindowCallback open_mask_window_cb, GBDATA *gb_main)
STL namespace.
awt_input_handler(awt_input_mask_global &global_, const std::string &child_path_, GB_TYPES type_, const std::string &label_)
void AW_POPDOWN(AW_window *window)
Definition: AW_window.cxx:52
static string check_data_path(const string &path, GB_ERROR &error)
const std::string & get_label() const
char * GBS_string_2_key(const char *str)
Definition: adstring.cxx:52
bool isNull() const
test if SmartPtr is NULp
Definition: smartptr.h:248
static string find_internal_name(const string &mask_name, bool search_in_local)
MaskCommand
static string scan_string_parameter(const string &line, size_t &scan_pos, GB_ERROR &error, bool allow_escaped=false)
#define AWAR_INPUT_MASK_HIDDEN
void setNull()
set SmartPtr to NULp
Definition: smartptr.h:251
static awt_input_mask_descriptor * quick_scan_input_mask(const string &mask_name, const string &filename, bool local)
char buffer[MESSAGE_BUFFERSIZE]
Definition: seq_search.cxx:34
GB_ERROR GB_push_transaction(GBDATA *gbd)
Definition: arbdb.cxx:2482
const awt_input_mask_descriptor * AWT_look_input_mask(int id)
virtual GB_ERROR set_value(const std::string &new_value)=0
#define cb(action)
static Shaders registered
size_t next_non_white(const string &line, size_t start)
void update_toggle_field()
GB_ERROR remove_id(const std::string &name)
AW_awar * add_callback(const RootCallback &cb)
Definition: AW_awar.cxx:234
virtual std::string awar2db(const std::string &awar_content) const
static HelixNrInfo * start
GB_ERROR GB_check_hkey(const char *key) __ATTR__USERESULT
Definition: adstring.cxx:92
static int scan_keyword_parameter(const string &line, size_t &scan_pos, GB_ERROR &error, const char **allowed_keywords)
static vector< awt_input_mask_descriptor > existing_masks
const char * read_char_pntr() const
Definition: AW_awar.cxx:171
GB_ERROR add_local_id(const std::string &name, awt_mask_item *handler)
awt_mask_awar_item(awt_input_mask_global &global_, const std::string &awar_base, const std::string &default_value, bool saved_with_properties)
bool edit_allowed() const
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:353
awt_item_type AWT_getItemType(const string &itemtype_name)
static void create_new_input_mask(AW_window *aww, awt_item_type item_type)
WindowCallback makeHelpCallback(const char *helpfile)
Definition: aw_window.hxx:106
static void registerType(awt_item_type type, AW_window_menu_modes *awm, AWT_OpenMaskWindowCallback open_window_cb)
map< string, awt_input_mask_ptr > InputMaskList
GB_TYPES GB_read_type(GBDATA *gbd)
Definition: arbdb.cxx:1641
void set_type(GB_TYPES typ)
const char * hotkey(const std::string &label)
void build_widget(AW_window *aws) OVERRIDE
size_t default_toggle() const
virtual GB_ERROR relink()=0
~awt_assignment() OVERRIDE
void create_toggle_field(const char *awar_name, AW_label label, const char *mnemonic)
AW_window_menu_modes * getWindow() const
static TypeRegistry registeredTypes
virtual ~awt_mask_action()
#define true
Definition: ureadseq.h:14
static bool was_last_parameter
static long scan_optional_parameter(const string &line, size_t &scan_pos, GB_ERROR &error, long if_empty)
#define false
Definition: ureadseq.h:13
std::string awar2db(const std::string &awar_content) const OVERRIDE
static long scan_long_parameter(const string &line, size_t &scan_pos, GB_ERROR &error)
virtual void remove_db_callbacks()
static void error(const char *msg)
Definition: mkptypes.cxx:96
virtual const char * getKeyPath() const =0
#define ARB_INPUT_MASK_ID
SmartPtr< awt_input_mask > awt_input_mask_ptr
GB_ERROR GB_abort_transaction(GBDATA *gbd)
Definition: arbdb.cxx:2527
#define MIN_TEXTFIELD_SIZE
GB_ERROR remove(const std::string &name)
const char * mnemonic
#define MAX_TEXTFIELD_SIZE
static bool global_awars_created
static int scan_flag_parameter(const string &line, size_t &scan_pos, GB_ERROR &error, const string &allowed_flags)
void label(const char *label)
Definition: AW_window.cxx:102
static char * selectMnemonic(const char *orgTitle, char *availableMnemonics, char &mnemonic)
virtual GBDATA * current(AW_root *root, GBDATA *gb_main) const =0
int32_t ID
void awar_changed() OVERRIDE
static void AWT_open_input_mask(AW_window *aww, const string *internal_mask_name, const string *mask_to_open)
bool isInternalMaskName(const string &s)
GB_ERROR add(const std::string &name, awt_mask_item *item)
void AWT_destroy_input_masks()
void db_changed() FINAL_OVERRIDE
static GB_ERROR writeDefaultMaskfile(const string &fullname, const string &maskname, const string &itemtypename, bool hidden)
std::string awar2db(const std::string &awar_content) const OVERRIDE
static struct MaskCommandDefinition mask_command[MASK_COMMANDS+1]
int GB_read_flag(GBDATA *gbd)
Definition: arbdb.cxx:2784
char * read_string() const
Definition: AW_awar.cxx:201
GB_CSTR GB_path_in_ARBLIB(const char *relative_path)
Definition: adsocket.cxx:1103
AW_awar * awar(const char *awar)
Definition: AW_root.cxx:554
GB_ERROR GB_pop_transaction(GBDATA *gbd)
Definition: arbdb.cxx:2512
const char * get_dup_error(const string &maskName) const
void insert_sub_menu(const char *name, const char *mnemonic, AW_active mask=AWM_ALL)
Definition: AW_window.cxx:642
GB_TYPES GBT_get_type_of_changekey(GBDATA *gb_main, const char *field_name, const char *change_key_path)
Definition: adChangeKey.cxx:34
Definition: arbdb.h:86
~awt_input_handler() OVERRIDE
AW_awar * remove_callback(const RootCallback &cb)
Definition: AW_awar.cxx:527
virtual std::string db2awar(const std::string &db_content) const
static const char * awt_itemtype_names[AWT_IT_TYPES+1]
static AW_window_menu_modes_opengl * awm
AWT_registered_itemtype(AW_window_menu_modes *awm_, AWT_OpenMaskWindowCallback open_window_cb_)
static void AWT_input_mask_perform_action(AW_window *, awt_mask_action *action)
static void add_new_input_mask(const string &maskname, const string &fullname, bool local)
virtual ~awt_mask_item()
static bool scanned_existing_input_masks
static void AWT_reload_input_mask(AW_window *aww, const string *internal_mask_name)
long int flag
Definition: f2c.h:39
#define AWT_SCOPE_GLOBAL
GB_ERROR AWT_initialize_input_mask(AW_root *root, GBDATA *gb_main, const awt_item_type_selector *sel, const char *internal_mask_name, bool local)
map< awt_item_type, AWT_registered_itemtype > TypeRegistry
int aw_question(const char *unique_id, const char *question, const char *buttons, bool sameSizeButtons, const char *helpfile)
Definition: AW_question.cxx:26
static void awt_open_input_mask(AW_window *aww, const string *internal_mask_name, const string *mask_to_open, bool reload, bool hide_current)
void create_input_field(const char *awar_name, int columns=0)
Definition: AW_button.cxx:855
fputs(TRACE_PREFIX, stderr)
Definition: arbdb.h:63
GB_ERROR set_name(const std::string &name_, bool is_global)
static void awar_changed_cb(AW_root *, awt_mask_awar_item *item)
AW_awar * awar_int(const char *var_name, long default_value=0, AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:580
MaskCommand findCommand(const string &cmd_name)
static void create_global_awars(AW_root *awr)
awt_variable(awt_input_mask_global &global_, const std::string &id, bool is_global_, const std::string &default_value, GB_ERROR &error)
xml element
~awt_variable() OVERRIDE
void GB_write_flag(GBDATA *gbd, long flag)
Definition: arbdb.cxx:2761
std::string awar_name() const
#define AWAR_INPUT_MASK_SCOPE
static void link_mask_to_database(awt_input_mask_ptr mask)
virtual std::string get_value() const =0
TypeRegistry::const_iterator TypeRegistryIter
static void unlink_mask_from_database(awt_input_mask_ptr mask)
std::string db2awar(const std::string &db_content) const OVERRIDE
bool GB_is_directory(const char *path)
Definition: arb_file.cxx:176
#define OVERRIDE
Definition: cxxforward.h:93
void no_item_selected() const
void remove_awar_callbacks(AW_root *root, const RootCallback &cb) const
int isKeyword(const char *current, const char *keyword)
void GB_remove_callback(GBDATA *gbd, GB_CB_TYPE type, const DatabaseCallback &dbcb)
Definition: ad_cb.cxx:360
static awt_input_mask_ptr awt_create_input_mask(AW_root *root, GBDATA *gb_main, const awt_item_type_selector *sel, const string &mask_name, bool local, GB_ERROR &error, bool reloading)
void close_sub_menu()
Definition: AW_window.cxx:483
static GB_ERROR readLine(FILE *in, string &line, size_t &lineNo)
virtual void awar_changed()=0
awt_assignment(awt_input_mask_ptr mask_, const string &id_dest_, const string &id_source_)
awt_mask_item(awt_input_mask_global &global_)
void aw_message(const char *msg)
Definition: AW_status.cxx:932
static void scan_string_or_keyword_parameter(const string &line, size_t &scan_pos, GB_ERROR &error, string &string_para, int &keyword_index, const char **allowed_keywords)
#define SEC_YBORDER
AWT_OpenMaskWindowCallback getOpenCb() const
GB_ERROR set_value(const std::string &new_value) OVERRIDE
GB_ERROR GBT_add_new_changekey_to_keypath(GBDATA *gb_main, const char *name, int type, const char *keypath)
Definition: adChangeKey.cxx:87
const std::string & get_child_path() const
void insert_default_toggle(AW_label toggle_label, const char *mnemonic, const char *var_value)
awt_input_mask_ptr mask
AW_root * get_root()
Definition: aw_window.hxx:348
void build_widget(AW_window *aws) OVERRIDE
const AW_awar * awar() const
#define SEC_LINE_WIDTH
static int line
Definition: arb_a2ps.c:296
#define NULp
Definition: cxxforward.h:97
bool seenDups() const
static bool in_item_changed_callback
const char * fromText(const string &anystr)
static void parse_CMD_RADIO(string &line, size_t &scan_pos, GB_ERROR &error, const string &command, awt_mask_item_ptr &handler1, awt_mask_item_ptr &handler2, awt_input_mask_global &global)
GB_ERROR write_string(const char *aw_string)
static char * command
Definition: arb_a2ps.c:319
std::string db2awar(const std::string &db_content) const OVERRIDE
#define AWAR_INPUT_MASKS_EDIT_ENABLED
void sep______________()
Definition: AW_window.cxx:750
static bool in_awar_changed_callback
#define AWAR_INPUT_MASK_NAME
NOT4PERL char * GB_command_interpreter_in_env(const char *str, const char *commands, const GBL_call_env &callEnv)
Definition: gb_aci.cxx:361
GB_TYPES
Definition: arbdb.h:62
virtual GB_ERROR link_to(GBDATA *gb_new_item)=0
static bool scan_bool_parameter(const string &line, size_t &scan_pos, GB_ERROR &error)
static string scan_identifier(const string &line, size_t &scan_pos, GB_ERROR &error)
const char * fromKey(const char *id)
void build_widget(AW_window *aws) OVERRIDE
static void check_no_parameter(const string &line, size_t &scan_pos, GB_ERROR &error, const string &command)
GB_transaction ta(gb_var)
static void scan_existing_input_masks()
#define BUFSIZE
GBDATA * gb_main
Definition: adname.cxx:33
GB_ERROR relink() FINAL_OVERRIDE
AW_awar * awar_string(const char *var_name, const char *default_value="", AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:570
GBDATA * GB_search(GBDATA *gbd, const char *fieldpath, GB_TYPES create)
Definition: adquery.cxx:531
NOT4PERL bool GB_inside_callback(GBDATA *of_gbd, GB_CB_TYPE cbtype)
Definition: ad_cb.cxx:115
~awt_marked_checkbox() OVERRIDE
GB_ERROR add_global_id(const std::string &name, awt_mask_item *handler)
GB_CB_TYPE
Definition: arbdb_base.h:46
#define min(a, b)
Definition: f2c.h:153
GBDATA * get_gb_main(DbSel db)
Definition: merge.hxx:88
static void awt_input_mask_awar_changed_cb(AW_root *, awt_input_mask *mask)
awt_mask_action(awt_input_mask_ptr mask_)
GB_ERROR remove_name()
GB_ERROR GB_create_directory(const char *path)
void add_awar_callbacks(AW_root *root, const RootCallback &cb) const
#define AWAR_INPUT_MASK_ITEM
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:195
const char * label
GB_ERROR GB_write_autoconv_string(GBDATA *gbd, const char *val)
Definition: arbdb.cxx:1477
#define max(a, b)
Definition: f2c.h:154
GB_write_int const char s
Definition: AW_awar.cxx:156