| 1 | // =============================================================== // |
|---|
| 2 | // // |
|---|
| 3 | // File : NT_ins_col.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 <RangeList.h> |
|---|
| 14 | #include <arbdbt.h> |
|---|
| 15 | #include <insdel.h> |
|---|
| 16 | #include <aw_window.hxx> |
|---|
| 17 | #include <aw_root.hxx> |
|---|
| 18 | #include <aw_awars.hxx> |
|---|
| 19 | #include <aw_msg.hxx> |
|---|
| 20 | #include <awt_sel_boxes.hxx> |
|---|
| 21 | #include <arb_defs.h> |
|---|
| 22 | #include <awt_config_manager.hxx> |
|---|
| 23 | |
|---|
| 24 | #define AWAR_INSDEL "insdel/" |
|---|
| 25 | #define TMP_AWAR_INSDEL "tmp/" AWAR_INSDEL |
|---|
| 26 | |
|---|
| 27 | #define AWAR_INSDEL_AMOUNT AWAR_INSDEL "nchar" |
|---|
| 28 | #define AWAR_INSDEL_DELETABLE AWAR_INSDEL "characters" |
|---|
| 29 | #define AWAR_INSDEL_RANGE AWAR_INSDEL "range" |
|---|
| 30 | #define AWAR_INSDEL_SAI AWAR_INSDEL "sainame" |
|---|
| 31 | #define AWAR_INSDEL_CONTAINS AWAR_INSDEL "contain" |
|---|
| 32 | #define AWAR_INSDEL_SAI_CHARS AWAR_INSDEL "saichars" |
|---|
| 33 | #define AWAR_INSDEL_AFFECTED TMP_AWAR_INSDEL "affected" |
|---|
| 34 | #define AWAR_INSDEL_WHAT TMP_AWAR_INSDEL "what" |
|---|
| 35 | #define AWAR_INSDEL_DIRECTION AWAR_INSDEL "direction" |
|---|
| 36 | |
|---|
| 37 | enum SaiContains { DOESNT_CONTAIN, CONTAINS }; |
|---|
| 38 | enum InsdelMode { INSERT, DELETE }; |
|---|
| 39 | |
|---|
| 40 | class StaticData { |
|---|
| 41 | char *ali; |
|---|
| 42 | RangeList ranges; |
|---|
| 43 | |
|---|
| 44 | public: |
|---|
| 45 | StaticData() : ali(NULp) {} |
|---|
| 46 | StaticData(const StaticData& other) : ali(nulldup(other.ali)), ranges(other.ranges) {} |
|---|
| 47 | DECLARE_ASSIGNMENT_OPERATOR(StaticData); |
|---|
| 48 | ~StaticData() { free(ali); } |
|---|
| 49 | |
|---|
| 50 | GB_ERROR track_ali(GBDATA *gb_main) { |
|---|
| 51 | freeset(ali, GBT_get_default_alignment(gb_main)); |
|---|
| 52 | return ali ? NULp : GB_await_error(); |
|---|
| 53 | } |
|---|
| 54 | |
|---|
| 55 | const char *get_ali() const { return ali; } |
|---|
| 56 | |
|---|
| 57 | const RangeList& get_ranges() const { return ranges; } |
|---|
| 58 | void set_ranges(const RangeList& new_ranges) { ranges = new_ranges; } |
|---|
| 59 | }; |
|---|
| 60 | |
|---|
| 61 | static StaticData SELECTED; |
|---|
| 62 | |
|---|
| 63 | static void cleanup_when_closing(AW_window*) { |
|---|
| 64 | SELECTED = StaticData(); |
|---|
| 65 | } |
|---|
| 66 | |
|---|
| 67 | static int columns_of(const RangeList& ranges) { |
|---|
| 68 | int count = 0; |
|---|
| 69 | for (RangeList::iterator r = ranges.begin(); r != ranges.end(); ++r) { |
|---|
| 70 | count += r->size(); |
|---|
| 71 | } |
|---|
| 72 | return count; |
|---|
| 73 | } |
|---|
| 74 | |
|---|
| 75 | static void range_count_update_cb(AW_root *root) { |
|---|
| 76 | UseRange use = UseRange(root->awar(AWAR_INSDEL_RANGE)->read_int()); |
|---|
| 77 | int count = 0; |
|---|
| 78 | switch (use) { |
|---|
| 79 | case RANGES: count = SELECTED.get_ranges().size(); break; |
|---|
| 80 | case SINGLE_COLUMNS: count = columns_of(SELECTED.get_ranges()); break; |
|---|
| 81 | } |
|---|
| 82 | root->awar(AWAR_INSDEL_AFFECTED)->write_int(count); |
|---|
| 83 | } |
|---|
| 84 | |
|---|
| 85 | static void range_changed_cb(AW_root *root) { |
|---|
| 86 | UseRange use = UseRange(root->awar(AWAR_INSDEL_RANGE)->read_int()); |
|---|
| 87 | const char *what = NULp; |
|---|
| 88 | switch (use) { |
|---|
| 89 | case RANGES: what = "selected ranges"; break; |
|---|
| 90 | case SINGLE_COLUMNS: what = "selected columns"; break; |
|---|
| 91 | } |
|---|
| 92 | root->awar(AWAR_INSDEL_WHAT)->write_string(what); |
|---|
| 93 | range_count_update_cb(root); |
|---|
| 94 | } |
|---|
| 95 | |
|---|
| 96 | static GB_ERROR update_RangeList(AW_root *root, GBDATA *gb_main) { |
|---|
| 97 | const char *saiName = root->awar(AWAR_INSDEL_SAI)->read_char_pntr(); |
|---|
| 98 | GB_transaction ta(gb_main); |
|---|
| 99 | GBDATA *gb_sai = GBT_expect_SAI(gb_main, saiName); |
|---|
| 100 | GB_ERROR error = NULp; |
|---|
| 101 | |
|---|
| 102 | if (!gb_sai) error = GB_await_error(); |
|---|
| 103 | if (!error) error = SELECTED.track_ali(gb_main); |
|---|
| 104 | |
|---|
| 105 | if (!error) { |
|---|
| 106 | GBDATA *gb_data = GBT_find_sequence(gb_sai, SELECTED.get_ali()); |
|---|
| 107 | if (!gb_data) { |
|---|
| 108 | if (GB_have_error()) error = GB_await_error(); |
|---|
| 109 | else error = GBS_global_string("SAI '%s' has no data in alignment '%s'", saiName, SELECTED.get_ali()); |
|---|
| 110 | } |
|---|
| 111 | else { |
|---|
| 112 | const char *data = GB_read_char_pntr(gb_data); // @@@ NOT_ALL_SAI_HAVE_DATA |
|---|
| 113 | if (!data) error = GB_await_error(); |
|---|
| 114 | else { |
|---|
| 115 | const char *chars = root->awar(AWAR_INSDEL_SAI_CHARS)->read_char_pntr(); |
|---|
| 116 | SaiContains contains = SaiContains(root->awar(AWAR_INSDEL_CONTAINS)->read_int()); |
|---|
| 117 | |
|---|
| 118 | SELECTED.set_ranges(build_RangeList_from_string(data, chars, contains == DOESNT_CONTAIN)); |
|---|
| 119 | } |
|---|
| 120 | } |
|---|
| 121 | } |
|---|
| 122 | if (error) { |
|---|
| 123 | SELECTED.set_ranges(RangeList()); |
|---|
| 124 | if (!saiName[0]) error = NULp; // do not show "Could not find extended with name ''" |
|---|
| 125 | } |
|---|
| 126 | range_count_update_cb(root); |
|---|
| 127 | |
|---|
| 128 | return error; |
|---|
| 129 | } |
|---|
| 130 | |
|---|
| 131 | static void update_RangeList_cb(AW_root *root) { |
|---|
| 132 | aw_message_if(update_RangeList(root, GLOBAL.gb_main)); |
|---|
| 133 | } |
|---|
| 134 | |
|---|
| 135 | void create_insertDeleteColumn_variables(AW_root *root, AW_default props) { |
|---|
| 136 | root->awar_int (AWAR_CURSOR_POSITION, info2bio(0), GLOBAL.gb_main); |
|---|
| 137 | root->awar_int (AWAR_INSDEL_AMOUNT, 0, props)->set_minmax(0, 9999999); |
|---|
| 138 | root->awar_string(AWAR_INSDEL_DELETABLE, "-.", props); |
|---|
| 139 | root->awar_int (AWAR_INSDEL_RANGE, RANGES, props)->add_callback(range_changed_cb); |
|---|
| 140 | |
|---|
| 141 | root->awar_string(AWAR_INSDEL_SAI, "", props)->add_callback(update_RangeList_cb); |
|---|
| 142 | root->awar_int (AWAR_INSDEL_CONTAINS, DOESNT_CONTAIN, props)->add_callback(update_RangeList_cb); |
|---|
| 143 | root->awar_string(AWAR_INSDEL_SAI_CHARS, "-.", props)->add_callback(update_RangeList_cb); |
|---|
| 144 | |
|---|
| 145 | root->awar_int (AWAR_INSDEL_AFFECTED, 0, props); |
|---|
| 146 | root->awar_string(AWAR_INSDEL_WHAT, "???", props); |
|---|
| 147 | root->awar_int (AWAR_INSDEL_DIRECTION, BEHIND, props); |
|---|
| 148 | |
|---|
| 149 | range_changed_cb(root); |
|---|
| 150 | update_RangeList(root, GLOBAL.gb_main); |
|---|
| 151 | } |
|---|
| 152 | |
|---|
| 153 | static void insdel_event(AW_window *aws, InsdelMode mode) { |
|---|
| 154 | GBDATA *gb_main = GLOBAL.gb_main; |
|---|
| 155 | AW_root *root = aws->get_root(); |
|---|
| 156 | |
|---|
| 157 | long pos = bio2info(root->awar(AWAR_CURSOR_POSITION)->read_int()); |
|---|
| 158 | long nchar = root->awar(AWAR_INSDEL_AMOUNT)->read_int(); |
|---|
| 159 | const char *deletable = root->awar(AWAR_INSDEL_DELETABLE)->read_char_pntr(); |
|---|
| 160 | |
|---|
| 161 | if (mode == DELETE) nchar = -nchar; |
|---|
| 162 | |
|---|
| 163 | GB_ERROR error = GB_begin_transaction(gb_main); |
|---|
| 164 | if (!error) error = SELECTED.track_ali(gb_main); |
|---|
| 165 | if (!error) error = ARB_insdel_columns(gb_main, SELECTED.get_ali(), pos, nchar, deletable); |
|---|
| 166 | if (!error) error = GBT_check_data(gb_main, NULp); |
|---|
| 167 | |
|---|
| 168 | GB_end_transaction_show_error(gb_main, error, aw_message); |
|---|
| 169 | } |
|---|
| 170 | |
|---|
| 171 | static void insdel_sai_event(AW_window *aws, InsdelMode mode) { |
|---|
| 172 | GBDATA *gb_main = GLOBAL.gb_main; |
|---|
| 173 | GB_ERROR error = GB_begin_transaction(GLOBAL.gb_main); |
|---|
| 174 | if (!error) error = SELECTED.track_ali(gb_main); |
|---|
| 175 | |
|---|
| 176 | if (!error) { |
|---|
| 177 | AW_root *root = aws->get_root(); |
|---|
| 178 | |
|---|
| 179 | switch (mode) { |
|---|
| 180 | case INSERT: { |
|---|
| 181 | UseRange units = UseRange(root->awar(AWAR_INSDEL_RANGE)->read_int()); |
|---|
| 182 | InsertWhere where = InsertWhere(root->awar(AWAR_INSDEL_DIRECTION)->read_int()); |
|---|
| 183 | size_t amount = root->awar(AWAR_INSDEL_AMOUNT)->read_int(); |
|---|
| 184 | |
|---|
| 185 | error = ARB_insert_columns_using_SAI(gb_main, SELECTED.get_ali(), SELECTED.get_ranges(), units, where, amount); |
|---|
| 186 | break; |
|---|
| 187 | } |
|---|
| 188 | case DELETE: { |
|---|
| 189 | const char *deletable = root->awar(AWAR_INSDEL_DELETABLE)->read_char_pntr(); |
|---|
| 190 | |
|---|
| 191 | error = ARB_delete_columns_using_SAI(gb_main, SELECTED.get_ali(), SELECTED.get_ranges(), deletable); |
|---|
| 192 | break; |
|---|
| 193 | } |
|---|
| 194 | } |
|---|
| 195 | } |
|---|
| 196 | if (!error) error = GBT_check_data(gb_main, NULp); |
|---|
| 197 | |
|---|
| 198 | GB_end_transaction_show_error(gb_main, error, aw_message); |
|---|
| 199 | } |
|---|
| 200 | |
|---|
| 201 | AW_window *create_insertDeleteColumn_window(AW_root *root) { |
|---|
| 202 | static AW_window_simple *aws = NULp; |
|---|
| 203 | if (!aws) { |
|---|
| 204 | aws = new AW_window_simple; |
|---|
| 205 | |
|---|
| 206 | aws->init(root, "INSDEL_COLUMNS", "Insert/delete columns"); |
|---|
| 207 | |
|---|
| 208 | aws->load_xfig("insdel.fig"); |
|---|
| 209 | aws->button_length(8); |
|---|
| 210 | |
|---|
| 211 | aws->at("close"); |
|---|
| 212 | aws->callback(AW_POPDOWN); |
|---|
| 213 | aws->create_button("CLOSE", "CLOSE", "C"); |
|---|
| 214 | |
|---|
| 215 | aws->callback(makeHelpCallback("insdel.hlp")); |
|---|
| 216 | aws->at("help"); |
|---|
| 217 | aws->create_button("HELP", "HELP", "H"); |
|---|
| 218 | |
|---|
| 219 | aws->label_length(27); |
|---|
| 220 | |
|---|
| 221 | aws->at("pos"); |
|---|
| 222 | aws->label("Sequence Position"); |
|---|
| 223 | aws->create_input_field(AWAR_CURSOR_POSITION, 7); |
|---|
| 224 | |
|---|
| 225 | aws->at("len"); |
|---|
| 226 | aws->label("How many Characters"); |
|---|
| 227 | aws->create_input_field(AWAR_INSDEL_AMOUNT, 7); |
|---|
| 228 | |
|---|
| 229 | aws->at("characters"); |
|---|
| 230 | aws->label("Delete Only (% = all)"); |
|---|
| 231 | aws->create_input_field(AWAR_INSDEL_DELETABLE, 7); |
|---|
| 232 | |
|---|
| 233 | aws->auto_space(10, 0); |
|---|
| 234 | |
|---|
| 235 | aws->at("actions"); |
|---|
| 236 | aws->callback(makeWindowCallback(insdel_event, INSERT)); aws->create_button("INSERT", "INSERT", "I"); |
|---|
| 237 | aws->callback(makeWindowCallback(insdel_event, DELETE)); aws->create_button("DELETE", "DELETE", "D"); |
|---|
| 238 | } |
|---|
| 239 | return aws; |
|---|
| 240 | } |
|---|
| 241 | |
|---|
| 242 | static AWT_config_mapping_def insdel_by_SAI_config_def[] = { |
|---|
| 243 | { AWAR_INSDEL_RANGE, "range" }, |
|---|
| 244 | { AWAR_INSDEL_SAI, "sai" }, |
|---|
| 245 | { AWAR_INSDEL_CONTAINS, "contain" }, |
|---|
| 246 | { AWAR_INSDEL_SAI_CHARS, "chars" }, |
|---|
| 247 | { AWAR_INSDEL_DELETABLE, "deletable" }, |
|---|
| 248 | { AWAR_INSDEL_AMOUNT, "amount" }, |
|---|
| 249 | { AWAR_INSDEL_DIRECTION, "direction" }, |
|---|
| 250 | |
|---|
| 251 | { NULp, NULp }, |
|---|
| 252 | }; |
|---|
| 253 | |
|---|
| 254 | static AWT_predefined_config insdel_by_SAI_predef_config[] = { |
|---|
| 255 | { |
|---|
| 256 | "*gaps_by_variability", |
|---|
| 257 | "Use to insert 2 gaps next to all\ncolumns with high variability", |
|---|
| 258 | "amount='2';chars='123';contain='1';direction='1';range='1';sai='POS_VAR_BY_PARSIMONY'", |
|---|
| 259 | }, |
|---|
| 260 | { |
|---|
| 261 | "*erase_columns_without_data", |
|---|
| 262 | "selects all columns where \nMAX_FREQUENCY contains '='", |
|---|
| 263 | "chars='=';contain='1';deletable='-.';range='1';sai='MAX_FREQUENCY'", |
|---|
| 264 | }, |
|---|
| 265 | { NULp, NULp, NULp }, |
|---|
| 266 | }; |
|---|
| 267 | |
|---|
| 268 | AW_window *create_insertDeleteBySAI_window(AW_root *root, GBDATA *gb_main) { |
|---|
| 269 | static AW_window_simple *aws = NULp; |
|---|
| 270 | if (!aws) { |
|---|
| 271 | aws = new AW_window_simple; |
|---|
| 272 | |
|---|
| 273 | aws->init(root, "INSDEL_BY_SAI", "Insert/delete using SAI"); |
|---|
| 274 | |
|---|
| 275 | aws->load_xfig("insdel_sai.fig"); |
|---|
| 276 | aws->button_length(8); |
|---|
| 277 | |
|---|
| 278 | aws->at("close"); |
|---|
| 279 | aws->callback(AW_POPDOWN); |
|---|
| 280 | aws->create_button("CLOSE", "CLOSE", "C"); |
|---|
| 281 | |
|---|
| 282 | aws->callback(makeHelpCallback("insdel_sai.hlp")); |
|---|
| 283 | aws->at("help"); |
|---|
| 284 | aws->create_button("HELP", "HELP", "H"); |
|---|
| 285 | |
|---|
| 286 | aws->at("config"); |
|---|
| 287 | AWT_insert_config_manager(aws, AW_ROOT_DEFAULT, "insdel_by_sai", insdel_by_SAI_config_def, NULp, insdel_by_SAI_predef_config); |
|---|
| 288 | |
|---|
| 289 | aws->at("select"); |
|---|
| 290 | aws->create_option_menu(AWAR_INSDEL_RANGE); |
|---|
| 291 | aws->insert_option("ranges", "r", RANGES); |
|---|
| 292 | aws->insert_option("columns", "c", SINGLE_COLUMNS); |
|---|
| 293 | aws->update_option_menu(); |
|---|
| 294 | |
|---|
| 295 | aws->button_length(25); |
|---|
| 296 | |
|---|
| 297 | aws->at("sai"); |
|---|
| 298 | awt_create_SAI_selection_button(gb_main, aws, AWAR_INSDEL_SAI); |
|---|
| 299 | |
|---|
| 300 | aws->at("contains"); |
|---|
| 301 | aws->create_option_menu(AWAR_INSDEL_CONTAINS); |
|---|
| 302 | aws->insert_option("contains", "c", CONTAINS); |
|---|
| 303 | aws->insert_option("doesn't contain", "d", DOESNT_CONTAIN); |
|---|
| 304 | aws->update_option_menu(); |
|---|
| 305 | |
|---|
| 306 | aws->at("characters"); |
|---|
| 307 | aws->create_input_field(AWAR_INSDEL_SAI_CHARS, 18); |
|---|
| 308 | |
|---|
| 309 | aws->button_length(18); |
|---|
| 310 | |
|---|
| 311 | aws->at("affected"); |
|---|
| 312 | aws->create_button(NULp, AWAR_INSDEL_AFFECTED, NULp, "+"); |
|---|
| 313 | |
|---|
| 314 | aws->button_length(7); |
|---|
| 315 | |
|---|
| 316 | aws->at("delete"); |
|---|
| 317 | aws->callback(makeWindowCallback(insdel_sai_event, DELETE)); |
|---|
| 318 | aws->create_button("DELETE", "DELETE", "D"); |
|---|
| 319 | |
|---|
| 320 | aws->at("deletable"); |
|---|
| 321 | aws->create_input_field(AWAR_INSDEL_DELETABLE, 7); |
|---|
| 322 | |
|---|
| 323 | aws->at("insert"); |
|---|
| 324 | aws->callback(makeWindowCallback(insdel_sai_event, INSERT)); |
|---|
| 325 | aws->create_button("INSERT", "INSERT", "I"); |
|---|
| 326 | |
|---|
| 327 | aws->at("amount"); |
|---|
| 328 | aws->create_input_field(AWAR_INSDEL_AMOUNT, 7); |
|---|
| 329 | |
|---|
| 330 | aws->at("direction"); |
|---|
| 331 | aws->create_option_menu(AWAR_INSDEL_DIRECTION); |
|---|
| 332 | aws->insert_option("in front of", "f", INFRONTOF); |
|---|
| 333 | aws->insert_option("behind", "b", BEHIND); |
|---|
| 334 | aws->update_option_menu(); |
|---|
| 335 | |
|---|
| 336 | // add window text which depends on AWAR_INSDEL_RANGE |
|---|
| 337 | aws->button_length(15); |
|---|
| 338 | aws->at("what0"); aws->create_button(NULp, AWAR_INSDEL_WHAT); |
|---|
| 339 | aws->at("what1"); aws->create_button(NULp, AWAR_INSDEL_WHAT); |
|---|
| 340 | aws->at("what2"); aws->create_button(NULp, AWAR_INSDEL_WHAT); |
|---|
| 341 | |
|---|
| 342 | aws->on_hide(cleanup_when_closing); |
|---|
| 343 | } |
|---|
| 344 | return aws; |
|---|
| 345 | } |
|---|