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