source: trunk/EDIT4/ED4_detect_bad_ali.cxx

Last change on this file was 19393, checked in by westram, 17 months ago
  • reintegrates 'ali' into 'trunk'
    • refactored misused enum
    • support for helix pairs:
      • drop non-standard defs
      • add more user defs
    • change defaults
    • add several predefined configs (esp. for IUPAC ambiguity codes)
  • adds: log:branches/ali@19376:19392
File size: 25.1 KB
Line 
1// ========================================================= //
2//                                                           //
3//   File      : ED4_detect_bad_ali.cxx                      //
4//   Purpose   : detect alignment errors in helix regions    //
5//                                                           //
6//   Coded by Ralf Westram (coder@reallysoft.de) in May 23   //
7//   http://www.arb-home.de/                                 //
8//                                                           //
9// ========================================================= //
10
11#include "ed4_detect_bad_ali.hxx"
12#include "ed4_class.hxx"
13
14#include <AW_helix.hxx>
15
16#include <aw_awar_defs.hxx>
17#include <aw_awar.hxx>
18#include <aw_msg.hxx>
19#include <aw_select.hxx>
20#include <aw_root.hxx>
21
22#include <arbdbt.h>
23#include <arb_defs.h>
24
25#include <string>
26#include <map>
27#include <vector>
28#include <items.h>
29#include <item_sel_list.h>
30
31using namespace std;
32
33const long NOT_CALCULATED = -1;
34
35typedef map<string, long>            BadPositionsForSpecies;
36typedef const BadPositionsForSpecies BadPositionsForSpeciesConst;
37
38typedef map<size_t, size_t> PairedPositions;
39
40class HelixAlignmentQuality : virtual Noncopyable {
41    GBDATA          *gb_main;
42    const AW_helix&  helix;
43
44    string ali;
45    string error;
46
47    char symbol2count[256];
48
49    BadPositionsForSpecies bad_positions;    // list of examined species
50    PairedPositions        paired_positions; // list of paring positions of all involved helices
51
52    void note_error(GB_ERROR err) {
53        if (err && !has_error()) error = err;
54    }
55
56    void init_bad_positions(const char *species_list) {
57        bad_positions.clear();
58        if (!has_error()) {
59            ConstStrArray species;
60            GBT_split_string(species, species_list, ";", SPLIT_DROPEMPTY);
61
62            for (size_t i = 0; i<species.size(); ++i) {
63                bad_positions[species[i]] = NOT_CALCULATED;
64            }
65            if (bad_positions.empty()) {
66                note_error("No species found");
67            }
68        }
69    }
70    void add_pair_position(size_t pos, size_t pair_pos) {
71        if (pos>pair_pos) swap(pos, pair_pos);
72        arb_assert(pos<pair_pos);
73        if (paired_positions.find(pos) != paired_positions.end()) {
74            note_error(GBS_global_string("Duplicate entry for helix position %i", info2bio(pos)));
75        }
76        else {
77            paired_positions[pos] = pair_pos;
78        }
79    }
80    void init_paired_positions(const CharPtrArray& helices) {
81        paired_positions.clear();
82        if (!has_error()) {
83            if (helices.size() == 1 && strcmp(helices[0], "*") == 0) {
84                // use all helices
85                for (long pos = helix.first_pair_position(); pos != -1; pos = helix.next_pair_position(pos)) {
86                    const BI_helix_entry& entry = helix.entry(pos);
87                    if (entry.helix_nr[0] == '-') { // only add left helices
88                        add_pair_position(pos, entry.pair_pos);
89                    }
90                }
91            }
92            else {
93                for (size_t i = 0; i<helices.size() && !has_error(); ++i) {
94                    long firstPos = helix.first_position(helices[i]);
95                    if (firstPos == -1) {
96                        note_error(GBS_global_string("Invalid helix number '%s'", helices[i]));
97                    }
98                    else {
99                        long lastPos = helix.last_position(helices[i]);
100                        arb_assert(lastPos != -1); // otherwise BI_helix is corrupted
101
102                        for (long pos = firstPos; pos<=lastPos && pos>0 && !has_error(); ) {
103                            const BI_helix_entry& entry = helix.entry(pos);
104                            add_pair_position(pos, entry.pair_pos);
105                            pos = entry.next_pair_pos;
106                        }
107                    }
108                }
109            }
110
111            if (paired_positions.empty()) {
112                note_error("List of helix positions to examine is empty");
113            }
114        }
115    }
116    void init_bad_symbol_table(const char *bad_symbols) {
117        memset(symbol2count, 0, 256);
118        int count = 0;;
119        for (int i = 0; bad_symbols[i]; ++i) {
120            if (bad_symbols[i] != ' ') { // ignore space
121                symbol2count[safeCharIndex(bad_symbols[i])] = 1;
122                ++count;
123            }
124        }
125        if (!count) {
126            note_error("no 'bad' helix symbol defined");
127        }
128    }
129
130    long calculate_bad_positions(const string& species) {
131        long bad = -1;
132
133        {
134            GB_transaction  ta(gb_main);
135            GBDATA         *gb_species = GBT_find_species(gb_main, species.c_str());
136
137            if (!gb_species) {
138                note_error(GBS_global_string("no such species: '%s'", species.c_str()));
139            }
140            else {
141                GBDATA *gb_seq = GBT_find_sequence(gb_species, ali.c_str());
142                if (!gb_seq) {
143                    note_error(GBS_global_string("species '%s' has no data in alignment '%s'",
144                                                 species.c_str(), ali.c_str()));
145                }
146                else {
147                    GB_CSTR      sequence = GB_read_char_pntr(gb_seq);
148                    const size_t seq_len  = GB_read_string_count(gb_seq);
149
150                    bad = 0;
151                    for (PairedPositions::const_iterator pp = paired_positions.begin(); pp != paired_positions.end(); ++pp) {
152                        const size_t p1 = pp->first;
153                        const size_t p2 = pp->second;
154
155                        const char b1 = p1<seq_len ? sequence[p1] : '.';
156                        const char b2 = p2<seq_len ? sequence[p2] : '.';
157
158                        const char sym  = helix.get_symbol(b1, b2);
159                        bad            += symbol2count[safeCharIndex(sym)];
160                    }
161                }
162            }
163        }
164
165        return bad;
166    }
167
168    void update_bad_position_counts() {
169        for (BadPositionsForSpecies::iterator bp = bad_positions.begin(); bp != bad_positions.end(); ++bp) {
170            if (bp->second == NOT_CALCULATED) {
171                bp->second = calculate_bad_positions(bp->first);
172            }
173        }
174    }
175
176public:
177    HelixAlignmentQuality(GBDATA     *gb_main_, const AW_helix& helix_, const char *ali_,
178                          const char *species_list, // @@@ pass ConstStrArray instead?
179                          const CharPtrArray& helices, // contains helix numbers to use (as text) or one entry containing a '*' (meaning: all)
180                          const char *bad_symbols)
181        : gb_main(gb_main_),
182          helix(helix_),
183          ali(ali_)
184    {
185        note_error(helix.get_error());
186        init_bad_positions(species_list);
187        init_paired_positions(helices);
188        init_bad_symbol_table(bad_symbols);
189    }
190
191    bool has_error() const { return !error.empty(); }
192    GB_ERROR get_error() const { return has_error() ? error.c_str() : NULp; }
193
194    size_t size() const { arb_assert(!has_error()); return bad_positions.size(); }
195    size_t positions() const { arb_assert(!has_error()); return paired_positions.size(); }
196
197    BadPositionsForSpeciesConst results() {
198        arb_assert(!has_error());
199        update_bad_position_counts();
200        return bad_positions;
201    }
202};
203
204// --------------------------------------------------------------------------------
205
206class BadPositionsOrder {
207    BadPositionsForSpeciesConst bad_pos;
208
209public:
210    BadPositionsOrder(BadPositionsForSpeciesConst bad_pos_) :
211        bad_pos(bad_pos_)
212    {}
213
214    bool operator()(const string& s1, const string& s2) const {
215        long b1       = bad_pos.find(s1)->second;
216        long b2       = bad_pos.find(s2)->second;
217        long cmp      = b2 - b1;
218        if (!cmp) cmp = s1.compare(s2);
219        return cmp<0;
220    }
221};
222
223typedef vector<string> StringVector;
224
225static void getSpeciesSortedByBadPositions(BadPositionsForSpeciesConst& bad_pos, StringVector& result) {
226    result.clear();
227
228    for (BadPositionsForSpeciesConst::const_iterator s = bad_pos.begin(); s != bad_pos.end(); ++s) {
229        long badCount = long(s->second);
230        if (badCount>0) result.push_back(s->first);
231    }
232
233    sort(result.begin(), result.end(), BadPositionsOrder(bad_pos));
234}
235
236static void parse_helix_list(StrArray& result_helices, const char *helix_list) {
237    ConstStrArray list_entries;
238    GBT_split_string(list_entries, helix_list, ',');
239
240    for (size_t i = 0; i<list_entries.size(); ++i) {
241        const char *entry = list_entries[i];
242        if (strcmp(entry, "*") == 0) {
243            result_helices.erase();
244            result_helices.put(strdup("*"));
245            return;
246        }
247        else {
248            const char *minus = strchr(entry, '-');
249            if (minus) {
250                int h1 = atoi(entry);
251                int h2 = atoi(minus+1);
252
253                if (h1>h2) swap(h1, h2);
254
255                for (int h = h1; h<=h2; ++h) {
256                    result_helices.put(GBS_global_string_copy("%i", h));
257                }
258            }
259            else {
260                result_helices.put(strdup(entry));
261            }
262        }
263    }
264}
265
266#define StrArray_FROM_HELIXLIST(varname, helixlist) StrArray varname; parse_helix_list(varname, helixlist)
267
268// --------------------------------------------------------------------------------
269
270#ifdef UNIT_TESTS
271#ifndef TEST_UNIT_H
272#include <test_unit.h>
273#endif
274#include <arb_strbuf.h>
275
276static char *BadPositionsToString(BadPositionsForSpeciesConst& bad_pos) {
277    StringVector sortedSpecies;
278    getSpeciesSortedByBadPositions(bad_pos, sortedSpecies);
279
280    GBS_strstruct result(sortedSpecies.size()*(8+1+3+1)+1);
281
282    for (StringVector::const_iterator s = sortedSpecies.begin(); s != sortedSpecies.end(); ++s) {
283        const string& species  = *s;
284        long          badCount = bad_pos.find(species)->second;
285        result.ncat(species.c_str(), species.length());
286        result.put('=');
287        result.putlong(badCount);
288        result.put(',');
289    }
290
291    result.cut_tail(1);
292    return result.release();
293}
294
295
296
297void TEST_count_bad_ali_positions() {
298    GB_shell shell;
299    {
300        AW_root  aw_root("min_ascii.arb", UNITTEST_MOCK);
301        GBDATA  *gb_main = GB_open("TEST_trees.arb", "r");
302
303        char *ali = GBT_get_default_alignment(gb_main);
304
305        AW_helix helix(&aw_root);
306        helix.init(gb_main, ali);
307
308        char *marked_species;
309        char *all_species;
310        {
311            GB_transaction ta(gb_main);
312
313            marked_species = GBT_store_marked_species(gb_main, false);
314            GBT_mark_all(gb_main, 1);
315            all_species    = GBT_store_marked_species(gb_main, false);
316        }
317
318        StrArray_FROM_HELIXLIST(helices_none, "");
319        StrArray_FROM_HELIXLIST(helices_all, "*");
320        StrArray_FROM_HELIXLIST(helices_1to5, "1-5");
321        StrArray_FROM_HELIXLIST(helices_4to5, "4-5");
322        StrArray_FROM_HELIXLIST(helices_1, "1");
323        StrArray_FROM_HELIXLIST(helices_51, "5,1");
324        StrArray_FROM_HELIXLIST(helices_514, "5,1,4");
325        StrArray_FROM_HELIXLIST(helices_515, "5,1,5");
326
327        {
328            HelixAlignmentQuality marked_quality(gb_main, helix, ali, marked_species, helices_1,    "#");
329            HelixAlignmentQuality all_quality   (gb_main, helix, ali, all_species,    helices_51,   "#");
330            HelixAlignmentQuality all2_quality  (gb_main, helix, ali, all_species,    helices_514,  "#*+");
331            HelixAlignmentQuality all3_quality  (gb_main, helix, ali, all_species,    helices_all,  "#*+");
332            HelixAlignmentQuality all4_quality  (gb_main, helix, ali, all_species,    helices_4to5, "#*+");
333
334            TEST_EXPECT_NO_ERROR(marked_quality.get_error());
335            TEST_EXPECT_NO_ERROR(all_quality.get_error());
336            TEST_EXPECT_NO_ERROR(all2_quality.get_error());
337            TEST_EXPECT_NO_ERROR(all3_quality.get_error());
338            TEST_EXPECT_NO_ERROR(all4_quality.get_error());
339
340            // test number of examined species:
341            TEST_EXPECT_EQUAL(marked_quality.size(),  6);
342            TEST_EXPECT_EQUAL(all_quality.size(),    15);
343            TEST_EXPECT_EQUAL(all2_quality.size(),   15);
344            TEST_EXPECT_EQUAL(all3_quality.size(),   15);
345            TEST_EXPECT_EQUAL(all4_quality.size(),   15);
346
347            TEST_EXPECT_EQUAL(marked_quality.positions(), 10);
348            TEST_EXPECT_EQUAL(all_quality.positions(), 18);
349            TEST_EXPECT_EQUAL(all2_quality.positions(), 20);
350            TEST_EXPECT_EQUAL(all3_quality.positions(), 20);
351            TEST_EXPECT_EQUAL(all4_quality.positions(), 10);
352
353            TEST_EXPECT_EQUAL_STRINGCOPY__NOERROREXPORTED(BadPositionsToString(marked_quality.results()), "CorGluta=3,CorAquat=1,CytAquat=1");
354            TEST_EXPECT_EQUAL_STRINGCOPY__NOERROREXPORTED(BadPositionsToString(all_quality.results()), "CloTyro3=7,CytAquat=7,CloInnoc=3,CorGluta=3,CloBifer=1,CloCarni=1,CloPaste=1,CloTyro2=1,CloTyro4=1,CloTyrob=1,CorAquat=1");
355            TEST_EXPECT_EQUAL_STRINGCOPY__NOERROREXPORTED(BadPositionsToString(all2_quality.results()), "CloTyro3=10,CytAquat=8,CloTyro2=7,CloTyro4=7,CloTyrob=7,CorGluta=4,CloInnoc=3,CloBifer=2,CloButy2=1,CloButyr=1,CloCarni=1,CloPaste=1,CorAquat=1");
356            TEST_EXPECT_EQUAL_STRINGCOPY__NOERROREXPORTED(BadPositionsToString(all3_quality.results()), "CloTyro3=10,CytAquat=8,CloTyro2=7,CloTyro4=7,CloTyrob=7,CorGluta=4,CloInnoc=3,CloBifer=2,CloButy2=1,CloButyr=1,CloCarni=1,CloPaste=1,CorAquat=1");
357            TEST_EXPECT_EQUAL_STRINGCOPY__NOERROREXPORTED(BadPositionsToString(all4_quality.results()), "CytAquat=6,CloTyro3=5,CloInnoc=2,CloTyro2=2,CloTyro4=2,CloTyrob=2,CloBifer=1");
358        }
359
360        // test errors:
361        {
362            HelixAlignmentQuality err1(gb_main, helix, ali, "",             helices_51,   "#");
363            HelixAlignmentQuality err2(gb_main, helix, ali, marked_species, helices_none, "#");
364            HelixAlignmentQuality err3(gb_main, helix, ali, marked_species, helices_51,   "  "); // define no bad helix symbol (spaces are ignored)
365            HelixAlignmentQuality err4(gb_main, helix, ali, marked_species, helices_515,  "#");
366            HelixAlignmentQuality err5(gb_main, helix, ali, "fakeSpec",     helices_51,   "#");
367            HelixAlignmentQuality err6(gb_main, helix, ali, marked_species, helices_1to5, "#");
368
369            TEST_EXPECT_ERROR_CONTAINS(err1.get_error(), "No species found");
370            TEST_EXPECT_ERROR_CONTAINS(err2.get_error(), "Invalid helix number ''");
371            TEST_EXPECT_ERROR_CONTAINS(err3.get_error(), "no 'bad' helix symbol defined");
372            TEST_EXPECT_ERROR_CONTAINS(err4.get_error(), "Duplicate entry for helix position 65");
373
374            TEST_EXPECT_NO_ERROR(err5.get_error()); // no error yet
375            TEST_EXPECT_EQUAL(err5.size(), 1);      // number of species
376            TEST_EXPECT_EQUAL(err5.positions(), 18);
377            err5.results();                         // triggers error
378            TEST_EXPECT_ERROR_CONTAINS(err5.get_error(), "no such species: 'fakeSpec'");
379
380            TEST_EXPECT_ERROR_CONTAINS(err6.get_error(), "Invalid helix number '2'");
381        }
382
383        free(all_species);
384        free(marked_species);
385        free(ali);
386
387        GB_close(gb_main);
388    }
389}
390
391#endif // UNIT_TESTS
392
393// --------------------------------------------------------------------------------
394
395#define AWAR_BADALI_BASE      "badali/"
396#define AWAR_BADALI_HELIXLIST AWAR_BADALI_BASE "helixlist" // helix-numbers (comma-separated)
397#define AWAR_BADALI_SYMBOLS   AWAR_BADALI_BASE "symbols"   // helix-symbols which count as "bad"
398
399#define AWAR_BADALI_TEMP    "tmp/" AWAR_BADALI_BASE
400#define AWAR_BADALI_SPECIES AWAR_BADALI_TEMP "selected" // selected species
401#define AWAR_BADALI_FIELD   AWAR_BADALI_TEMP "field"    // name of field to store bad positions
402
403void ED4_create_detect_bad_alignment_awars(AW_root *aw_root, AW_default aw_def) {
404    aw_root->awar_string(AWAR_BADALI_HELIXLIST, "",  aw_def)->set_srt(" =,:,,=,");
405    aw_root->awar_string(AWAR_BADALI_SYMBOLS,   "#", aw_def);
406    aw_root->awar_string(AWAR_BADALI_SPECIES,   "",  aw_def);
407    aw_root->awar_string(AWAR_BADALI_FIELD,     "",  aw_def);
408}
409
410static ARB_ERROR add_species_to_list_cb(ED4_base *base, StrArray *species) {
411    ARB_ERROR error = NULp;
412
413    if (base->is_species_manager()) {
414        ED4_species_manager       *species_manager       = base->to_species_manager();
415        ED4_species_name_terminal *species_name_terminal = species_manager->search_spec_child_rek(LEV_SPECIES_NAME)->to_species_name_terminal();
416
417        if (species_name_terminal->get_species_pointer() && !species_manager->is_SAI_manager()) {
418            char *species_name = GB_read_as_string(species_name_terminal->get_species_pointer());
419            species->put(species_name);
420        }
421    }
422
423    return error;
424}
425
426static char *create_list_of_loaded_species() {
427    GB_transaction ta(ED4_ROOT->get_gb_main());
428    StrArray       species;
429    ARB_ERROR      error    = ED4_ROOT->root_group_man->route_down_hierarchy(makeED4_route_cb(add_species_to_list_cb, &species));
430    aw_message_if(error.deliver());
431    return GBT_join_strings(species, ';');
432}
433
434static void calc_and_update_alignment_errors_cb(AW_window *aww, AW_selection_list *sellst) {
435    // Performs the following jobs:
436    // - calculate alignment errors.
437    // - update the list of worst helix alignments (in GUI).
438    // - update/write contents of database field (alignment error count; optional)
439
440    AW_root    *aw_root = aww->get_root();
441    GBDATA     *gb_main = ED4_ROOT->get_gb_main();
442    const char *target_field;
443
444    {
445        GB_transaction ta(gb_main);
446
447        target_field = prepare_and_get_selected_itemfield(aw_root, AWAR_BADALI_FIELD, gb_main, SPECIES_get_selector(), FIF_ALLOW_NONE);
448        if (!target_field) {
449            if (GB_have_error()) {
450                aw_message(GBS_global_string("Invalid target field selected: %s", GB_await_error()));
451                return;
452            }
453        }
454    }
455
456    char *species_list = create_list_of_loaded_species();
457    char *bad_symbols  = aw_root->awar(AWAR_BADALI_SYMBOLS)->read_string();
458
459    StrArray_FROM_HELIXLIST(helices, aw_root->awar(AWAR_BADALI_HELIXLIST)->read_char_pntr());
460
461    // @@@ better show progress (next command may need much time)
462    HelixAlignmentQuality quality(gb_main,
463                                  *ED4_ROOT->helix,
464                                  ED4_ROOT->get_alignment_name(),
465                                  species_list,
466                                  helices,
467                                  bad_symbols);
468
469    sellst->clear();
470    if (!quality.has_error()) {
471        BadPositionsForSpeciesConst& bad_pos = quality.results();
472        if (!quality.has_error()) {
473            const bool writeToField = target_field;
474            if (writeToField) {
475                GB_transaction  ta(gb_main);
476                GB_ERROR        error           = NULp;
477                GBDATA         *gb_species_data = GBT_get_species_data(gb_main);
478
479                for (BadPositionsForSpeciesConst::const_iterator bp = bad_pos.begin(); bp != bad_pos.end() && !error; ++bp) { // this loop includes zero counts
480                    const char* species_name  = bp->first.c_str();
481                    long        bad_positions = bp->second;
482
483                    GBDATA *gb_species = GBT_find_species_rel_species_data(gb_species_data, species_name);
484                    if (!gb_species) {
485                        error = GBS_global_string("Could not find species '%s' (Reason: %s)", species_name, GB_await_error());
486                    }
487                    else {
488                        GBDATA *gb_field     = GBT_searchOrCreate_itemfield_according_to_changekey(gb_species, target_field, SPECIES_get_selector().change_key_path);
489                        if (!gb_field) error = GB_await_error();
490                        if (!error) error    = GB_write_lossless_int(gb_field, bad_positions);
491                    }
492                }
493
494                aw_message_if(error);
495            }
496
497            StringVector order;
498            getSpeciesSortedByBadPositions(bad_pos, order);
499
500            for (StringVector::const_iterator species = order.begin(); species != order.end(); ++species) { // this loop excludes zero counts
501                const char *species_name = species->c_str();
502                size_t      bad          = bad_pos.find(*species)->second;
503
504                sellst->insert(GBS_global_string("%-8s | %zu", species_name, bad), species_name);
505            }
506            sellst->insert_default("<acceptable helix alignment>", "");
507        }
508    }
509
510    if (quality.has_error()) {
511        sellst->clear();
512        sellst->insert_default(GBS_global_string("<Error: %s>", quality.get_error()), "");
513    }
514
515    sellst->update();
516
517    free(bad_symbols);
518    free(species_list);
519}
520
521enum JumpWhy { BY_SELECTION, BY_BUTTON };
522
523static void jump_to_next_helix_cb(AW_window *, JumpWhy called) {
524    ED4_MostRecentWinContext context;
525
526    ED4_window *win     = current_ed4w();
527    AW_root    *aw_root = win->aww->get_root();
528
529    StrArray_FROM_HELIXLIST(helices, aw_root->awar(AWAR_BADALI_HELIXLIST)->read_char_pntr());
530
531    AW_awar *awar_helixnr    = aw_root->awar(win->awar_path_for_helixNr);
532    int      current_helixnr = atoi(awar_helixnr->read_char_pntr());
533    int      wanted_helixnr  = 0;
534    int      preference      = current_helixnr>0 ? 1 : -1;
535
536    if (current_helixnr == 0) {
537        wanted_helixnr = atoi(helices[0]);
538    }
539    else {
540        if (called == BY_SELECTION) {
541            wanted_helixnr = abs(current_helixnr);
542        }
543        else { // if called == BY_BUTTON => select new helix
544            wanted_helixnr = atoi(helices[0]);
545            for (size_t i = 0; i<helices.size()-1; ++i) {
546                if (abs(current_helixnr) == abs(atoi(helices[i])))  {
547                    wanted_helixnr = atoi(helices[i+1]);
548                }
549            }
550        }
551    }
552
553    wanted_helixnr *= preference; // choose left or right helix
554
555    if (wanted_helixnr != 0) {
556        if (wanted_helixnr != current_helixnr || called == BY_BUTTON) { // avoid triggering callback w/o real change
557            awar_helixnr->write_string(GBS_global_string("%i", wanted_helixnr));
558            // callback is NOT bound to AWAR (but to inputfield) -> call it manually:
559            ED4_set_helixnr(win->aww, win->awar_path_for_helixNr);
560        }
561    }
562    else {
563        aw_message("No helix to jump to.");
564    }
565}
566
567enum SelectedAwar { SELECTED_SPECIES, SELECTED_BAD_ALI };
568
569static void selected_changed_cb(AW_root *aw_root, SelectedAwar whatChanged) {
570    static bool in_callback = false;
571
572    if (!in_callback) {
573        LocallyModify<bool> flag(in_callback, true);
574
575        const char *source_awar_name = AWAR_BADALI_SPECIES;
576        const char *dest_awar_name   = AWAR_SPECIES_NAME;
577
578        if (whatChanged == SELECTED_SPECIES) {
579            swap(source_awar_name, dest_awar_name);
580        }
581
582        const char *selected_species = aw_root->awar(source_awar_name)->read_char_pntr();
583        if (selected_species[0]) { // if nothing selected => do not change other AWAR
584            aw_root->awar(dest_awar_name)->write_string(selected_species);
585            if (SELECTED_BAD_ALI) {
586                jump_to_next_helix_cb(NULp, BY_SELECTION);
587            }
588        }
589    }
590}
591
592void ED4_popup_detect_bad_alignment_window(AW_window *editor_window, const WindowCallback *helixSettings_cb) {
593    static AW_window_simple *aws = NULp;
594
595    ED4_LocalWinContext uses(editor_window);
596
597    if (!aws) {
598        AW_root *aw_root = editor_window->get_root();
599
600        aws = new AW_window_simple;
601
602        aws->init(aw_root, "DETECT_BAD_ALI", "Detect bad helix alignment");
603        aws->load_xfig("edit4/detect_bad_ali.fig");
604
605        aws->button_length(10);
606
607        aws->at("close");
608        aws->callback(AW_POPDOWN);
609        aws->create_button("CLOSE", "CLOSE", "C");
610
611        aws->at("help");
612        aws->callback(makeHelpCallback("bad_alignment.hlp"));
613        aws->create_button("HELP", "HELP", "H");
614
615        aws->at("list");
616        AW_selection_list *sellst = aws->create_selection_list(AWAR_BADALI_SPECIES);
617        sellst->insert_default("<not calculated>", "");
618        sellst->update();
619
620        aws->at("config");
621        aws->auto_space(5, 5);
622        aws->label_length(20);
623
624        aws->label("Helices to examine\n"
625                   "(comma-separated list)");
626        aws->create_input_field(AWAR_BADALI_HELIXLIST, 15);
627
628        aws->callback(makeWindowCallback(jump_to_next_helix_cb, BY_BUTTON));
629        aws->create_autosize_button("JUMP", "Jump", "J");
630
631        aws->at_newline();
632
633        aws->label("Detected symbols");
634        aws->create_input_field(AWAR_BADALI_SYMBOLS, 5);
635
636        aws->callback(*helixSettings_cb);
637        aws->create_autosize_button("HELIX_SETTINGS", "Helix settings", "H");
638
639        aws->at_newline();
640        aws->label("Write to database field");
641        create_itemfield_selection_button(aws, FieldSelDef(AWAR_BADALI_FIELD, ED4_ROOT->get_gb_main(), SPECIES_get_selector(), FIELD_FILTER_INT_WRITEABLE, "target field", SF_ALLOW_NEW), NULp);
642
643        aws->at("calc");
644        aws->callback(makeWindowCallback(calc_and_update_alignment_errors_cb, sellst));
645        aws->create_button("CALCULATE", "Calculate", "C");
646
647        aw_root->awar(AWAR_BADALI_SPECIES)->add_callback(makeRootCallback(selected_changed_cb, SELECTED_BAD_ALI));
648        aw_root->awar(AWAR_SPECIES_NAME)->add_callback(makeRootCallback(selected_changed_cb, SELECTED_SPECIES));
649    }
650
651    e4_assert(aws);
652    aws->activate();
653
654}
655
656
Note: See TracBrowser for help on using the repository browser.