ARB
config_manager.cxx
Go to the documentation of this file.
1 // ==================================================================== //
2 // //
3 // File : config_manager.cxx //
4 // Purpose : general interface to store/restore //
5 // a set of related awars //
6 // //
7 // Coded by Ralf Westram (coder@reallysoft.de) in January 2002 //
8 // Copyright Department of Microbiology (Technical University Munich) //
9 // //
10 // Visit our web site at: http://www.arb-home.de/ //
11 // //
12 // ==================================================================== //
13 
14 #include "config_manager.hxx"
15 #include "sel_boxes.hxx"
16 
17 #include <aw_root.hxx>
18 #include <aw_question.hxx>
19 #include <aw_awar.hxx>
20 #include <aw_msg.hxx>
21 #include <aw_select.hxx>
22 
23 #include <arb_defs.h>
24 #include <arb_str.h>
25 #include <arb_strbuf.h>
26 
27 #include <list>
28 #include <string>
29 
30 using namespace std;
31 
32 // --------------------------
33 // AWT_configuration
34 
35 enum ConfigAwar {
40 
41  // 'Edit' subwindow
44 
45  CONFIG_AWARS, // must be last
46 };
47 
48 bool is_prefined(const string& cfgname) { return cfgname[0] == '*'; }
49 
50 class ConfigDefinition : virtual Noncopyable {
51  AW_default default_file;
52  string id;
53 
54  AW_awar *std_awar[CONFIG_AWARS];
55 
56  static string container_name_for(const string& id_, bool temp) {
57 #if defined(ASSERTION_USED)
58  GB_ERROR keyError = GB_check_key(id_.c_str());
59  aw_assert(keyError == NULp);
60 #endif
61  return string("tmp/general_configs/" + (temp ? 0 : 4)) + id_;
62  }
63 
64 public:
65  ConfigDefinition(AW_default default_file_, const char *id_)
66  : default_file(default_file_),
67  id(id_)
68  {
69  std_awar[VISIBLE_COMMENT] = get_awar("comment", true);
70  std_awar[STORED_COMMENTS] = get_awar("comments");
71  std_awar[EXISTING_CFGS] = get_awar("existing");
72  std_awar[CURRENT_CFG] = get_awar("current");
73  std_awar[SELECTED_FIELD] = get_awar("field", true);
74  std_awar[FIELD_CONTENT] = get_awar("content", true);
75  }
76 
77  bool operator<(const ConfigDefinition& other) const { return id<other.id; }
78 
79  AW_default get_db() const { return default_file; }
80  const char *get_id() const { return id.c_str(); } // = type of configuration. multiple config manager may share same id.
81 
82  string get_awar_name(const string& subname, bool temp = false) const {
83  return container_name_for(id, temp)+'/'+subname;
84  }
85  string get_config_dbpath(const string& cfgname) const {
86  return get_awar_name(string("cfg_")+cfgname);
87  }
88 
89  AW_awar *get_awar(const string& subname, bool temp = false) const {
90  string awar_name = get_awar_name(subname, temp);
91  return AW_root::SINGLETON->awar_string(awar_name.c_str(), "", default_file);
92  }
93  AW_awar *get_awar(ConfigAwar a) const { return std_awar[a]; }
94 
95  string get_awar_value(ConfigAwar a) const { return get_awar(a)->read_char_pntr(); }
96  void set_awar_value(ConfigAwar a, const string& new_value) const { get_awar(a)->write_string(new_value.c_str()); }
97 
98  static bool have_existing_config(AW_default default_file_, const string& id_) {
100 
101  string container_path = container_name_for(id_, false);
102  GB_transaction ta(default_file_);
103  GBDATA *gb_cfg_manager = GB_search(default_file_, container_path.c_str(), GB_FIND);
104 
106  return gb_cfg_manager;
107  }
108 
110  std_awar[CURRENT_CFG]->write_string("");
111  std_awar[EXISTING_CFGS]->write_string("");
112  std_awar[STORED_COMMENTS]->write_string("");
113 
114  // mark whole container (the db-entry) as temp -> will not be saved with properties
115  string container_path = container_name_for(id, false);
116  GB_transaction ta(default_file);
117  GBDATA *gb_cfg_manager = GB_search(default_file, container_path.c_str(), GB_FIND);
118  awt_assert(gb_cfg_manager); // method should be called only for config managers existing in properties
119 
120  GB_ERROR error = GB_set_temporary(gb_cfg_manager);
121  if (error) {
122  aw_message(GBS_global_string("Failed to erase config manager '%s' after conversion (Reason: %s)", id.c_str(), error));
123  }
124  }
125 };
126 
128  string macro_id;
129  string title;
130 
131  manager_window_def(string macro_id_, string title_) : macro_id(macro_id_), title(title_) {}
132  manager_window_def() : macro_id(""), title("") {}
133 };
134 
135 class AWT_configuration : public ConfigDefinition { // derived from Noncopyable
136  StoreConfigCallback store;
137  RestoreConfigCallback load_or_reset;
138 
139  const AWT_predefined_config *predefined;
140 
141  AW_window *aw_edit;
142  AW_selection_list *field_selection;
143 
144  manager_window_def win_def;
145 
146  GB_ERROR update_config(const string& cfgname, const AWT_config& config);
147 
148 public:
149  AWT_configuration(AW_default default_file_, const char *id_, const StoreConfigCallback& store_, const RestoreConfigCallback& load_or_reset_, const AWT_predefined_config *predef)
150  : ConfigDefinition(default_file_, id_),
151  store(store_),
152  load_or_reset(load_or_reset_),
153  predefined(predef),
154  aw_edit(NULp),
155  field_selection(NULp)
156  {
157  }
158 
159  string get_config(const string& cfgname) {
160  if (is_prefined(cfgname)) {
161  const AWT_predefined_config *predef = find_predefined(cfgname);
162  return predef ? predef->config : "";
163  }
164  else {
165  GB_transaction ta(get_db());
166  GBDATA *gb_cfg = GB_search(get_db(), get_config_dbpath(cfgname).c_str(), GB_FIND);
167  return gb_cfg ? GB_read_char_pntr(gb_cfg) : "";
168  }
169  }
170  GB_ERROR set_config(const string& cfgname, const string& new_value) {
171  GB_ERROR error;
172  if (is_prefined(cfgname)) {
173  error = "cannot modify predefined config";
174  }
175  else {
176  GB_transaction ta(get_db());
177  GBDATA *gb_cfg = GB_search(get_db(), get_config_dbpath(cfgname).c_str(), GB_STRING);
178  if (!gb_cfg) {
179  error = GB_await_error();
180  }
181  else {
182  error = GB_write_string(gb_cfg, new_value.c_str());
183  get_awar(CURRENT_CFG)->touch(); // force refresh of config editor
184  }
185  }
186  return error;
187  }
188 
189  char *Store() const { return store(); }
190  GB_ERROR Restore(const string& s) const {
191  GB_ERROR error = NULp;
192 
193  if (s.empty()) error = "empty/nonexistant config";
194  else load_or_reset(s.c_str());
195 
196  return error;
197  }
198  void Reset() const {
199  load_or_reset(NULp);
200  }
201 
202  GB_ERROR Save(const char* filename, const string& cfg_name, const string& comment); // AWAR content -> FILE
203  GB_ERROR Load(const char* filename, const string& cfg_name, string& found_comment); // FILE -> AWAR content
204 
205  bool has_existing(string lookFor) {
206  string S(";");
207  string existing = S+ get_awar_value(EXISTING_CFGS) +S;
208  string wanted = S+ lookFor +S;
209 
210  return existing.find(wanted) != string::npos;
211  }
212 
213  void erase_deleted_configs();
214 
216  if (predefined) {
217  for (int i = 0; predefined[i].name; ++i) {
218  awt_assert(predefined[i].name[0] == '*'); // names have to start with '*'
219  cfgs.put(predefined[i].name);
220  }
221  }
222  }
223  const AWT_predefined_config *find_predefined(const string& cfgname) {
224  awt_assert(is_prefined(cfgname));
225  for (int i = 0; predefined[i].name; ++i) {
226  if (cfgname == predefined[i].name) {
227  return &predefined[i];
228  }
229  }
230  return NULp;
231  }
232 
233  void configure_manager_window(const manager_window_def& mw_def) { win_def = mw_def; }
235  win_def = manager_window_def(
236  GBS_global_string("%s_config", aww->get_window_id()),
237  GBS_global_string("Configurations for '%s'", aww->get_window_title()));
238  }
239 
240  const char *get_macro_id() const {
241  // returns macro id used for config manager window
242  awt_assert(!win_def.macro_id.empty());
243  return win_def.macro_id.c_str();
244  }
245  const char *get_title() const {
246  // returns title used for config manager window
247  awt_assert(!win_def.title.empty());
248  return win_def.title.c_str();
249  }
250 
251  void popup_edit_window(AW_window *aw_config);
252  void update_field_selection_list();
253  void update_field_content();
254  void store_changed_field_content();
255  void delete_selected_field();
256  void keep_changed_fields();
257 };
258 
259 #define HEADER "ARB_CONFIGURATION"
260 #define HEADERLEN 17
261 
262 GB_ERROR AWT_configuration::Save(const char* filename, const string& cfg_name, const string& comment) {
263  awt_assert(strlen(HEADER) == HEADERLEN);
264 
265  printf("Saving config to '%s'..\n", filename);
266 
267  FILE *out = fopen(filename, "wt");
268  GB_ERROR error = NULp;
269  if (!out) {
270  error = GB_IO_error("saving", filename);
271  }
272  else {
273  if (comment.empty()) {
274  fprintf(out, HEADER ":%s\n", get_id()); // =same as old format
275  }
276  else {
277  string encoded_comment(comment);
278  ConfigMapping::encode_escapes(encoded_comment, "");
279  fprintf(out, HEADER ":%s;%s\n", get_id(), encoded_comment.c_str());
280  }
281 
282  string content = get_config(cfg_name);
283  fputs(content.c_str(), out);
284  fclose(out);
285  }
286  return error;
287 }
288 
289 GB_ERROR AWT_configuration::Load(const char* filename, const string& cfg_name, string& found_comment) {
290  GB_ERROR error = NULp;
291 
292  found_comment = "";
293  printf("Loading config from '%s'..\n", filename);
294 
295  char *content = GB_read_file(filename);
296  if (!content) {
297  error = GB_await_error();
298  }
299  else {
300  if (strncmp(content, HEADER ":", HEADERLEN+1) != 0) {
301  error = "Unexpected content (" HEADER " missing)";
302  }
303  else {
304  char *id_pos = content+HEADERLEN+1;
305  char *nl = strchr(id_pos, '\n');
306 
307  if (!nl) {
308  error = "Unexpected content (no ID)";
309  }
310  else {
311  *nl++ = 0;
312 
313  char *comment = strchr(id_pos, ';');
314  if (comment) *comment++ = 0;
315 
316  if (strcmp(id_pos, get_id()) != 0) {
317  error = GBS_global_string("Wrong config type (expected=%s, found=%s)", get_id(), id_pos);
318  }
319  else {
320  error = set_config(cfg_name, nl);
321  if (comment && !error) {
322  found_comment = comment;
323  error = ConfigMapping::decode_escapes(found_comment);
324  }
325  }
326  }
327  }
328 
329  if (error) {
330  error = GBS_global_string("Error: %s (while reading %s)", error, filename);
331  }
332 
333  free(content);
334  }
335 
336  return error;
337 }
338 
340  string cfg_base = get_awar_name("", false);
341  GB_ERROR error = NULp;
342  {
343  GB_transaction ta(get_db());
344  GBDATA *gb_base = GB_search(get_db(), cfg_base.c_str(), GB_FIND);
345  if (gb_base) {
346  for (GBDATA *gb_cfg = GB_child(gb_base); gb_cfg && !error; ) {
347  GBDATA *gb_next = GB_nextChild(gb_cfg);
348  const char *key = GB_read_key_pntr(gb_cfg);
349  if (key && ARB_strBeginsWith(key, "cfg_")) {
350  const char *name = key+4;
351  if (!has_existing(name)) {
352  error = GB_delete(gb_cfg);
353  }
354  }
355  gb_cfg = gb_next;
356  }
357  }
358  }
359  aw_message_if(error);
360 }
361 
362 void remove_from_configs(const string& config, string& existing_configs) {
363  ConstStrArray cfgs;
364  GBT_split_string(cfgs, existing_configs.c_str(), ";", SPLIT_DROPEMPTY);
365 
366  ConstStrArray remaining;
367  for (int i = 0; cfgs[i]; ++i) {
368  if (strcmp(cfgs[i], config.c_str()) != 0) {
369  remaining.put(cfgs[i]);
370  }
371  }
372 
373  char *rest = GBT_join_strings(remaining, ';');
374  existing_configs = rest;
375  free(rest);
376 }
377 
378 #define NO_CONFIG_SELECTED "<no config selected>"
379 
381  AW_awar *awar_current = config->get_awar(CURRENT_CFG);
382  AW_awar *awar_comment = config->get_awar(VISIBLE_COMMENT);
383 
384  // convert name to key (but allow empty string and strings starting with '*')
385  string name;
386  {
387  const char *entered_name = awar_current->read_char_pntr();
388  if (entered_name[0]) {
389  bool isPredefined = is_prefined(entered_name);
390  char *asKey = GBS_string_2_key(entered_name);
391  name = isPredefined ? string(1, '*')+asKey : asKey;
392  free(asKey);
393  }
394  else {
395  name = "";
396  }
397  }
398 
399  awar_current->write_string(name.c_str());
400 
401  // refresh comment field
402  if (name[0]) { // cfg not empty
403  if (config->has_existing(name)) { // load comment of existing config
404  string storedComments = config->get_awar_value(STORED_COMMENTS);
405  AWT_config comments(storedComments.c_str());
406 
407  const char *display;
408  if (comments.parseError()) {
409  display = GBS_global_string("Error reading config comments:\n%s", comments.parseError());
410  }
411  else {
412  const char *saved_comment = comments.get_entry(name.c_str());
413  display = null2empty(saved_comment);
414  }
415  awar_comment->write_string(display);
416  }
417  else if (is_prefined(name)) {
418  const AWT_predefined_config *found = config->find_predefined(name);
419  awar_comment->write_string(found ? found->description : NO_CONFIG_SELECTED);
420  }
421  else { // new config (not stored yet)
422  // click <new> and enter name -> clear comment
423  // click existing and change name -> reuse existing comment
424  if (strcmp(awar_comment->read_char_pntr(), NO_CONFIG_SELECTED) == 0) {
425  awar_comment->write_string("");
426  }
427  }
428  }
429  else { // no config selected
430  awar_comment->write_string(NO_CONFIG_SELECTED);
431  }
432 
433  // refresh field selection list + content field
434  config->update_field_selection_list();
435 }
436 
437 inline void save_comments(const AWT_config& comments, AWT_configuration *config) {
438  char *comments_string = comments.config_string();
439  config->set_awar_value(STORED_COMMENTS, comments_string);
440  free(comments_string);
441 }
442 
444  string curr_cfg = config->get_awar_value(CURRENT_CFG);
445  if (!curr_cfg.empty()) {
446  string changed_comment = config->get_awar_value(VISIBLE_COMMENT);
447  if (is_prefined(curr_cfg)) {
448  const AWT_predefined_config *found = config->find_predefined(curr_cfg);
449  if (found && changed_comment != found->description) {
450  aw_message("The description of predefined configs is immutable");
451  config->get_awar(CURRENT_CFG)->touch(); // reload comment
452  }
453  }
454  else if (config->has_existing(curr_cfg)) {
455  AWT_config comments(config->get_awar_value(STORED_COMMENTS).c_str());
456  if (comments.parseError()) {
457  aw_message(GBS_global_string("Failed to parse config-comments (%s)", comments.parseError()));
458  }
459  else {
460  if (changed_comment.empty()) {
461  comments.delete_entry(curr_cfg.c_str());
462  }
463  else {
464  comments.set_entry(curr_cfg.c_str(), changed_comment.c_str());
465  }
466  save_comments(comments, config);
467  }
468  }
469  }
470 }
471 static void erase_comment_cb(AW_window*, AW_awar *awar_comment) {
472  awar_comment->write_string("");
473 }
474 
475 static void restore_cb(AW_window *, AWT_configuration *config) {
476  string cfgName = config->get_awar_value(CURRENT_CFG);
477  GB_ERROR error;
478  if (cfgName.empty()) {
479  error = "Please select config to restore";
480  }
481  else {
482  error = config->Restore(config->get_config(cfgName));
483  }
484  aw_message_if(error);
485 }
486 static void store_cb(AW_window *, AWT_configuration *config) {
487  string cfgName = config->get_awar_value(CURRENT_CFG);
488  if (cfgName.empty()) aw_message("Please select or enter name of config to store");
489  else if (is_prefined(cfgName)) aw_message("You can't modify predefined configs");
490  else {
491  string existing = config->get_awar_value(EXISTING_CFGS);
492 
493  AW_awar *awar_comment = config->get_awar(VISIBLE_COMMENT);
494  string visibleComment(awar_comment->read_char_pntr());
495 
496  remove_from_configs(cfgName, existing); // remove selected from existing configs
497 
498  existing = existing.empty() ? cfgName : (string(cfgName)+';'+existing);
499  {
500  char *cfgStr = config->Store();
501  GB_ERROR error = config->set_config(cfgName, cfgStr);
502  aw_message_if(error);
503  free(cfgStr);
504  }
505  config->set_awar_value(EXISTING_CFGS, existing);
506  awar_comment->rewrite_string(visibleComment.c_str()); // force new config to use last visible comment
507 
508  config->get_awar(CURRENT_CFG)->touch(); // force refresh of config editor
509  }
510 }
511 static void delete_cb(AW_window *, AWT_configuration *config) {
512  string cfgName = config->get_awar_value(CURRENT_CFG);
513  if (is_prefined(cfgName)) {
514  aw_message("You may not delete predefined configs");
515  }
516  else {
517  string existing = config->get_awar_value(EXISTING_CFGS);
518  remove_from_configs(cfgName, existing); // remove selected from existing configs
519  config->set_awar_value(CURRENT_CFG, "");
520  config->set_awar_value(EXISTING_CFGS, existing);
521 
522  // erase existing comment:
523  AWT_config comments(config->get_awar_value(STORED_COMMENTS).c_str());
524  comments.delete_entry(cfgName.c_str());
525  save_comments(comments, config);
526 
527  config->erase_deleted_configs();
528  }
529 }
530 static void load_cb(AW_window *, AWT_configuration *config) {
531  string cfgName = config->get_awar_value(CURRENT_CFG);
532  GB_ERROR error = NULp;
533 
534  if (cfgName.empty()) error = "Please enter or select target config";
535  else if (is_prefined(cfgName)) error = "You may not load over a predefined config";
536  else {
537  char *loadMask = GBS_global_string_copy("%s_*", config->get_id());
538  char *filename = aw_modal_file_selection("Load config from file", "$(ARBCONFIG)", loadMask, ".arbcfg");
539  if (filename) {
540  string comment;
541 
542  error = config->Load(filename, cfgName, comment);
543  if (!error) {
544  // after successful load restore and store config
545  restore_cb(NULp, config);
546  store_cb(NULp, config);
547  config->set_awar_value(VISIBLE_COMMENT, comment);
548  }
549  free(filename);
550  }
551  free(loadMask);
552  }
553  aw_message_if(error);
554 }
555 static void save_cb(AW_window *, AWT_configuration *config) {
556  string cfgName = config->get_awar_value(CURRENT_CFG);
557  GB_ERROR error = NULp;
558 
559  if (cfgName.empty()) error = "Please select config to save";
560  else {
561  char *saveAs = GBS_global_string_copy("%s_%s",
562  config->get_id(),
563  cfgName.c_str() + (cfgName[0] == '*')); // skip leading '*'
564 
565  char *filename = aw_modal_file_selection("Save config to file", "$(ARBCONFIG)", saveAs, ".arbcfg");
566  if (filename && filename[0]) {
567  restore_cb(NULp, config);
568  string comment = config->get_awar_value(VISIBLE_COMMENT);
569  error = config->Save(filename, cfgName, comment);
570  free(filename);
571  }
572  free(saveAs);
573  }
574  aw_message_if(error);
575 }
576 
577 #if defined(DEBUG)
578 
579 static string esc(const string& str) {
580  // escape C string
581 
582  char *escaped = GBS_string_eval(str.c_str(), "\\\\=\\\\\\\\:\"=\\\\\":\\n=\\\\n:\\t=\\\\t");
583  // unescaped once by compiler and once by SRT interpreter
584  // results in SRT: '\=\\:"=\":<lf>=\n:<tab>=\t'
585 
586  string result(escaped);
587  free(escaped);
588  return result;
589 }
590 
591 static void dump_cb(AW_window *, AWT_configuration *config) {
592  // dump code ready to insert into AWT_predefined_config
593  string cfgName = config->get_awar_value(CURRENT_CFG);
594  GB_ERROR error = NULp;
595 
596  if (cfgName.empty()) error = "Please select config to dump";
597  else {
598  string comment = esc(config->get_awar_value(VISIBLE_COMMENT));
599  string confStr = esc(config->get_config(cfgName));
600 
601  cfgName = esc(cfgName);
602  const char *cfg = cfgName.c_str();
603 
604  fprintf(stderr, " { \"*%s\", \"%s\", \"%s\" },\n",
605  cfg[0] == '*' ? cfg+1 : cfg,
606  comment.c_str(),
607  confStr.c_str());
608  }
609  aw_message_if(error);
610 }
611 #endif
612 
613 
615  if (field_selection) {
616  string cfgName = get_awar_value(CURRENT_CFG);
617  char *selected = get_awar(SELECTED_FIELD)->read_string();
618  bool seenSelected = false;
619 
620  field_selection->clear();
621  if (!cfgName.empty() && has_existing(cfgName)) {
622  string configString = get_config(cfgName);
623  AWT_config stored(configString.c_str());
624  ConstStrArray entries;
625  stored.get_entries(entries);
626 
627  StrArray entries_with_content;
628  size_t maxlen = 0;
629  for (size_t e = 0; e<entries.size(); ++e) {
630  maxlen = std::max(maxlen, strlen(entries[e]));
631  if (strcmp(selected, entries[e]) == 0) seenSelected = true;
632  }
633  for (size_t e = 0; e<entries.size(); ++e) {
634  field_selection->insert(GBS_global_string("%-*s | %s",
635  int(maxlen), entries[e],
636  stored.get_entry(entries[e])),
637  entries[e]);
638  }
639  }
640  field_selection->insert_default("", "");
641  field_selection->update();
642 
643  if (!seenSelected) {
644  get_awar(SELECTED_FIELD)->write_string("");
645  }
646  else {
647  get_awar(SELECTED_FIELD)->touch();
648  }
649  free(selected);
650  }
651 }
652 
654  string cfgName = get_awar_value(CURRENT_CFG);
655  string content = "<select a field below>";
656  if (!cfgName.empty() && has_existing(cfgName)) {
657  string selected = get_awar_value(SELECTED_FIELD);
658  if (!selected.empty()) {
659  string configString = get_config(cfgName);
660  AWT_config stored(configString.c_str());
661 
662  if (stored.has_entry(selected.c_str())) {
663  content = stored.get_entry(selected.c_str());
664  }
665  else {
666  content = GBS_global_string("<field '%s' not stored in config>", selected.c_str());
667  }
668  }
669  }
670  set_awar_value(FIELD_CONTENT, content.c_str());
671 }
672 
673 GB_ERROR AWT_configuration::update_config(const string& cfgname, const AWT_config& config) {
674  char *changedConfigString = config.config_string();
675  GB_ERROR error = set_config(cfgname, changedConfigString);
676  free(changedConfigString);
677  return error;
678 }
679 
681  string cfgName = get_awar_value(CURRENT_CFG);
682  if (!cfgName.empty() && has_existing(cfgName)) {
683  string selected = get_awar_value(SELECTED_FIELD);
684  if (!selected.empty()) {
685  string configString = get_config(cfgName);
686  AWT_config stored(configString.c_str());
687  if (stored.has_entry(selected.c_str())) {
688  string stored_content = stored.get_entry(selected.c_str());
689  string changed_content = get_awar_value(FIELD_CONTENT);
690 
691  if (stored_content != changed_content) {
692  stored.set_entry(selected.c_str(), changed_content.c_str());
693  aw_message_if(update_config(cfgName, stored));
694  }
695  }
696  }
697  }
698 }
699 
701  string cfgName = get_awar_value(CURRENT_CFG);
702  if (!cfgName.empty() && has_existing(cfgName)) {
703  string selected = get_awar_value(SELECTED_FIELD);
704  if (!selected.empty()) {
705  string configString = get_config(cfgName);
706  AWT_config stored(configString.c_str());
707  if (stored.has_entry(selected.c_str())) {
708  stored.delete_entry(selected.c_str());
709  aw_message_if(update_config(cfgName, stored));
710  field_selection->move_selection(1);
711  update_field_selection_list();
712  }
713  }
714  }
715 }
716 
718  string cfgName = get_awar_value(CURRENT_CFG);
719  if (!cfgName.empty() && has_existing(cfgName)) {
720  string configString = get_config(cfgName);
721  AWT_config stored(configString.c_str());
722 
723  char *current_state = Store();
724  AWT_config current(current_state);
725 
726  ConstStrArray entries;
727  stored.get_entries(entries);
728  int deleted = 0;
729 
730  for (size_t e = 0; e<entries.size(); ++e) {
731  const char *entry = entries[e];
732  const char *stored_content = stored.get_entry(entry);
733 
734  if (current.has_entry(entry)) {
735  const char *current_content = current.get_entry(entry);
736  if (strcmp(stored_content, current_content) == 0) {
737  stored.delete_entry(entry);
738  deleted++;
739  }
740  }
741  else {
742  aw_message(GBS_global_string("Entry '%s' is not (or no longer) supported", entry));
743  }
744  }
745 
746  if (deleted) {
747  aw_message_if(update_config(cfgName, stored));
748  update_field_selection_list();
749  }
750  else {
751  aw_message("All entries differ from current state");
752  }
753 
754  free(current_state);
755  }
756 }
757 
762 
764  if (!aw_edit) {
765  AW_root *root = aw_config->get_root();
766  AW_window_simple *aws = new AW_window_simple;
767  {
768  char *wid = GBS_global_string_copy("%s_edit", aw_config->get_window_id());
769  aws->init(root, wid, "Edit configuration entries");
770  free(wid);
771  }
772  aws->load_xfig("awt/edit_config.fig");
773 
774  aws->at("close");
775  aws->callback(AW_POPDOWN);
776  aws->create_button("CLOSE", "CLOSE");
777 
778  aws->at("help");
779  aws->callback(makeHelpCallback("prop_configs_edit.hlp"));
780  aws->create_button("HELP", "HELP");
781 
782  aws->at("content");
783  aws->create_input_field(get_awar(FIELD_CONTENT)->awar_name);
784 
785  aws->at("name");
786  aws->create_button(NULp, get_awar(CURRENT_CFG)->awar_name, NULp, "+");
787 
788  aws->at("entries");
789  field_selection = aws->create_selection_list(get_awar(SELECTED_FIELD)->awar_name);
790 
791  aws->auto_space(0, 3);
792  aws->button_length(10);
793  aws->at("button");
794 
795  int xpos = aws->get_at_xposition();
796  int ypos = aws->get_at_yposition();
797 
798  aws->callback(makeWindowCallback(delete_field_cb, this));
799  aws->create_button("DELETE", "Delete\nselected\nentry", "D");
800 
801  aws->at_newline();
802  ypos = aws->get_at_yposition();
803  aws->at("button");
804  aws->at(xpos, ypos);
805 
806  aws->callback(makeWindowCallback(keep_changed_fields_cb, this));
807  aws->create_button("KEEP_CHANGED", "Keep only\nentries\ndiffering\nfrom\ncurrent\nstate", "K");
808 
809  aw_edit = aws;
810 
811  // bind callbacks to awars
812  get_awar(SELECTED_FIELD)->add_callback(makeRootCallback(selected_field_changed_cb, this));
813  get_awar(FIELD_CONTENT)->add_callback(makeRootCallback(field_content_changed_cb, this));
814 
815  // fill selection list
816  update_field_selection_list();
817  }
818 
819  aw_edit->activate();
820 }
821 
822 static void edit_cb(AW_window *aww, AWT_configuration *config) { config->popup_edit_window(aww); }
823 static void reset_cb(AW_window *, AWT_configuration *config) { config->Reset(); }
824 
825 static void get_existing_configs(ConfigDefinition& configDef, ConstStrArray& cfgs) {
826  string cfgs_str = configDef.get_awar_value(EXISTING_CFGS);
827  GBT_split_string(cfgs, cfgs_str.c_str(), ";", SPLIT_DROPEMPTY);
828 }
829 
831  ConstStrArray cfgs;
832  get_existing_configs(*config, cfgs);
833 
834  config->add_predefined_to(cfgs);
835  sel->init_from_array(cfgs, "<new>", "");
836 }
837 
839  AW_window_simple *aws = new AW_window_simple;
840 
841  aws->init(aw_root, config->get_macro_id(), config->get_title());
842  aws->load_xfig("awt/manage_config.fig");
843 
844  aws->at("close");
845  aws->callback(AW_POPDOWN);
846  aws->create_button("CLOSE", "CLOSE");
847 
848  aws->at("help");
849  aws->callback(makeHelpCallback("prop_configs.hlp"));
850  aws->create_button("HELP", "HELP");
851 
852  // create awars
853  AW_awar *awar_existing = config->get_awar(EXISTING_CFGS);
854  AW_awar *awar_current = config->get_awar(CURRENT_CFG);
855  AW_awar *awar_comment = config->get_awar(VISIBLE_COMMENT);
856 
857  aws->at("comment");
858  aws->create_text_field(awar_comment->awar_name);
859 
860  aws->at("clr");
861  aws->callback(makeWindowCallback(erase_comment_cb, awar_comment));
862  aws->create_autosize_button("erase", "Erase", "E");
863 
864  awar_current->add_callback(makeRootCallback(current_changed_cb, config));
865  awar_comment->add_callback(makeRootCallback(comment_changed_cb, config));
866 
867  AW_selection_list *sel = awt_create_selection_list_with_input_field(aws, awar_current->awar_name, "cfgs", "name");
868 
869  awar_existing->add_callback(makeRootCallback(refresh_config_sellist_cb, config, sel));
870  awar_existing->touch(); // fills selection list
871  awar_current->touch(); // initialized comment textbox
872 
873  aws->auto_space(0, 3);
874  aws->button_length(10);
875  aws->at("button");
876 
877  int xpos = aws->get_at_xposition();
878  int ypos = aws->get_at_yposition();
879 
880  struct but {
881  void (*cb)(AW_window*, AWT_configuration*);
882  const char *id;
883  const char *label;
884  const char *mnemonic;
885  } butDef[] = {
886  { restore_cb, "RESTORE", "Restore", "R" },
887  { store_cb, "STORE", "Store", "S" },
888  { delete_cb, "DELETE", "Delete", "D" },
889  { load_cb, "LOAD", "Load", "L" },
890  { save_cb, "SAVE", "Save", "v" },
891  { reset_cb, "RESET", "Factory\ndefaults", "F" },
892  { edit_cb, "EDIT", "Edit", "E" },
893 #if defined(DEBUG)
894  { dump_cb, "DUMP", "dump\npredef", "U" },
895 #endif
896  };
897  const int buttons = ARRAY_ELEMS(butDef);
898  for (int b = 0; b<buttons; ++b) {
899  const but& B = butDef[b];
900 
901  if (b>0) {
902  aws->at("button");
903  aws->at(xpos, ypos);
904  }
905 
906  aws->callback(makeWindowCallback(B.cb, config));
907  aws->create_button(B.id, B.label, B.mnemonic);
908 
909  aws->at_newline();
910  ypos = aws->get_at_yposition();
911  }
912 
913  return aws;
914 }
915 
917  string sourceId;
918  string targetId;
919  string namePrefix;
920 
921  mutable bool used;
922 
923  ConfigManagerConversionDef(const char *old_config_id, const char *new_config_id, const char *name_prefix)
924  : sourceId(old_config_id),
925  targetId(new_config_id),
926  namePrefix(name_prefix),
927  used(false)
928  {
929  awt_assert(!GB_check_key(old_config_id));
930  awt_assert(!GB_check_key(new_config_id));
931  }
932 
933  string getTargetNameFor(const string& sourceName) {
934  return namePrefix.empty()
935  ? sourceName
936  : namePrefix + '_' + sourceName;
937  }
938 };
939 typedef list<ConfigManagerConversionDef> ConversionDefList; // will only have few elements
940 static ConversionDefList conversions;
941 
943  bool have_convertable_source = ConfigDefinition::have_existing_config(default_file, conv.sourceId);
944  for (ConversionDefList::iterator c = conversions.begin(); !have_convertable_source && c != conversions.end(); ++c) {
945  if (c->targetId == conv.sourceId) {
946  if (c->used) GBK_terminatef("looping conversion rules defined by calls to AWT_define_config_manager_conversion"); // coders error: rules loop (eg. A->B->A)
947  LocallyModify<bool> detectLooping(c->used, true);
948  have_convertable_source = have_or_willConvert_source_config(*c, default_file);
949  }
950  }
951  return have_convertable_source;
952 }
953 
954 void AWT_define_config_manager_conversion(const char *old_config_id, const char *new_config_id, const char *name_prefix) {
968  conversions.push_back(ConfigManagerConversionDef(old_config_id, new_config_id, null2empty(name_prefix)));
969 }
970 
971 // these callbacks should never be used
972 static char *dont_store_cb() { awt_assert(0); return NULp; }
973 static void dont_restore_cb() { awt_assert(0); }
974 
975 static void move_configs_convertable_to(AWT_configuration *targetConf, AW_default default_file, bool in_recursion) {
976  StoreConfigCallback scb = makeStoreConfigCallback(dont_store_cb);
977  RestoreConfigCallback rcb = makeRestoreConfigCallback(dont_restore_cb);
978 
979  string targetId = targetConf->get_id();
980 
981  int errors = 0; // count failed conversions (configs or managers)
982  int succeeded = 0; // count successful conversions (single configs)
983  int attempted = 0; // count attempted conversions (whole managers)
984 
985  if (!in_recursion) {
986  for (ConversionDefList::iterator c = conversions.begin(); c != conversions.end(); ++c) {
987  if (c->sourceId == targetId) {
988  aw_message(GBS_global_string("Invalid dangerous conversion '%s'->'%s' uses final target as source. Conversion aborted.", c->sourceId.c_str(), c->targetId.c_str()));
989  return;
990  }
991  }
992  }
993 
994  for (ConversionDefList::iterator c = conversions.begin(); c != conversions.end(); ++c) {
995  if (c->targetId == targetId) { // apply all conversion with matching target config id
996  attempted++;
997  if (have_or_willConvert_source_config(*c, default_file)) {
998  if (c->used) { // never run "conversion from" multiple times on the same source -> avoids deadlocks
999  aw_message(GBS_global_string("Invalid looping conversion rules defined => skip repeated conversion '%s'->'%s'",
1000  c->sourceId.c_str(),
1001  c->targetId.c_str()));
1002  errors++;
1003  // These rules were defined by calls to AWT_define_config_manager_conversion.
1004  // This is a coders error: rules loop somehow eg. A->B->A
1005  }
1006  else {
1007  AWT_configuration sourceConf(default_file, c->sourceId.c_str(), scb, rcb, NULp);
1008 
1009  // first recurse move_configs_convertable_to with sourceConf (implements chained conversions):
1010  LocallyModify<bool> detectLooping(c->used, true);
1011  move_configs_convertable_to(&sourceConf, default_file, true);
1012 
1013  ConstStrArray cfgs;
1014  get_existing_configs(sourceConf, cfgs);
1015 
1016  AWT_config sourceComments(sourceConf.get_awar_value(STORED_COMMENTS).c_str());
1017  if (sourceComments.parseError()) {
1018  aw_message(GBS_global_string("Failed to parse config-comments (%s). Will continue conversion, but comments are lost.", sourceComments.parseError()));
1019  }
1020  AWT_config targetComments("");
1021 
1022  if (!cfgs.empty()) {
1023  string existing = targetConf->get_awar_value(EXISTING_CFGS);
1024 
1025  size_t cfg_count = cfgs.size();
1026  for (size_t n = 0; n<cfg_count; ++n) {
1027  string sourceName = cfgs[n];
1028  awt_assert(!sourceName.empty());
1029 
1030  string configData = sourceConf.get_config(sourceName);
1031  string targetName = c->getTargetNameFor(sourceName);
1032 
1033  GB_ERROR error;
1034  if (targetConf->has_existing(targetName)) {
1035  error = GBS_global_string("config '%s' already exists in '%s'-manager",
1036  targetName.c_str(), c->targetId.c_str());
1037  }
1038  else {
1039  error = targetConf->set_config(targetName, configData);
1040  }
1041 
1042  if (!error && !sourceComments.parseError() && sourceComments.has_entry(sourceName.c_str())) {
1043  targetComments.set_entry(targetName.c_str(), sourceComments.get_entry(sourceName.c_str()));
1044  }
1045 
1046  if (error) {
1047  aw_message(GBS_global_string("Failed to convert managed config '%s' (Reason: %s)",
1048  sourceName.c_str(), error));
1049  errors++;
1050  }
1051  else {
1052  existing = existing.empty() ? targetName : (targetName+';'+existing);
1053  succeeded++;
1054  }
1055  }
1056 
1057  save_comments(targetComments, targetConf); // store converted comments
1058  targetConf->set_awar_value(EXISTING_CFGS, existing); // update existing configs
1059  sourceConf.erase_all_managed_configs(); // from properties
1060  }
1061  }
1062  }
1063  }
1064  }
1065 
1066  const bool final_conversion = !in_recursion;
1067  const bool sth_converted = succeeded || errors;
1068  const bool show_report = sth_converted && (final_conversion || errors);
1069  const bool recommend_save = sth_converted && final_conversion;
1070 
1071  if (show_report) {
1072  GBS_strstruct report(500);
1073 
1074  report.cat(errors ? "Failed to convert" : "Successfully converted");
1075  report.cat(" GUI configurations: ");
1076  report.putlong(errors ? errors : succeeded);
1077  if (errors && succeeded) {
1078  report.nprintf(50, " (succeeded for %i)", succeeded);
1079  }
1080  aw_message(report.get_data());
1081  }
1082  if (recommend_save) aw_message("Unless you save properties, the conversion will be redone in your next arb session.");
1083  if (final_conversion && !attempted && !conversions.empty()) {
1084  aw_message(GBS_global_string("Detected only useless conversion rules (no rule targets '%s')", targetId.c_str()));
1085  }
1086 }
1087 
1088 static list<manager_window_def> predefMan;
1089 
1090 void AWT_predef_config_manager(const char *macro_id, const char *window_title) {
1102  predefMan.push_back(manager_window_def(macro_id, window_title));
1103 }
1104 
1105 static void destroy_AWT_configuration(AWT_configuration *c) { delete c; }
1106 
1107 void AWT_insert_config_manager(AW_window *aww, AW_default default_file_, const char *id, const StoreConfigCallback& store_cb,
1108  const RestoreConfigCallback& load_or_reset_cb, const char *macro_id, const AWT_predefined_config *predef)
1109 {
1118  AWT_configuration * const config = new AWT_configuration(default_file_, id, store_cb, load_or_reset_cb, predef);
1119 
1120  // detect using multiple config managers in same parent window
1121  {
1122  static AW_window *last_aww = NULp;
1123  static int configManCounter = -666;
1124 
1125  if (aww != last_aww) {
1126  // first config manager in this window (=normal case)
1127  last_aww = aww;
1128  configManCounter = 0;
1129  }
1130 
1131  if (predefMan.empty()) {
1132  awt_assert(configManCounter == 0); // you are calling AWT_insert_config_manager multiple times for same 'aww'!
1133  // Please also use AWT_predef_config_manager multiple times to make these managers distinguishable.
1134 
1136  }
1137  else {
1138  config->configure_manager_window(predefMan.front());
1139  predefMan.pop_front();
1140  }
1141  configManCounter++;
1142  }
1143 
1144  int old_button_length = aww->get_button_length();
1145 
1146  aww->button_length(0); // -> autodetect size by size of graphic
1147  aww->callback(makeCreateWindowCallback(create_config_manager_window, destroy_AWT_configuration, config));
1148  aww->create_button(macro_id ? macro_id : "SAVELOAD_CONFIG", "#conf_save.xpm");
1149 
1150  aww->button_length(old_button_length);
1151 
1152  move_configs_convertable_to(config, default_file_, false);
1153  conversions.clear();
1154 }
1155 
1156 static char *store_generated_config_cb(const ConfigSetupCallback *setup_cb) {
1157  AWT_config_definition cdef;
1158  (*setup_cb)(cdef);
1159 
1160  return cdef.read();
1161 }
1162 static void load_or_reset_generated_config_cb(const char *stored_string, const ConfigSetupCallback *setup_cb) {
1163  AWT_config_definition cdef;
1164  (*setup_cb)(cdef);
1165 
1166  if (stored_string) cdef.write(stored_string);
1167  else cdef.reset();
1168 }
1169 void AWT_insert_config_manager(AW_window *aww, AW_default default_file_, const char *id, ConfigSetupCallback setup_cb, const char *macro_id, const AWT_predefined_config *predef) {
1178  ConfigSetupCallback * const setup_cb_copy = new ConfigSetupCallback(setup_cb); // not freed (bound to cb)
1179  AWT_insert_config_manager(aww, default_file_, id,
1180  makeStoreConfigCallback(store_generated_config_cb, setup_cb_copy),
1181  makeRestoreConfigCallback(load_or_reset_generated_config_cb, setup_cb_copy),
1182  macro_id, predef);
1183 }
1184 
1186  cdef.add(mapping);
1187 }
1188 
1189 void AWT_insert_config_manager(AW_window *aww, AW_default default_file_, const char *id, const AWT_config_mapping_def *mapping, const char *macro_id, const AWT_predefined_config *predef) {
1197  AWT_insert_config_manager(aww, default_file_, id, makeConfigSetupCallback(generate_config_from_mapping_cb, mapping), macro_id, predef);
1198 }
1199 
1200 // -------------------
1201 // AWT_config
1202 
1203 AWT_config::AWT_config(const char *cfgStr) :
1204  mapping(new ConfigMapping),
1205  parse_error(NULp)
1206 {
1207  parse_error = mapping->parseFrom(cfgStr);
1208 }
1209 
1210 inline void warn_unknown_awar(const string& awar_name) {
1211  aw_message(GBS_global_string("Warning: unknown awar referenced\n(%s)", awar_name.c_str()));
1212 }
1213 
1214 void AWT_config::init_from_awars(const ConfigMapping& cfgname2awar) {
1215  config_map& valuemap = *mapping;
1216  AW_root *aw_root = AW_root::SINGLETON;
1217 
1218  int skipped = 0;
1219  for (config_map::const_iterator c = cfgname2awar.begin(); c != cfgname2awar.end(); ++c) {
1220  const string& key(c->first);
1221  const string& awar_name(c->second);
1222 
1223  AW_awar *awar = aw_root->awar_no_error(awar_name.c_str());
1224  if (awar) {
1225  char *awar_value = awar->read_as_string();
1226  valuemap[key] = awar_value;
1227  free(awar_value);
1228  }
1229  else {
1230  valuemap.erase(key);
1231  warn_unknown_awar(awar_name);
1232  ++skipped;
1233  }
1234  }
1235 
1236  awt_assert((valuemap.size()+skipped) == cfgname2awar.size());
1237  awt_assert(!parse_error);
1238 }
1239 
1241  mapping(new ConfigMapping),
1242  parse_error(NULp)
1243 {
1244  init_from_awars(cfgname2awar);
1245 }
1246 
1248  mapping(new ConfigMapping),
1249  parse_error(NULp)
1250 {
1251  init_from_awars(cfg_def->get_mapping());
1252 }
1253 
1255  delete mapping;
1256 }
1257 
1258 void AWT_config::write_to_awars(const ConfigMapping& cfgname2awar, bool warn) const {
1259  // writes values from config into awars (write-order: alphabetical by config-key)
1260 
1261  awt_assert(!parse_error);
1262  AW_root *aw_root = AW_root::SINGLETON;
1263  int unmapped = 0;
1264  for (config_map::const_iterator e = mapping->begin(); e != mapping->end(); ++e) {
1265  const string& config_name(e->first);
1266  const string& value(e->second);
1267 
1268  config_map::const_iterator found = cfgname2awar.find(config_name);
1269  if (found == cfgname2awar.end()) {
1270  if (warn) aw_message(GBS_global_string("config contains unknown entry '%s'", config_name.c_str()));
1271  unmapped++;
1272  }
1273  else {
1274  const string& awar_name(found->second);
1275  AW_awar *awar = aw_root->awar(awar_name.c_str());
1276  awar->write_as_string(value.c_str());
1277  }
1278  }
1279 
1280  if (unmapped && warn) {
1281  int mapped = mapping->size()-unmapped;
1282  aw_message(GBS_global_string("Not all config entries were valid:\n"
1283  "(known/restored: %i, unknown/ignored: %i)\n"
1284  "Note: ok for configs shared between multiple windows",
1285  mapped, unmapped));
1286  }
1287 }
1288 
1290  mapping->get_entries(to_array);
1291 }
1292 
1293 // ------------------------------
1294 // AWT_config_definition
1295 
1297  : config_mapping(new ConfigMapping)
1298 {}
1299 
1301  : config_mapping(new ConfigMapping)
1302 {
1303  add(mdef);
1304 }
1305 
1307  delete config_mapping;
1308 }
1309 
1310 void AWT_config_definition::add(const char *awar_name, const char *config_name) {
1311  (*config_mapping)[config_name] = awar_name;
1312 }
1313 void AWT_config_definition::add(const char *awar_name, const char *config_name, int counter) {
1314  add(awar_name, GBS_global_string("%s%i", config_name, counter));
1315 }
1317  while (mdef->awar_name && mdef->config_name) {
1318  add(mdef->awar_name, mdef->config_name);
1319  mdef++;
1320  }
1321 }
1322 
1324  // creates a string from awar values
1325 
1326  AWT_config current_state(*config_mapping);
1327  return current_state.config_string();
1328 }
1329 void AWT_config_definition::write(const char *cfgStr) const {
1330  // write values from string to awars
1331  // if the string contains unknown settings, they are silently ignored
1332 
1333  awt_assert(cfgStr);
1334 
1335  AWT_config wanted_state(cfgStr);
1336  GB_ERROR error = wanted_state.parseError();
1337  if (!error) {
1338  char *old_state = read();
1339 
1340  wanted_state.write_to_awars(*config_mapping, true);
1341  if (strcmp(old_state, cfgStr) != 0) { // expect that anything gets changed?
1342  char *new_state = read();
1343  if (strcmp(new_state, cfgStr) != 0) {
1344  bool retry = true;
1345  int maxRetries = 10;
1346  while (retry && maxRetries--) {
1347  printf("Note: repeating config restore (did not set all awars correct)\n");
1348  wanted_state.write_to_awars(*config_mapping, false);
1349  char *new_state2 = read();
1350  if (strcmp(new_state, new_state2) != 0) { // retrying had some effect -> repeat
1351  reassign(new_state, new_state2);
1352  }
1353  else {
1354  retry = false;
1355  free(new_state2);
1356  }
1357  }
1358  if (retry) {
1359  error = "Unable to restore everything (might be caused by outdated, now invalid settings)";
1360  }
1361  }
1362  free(new_state);
1363  }
1364  free(old_state);
1365  }
1366  if (error) aw_message(GBS_global_string("Error restoring configuration (%s)", error));
1367 }
1368 
1370  // reset all awars (stored in config) to factory defaults
1371  AW_root *aw_root = AW_root::SINGLETON;
1372  for (config_map::const_iterator e = config_mapping->begin(); e != config_mapping->end(); ++e) {
1373  const string& awar_name(e->second);
1374  AW_awar *awar = aw_root->awar_no_error(awar_name.c_str());
1375  if (awar) {
1376  awar->reset_to_default();
1377  }
1378  else {
1379  warn_unknown_awar(awar_name);
1380  }
1381  }
1382 }
1383 
1384 // --------------------------------------------------------------------------------
1385 
1386 void AWT_modify_managed_configs(AW_default default_file, const char *id, ConfigModifyCallback mod_cb, AW_CL cl_user) {
1394  ConfigDefinition configDef(default_file, id);
1395 
1396  ConstStrArray cfgs;
1397  get_existing_configs(configDef, cfgs);
1398 
1399  for (size_t c = 0; c<cfgs.size(); ++c) {
1400  GB_transaction ta(configDef.get_db());
1401  GBDATA *gb_cfg = GB_search(configDef.get_db(), configDef.get_config_dbpath(cfgs[c]).c_str(), GB_FIND);
1402  GB_ERROR error = NULp;
1403 
1404  if (gb_cfg) {
1405  const char *content = GB_read_char_pntr(gb_cfg);
1406 
1407  AWT_config cmap(content);
1408  error = cmap.parseError();
1409  if (!error) {
1410  ConstStrArray entries;
1411  cmap.get_entries(entries);
1412 
1413  bool update = false;
1414  for (size_t e = 0; e<entries.size(); ++e) {
1415  const char *old_content = cmap.get_entry(entries[e]);
1416  char *new_content = mod_cb(entries[e], old_content, cl_user);
1417 
1418  if (!new_content) {
1419  cmap.delete_entry(entries[e]);
1420  update = true;
1421  }
1422  else if (strcmp(old_content, new_content) != 0) {
1423  cmap.set_entry(entries[e], new_content);
1424  update = true;
1425  }
1426  free(new_content);
1427  }
1428 
1429  if (update) {
1430  char *cs = cmap.config_string();
1431  error = GB_write_string(gb_cfg, cs);
1432  free(cs);
1433  }
1434  }
1435  }
1436 
1437  if (error) {
1438  error = GBS_global_string("%s (config='%s')", error, cfgs[c]);
1439  aw_message(error);
1440  }
1441  }
1442 }
1443 
1444 
AW_awar * get_awar(const string &subname, bool temp=false) const
GB_ERROR GB_check_key(const char *key) __ATTR__USERESULT
Definition: adstring.cxx:85
void set_awar_value(ConfigAwar a, const string &new_value) const
const char * get_macro_id() const
AWT_configuration(AW_default default_file_, const char *id_, const StoreConfigCallback &store_, const RestoreConfigCallback &load_or_reset_, const AWT_predefined_config *predef)
#define awt_assert(cond)
Definition: TreeAwars.cxx:26
static bool have_existing_config(AW_default default_file_, const string &id_)
const char * GB_ERROR
Definition: arb_core.h:25
string result
const char * id
Definition: AliAdmin.cxx:17
GB_ERROR Restore(const string &s) const
void put(const char *elem)
Definition: arb_strarray.h:188
void delete_entry(const char *entry)
void button_length(int length)
Definition: AW_at.cxx:288
void add(const char *awar_name, const char *config_name)
bool has_entry(const char *entry) const
static void get_existing_configs(ConfigDefinition &configDef, ConstStrArray &cfgs)
size_t size() const
Definition: arb_strarray.h:85
GBDATA * GB_child(GBDATA *father)
Definition: adquery.cxx:322
return string(buffer, length)
void AWT_insert_config_manager(AW_window *aww, AW_default default_file_, const char *id, const StoreConfigCallback &store_cb, const RestoreConfigCallback &load_or_reset_cb, const char *macro_id, const AWT_predefined_config *predef)
GB_ERROR GB_write_string(GBDATA *gbd, const char *s)
Definition: arbdb.cxx:1387
void load_xfig(const char *file, bool resize=true)
Definition: AW_window.cxx:729
const char * get_window_id() const
Definition: aw_window.hxx:375
static void save_cb(AW_window *, AWT_configuration *config)
static void move_configs_convertable_to(AWT_configuration *targetConf, AW_default default_file, bool in_recursion)
#define HEADER
manager_window_def(string macro_id_, string title_)
GB_ERROR Save(const char *filename, const string &cfg_name, const string &comment)
const char * get_id() const
static list< manager_window_def > predefMan
void store_changed_field_content()
void warn_unknown_awar(const string &awar_name)
void write_to_awars(const ConfigMapping &cfgname2awar, bool warn) const
AW_default get_db() const
std::map< std::string, std::string > config_map
Definition: ConfigMapping.h:28
GB_ERROR GB_IO_error(const char *action, const char *filename)
Definition: arb_msg.cxx:285
static ConversionDefList conversions
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:203
bool GB_have_error()
Definition: arb_msg.cxx:338
void GBK_terminatef(const char *templat,...)
Definition: arb_msg.cxx:523
STL namespace.
char * GBS_string_eval(const char *insource, const char *icommand)
Definition: admatch.cxx:699
void AW_POPDOWN(AW_window *window)
Definition: AW_window.cxx:52
char * GBS_string_2_key(const char *str)
Definition: adstring.cxx:52
void cat(const char *from)
Definition: arb_strbuf.h:199
GB_ERROR set_config(const string &cfgname, const string &new_value)
const AWT_predefined_config * find_predefined(const string &cfgname)
string get_awar_name(const string &subname, bool temp=false) const
#define ARRAY_ELEMS(array)
Definition: arb_defs.h:19
string get_config(const string &cfgname)
GB_ERROR parseError() const
void erase_all_managed_configs()
bool empty() const
Definition: arb_strarray.h:86
#define cb(action)
void add_predefined_to(ConstStrArray &cfgs)
AW_awar * add_callback(const RootCallback &cb)
Definition: AW_awar.cxx:231
GB_ERROR GB_delete(GBDATA *&source)
Definition: arbdb.cxx:1916
static AW_window * create_config_manager_window(AW_root *aw_root, AWT_configuration *config)
const char * read_char_pntr() const
Definition: AW_awar.cxx:168
void putlong(long l)
Definition: arb_strbuf.h:240
static void dont_restore_cb()
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:342
static AW_root * SINGLETON
Definition: aw_root.hxx:102
WindowCallback makeHelpCallback(const char *helpfile)
Definition: aw_window.hxx:106
void AWT_modify_managed_configs(AW_default default_file, const char *id, ConfigModifyCallback mod_cb, AW_CL cl_user)
GB_CSTR GB_read_key_pntr(GBDATA *gbd)
Definition: arbdb.cxx:1656
static void keep_changed_fields_cb(AW_window *, AWT_configuration *config)
void get_entries(class ConstStrArray &to_array)
Definition: ConfigMapping.h:73
static void delete_cb(AW_window *, AWT_configuration *config)
static void restore_cb(AW_window *, AWT_configuration *config)
char *(* ConfigModifyCallback)(const char *key, const char *value, AW_CL cl_user)
ConfigManagerConversionDef(const char *old_config_id, const char *new_config_id, const char *name_prefix)
#define aw_assert(bed)
Definition: aw_position.hxx:29
static void encode_escapes(std::string &s, const char *to_escape)
#define false
Definition: ureadseq.h:13
static void refresh_config_sellist_cb(AW_root *, AWT_configuration *config, AW_selection_list *sel)
const char * get_window_title() const
Definition: AW_window.cxx:1083
void popup_edit_window(AW_window *aw_config)
void touch()
Definition: AW_awar.cxx:207
static void error(const char *msg)
Definition: mkptypes.cxx:96
void update_field_selection_list()
static void reset_cb(AW_window *, AWT_configuration *config)
#define NO_CONFIG_SELECTED
const char * mnemonic
static GB_ERROR decode_escapes(std::string &s)
static void generate_config_from_mapping_cb(AWT_config_definition &cdef, const AWT_config_mapping_def *mapping)
char * read_as_string() const
const char * get_title() const
void AWT_predef_config_manager(const char *macro_id, const char *window_title)
static void current_changed_cb(AW_root *, AWT_configuration *config)
list< ConfigManagerConversionDef > ConversionDefList
void Reset() const
#define HEADERLEN
static bool have_or_willConvert_source_config(const ConfigManagerConversionDef &conv, AW_default default_file)
GB_ERROR reset_to_default()
Definition: AW_awar.cxx:214
static void destroy_AWT_configuration(AWT_configuration *c)
static void delete_field_cb(AW_window *, AWT_configuration *config)
AWT_config(const char *cfgStr)
static void comment_changed_cb(AW_root *, AWT_configuration *config)
static void selected_field_changed_cb(AW_root *, AWT_configuration *config)
AW_awar * awar_no_error(const char *awar)
end timer stuff
Definition: AW_root.cxx:563
AW_awar * awar(const char *awar)
Definition: AW_root.cxx:568
void save_comments(const AWT_config &comments, AWT_configuration *config)
Definition: arbdb.h:86
int get_button_length() const
Definition: AW_at.cxx:292
void nl()
Definition: test_unit.h:415
ConfigDefinition(AW_default default_file_, const char *id_)
void configure_manager_window_popping_up_from(AW_window *aww)
static void load_cb(AW_window *, AWT_configuration *config)
void remove_from_configs(const string &config, string &existing_configs)
GB_ERROR write_as_string(const char *aw_string)
GB_ERROR GB_set_temporary(GBDATA *gbd) __ATTR__USERESULT
Definition: arbdb.cxx:2282
char * awar_name
Definition: aw_awar.hxx:103
char * GBT_join_strings(const CharPtrArray &strings, char separator)
fputs(TRACE_PREFIX, stderr)
long AW_CL
Definition: cb.h:21
GB_ERROR Load(const char *filename, const string &cfg_name, string &found_comment)
bool is_prefined(const string &cfgname)
void get_entries(class ConstStrArray &to_array)
void AWT_define_config_manager_conversion(const char *old_config_id, const char *new_config_id, const char *name_prefix)
GB_ERROR parseFrom(const std::string &configString)
void nprintf(size_t maxlen, const char *templat,...) __ATTR__FORMAT_MEMBER(2)
Definition: arb_strbuf.cxx:29
void configure_manager_window(const manager_window_def &mw_def)
static void store_cb(AW_window *, AWT_configuration *config)
string get_config_dbpath(const string &cfgname) const
bool operator<(const ConfigDefinition &other) const
void set_entry(const char *entry, const char *value)
static void field_content_changed_cb(AW_root *, AWT_configuration *config)
string get_awar_value(ConfigAwar a) const
static void load_or_reset_generated_config_cb(const char *stored_string, const ConfigSetupCallback *setup_cb)
string getTargetNameFor(const string &sourceName)
void aw_message(const char *msg)
Definition: AW_status.cxx:1142
AW_root * get_root()
Definition: aw_window.hxx:359
const ConfigMapping & get_mapping() const
AW_selection_list * awt_create_selection_list_with_input_field(AW_window *aww, const char *awar_name, const char *at_box, const char *at_field)
Definition: sel_boxes.cxx:1210
char * aw_modal_file_selection(const char *title, const char *dir, const char *def_name, const char *suffix)
Definition: AW_modal.cxx:311
static void erase_comment_cb(AW_window *, AW_awar *awar_comment)
#define NULp
Definition: cxxforward.h:116
ConfigAwar
GB_ERROR write_string(const char *aw_string)
void GBT_split_string(ConstStrArray &dest, const char *namelist, const char *separator, SplitMode mode)
Definition: arb_strarray.h:223
const char * get_awar_name(const char *awar_base_name, const char *entry)
Definition: MG_main.cxx:384
bool ARB_strBeginsWith(const char *str, const char *with)
Definition: arb_str.h:42
bool has_existing(string lookFor)
const char * get_data() const
Definition: arb_strbuf.h:120
static char * store_generated_config_cb(const ConfigSetupCallback *setup_cb)
GBDATA * GB_nextChild(GBDATA *child)
Definition: adquery.cxx:326
char * Store() const
static char * dont_store_cb()
GB_transaction ta(gb_var)
void callback(const WindowCallback &cb)
Definition: AW_window.cxx:142
const char * get_entry(const char *entry) const
GB_CSTR GB_read_char_pntr(GBDATA *gbd)
Definition: arbdb.cxx:904
void init_from_array(const CharPtrArray &entries, const char *default_displayed, const char *default_value)
Definition: AW_select.cxx:322
AW_awar * awar_string(const char *var_name, const char *default_value="", AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:584
GBDATA * GB_search(GBDATA *gbd, const char *fieldpath, GB_TYPES create)
Definition: adquery.cxx:531
static void edit_cb(AW_window *aww, AWT_configuration *config)
char * config_string() const
AW_awar * get_awar(ConfigAwar a) const
void aw_message_if(GB_ERROR error)
Definition: aw_msg.hxx:21
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:194
const char * label
void write(const char *cfgStr) const
void create_button(const char *macro_name, AW_label label, const char *mnemonic=NULp, const char *color=NULp)
Definition: AW_button.cxx:448
GB_ERROR rewrite_string(const char *aw_string)
char * GB_read_file(const char *path)
Definition: adsocket.cxx:288
#define max(a, b)
Definition: f2c.h:154
GB_write_int const char s
Definition: AW_awar.cxx:154