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