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