| 1 | // =============================================================== // |
|---|
| 2 | // // |
|---|
| 3 | // File : NT_edconf.cxx // |
|---|
| 4 | // Purpose : // |
|---|
| 5 | // // |
|---|
| 6 | // Institute of Microbiology (Technical University Munich) // |
|---|
| 7 | // http://www.arb-home.de/ // |
|---|
| 8 | // // |
|---|
| 9 | // =============================================================== // |
|---|
| 10 | |
|---|
| 11 | #include "NT_local.h" |
|---|
| 12 | |
|---|
| 13 | #include <TreeDisplay.hxx> |
|---|
| 14 | |
|---|
| 15 | #include <sel_boxes.hxx> |
|---|
| 16 | #include <selection_admin.h> |
|---|
| 17 | #include <config_manager.hxx> |
|---|
| 18 | |
|---|
| 19 | #include <aw_awars.hxx> |
|---|
| 20 | #include <aw_root.hxx> |
|---|
| 21 | #include <aw_msg.hxx> |
|---|
| 22 | #include <aw_select.hxx> |
|---|
| 23 | #include <aw_system.hxx> |
|---|
| 24 | |
|---|
| 25 | #include <ad_config.h> |
|---|
| 26 | #include <ad_cb_prot.h> |
|---|
| 27 | |
|---|
| 28 | #include <map> |
|---|
| 29 | |
|---|
| 30 | using namespace std; |
|---|
| 31 | |
|---|
| 32 | // AWT_canvas-local (%i=canvas-id): |
|---|
| 33 | #define AWAR_CL_SELECTED_CONFIGS "configuration_data/win%i/selected" |
|---|
| 34 | #define AWAR_CL_DISPLAY_CONFIG_MARKERS "configuration_data/win%i/display" |
|---|
| 35 | |
|---|
| 36 | #define AWAR_CONFIG_COMMENT "tmp/configuration/comment" |
|---|
| 37 | #define AWAR_CONFIGURATION "focus/configuration" |
|---|
| 38 | |
|---|
| 39 | typedef map<string, string> ConfigHits; // key=speciesname; value[markerIdx]==1 -> highlighted |
|---|
| 40 | |
|---|
| 41 | class ConfigMarkerDisplay FINAL_TYPE : public MarkerDisplay, virtual Noncopyable { |
|---|
| 42 | GBDATA *gb_main; |
|---|
| 43 | SmartPtr<ConstStrArray> config; // configuration names |
|---|
| 44 | StrArray errors; // config load-errors |
|---|
| 45 | ConfigHits hits; |
|---|
| 46 | |
|---|
| 47 | void updateHits() { |
|---|
| 48 | flush_cache(); |
|---|
| 49 | hits.clear(); |
|---|
| 50 | errors.erase(); |
|---|
| 51 | for (int c = 0; c<size(); ++c) { |
|---|
| 52 | GB_ERROR error; |
|---|
| 53 | GBT_config cfg(gb_main, (*config)[c], error); |
|---|
| 54 | |
|---|
| 55 | for (int area = 0; area<=1 && !error; ++area) { |
|---|
| 56 | GBT_config_parser cparser(cfg, area); |
|---|
| 57 | |
|---|
| 58 | while (1) { |
|---|
| 59 | const GBT_config_item& item = cparser.nextItem(error); |
|---|
| 60 | if (error || item.type == CI_END_OF_CONFIG) break; |
|---|
| 61 | if (item.type == CI_SPECIES) { |
|---|
| 62 | ConfigHits::iterator found = hits.find(item.name); |
|---|
| 63 | if (found == hits.end()) { |
|---|
| 64 | string h(size(), '0'); |
|---|
| 65 | h[c] = '1'; |
|---|
| 66 | hits[item.name] = h; |
|---|
| 67 | } |
|---|
| 68 | else { |
|---|
| 69 | (found->second)[c] = '1'; |
|---|
| 70 | } |
|---|
| 71 | } |
|---|
| 72 | } |
|---|
| 73 | } |
|---|
| 74 | |
|---|
| 75 | errors.put(ARB_strdup(null2empty(error))); |
|---|
| 76 | } |
|---|
| 77 | } |
|---|
| 78 | |
|---|
| 79 | public: |
|---|
| 80 | ConfigMarkerDisplay(SmartPtr<ConstStrArray> config_, GBDATA *gb_main_) |
|---|
| 81 | : MarkerDisplay(config_->size()), |
|---|
| 82 | gb_main(gb_main_), |
|---|
| 83 | config(config_) |
|---|
| 84 | { |
|---|
| 85 | updateHits(); |
|---|
| 86 | } |
|---|
| 87 | const char *get_marker_name(int markerIdx) const OVERRIDE { |
|---|
| 88 | const char *error = errors[markerIdx]; |
|---|
| 89 | const char *name = (*config)[markerIdx]; |
|---|
| 90 | if (error && error[0]) return GBS_global_string("%s (Error: %s)", name, error); |
|---|
| 91 | return name; |
|---|
| 92 | } |
|---|
| 93 | void retrieve_marker_state(const char *speciesName, NodeMarkers& node) OVERRIDE { |
|---|
| 94 | ConfigHits::const_iterator found = hits.find(speciesName); |
|---|
| 95 | if (found != hits.end()) { |
|---|
| 96 | const string& hit = found->second; |
|---|
| 97 | |
|---|
| 98 | for (int c = 0; c<size(); ++c) { |
|---|
| 99 | if (hit[c] == '1') node.incMarker(c); |
|---|
| 100 | } |
|---|
| 101 | } |
|---|
| 102 | node.incNodeSize(); |
|---|
| 103 | } |
|---|
| 104 | |
|---|
| 105 | void handle_click(int markerIdx, AW_MouseButton button, AWT_graphic_exports& exports) OVERRIDE { |
|---|
| 106 | if (button == AW_BUTTON_LEFT || button == AW_BUTTON_RIGHT) { |
|---|
| 107 | const char *markerName = get_marker_name(markerIdx); |
|---|
| 108 | AW_root::SINGLETON->awar(AWAR_CONFIGURATION)->write_string(markerName); // select config of clicked marker |
|---|
| 109 | if (button == AW_BUTTON_RIGHT) { // extract configuration |
|---|
| 110 | extract_species_selection(GLOBAL.gb_main, markerName, SELECTION_EXTRACT); |
|---|
| 111 | exports.request_structure_update(); // request to recalculate branch colors |
|---|
| 112 | } |
|---|
| 113 | } |
|---|
| 114 | } |
|---|
| 115 | }; |
|---|
| 116 | |
|---|
| 117 | inline bool displays_config_markers(MarkerDisplay *md) { return dynamic_cast<ConfigMarkerDisplay*>(md); } |
|---|
| 118 | |
|---|
| 119 | #define CONFIG_SEPARATOR "\1" |
|---|
| 120 | |
|---|
| 121 | inline AW_awar *get_canvas_awar(const char *awar_name_format, int canvas_id) { |
|---|
| 122 | return AW_root::SINGLETON->awar_no_error(GBS_global_string(awar_name_format, canvas_id)); |
|---|
| 123 | } |
|---|
| 124 | inline AW_awar *get_config_awar (int canvas_id) { return get_canvas_awar(AWAR_CL_SELECTED_CONFIGS, canvas_id); } |
|---|
| 125 | inline AW_awar *get_display_toggle_awar(int canvas_id) { return get_canvas_awar(AWAR_CL_DISPLAY_CONFIG_MARKERS, canvas_id); } |
|---|
| 126 | |
|---|
| 127 | static SmartPtr<ConstStrArray> get_selected_configs_from_awar(int canvas_id) { |
|---|
| 128 | // returns configs stored in awar as array (empty array if awar undefined!) |
|---|
| 129 | SmartPtr<ConstStrArray> config(new ConstStrArray); |
|---|
| 130 | |
|---|
| 131 | AW_awar *awar = get_config_awar(canvas_id); |
|---|
| 132 | if (awar) { |
|---|
| 133 | char *config_str = awar->read_string(); |
|---|
| 134 | GBT_splitNdestroy_string(*config, config_str, CONFIG_SEPARATOR, SPLIT_DROPEMPTY); |
|---|
| 135 | } |
|---|
| 136 | |
|---|
| 137 | return config; |
|---|
| 138 | } |
|---|
| 139 | static void write_configs_to_awar(int canvas_id, const CharPtrArray& configs) { |
|---|
| 140 | char *config_str = GBT_join_strings(configs, CONFIG_SEPARATOR[0]); |
|---|
| 141 | AW_root::SINGLETON->awar(GBS_global_string(AWAR_CL_SELECTED_CONFIGS, canvas_id))->write_string(config_str); |
|---|
| 142 | free(config_str); |
|---|
| 143 | } |
|---|
| 144 | |
|---|
| 145 | // -------------------------------------------------------------------------------- |
|---|
| 146 | |
|---|
| 147 | static AW_selection *selected_configs_list[MAX_NT_WINDOWS] = { MAX_NT_WINDOWS_NULLINIT }; |
|---|
| 148 | static bool allow_selection2awar_update = true; |
|---|
| 149 | static bool allow_to_activate_display = false; |
|---|
| 150 | |
|---|
| 151 | static void init_config_awars(AW_root *root) { |
|---|
| 152 | root->awar_string(AWAR_CONFIGURATION, DEFAULT_CONFIGURATION, GLOBAL.gb_main); |
|---|
| 153 | } |
|---|
| 154 | static void selected_configs_awar_changed_cb(AW_root *aw_root, TREE_canvas *ntw) { |
|---|
| 155 | AWT_graphic_tree *agt = DOWNCAST(AWT_graphic_tree*, ntw->gfx); |
|---|
| 156 | int ntw_id = ntw->get_index(); |
|---|
| 157 | SmartPtr<ConstStrArray> config = get_selected_configs_from_awar(ntw_id); |
|---|
| 158 | bool redraw = false; |
|---|
| 159 | |
|---|
| 160 | if (config->empty() || get_display_toggle_awar(ntw_id)->read_int() == 0) { |
|---|
| 161 | if (displays_config_markers(agt->get_marker_display())) { // only hide config markers |
|---|
| 162 | agt->hide_marker_display(); |
|---|
| 163 | redraw = true; |
|---|
| 164 | } |
|---|
| 165 | } |
|---|
| 166 | else { |
|---|
| 167 | bool activate = allow_to_activate_display || displays_config_markers(agt->get_marker_display()); |
|---|
| 168 | |
|---|
| 169 | if (activate) { |
|---|
| 170 | init_config_awars(aw_root); |
|---|
| 171 | ConfigMarkerDisplay *disp = new ConfigMarkerDisplay(config, ntw->gb_main); |
|---|
| 172 | agt->set_marker_display(disp); |
|---|
| 173 | redraw = true; |
|---|
| 174 | } |
|---|
| 175 | } |
|---|
| 176 | |
|---|
| 177 | if (selected_configs_list[ntw_id]) { // if configuration_marker_window has been opened |
|---|
| 178 | // update content of subset-selection (needed when reloading a config-set (not implemented yet) or after renaming a config) |
|---|
| 179 | LocallyModify<bool> avoid(allow_selection2awar_update, false); |
|---|
| 180 | awt_set_subset_selection_content(selected_configs_list[ntw_id], *config); |
|---|
| 181 | } |
|---|
| 182 | |
|---|
| 183 | if (redraw) AW_root::SINGLETON->awar(AWAR_TREE_REFRESH)->touch(); |
|---|
| 184 | } |
|---|
| 185 | |
|---|
| 186 | static void selected_configs_display_awar_changed_cb(AW_root *root, TREE_canvas *ntw) { |
|---|
| 187 | LocallyModify<bool> allowInteractiveActivation(allow_to_activate_display, true); |
|---|
| 188 | selected_configs_awar_changed_cb(root, ntw); |
|---|
| 189 | } |
|---|
| 190 | |
|---|
| 191 | static void configs_selectionlist_changed_cb(AW_selection *selected_configs, bool interactive_change, AW_CL ntw_id) { |
|---|
| 192 | if (allow_selection2awar_update) { |
|---|
| 193 | LocallyModify<bool> allowInteractiveActivation(allow_to_activate_display, interactive_change); |
|---|
| 194 | |
|---|
| 195 | StrArray config; |
|---|
| 196 | selected_configs->get_values(config); |
|---|
| 197 | write_configs_to_awar(ntw_id, config); |
|---|
| 198 | } |
|---|
| 199 | } |
|---|
| 200 | |
|---|
| 201 | static void config_modified_cb(GBDATA *gb_cfg_area) { // called with "top_area" AND "middle_area" entry! |
|---|
| 202 | static GBDATA *gb_lastname = NULp; |
|---|
| 203 | static GB_ULONG lastcall = 0; |
|---|
| 204 | |
|---|
| 205 | GBDATA *gb_name = GB_entry(GB_get_father(gb_cfg_area), "name"); |
|---|
| 206 | GB_ULONG thiscall = GB_time_of_day(); |
|---|
| 207 | |
|---|
| 208 | bool is_same_modification = gb_name == gb_lastname && (thiscall == lastcall || thiscall == (lastcall+1)); |
|---|
| 209 | if (!is_same_modification) { // avoid duplicate check if "top_area" and "middle_area" changed (=standard case) |
|---|
| 210 | // touch all canvas-specific awars that contain 'name' |
|---|
| 211 | const char *name = GB_read_char_pntr(gb_name); |
|---|
| 212 | |
|---|
| 213 | for (int canvas_id = 0; canvas_id<MAX_NT_WINDOWS; ++canvas_id) { |
|---|
| 214 | SmartPtr<ConstStrArray> config = get_selected_configs_from_awar(canvas_id); |
|---|
| 215 | for (size_t c = 0; c<config->size(); ++c) { |
|---|
| 216 | if (strcmp((*config)[c], name) == 0) { |
|---|
| 217 | get_config_awar(canvas_id)->touch(); |
|---|
| 218 | break; |
|---|
| 219 | } |
|---|
| 220 | } |
|---|
| 221 | } |
|---|
| 222 | } |
|---|
| 223 | gb_lastname = gb_name; |
|---|
| 224 | lastcall = thiscall; |
|---|
| 225 | } |
|---|
| 226 | |
|---|
| 227 | #define CONFIG_BASE_PATH "/configuration_data/configuration" |
|---|
| 228 | |
|---|
| 229 | static void install_config_change_callbacks(GBDATA *gb_main) { |
|---|
| 230 | static bool installed = false; |
|---|
| 231 | if (!installed) { |
|---|
| 232 | DatabaseCallback dbcb = makeDatabaseCallback(config_modified_cb); |
|---|
| 233 | ASSERT_NO_ERROR(GB_add_hierarchy_callback(gb_main, CONFIG_BASE_PATH "/middle_area", GB_CB_CHANGED, dbcb)); |
|---|
| 234 | ASSERT_NO_ERROR(GB_add_hierarchy_callback(gb_main, CONFIG_BASE_PATH "/top_area", GB_CB_CHANGED, dbcb)); |
|---|
| 235 | |
|---|
| 236 | installed = true; |
|---|
| 237 | } |
|---|
| 238 | } |
|---|
| 239 | |
|---|
| 240 | void NT_activate_configMarkers_display(TREE_canvas *ntw) { |
|---|
| 241 | GBDATA *gb_main = ntw->gb_main; |
|---|
| 242 | |
|---|
| 243 | int ntw_idx = ntw->get_index(); |
|---|
| 244 | AW_awar *awar_selCfgs = ntw->awr->awar_string(GBS_global_string(AWAR_CL_SELECTED_CONFIGS, ntw_idx), "", gb_main); |
|---|
| 245 | awar_selCfgs->add_callback(makeRootCallback(selected_configs_awar_changed_cb, ntw)); |
|---|
| 246 | |
|---|
| 247 | AW_awar *awar_dispCfgs = ntw->awr->awar_int(GBS_global_string(AWAR_CL_DISPLAY_CONFIG_MARKERS, ntw_idx), 1, gb_main); |
|---|
| 248 | awar_dispCfgs->add_callback(makeRootCallback(selected_configs_display_awar_changed_cb, ntw)); |
|---|
| 249 | |
|---|
| 250 | awar_selCfgs->touch(); // force initial refresh |
|---|
| 251 | install_config_change_callbacks(gb_main); |
|---|
| 252 | } |
|---|
| 253 | |
|---|
| 254 | // define where to store config-sets (using config-manager): |
|---|
| 255 | #define MANAGED_CONFIGSET_SECTION "configmarkers" |
|---|
| 256 | #define MANAGED_CONFIGSET_ENTRY "selected_configs" |
|---|
| 257 | |
|---|
| 258 | static void setup_configmarker_config_cb(AWT_config_definition& config, int ntw_id) { |
|---|
| 259 | AW_awar *selcfg_awar = get_config_awar(ntw_id); |
|---|
| 260 | nt_assert(selcfg_awar); |
|---|
| 261 | if (selcfg_awar) { |
|---|
| 262 | config.add(selcfg_awar->awar_name, MANAGED_CONFIGSET_ENTRY); |
|---|
| 263 | } |
|---|
| 264 | } |
|---|
| 265 | |
|---|
| 266 | struct ConfigModifier : virtual Noncopyable { |
|---|
| 267 | virtual ~ConfigModifier() {} |
|---|
| 268 | virtual const char *modify(const char *old) const = 0; |
|---|
| 269 | |
|---|
| 270 | bool modifyConfig(ConstStrArray& config) const { |
|---|
| 271 | bool changed = false; |
|---|
| 272 | for (size_t i = 0; i<config.size(); ++i) { |
|---|
| 273 | const char *newContent = modify(config[i]); |
|---|
| 274 | if (!newContent) { |
|---|
| 275 | config.remove(i); |
|---|
| 276 | changed = true; |
|---|
| 277 | } |
|---|
| 278 | else if (strcmp(newContent, config[i]) != 0) { |
|---|
| 279 | config.replace(i, newContent); |
|---|
| 280 | changed = true; |
|---|
| 281 | } |
|---|
| 282 | } |
|---|
| 283 | return changed; |
|---|
| 284 | } |
|---|
| 285 | }; |
|---|
| 286 | class ConfigRenamer : public ConfigModifier { // derived from Noncopyable |
|---|
| 287 | const char *oldName; |
|---|
| 288 | const char *newName; |
|---|
| 289 | const char *modify(const char *name) const OVERRIDE { |
|---|
| 290 | return strcmp(name, oldName) == 0 ? newName : name; |
|---|
| 291 | } |
|---|
| 292 | public: |
|---|
| 293 | ConfigRenamer(const char *oldName_, const char *newName_) |
|---|
| 294 | : oldName(oldName_), |
|---|
| 295 | newName(newName_) |
|---|
| 296 | {} |
|---|
| 297 | }; |
|---|
| 298 | class ConfigDeleter : public ConfigModifier { // derived from Noncopyable |
|---|
| 299 | const char *toDelete; |
|---|
| 300 | const char *modify(const char *name) const OVERRIDE { |
|---|
| 301 | return strcmp(name, toDelete) == 0 ? NULp : name; |
|---|
| 302 | } |
|---|
| 303 | public: |
|---|
| 304 | ConfigDeleter(const char *toDelete_) |
|---|
| 305 | : toDelete(toDelete_) |
|---|
| 306 | {} |
|---|
| 307 | }; |
|---|
| 308 | |
|---|
| 309 | static char *correct_managed_configsets_cb(const char *key, const char *value, AW_CL cl_ConfigModifier) { |
|---|
| 310 | char *modified_value = NULp; |
|---|
| 311 | if (strcmp(key, MANAGED_CONFIGSET_ENTRY) == 0) { |
|---|
| 312 | const ConfigModifier *mod = (const ConfigModifier*)cl_ConfigModifier; |
|---|
| 313 | ConstStrArray config; |
|---|
| 314 | GBT_split_string(config, value, CONFIG_SEPARATOR, SPLIT_DROPEMPTY); |
|---|
| 315 | if (mod->modifyConfig(config)) { |
|---|
| 316 | modified_value = GBT_join_strings(config, CONFIG_SEPARATOR[0]); |
|---|
| 317 | } |
|---|
| 318 | } |
|---|
| 319 | return modified_value ? modified_value : ARB_strdup(value); |
|---|
| 320 | } |
|---|
| 321 | static void modify_configurations(const ConfigModifier& mod) { |
|---|
| 322 | for (int canvas_id = 0; canvas_id<MAX_NT_WINDOWS; ++canvas_id) { |
|---|
| 323 | // modify currently selected configs: |
|---|
| 324 | SmartPtr<ConstStrArray> config = get_selected_configs_from_awar(canvas_id); |
|---|
| 325 | if (mod.modifyConfig(*config)) { |
|---|
| 326 | write_configs_to_awar(canvas_id, *config); |
|---|
| 327 | } |
|---|
| 328 | } |
|---|
| 329 | // change all configuration-sets stored in config-manager (shared by all windows) |
|---|
| 330 | AWT_modify_managed_configs(GLOBAL.gb_main, MANAGED_CONFIGSET_SECTION, correct_managed_configsets_cb, AW_CL(&mod)); |
|---|
| 331 | } |
|---|
| 332 | |
|---|
| 333 | static AW_window *create_configuration_marker_window(AW_root *root, TREE_canvas *ntw) { |
|---|
| 334 | AW_window_simple *aws = new AW_window_simple; |
|---|
| 335 | |
|---|
| 336 | int ntw_id = ntw->get_index(); |
|---|
| 337 | aws->init(root, GBS_global_string("MARK_CONFIGS_%i", ntw_id), "Highlight configurations in tree"); |
|---|
| 338 | aws->load_xfig("mark_configs.fig"); |
|---|
| 339 | |
|---|
| 340 | aws->auto_space(10, 10); |
|---|
| 341 | |
|---|
| 342 | aws->at("close"); |
|---|
| 343 | aws->callback(AW_POPDOWN); |
|---|
| 344 | aws->create_button("CLOSE", "CLOSE", "C"); |
|---|
| 345 | |
|---|
| 346 | aws->at("help"); |
|---|
| 347 | aws->callback(makeHelpCallback("species_configs_highlight.hlp")); |
|---|
| 348 | aws->create_button("HELP", "HELP", "H"); |
|---|
| 349 | |
|---|
| 350 | |
|---|
| 351 | aws->at("list"); |
|---|
| 352 | AW_DB_selection *all_configs = awt_create_CONFIG_selection_list(GLOBAL.gb_main, aws, AWAR_CONFIGURATION); |
|---|
| 353 | AW_selection *sub_sel; |
|---|
| 354 | { |
|---|
| 355 | LocallyModify<bool> avoid(allow_selection2awar_update, false); // avoid awar gets updated from empty sub-selectionlist |
|---|
| 356 | sub_sel = awt_create_subset_selection_list(aws, all_configs->get_sellist(), "selected", "add", "sort", false, configs_selectionlist_changed_cb, ntw->get_index()); |
|---|
| 357 | } |
|---|
| 358 | |
|---|
| 359 | awt_set_subset_selection_content(sub_sel, *get_selected_configs_from_awar(ntw_id)); |
|---|
| 360 | selected_configs_list[ntw_id] = sub_sel; |
|---|
| 361 | |
|---|
| 362 | // @@@ would like to use ntw-specific awar for this selection list (opening two lists links them) |
|---|
| 363 | |
|---|
| 364 | aws->at("show"); |
|---|
| 365 | aws->label("Display?"); |
|---|
| 366 | aws->create_toggle(get_display_toggle_awar(ntw_id)->awar_name); |
|---|
| 367 | |
|---|
| 368 | aws->at("settings"); |
|---|
| 369 | aws->callback(TREE_create_marker_settings_window); |
|---|
| 370 | aws->create_autosize_button("SETTINGS", "Settings", "S"); |
|---|
| 371 | |
|---|
| 372 | AWT_insert_config_manager(aws, GLOBAL.gb_main, MANAGED_CONFIGSET_SECTION, makeConfigSetupCallback(setup_configmarker_config_cb, ntw_id)); |
|---|
| 373 | |
|---|
| 374 | return aws; |
|---|
| 375 | } |
|---|
| 376 | |
|---|
| 377 | static void selected_config_changed_cb(AW_root *root) { |
|---|
| 378 | const char *config = root->awar(AWAR_CONFIGURATION)->read_char_pntr(); |
|---|
| 379 | |
|---|
| 380 | bool nonexisting_config = false; |
|---|
| 381 | GBDATA *gb_target_commment = NULp; |
|---|
| 382 | if (config[0]) { |
|---|
| 383 | GBDATA *gb_configuration = GBT_find_configuration(GLOBAL.gb_main, config); |
|---|
| 384 | if (gb_configuration) { |
|---|
| 385 | gb_target_commment = GB_entry(gb_configuration, "comment"); |
|---|
| 386 | } |
|---|
| 387 | else { |
|---|
| 388 | nonexisting_config = true; |
|---|
| 389 | } |
|---|
| 390 | } |
|---|
| 391 | |
|---|
| 392 | AW_awar *awar_comment = root->awar(AWAR_CONFIG_COMMENT); |
|---|
| 393 | if (gb_target_commment) { |
|---|
| 394 | if (!awar_comment->is_mapped()) awar_comment->write_string(""); |
|---|
| 395 | awar_comment->map(gb_target_commment); |
|---|
| 396 | } |
|---|
| 397 | else { |
|---|
| 398 | char *reuse_comment = nonexisting_config ? awar_comment->read_string() : ARB_strdup(""); |
|---|
| 399 | if (awar_comment->is_mapped()) { |
|---|
| 400 | awar_comment->unmap(); |
|---|
| 401 | } |
|---|
| 402 | awar_comment->write_string(reuse_comment); |
|---|
| 403 | free(reuse_comment); |
|---|
| 404 | } |
|---|
| 405 | } |
|---|
| 406 | static void config_comment_changed_cb(AW_root *root) { |
|---|
| 407 | // called when comment-awar changes or gets re-map-ped |
|---|
| 408 | |
|---|
| 409 | AW_awar *awar_comment = root->awar(AWAR_CONFIG_COMMENT); |
|---|
| 410 | const char *comment = awar_comment->read_char_pntr(); |
|---|
| 411 | |
|---|
| 412 | const char *config = root->awar(AWAR_CONFIGURATION)->read_char_pntr(); |
|---|
| 413 | GBDATA *gb_configuration = config[0] ? GBT_find_configuration(GLOBAL.gb_main, config) : NULp; |
|---|
| 414 | |
|---|
| 415 | GB_ERROR error = NULp; |
|---|
| 416 | if (awar_comment->is_mapped()) { |
|---|
| 417 | if (!comment[0]) { // empty existing comment |
|---|
| 418 | nt_assert(gb_configuration); |
|---|
| 419 | GBDATA *gb_commment = GB_entry(gb_configuration, "comment"); |
|---|
| 420 | nt_assert(gb_commment); |
|---|
| 421 | if (gb_commment) { |
|---|
| 422 | awar_comment->unmap(); |
|---|
| 423 | error = GB_delete(gb_commment); |
|---|
| 424 | } |
|---|
| 425 | } |
|---|
| 426 | } |
|---|
| 427 | else { |
|---|
| 428 | if (comment[0]) { // ignore empty comment for unmapped awar |
|---|
| 429 | if (gb_configuration) { |
|---|
| 430 | nt_assert(!GB_entry(gb_configuration, "comment")); |
|---|
| 431 | error = GBT_write_string(gb_configuration, "comment", comment); |
|---|
| 432 | if (!error) { |
|---|
| 433 | awar_comment->write_string(""); |
|---|
| 434 | selected_config_changed_cb(root); |
|---|
| 435 | } |
|---|
| 436 | } |
|---|
| 437 | else if (!config[0]) { |
|---|
| 438 | // do NOT warn if name field contains (not yet) existing name |
|---|
| 439 | // (allows to edit comment while creating new config) |
|---|
| 440 | error = "Please select an existing species selection to edit its comment"; |
|---|
| 441 | } |
|---|
| 442 | } |
|---|
| 443 | } |
|---|
| 444 | |
|---|
| 445 | aw_message_if(error); |
|---|
| 446 | } |
|---|
| 447 | |
|---|
| 448 | static void init_config_admin_awars(AW_root *root) { |
|---|
| 449 | init_config_awars(root); |
|---|
| 450 | root->awar_string(AWAR_CONFIG_COMMENT, "", GLOBAL.gb_main)->add_callback(config_comment_changed_cb); |
|---|
| 451 | root->awar(AWAR_CONFIGURATION)->add_callback(selected_config_changed_cb)->touch(); |
|---|
| 452 | } |
|---|
| 453 | |
|---|
| 454 | class NtSelectionAdmin: public SelectionAdmin { |
|---|
| 455 | RefPtr<TREE_canvas> ntw; |
|---|
| 456 | |
|---|
| 457 | public: |
|---|
| 458 | NtSelectionAdmin(TREE_canvas *ntw_) : ntw(ntw_) {} |
|---|
| 459 | |
|---|
| 460 | const char *get_macro_suffix() const { return GBS_global_string("%i", ntw->get_index()); } |
|---|
| 461 | GBDATA *get_gb_main() const { return ntw->get_graphic_tree()->get_gbmain(); } |
|---|
| 462 | |
|---|
| 463 | const char *get_selection_awarname() const { return AWAR_CONFIGURATION; } |
|---|
| 464 | const char *get_selectionComment_awarname() const { return AWAR_CONFIG_COMMENT; } |
|---|
| 465 | |
|---|
| 466 | const char *get_name_of_tree() const { return ntw->get_awar_tree()->read_char_pntr(); } |
|---|
| 467 | TreeNode *get_tree_root() const { return ntw->get_tree_root_node(); } |
|---|
| 468 | |
|---|
| 469 | const char *get_toparea_SAIs() const { |
|---|
| 470 | return AW_root::SINGLETON->awar(AWAR_TOPAREA_SAIS)->read_char_pntr(); |
|---|
| 471 | } |
|---|
| 472 | |
|---|
| 473 | void speciesSelection_renamed_cb(const char *old_name, const char *new_name) const { modify_configurations(ConfigRenamer(old_name, new_name)); } |
|---|
| 474 | void speciesSelection_deleted_cb(const char *name) const { modify_configurations(ConfigDeleter(name)); } |
|---|
| 475 | }; |
|---|
| 476 | |
|---|
| 477 | |
|---|
| 478 | void NT_popup_configuration_admin(AW_window *aw_main, TREE_canvas *ntw) { |
|---|
| 479 | // Note: these windows have to be tree-canvas-related, |
|---|
| 480 | // because species selections need to reflect the topology of the tree shown in canvas. |
|---|
| 481 | // |
|---|
| 482 | // We have to use a custom popup method, because there exist multiple callbacks for the same canvas. |
|---|
| 483 | |
|---|
| 484 | static AW_window *existing_aws[MAX_NT_WINDOWS] = { MAX_NT_WINDOWS_NULLINIT }; |
|---|
| 485 | |
|---|
| 486 | int ntw_id = ntw->get_index(); |
|---|
| 487 | if (!existing_aws[ntw_id]) { |
|---|
| 488 | AW_root *root = aw_main->get_root(); |
|---|
| 489 | init_config_admin_awars(root); |
|---|
| 490 | |
|---|
| 491 | NtSelectionAdmin * const admin = new NtSelectionAdmin(ntw); // bound to callbacks (inside create_species_selection_window) |
|---|
| 492 | AW_window *aws = create_species_selection_window(root, admin); |
|---|
| 493 | |
|---|
| 494 | aws->at("highlight"); |
|---|
| 495 | aws->callback(makeCreateWindowCallback(create_configuration_marker_window, ntw)); |
|---|
| 496 | aws->create_autosize_button(GBS_global_string("HIGHLIGHT_%i", ntw_id), "Highlight in tree", "t"); |
|---|
| 497 | |
|---|
| 498 | existing_aws[ntw_id] = aws; |
|---|
| 499 | } |
|---|
| 500 | existing_aws[ntw_id]->activate(); |
|---|
| 501 | } |
|---|
| 502 | |
|---|
| 503 | // ----------------------------------------- |
|---|
| 504 | // various ways to start the editor |
|---|
| 505 | |
|---|
| 506 | static void nt_start_editor_on_configuration(AW_window *aww) { |
|---|
| 507 | aww->hide(); |
|---|
| 508 | |
|---|
| 509 | const char *cfgName = aww->get_root()->awar(AWAR_CONFIGURATION)->read_char_pntr(); |
|---|
| 510 | char *quotedCfg = GBK_singlequote(cfgName); |
|---|
| 511 | |
|---|
| 512 | AW_system(GBS_global_string("arb_edit4 -c %s &", quotedCfg)); |
|---|
| 513 | |
|---|
| 514 | free(quotedCfg); |
|---|
| 515 | } |
|---|
| 516 | |
|---|
| 517 | AW_window *NT_create_startEditorOnOldConfiguration_window(AW_root *awr) { |
|---|
| 518 | static AW_window_simple *aws = NULp; |
|---|
| 519 | if (!aws) { |
|---|
| 520 | init_config_awars(awr); |
|---|
| 521 | |
|---|
| 522 | aws = new AW_window_simple; |
|---|
| 523 | aws->init(awr, "SELECT_CONFIGURATION", "SELECT A CONFIGURATION"); |
|---|
| 524 | aws->at(10, 10); |
|---|
| 525 | aws->auto_space(0, 0); |
|---|
| 526 | awt_create_CONFIG_selection_list(GLOBAL.gb_main, aws, AWAR_CONFIGURATION); |
|---|
| 527 | aws->at_newline(); |
|---|
| 528 | |
|---|
| 529 | aws->callback(nt_start_editor_on_configuration); |
|---|
| 530 | aws->create_button("START", "START"); |
|---|
| 531 | |
|---|
| 532 | aws->callback(AW_POPDOWN); |
|---|
| 533 | aws->create_button("CLOSE", "CLOSE", "C"); |
|---|
| 534 | |
|---|
| 535 | aws->window_fit(); |
|---|
| 536 | } |
|---|
| 537 | return aws; |
|---|
| 538 | } |
|---|
| 539 | |
|---|
| 540 | void NT_start_editor_on_tree(AW_window *aww, int use_species_aside, TREE_canvas *ntw) { |
|---|
| 541 | init_config_awars(aww->get_root()); |
|---|
| 542 | NtSelectionAdmin def(ntw); |
|---|
| 543 | GB_ERROR error = create_species_selection(def, DEFAULT_CONFIGURATION, use_species_aside, BY_CALLING_THE_EDITOR); |
|---|
| 544 | if (!error) error = GBK_system("arb_edit4 -c " DEFAULT_CONFIGURATION " &"); |
|---|
| 545 | aw_message_if(error); |
|---|
| 546 | } |
|---|
| 547 | |
|---|
| 548 | inline void nt_create_config_after_import(TREE_canvas *ntw) { |
|---|
| 549 | init_config_awars(ntw->awr); |
|---|
| 550 | |
|---|
| 551 | const char *dated_suffix = ARB_dateTime_suffix(); |
|---|
| 552 | char *configName = GBS_global_string_copy("imported_%s", dated_suffix); |
|---|
| 553 | |
|---|
| 554 | // ensure unique config-name |
|---|
| 555 | { |
|---|
| 556 | int unique = 1; |
|---|
| 557 | GB_transaction ta(ntw->gb_main); |
|---|
| 558 | while (GBT_find_configuration(ntw->gb_main, configName)) { |
|---|
| 559 | freeset(configName, GBS_global_string_copy("imported_%s_%i", dated_suffix, ++unique)); |
|---|
| 560 | } |
|---|
| 561 | } |
|---|
| 562 | |
|---|
| 563 | NtSelectionAdmin def(ntw); |
|---|
| 564 | GB_ERROR error = create_species_selection(def, configName, 0, FROM_IMPORTER); |
|---|
| 565 | aw_message_if(error); |
|---|
| 566 | |
|---|
| 567 | free(configName); |
|---|
| 568 | } |
|---|
| 569 | |
|---|
| 570 | void NT_create_config_after_import(TREE_canvas *ntw, bool imported_from_scratch) { |
|---|
| 571 | /*! create a new config after import |
|---|
| 572 | * @param imported_from_scratch if true -> DB was created from scratch, all species in DB are marked. |
|---|
| 573 | * if false -> data was imported into existing DB. Other species may be marked as well, imported species are "queried". |
|---|
| 574 | */ |
|---|
| 575 | |
|---|
| 576 | if (imported_from_scratch) { |
|---|
| 577 | nt_create_config_after_import(ntw); |
|---|
| 578 | } |
|---|
| 579 | else { |
|---|
| 580 | GB_transaction ta(ntw->gb_main); |
|---|
| 581 | |
|---|
| 582 | // remember marks + mark queried species: |
|---|
| 583 | for (GBDATA *gb_species = GBT_first_species(ntw->gb_main); gb_species; gb_species = GBT_next_species(gb_species)) { |
|---|
| 584 | GB_write_user_flag(gb_species, GB_USERFLAG_WASMARKED, GB_read_flag(gb_species)); |
|---|
| 585 | GB_write_flag(gb_species, GB_user_flag(gb_species, GB_USERFLAG_QUERY)); |
|---|
| 586 | } |
|---|
| 587 | |
|---|
| 588 | nt_create_config_after_import(ntw); |
|---|
| 589 | |
|---|
| 590 | // restore old marks: |
|---|
| 591 | for (GBDATA *gb_species = GBT_first_species(ntw->gb_main); gb_species; gb_species = GBT_next_species(gb_species)) { |
|---|
| 592 | GB_write_flag(gb_species, GB_user_flag(gb_species, GB_USERFLAG_WASMARKED)); |
|---|
| 593 | GB_clear_user_flag(gb_species, GB_USERFLAG_WASMARKED); |
|---|
| 594 | } |
|---|
| 595 | } |
|---|
| 596 | } |
|---|
| 597 | |
|---|