48 bool is_prefined(
const string& cfgname) {
return cfgname[0] ==
'*'; }
56 static string container_name_for(
const string& id_,
bool temp) {
57 #if defined(ASSERTION_USED)
61 return string(
"tmp/general_configs/" + (temp ? 0 : 4)) + id_;
66 : default_file(default_file_),
80 const char *
get_id()
const {
return id.c_str(); }
83 return container_name_for(
id, temp)+
'/'+subname;
101 string container_path = container_name_for(id_,
false);
106 return gb_cfg_manager;
115 string container_path = container_name_for(
id,
false);
136 StoreConfigCallback store;
137 RestoreConfigCallback load_or_reset;
152 load_or_reset(load_or_reset_),
155 field_selection(
NULp)
162 return predef ? predef->
config :
"";
173 error =
"cannot modify predefined config";
189 char *
Store()
const {
return store(); }
193 if (s.empty()) error =
"empty/nonexistant config";
194 else load_or_reset(s.c_str());
202 GB_ERROR Save(
const char* filename,
const string& cfg_name,
const string& comment);
203 GB_ERROR Load(
const char* filename,
const string& cfg_name,
string& found_comment);
208 string wanted = S+ lookFor +S;
210 return existing.find(wanted) != string::npos;
213 void erase_deleted_configs();
217 for (
int i = 0; predefined[i].
name; ++i) {
219 cfgs.
put(predefined[i].name);
225 for (
int i = 0; predefined[i].
name; ++i) {
226 if (cfgname == predefined[i].name) {
227 return &predefined[i];
248 return win_def.
title.c_str();
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();
259 #define HEADER "ARB_CONFIGURATION"
265 printf(
"Saving config to '%s'..\n", filename);
267 FILE *out = fopen(filename,
"wt");
273 if (comment.empty()) {
274 fprintf(out,
HEADER ":%s\n", get_id());
277 string encoded_comment(comment);
279 fprintf(out,
HEADER ":%s;%s\n", get_id(), encoded_comment.c_str());
282 string content = get_config(cfg_name);
283 fputs(content.c_str(), out);
293 printf(
"Loading config from '%s'..\n", filename);
301 error =
"Unexpected content (" HEADER " missing)";
305 char *
nl = strchr(id_pos,
'\n');
308 error =
"Unexpected content (no ID)";
313 char *comment = strchr(id_pos,
';');
314 if (comment) *comment++ = 0;
316 if (strcmp(id_pos, get_id()) != 0) {
317 error =
GBS_global_string(
"Wrong config type (expected=%s, found=%s)", get_id(), id_pos);
320 error = set_config(cfg_name, nl);
321 if (comment && !error) {
322 found_comment = comment;
350 const char *name = key+4;
351 if (!has_existing(name)) {
367 for (
int i = 0; cfgs[i]; ++i) {
368 if (strcmp(cfgs[i], config.c_str()) != 0) {
369 remaining.
put(cfgs[i]);
374 existing_configs = rest;
378 #define NO_CONFIG_SELECTED "<no config selected>"
388 if (entered_name[0]) {
391 name = isPredefined ?
string(1,
'*')+asKey : asKey;
408 if (comments.parseError()) {
409 display =
GBS_global_string(
"Error reading config comments:\n%s", comments.parseError());
412 const char *saved_comment = comments.get_entry(name.c_str());
413 display = null2empty(saved_comment);
440 free(comments_string);
445 if (!curr_cfg.empty()) {
449 if (found && changed_comment != found->
description) {
450 aw_message(
"The description of predefined configs is immutable");
456 if (comments.parseError()) {
460 if (changed_comment.empty()) {
461 comments.delete_entry(curr_cfg.c_str());
464 comments.set_entry(curr_cfg.c_str(), changed_comment.c_str());
478 if (cfgName.empty()) {
479 error =
"Please select config to restore";
488 if (cfgName.empty())
aw_message(
"Please select or enter name of config to store");
498 existing = existing.empty() ? cfgName : (
string(cfgName)+
';'+existing);
500 char *cfgStr = config->
Store();
514 aw_message(
"You may not delete predefined configs");
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";
542 error = config->
Load(filename, cfgName, comment);
559 if (cfgName.empty()) error =
"Please select config to save";
563 cfgName.c_str() + (cfgName[0] ==
'*'));
566 if (filename && filename[0]) {
569 error = config->
Save(filename, cfgName, comment);
579 static string esc(
const string&
str) {
582 char *escaped =
GBS_string_eval(str.c_str(),
"\\\\=\\\\\\\\:\"=\\\\\":\\n=\\\\n:\\t=\\\\t");
596 if (cfgName.empty()) error =
"Please select config to dump";
599 string confStr = esc(config->
get_config(cfgName));
601 cfgName = esc(cfgName);
602 const char *cfg = cfgName.c_str();
604 fprintf(stderr,
" { \"*%s\", \"%s\", \"%s\" },\n",
605 cfg[0] ==
'*' ? cfg+1 : cfg,
615 if (field_selection) {
618 bool seenSelected =
false;
620 field_selection->clear();
621 if (!cfgName.empty() && has_existing(cfgName)) {
622 string configString = get_config(cfgName);
625 stored.get_entries(entries);
627 StrArray entries_with_content;
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;
633 for (
size_t e = 0; e<entries.size(); ++e) {
635 int(maxlen), entries[e],
636 stored.get_entry(entries[e])),
640 field_selection->insert_default(
"",
"");
641 field_selection->update();
655 string content =
"<select a field below>";
656 if (!cfgName.empty() && has_existing(cfgName)) {
658 if (!selected.empty()) {
659 string configString = get_config(cfgName);
662 if (stored.has_entry(selected.c_str())) {
663 content = stored.
get_entry(selected.c_str());
666 content =
GBS_global_string(
"<field '%s' not stored in config>", selected.c_str());
673 GB_ERROR AWT_configuration::update_config(
const string& cfgname,
const AWT_config& config) {
675 GB_ERROR error = set_config(cfgname, changedConfigString);
676 free(changedConfigString);
682 if (!cfgName.empty() && has_existing(cfgName)) {
684 if (!selected.empty()) {
685 string configString = get_config(cfgName);
687 if (stored.has_entry(selected.c_str())) {
688 string stored_content = stored.
get_entry(selected.c_str());
691 if (stored_content != changed_content) {
692 stored.set_entry(selected.c_str(), changed_content.c_str());
702 if (!cfgName.empty() && has_existing(cfgName)) {
704 if (!selected.empty()) {
705 string configString = get_config(cfgName);
707 if (stored.has_entry(selected.c_str())) {
710 field_selection->move_selection(1);
711 update_field_selection_list();
719 if (!cfgName.empty() && has_existing(cfgName)) {
720 string configString = get_config(cfgName);
723 char *current_state = Store();
727 stored.get_entries(entries);
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);
735 const char *current_content = current.
get_entry(entry);
736 if (strcmp(stored_content, current_content) == 0) {
737 stored.delete_entry(entry);
748 update_field_selection_list();
751 aw_message(
"All entries differ from current state");
766 AW_window_simple *aws =
new AW_window_simple;
769 aws->init(root, wid,
"Edit configuration entries");
772 aws->load_xfig(
"awt/edit_config.fig");
776 aws->create_button(
"CLOSE",
"CLOSE");
780 aws->create_button(
"HELP",
"HELP");
789 field_selection = aws->create_selection_list(get_awar(
SELECTED_FIELD)->awar_name);
791 aws->auto_space(0, 3);
792 aws->button_length(10);
795 int xpos = aws->get_at_xposition();
796 int ypos = aws->get_at_yposition();
799 aws->create_button(
"DELETE",
"Delete\nselected\nentry",
"D");
802 ypos = aws->get_at_yposition();
807 aws->create_button(
"KEEP_CHANGED",
"Keep only\nentries\ndiffering\nfrom\ncurrent\nstate",
"K");
816 update_field_selection_list();
839 AW_window_simple *aws =
new AW_window_simple;
846 aws->create_button(
"CLOSE",
"CLOSE");
850 aws->create_button(
"HELP",
"HELP");
858 aws->create_text_field(awar_comment->
awar_name);
862 aws->create_autosize_button(
"erase",
"Erase",
"E");
870 awar_existing->
touch();
871 awar_current->
touch();
873 aws->auto_space(0, 3);
874 aws->button_length(10);
877 int xpos = aws->get_at_xposition();
878 int ypos = aws->get_at_yposition();
887 {
store_cb,
"STORE",
"Store",
"S" },
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" },
894 { dump_cb,
"DUMP",
"dump\npredef",
"U" },
898 for (
int b = 0; b<buttons; ++b) {
899 const but& B = butDef[b];
906 aws->callback(makeWindowCallback(B.cb, config));
907 aws->create_button(B.id, B.label, B.mnemonic);
910 ypos = aws->get_at_yposition();
924 : sourceId(old_config_id),
925 targetId(new_config_id),
926 namePrefix(name_prefix),
934 return namePrefix.empty()
936 : namePrefix +
'_' + sourceName;
944 for (ConversionDefList::iterator c = conversions.begin(); !have_convertable_source && c != conversions.end(); ++c) {
946 if (c->used)
GBK_terminatef(
"looping conversion rules defined by calls to AWT_define_config_manager_conversion");
951 return have_convertable_source;
976 StoreConfigCallback scb = makeStoreConfigCallback(
dont_store_cb);
977 RestoreConfigCallback rcb = makeRestoreConfigCallback(
dont_restore_cb);
979 string targetId = targetConf->
get_id();
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()));
994 for (ConversionDefList::iterator c = conversions.begin(); c != conversions.end(); ++c) {
995 if (c->targetId == targetId) {
1000 c->sourceId.c_str(),
1001 c->targetId.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()));
1022 if (!cfgs.
empty()) {
1025 size_t cfg_count = cfgs.
size();
1026 for (
size_t n = 0; n<cfg_count; ++n) {
1027 string sourceName = cfgs[n];
1030 string configData = sourceConf.get_config(sourceName);
1031 string targetName = c->getTargetNameFor(sourceName);
1036 targetName.c_str(), c->targetId.c_str());
1039 error = targetConf->
set_config(targetName, configData);
1042 if (!error && !sourceComments.parseError() && sourceComments.has_entry(sourceName.c_str())) {
1043 targetComments.
set_entry(targetName.c_str(), sourceComments.get_entry(sourceName.c_str()));
1048 sourceName.c_str(),
error));
1052 existing = existing.empty() ? targetName : (targetName+
';'+existing);
1059 sourceConf.erase_all_managed_configs();
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;
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);
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()) {
1108 const RestoreConfigCallback& load_or_reset_cb,
const char *macro_id,
const AWT_predefined_config *predef)
1123 static int configManCounter = -666;
1125 if (aww != last_aww) {
1128 configManCounter = 0;
1131 if (predefMan.empty()) {
1139 predefMan.pop_front();
1148 aww->
create_button(macro_id ? macro_id :
"SAVELOAD_CONFIG",
"#conf_save.xpm");
1153 conversions.clear();
1166 if (stored_string) cdef.
write(stored_string);
1178 ConfigSetupCallback *
const setup_cb_copy =
new ConfigSetupCallback(setup_cb);
1207 parse_error = mapping->
parseFrom(cfgStr);
1214 void AWT_config::init_from_awars(
const ConfigMapping& cfgname2awar) {
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);
1226 valuemap[key] = awar_value;
1230 valuemap.erase(key);
1236 awt_assert((valuemap.size()+skipped) == cfgname2awar.size());
1244 init_from_awars(cfgname2awar);
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);
1268 config_map::const_iterator found = cfgname2awar.find(config_name);
1269 if (found == cfgname2awar.end()) {
1274 const string& awar_name(found->second);
1280 if (unmapped && warn) {
1281 int mapped = mapping->size()-unmapped;
1283 "(known/restored: %i, unknown/ignored: %i)\n"
1284 "Note: ok for configs shared between multiple windows",
1307 delete config_mapping;
1311 (*config_mapping)[config_name] = awar_name;
1338 char *old_state =
read();
1341 if (strcmp(old_state, cfgStr) != 0) {
1342 char *new_state =
read();
1343 if (strcmp(new_state, cfgStr) != 0) {
1345 int maxRetries = 10;
1346 while (retry && maxRetries--) {
1347 printf(
"Note: repeating config restore (did not set all awars correct)\n");
1349 char *new_state2 =
read();
1350 if (strcmp(new_state, new_state2) != 0) {
1351 reassign(new_state, new_state2);
1359 error =
"Unable to restore everything (might be caused by outdated, now invalid settings)";
1372 for (config_map::const_iterator e = config_mapping->begin(); e != config_mapping->end(); ++e) {
1373 const string& awar_name(e->second);
1399 for (
size_t c = 0; c<cfgs.
size(); ++c) {
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);
1422 else if (strcmp(old_content, new_content) != 0) {
1423 cmap.
set_entry(entries[e], new_content);
AW_awar * get_awar(const string &subname, bool temp=false) const
GB_ERROR GB_check_key(const char *key) __ATTR__USERESULT
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)
static bool have_existing_config(AW_default default_file_, const string &id_)
GB_ERROR Restore(const string &s) const
void put(const char *elem)
void delete_entry(const char *entry)
void button_length(int length)
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)
GBDATA * GB_child(GBDATA *father)
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)
void load_xfig(const char *file, bool resize=true)
const char * get_window_id() const
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)
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
GB_ERROR GB_IO_error(const char *action, const char *filename)
static ConversionDefList conversions
const char * GBS_global_string(const char *templat,...)
void GBK_terminatef(const char *templat,...)
char * GBS_string_eval(const char *insource, const char *icommand)
void AW_POPDOWN(AW_window *window)
char * GBS_string_2_key(const char *str)
void cat(const char *from)
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)
string get_config(const string &cfgname)
GB_ERROR parseError() const
void erase_all_managed_configs()
void add_predefined_to(ConstStrArray &cfgs)
AW_awar * add_callback(const RootCallback &cb)
GB_ERROR GB_delete(GBDATA *&source)
static AW_window * create_config_manager_window(AW_root *aw_root, AWT_configuration *config)
const char * read_char_pntr() const
static void dont_restore_cb()
GB_ERROR GB_await_error()
static AW_root * SINGLETON
WindowCallback makeHelpCallback(const char *helpfile)
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)
void update_field_content()
static void keep_changed_fields_cb(AW_window *, AWT_configuration *config)
void get_entries(class ConstStrArray &to_array)
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)
void keep_changed_fields()
static void encode_escapes(std::string &s, const char *to_escape)
static void refresh_config_sellist_cb(AW_root *, AWT_configuration *config, AW_selection_list *sel)
const char * get_window_title() const
void popup_edit_window(AW_window *aw_config)
static void error(const char *msg)
void update_field_selection_list()
static void reset_cb(AW_window *, AWT_configuration *config)
#define NO_CONFIG_SELECTED
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
static bool have_or_willConvert_source_config(const ConfigManagerConversionDef &conv, AW_default default_file)
GB_ERROR reset_to_default()
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
AW_awar * awar(const char *awar)
void save_comments(const AWT_config &comments, AWT_configuration *config)
int get_button_length() const
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
char * GBT_join_strings(const CharPtrArray &strings, char separator)
fputs(TRACE_PREFIX, stderr)
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)
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)
void erase_deleted_configs()
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)
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)
char * aw_modal_file_selection(const char *title, const char *dir, const char *def_name, const char *suffix)
static void erase_comment_cb(AW_window *, AW_awar *awar_comment)
GB_ERROR write_string(const char *aw_string)
void GBT_split_string(ConstStrArray &dest, const char *namelist, const char *separator, SplitMode mode)
const char * get_awar_name(const char *awar_base_name, const char *entry)
bool ARB_strBeginsWith(const char *str, const char *with)
bool has_existing(string lookFor)
const char * get_data() const
static char * store_generated_config_cb(const ConfigSetupCallback *setup_cb)
GBDATA * GB_nextChild(GBDATA *child)
static char * dont_store_cb()
GB_transaction ta(gb_var)
void callback(const WindowCallback &cb)
const char * get_entry(const char *entry) const
GB_CSTR GB_read_char_pntr(GBDATA *gbd)
void init_from_array(const CharPtrArray &entries, const char *default_displayed, const char *default_value)
AW_awar * awar_string(const char *var_name, const char *default_value="", AW_default default_file=AW_ROOT_DEFAULT)
GBDATA * GB_search(GBDATA *gbd, const char *fieldpath, GB_TYPES create)
void delete_selected_field()
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)
char * GBS_global_string_copy(const char *templat,...)
void write(const char *cfgStr) const
void create_button(const char *macro_name, AW_label label, const char *mnemonic=NULp, const char *color=NULp)
GB_ERROR rewrite_string(const char *aw_string)
char * GB_read_file(const char *path)
GB_write_int const char s