source: tags/ms_r17q2/EDIT4/ED4_base.cxx

Last change on this file was 15513, checked in by westram, 7 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.8 KB
Line 
1#include <arbdbt.h>
2#include <ad_cb.h>
3
4#include <aw_preset.hxx>
5#include <aw_awar.hxx>
6#include <aw_msg.hxx>
7#include <aw_root.hxx>
8#include <aw_question.hxx>
9
10#include <arb_progress.h>
11#include <arb_strbuf.h>
12
13#include <ed4_extern.hxx>
14
15#include "ed4_class.hxx"
16#include "ed4_awars.hxx"
17#include "ed4_edit_string.hxx"
18#include "ed4_list.hxx"
19
20ED4_group_manager *ED4_base::is_in_folded_group() const {
21    if (!parent) return NULL;
22    ED4_manager *group = get_parent(LEV_GROUP);
23    if (!group) return NULL;
24    if (group->has_property(PROP_IS_FOLDED)) return group->to_group_manager();
25    return group->is_in_folded_group();
26}
27
28void ED4_base::changed_by_database()
29{
30    e4_assert(0);
31    // this happens if you add a new species_pointer to a ED4_base-derived type
32    // without defining changed_by_database for this type
33}
34
35void ED4_manager::changed_by_database() { request_refresh(); }
36
37void ED4_terminal::changed_by_database()
38{
39    if (GB_read_clock(GLOBAL_gb_main) > curr_timestamp) { // only if timer_cb occurred after last change by EDIT4
40
41        // test if alignment length has changed:
42        {
43            GBDATA *gb_alignment = GBT_get_alignment(GLOBAL_gb_main, ED4_ROOT->alignment_name);
44            e4_assert(gb_alignment);
45            GBDATA *gb_alignment_len = GB_search(gb_alignment, "alignment_len", GB_FIND);
46            int alignment_length = GB_read_int(gb_alignment_len);
47
48            if (MAXSEQUENCECHARACTERLENGTH!=alignment_length) {
49                ED4_alignment_length_changed(gb_alignment_len, GB_CB_CHANGED);
50            }
51        }
52
53        GBDATA *gb_seq = get_species_pointer();
54        int type = GB_read_type(gb_seq);
55
56        if (type==GB_STRING) {
57            char *data = (char*)GB_read_old_value();
58            if (data) {
59                int data_len = GB_read_old_size();
60                e4_assert(data_len >= 0);
61                char *dup_data = new char[data_len+1];
62
63                memcpy(dup_data, data, data_len);
64                dup_data[data_len] = 0;
65
66#if defined(DEBUG) && 0
67                char *n = GB_read_string(gb_seq);
68                e4_assert(strcmp(n, dup_data)!=0); // not really changed
69                delete n;
70#endif
71
72                ED4_species_manager *spman = get_parent(LEV_SPECIES)->to_species_manager();
73                spman->do_callbacks();
74
75                if (has_property(PROP_CONSENSUS_RELEVANT)) {
76                    ED4_multi_species_manager *multiman = get_parent(LEV_MULTI_SPECIES)->to_multi_species_manager();
77                    multiman->update_bases_and_rebuild_consensi(dup_data, data_len, spman, ED4_U_UP);
78                    request_refresh();
79                }
80
81                delete [] dup_data;
82            }
83            else { // sth else changed (e.g. protection)
84                GB_clear_error();
85            }
86        }
87    }
88}
89
90void ED4_base::deleted_from_database() {
91    my_species_pointer.notify_deleted();
92}
93
94void ED4_terminal::deleted_from_database() {
95    ED4_base::deleted_from_database();
96}
97
98void ED4_text_terminal::deleted_from_database() {
99    ED4_terminal::deleted_from_database();
100    parent->Delete();
101}
102
103void ED4_sequence_terminal::deleted_from_database()
104{
105#if defined(DEBUG)
106    printf("ED4_sequence_terminal::deleted_from_database (%p)\n", this);
107#endif // DEBUG
108
109    ED4_terminal::deleted_from_database();
110
111    bool was_consensus_relevant = has_property(PROP_CONSENSUS_RELEVANT);
112
113    clr_property(ED4_properties(PROP_CONSENSUS_RELEVANT|PROP_ALIGNMENT_DATA));
114
115    if (was_consensus_relevant) { 
116        const char *data     = (const char*)GB_read_old_value();
117        int         data_len = GB_read_old_size();
118
119        ED4_multi_species_manager *multi_species_man = get_parent(LEV_MULTI_SPECIES)->to_multi_species_manager();
120
121        multi_species_man->update_bases(data, data_len, 0);
122        multi_species_man->rebuild_consensi(get_parent(LEV_SPECIES)->to_species_manager(), ED4_U_UP);
123    }
124
125    parent->Delete();
126}
127
128void ED4_manager::deleted_from_database() {
129    if (is_species_manager()) {
130        ED4_species_manager *species_man = to_species_manager();
131        ED4_multi_species_manager *multi_man = species_man->parent->to_multi_species_manager();
132
133        multi_man->remove_member(species_man);
134        GB_push_transaction(GLOBAL_gb_main);
135        multi_man->update_consensus(multi_man, 0, species_man);
136        multi_man->rebuild_consensi(species_man, ED4_U_UP);
137        GB_pop_transaction(GLOBAL_gb_main);
138
139        request_resize();
140        // parent = 0;
141        // delete this; // @@@ crashes when removing callback deleted_from_database()
142    }
143    else {
144        e4_assert(0);
145    }
146}
147
148static void sequence_changed_cb(GBDATA *gb_seq, ED4_base *base, GB_CB_TYPE gbtype) {
149    if (base->get_species_pointer()!=gb_seq) {
150        e4_assert(0);
151        aw_message("Illegal callback (ED4_sequence_changed_cb())");
152    }
153
154    if (gbtype&GB_CB_DELETE) {
155        e4_assert(gbtype==GB_CB_DELETE);
156        base->deleted_from_database();
157    }
158
159    if (gbtype&GB_CB_CHANGED) {
160        base->changed_by_database();
161    }
162
163    if (gbtype&GB_CB_SON_CREATED) {
164        // @@@ New son for database-member was created ... what may we do now?
165    }
166}
167
168ED4_species_pointer::ED4_species_pointer() {
169    species_pointer = 0;
170}
171ED4_species_pointer::~ED4_species_pointer() {
172    e4_assert(species_pointer==0);      // must be destroyed before
173}
174
175void ED4_species_pointer::addCallback(ED4_base *base) {
176    GB_transaction ta(GLOBAL_gb_main);
177    GB_add_callback(species_pointer, GB_CB_CHANGED_OR_DELETED, makeDatabaseCallback(sequence_changed_cb, base));
178}
179void ED4_species_pointer::removeCallback(ED4_base *base) {
180    GB_transaction ta(GLOBAL_gb_main);
181    GB_remove_callback(species_pointer, GB_CB_CHANGED_OR_DELETED, makeDatabaseCallback(sequence_changed_cb, base));
182}
183
184void ED4_species_pointer::Set(GBDATA *gbd, ED4_base *base) {
185    if (species_pointer) removeCallback(base);
186    species_pointer = gbd;
187    if (species_pointer) addCallback(base);
188}
189
190// -----------------
191//      ED4_base
192
193inline bool ranges_overlap(int p1, int p2, int r1, int r2) {
194    // return true if ranges p1..p2 and r1..r2 overlap
195    e4_assert(p1 <= p2);
196    e4_assert(r1 <= r2);
197
198    return !((r2 <= p1) || (p2 <= r1)); // "exactly adjacent" means "not overlapping"
199}
200
201inline bool range_contained_in(int p1, int p2, int r1, int r2) {
202    // return true if range p1..p2 is contained in range r1..r2
203    e4_assert(p1 <= p2);
204    e4_assert(r1 <= r2);
205
206    return p1 >= r1 && p2 <= r2;
207}
208
209bool ED4_window::partly_shows(int x1, int y1, int x2, int y2) const {
210    // return true if rectangle x1/y1/x2/y2 overlaps with clipped screen
211    e4_assert(x1 <= x2);
212    e4_assert(y1 <= y2);
213
214    bool visible = (ranges_overlap(x1, x2, coords.window_left_clip_point, coords.window_right_clip_point) &&
215                    ranges_overlap(y1, y2, coords.window_upper_clip_point, coords.window_lower_clip_point));
216
217    return visible;
218}
219
220bool ED4_window::completely_shows(int x1, int y1, int x2, int y2) const {
221    // return true if rectangle x1/y1/x2/y2 is contained in clipped screen
222    e4_assert(x1 <= x2);
223    e4_assert(y1 <= y2);
224
225    bool visible = (range_contained_in(x1, x2, coords.window_left_clip_point, coords.window_right_clip_point) &&
226                    range_contained_in(y1, y2, coords.window_upper_clip_point, coords.window_lower_clip_point));
227
228    return visible;
229}
230
231char *ED4_base::resolve_pointer_to_string_copy(int *) const { return NULL; }
232const char *ED4_base::resolve_pointer_to_char_pntr(int *) const { return NULL; }
233
234ED4_group_manager *ED4_build_group_manager_start(ED4_manager                 *group_parent,
235                                                 GB_CSTR                      group_name,
236                                                 int                          group_depth,
237                                                 bool                         is_folded,
238                                                 ED4_reference_terminals&     refterms,
239                                                 ED4_multi_species_manager*&  multi_species_manager)
240{
241    char namebuffer[NAME_BUFFERSIZE];
242
243    sprintf(namebuffer, "Group_Manager.%ld", ED4_counter); // create new group manager
244    ED4_group_manager *group_manager = new ED4_group_manager(namebuffer, 0, 0, group_parent);
245    group_parent->append_member(group_manager);
246
247    sprintf(namebuffer, "Bracket_Terminal.%ld", ED4_counter);
248    ED4_bracket_terminal *bracket_terminal = new ED4_bracket_terminal(namebuffer, BRACKET_WIDTH, 0, group_manager);
249    group_manager->append_member(bracket_terminal);
250
251    sprintf(namebuffer, "MultiSpecies_Manager.%ld", ED4_counter); // create new multi_species_manager
252    multi_species_manager = new ED4_multi_species_manager(namebuffer, 0, 0, group_manager);
253    group_manager->append_member(multi_species_manager);
254
255    if (is_folded) group_manager->set_property(PROP_IS_FOLDED);
256    group_manager->set_property(PROP_MOVABLE);
257
258    multi_species_manager->set_property(PROP_IS_HANDLE);
259    bracket_terminal     ->set_property(PROP_IS_HANDLE);
260
261    {
262        sprintf(namebuffer, "Group_Spacer_Terminal_Beg.%ld", ED4_counter); // spacer at beginning of group
263        ED4_spacer_terminal *group_spacer_terminal = new ED4_spacer_terminal(namebuffer, false, 10, SPACER_HEIGHT, multi_species_manager);
264        multi_species_manager->append_member(group_spacer_terminal);
265    }
266
267    {
268        sprintf(namebuffer, "Consensus_Manager.%ld", ED4_counter);
269        ED4_species_manager *species_manager = new ED4_species_manager(ED4_SP_CONSENSUS, namebuffer, 0, 0, multi_species_manager);
270        species_manager->set_property(PROP_MOVABLE);
271        multi_species_manager->append_member(species_manager);
272
273        {
274            ED4_species_name_terminal *species_name_terminal = new ED4_species_name_terminal(group_name, MAXNAME_WIDTH - group_depth*BRACKET_WIDTH, TERMINAL_HEIGHT, species_manager);
275            species_name_terminal->set_property((ED4_properties) (PROP_SELECTABLE | PROP_DRAGABLE | PROP_IS_HANDLE));
276            species_name_terminal->set_links(NULL, refterms.sequence());
277            species_manager->append_member(species_name_terminal);
278        }
279
280
281        {
282            // add flag header terminal
283            sprintf(namebuffer, "Flag_Header_Terminal.%ld", ED4_counter);
284            ED4_flag_header_terminal *flag_header_terminal = new ED4_flag_header_terminal(namebuffer, 100, TERMINAL_HEIGHT, species_manager);
285            flag_header_terminal->set_links(NULL, refterms.sequence());
286            species_manager->append_member(flag_header_terminal);
287        }
288
289        {
290            sprintf(namebuffer, "Consensus_Seq_Manager.%ld", ED4_counter);
291            ED4_sequence_manager *sequence_manager = new ED4_sequence_manager(namebuffer, 0, 0, species_manager);
292            sequence_manager->set_property(PROP_MOVABLE);
293            species_manager->append_member(sequence_manager);
294
295            {
296                ED4_sequence_info_terminal *seq_info_term = new ED4_sequence_info_terminal("CONS", SEQUENCE_INFO_WIDTH, TERMINAL_HEIGHT, sequence_manager); // group info
297                seq_info_term->set_both_links(refterms.sequence_info());
298                seq_info_term->set_property((ED4_properties) (PROP_SELECTABLE | PROP_DRAGABLE | PROP_IS_HANDLE));
299                sequence_manager->append_member(seq_info_term);
300            }
301
302            {
303                sprintf(namebuffer, "Consensus_Seq_Terminal.%ld", ED4_counter);
304                ED4_sequence_terminal *sequence_terminal = new ED4_consensus_sequence_terminal(namebuffer, 0, TERMINAL_HEIGHT, sequence_manager);
305                sequence_terminal->set_property(PROP_CURSOR_ALLOWED);
306                sequence_terminal->set_both_links(refterms.sequence());
307                sequence_manager->append_member(sequence_terminal);
308            }
309        }
310    }
311
312    bracket_terminal->set_links(NULL, multi_species_manager);
313
314    return group_manager;
315}
316
317void ED4_build_group_manager_end(ED4_multi_species_manager *multi_species_manager) {
318    char namebuffer[NAME_BUFFERSIZE];
319
320    sprintf(namebuffer, "Group_Spacer_Terminal_End.%ld", ED4_counter); // spacer at end of group
321    ED4_spacer_terminal *group_spacer_terminal = new ED4_spacer_terminal(namebuffer, false, 10, SPACER_HEIGHT, multi_species_manager);
322    multi_species_manager->append_member(group_spacer_terminal);
323}
324
325void ED4_base::generate_configuration_string(GBS_strstruct& buffer) {
326    const char SEPARATOR = '\1';
327    if (is_manager()) {
328        ED4_container *container = to_manager();
329        if (is_group_manager()) {
330            buffer.put(SEPARATOR);
331            buffer.put(has_property(PROP_IS_FOLDED) ? 'F' : 'G');
332
333            for (int writeConsensus = 1; writeConsensus>=0; --writeConsensus) {
334                for (int i=0; i<container->members(); ++i) {
335                    ED4_base *child       = container->member(i);
336                    bool      isConsensus = child->is_consensus_manager();
337
338                    if (bool(writeConsensus) == isConsensus) {
339                        child->generate_configuration_string(buffer);
340                    }
341                }
342            }
343
344            buffer.put(SEPARATOR);
345            buffer.put('E');
346        }
347        else {
348            for (int i=0; i<container->members(); i++) {
349                container->member(i)->generate_configuration_string(buffer);
350            }
351        }
352    }
353    else {
354        if (is_species_name_terminal() && !((ED4_terminal*)this)->tflag.deleted) {
355            ED4_species_type species_type = get_species_type();
356            switch (species_type) {
357                case ED4_SP_CONSENSUS: {
358                    // write group name (control info already written inside manager-branch above)
359                    const char *paren = strchr(id, '(');
360                    if (paren) {
361                        int namelen = std::max(int(paren-id)-1, 0); // skip starting at " (" behind consensus name
362
363                        if (namelen>0) buffer.ncat(id, namelen);
364                        else           buffer.cat("<unnamed>");
365                    }
366                    else buffer.cat(id);
367                    break;
368                }
369                case ED4_SP_SAI:
370                    buffer.put(SEPARATOR);
371                    buffer.put('S');
372                    buffer.cat(resolve_pointer_to_char_pntr(NULL));
373                    break;
374                case ED4_SP_SPECIES:
375                    buffer.put(SEPARATOR);
376                    buffer.put('L');
377                    buffer.cat(resolve_pointer_to_char_pntr(NULL));
378                    break;
379                case ED4_SP_NONE:
380                    e4_assert(0);
381                    break;
382            }
383        }
384    }
385}
386
387
388ARB_ERROR ED4_base::route_down_hierarchy(const ED4_route_cb& cb) {
389    // executes 'cb' for every element in hierarchy
390    return cb(this);
391}
392
393ARB_ERROR ED4_manager::route_down_hierarchy(const ED4_route_cb& cb) {
394    ARB_ERROR error = cb(this);
395    if (!error) {
396        for (int i=0; i<members() && !error; i++) {
397            error = member(i)->route_down_hierarchy(cb);
398        }
399    }
400    return error;
401}
402
403ED4_base *ED4_manager::find_first_that(ED4_level level, const ED4_basePredicate& fulfills_predicate) {
404    if ((spec.level&level) && fulfills_predicate(this)) {
405        return this;
406    }
407
408    for (int i=0; i<members(); i++) {
409        ED4_base *child = member(i);
410
411        if (child->is_manager()) {
412            ED4_base *found = child->to_manager()->find_first_that(level, fulfills_predicate);
413            if (found) {
414                return found;
415            }
416        }
417        else if ((child->spec.level&level) && fulfills_predicate(child)) {
418            return child;
419        }
420    }
421
422    return 0;
423}
424
425int ED4_base::calc_group_depth() {
426    int       cntr        = 0;
427    ED4_base *temp_parent = parent;
428    while (temp_parent->parent && !(temp_parent->is_area_manager())) {
429        if (temp_parent->is_group_manager()) cntr++;
430        temp_parent = temp_parent->parent;
431    }
432    return cntr; // don't count our own group
433}
434
435ED4_base *ED4_manager::search_spec_child_rek(ED4_level level) {
436    // if (spec.level & level) return this; // old behavior (unwanted)
437    e4_assert(!(spec.level & level)); // if this fails, the old behavior was used => behavior of this call did change!
438
439    for (int i=0; i<members(); i++) { // first check children
440        if (member(i)->spec.level & level) {
441            return member(i);
442        }
443    }
444
445    for (int i=0; i<members(); i++) {
446        if (member(i)->is_manager()) {
447            ED4_base *result = member(i)->to_manager()->search_spec_child_rek(level);
448            if (result) return result;
449        }
450    }
451
452    return 0;
453}
454
455ED4_terminal *ED4_base::get_next_terminal()
456{
457    ED4_terminal *terminal = 0;
458
459    if (parent) {
460        terminal = parent->get_first_terminal(index+1);
461        if (!terminal) {
462            terminal = parent->get_next_terminal();
463        }
464    }
465
466    return terminal;
467}
468
469ED4_terminal *ED4_base::get_prev_terminal()
470{
471    ED4_terminal *terminal = 0;
472
473    if (parent) {
474        if (index) {
475            terminal = parent->get_last_terminal(index-1);
476        }
477        if (!terminal) {
478            terminal = parent->get_prev_terminal();
479        }
480    }
481
482    return terminal;
483}
484
485
486bool ED4_base::has_parent(ED4_manager *Parent)
487{
488    // return true if 'parent' is a parent of this
489
490    if (is_manager()) {
491        if (this == static_cast<ED4_base*>(Parent)) {
492            return true;
493        }
494    }
495
496    if (!parent) return false;
497    return parent->has_parent(Parent);
498}
499
500
501ED4_AREA_LEVEL ED4_base::get_area_level(ED4_multi_species_manager **multi_species_manager) const {
502    ED4_base       *area_base = get_parent(LEV_AREA);
503    ED4_AREA_LEVEL  result    = ED4_A_ERROR;
504
505    if (area_base) {
506        ED4_area_manager *area_man = area_base->to_area_manager();
507
508        if      (area_man == ED4_ROOT->top_area_man)    result = ED4_A_TOP_AREA;
509        else if (area_man == ED4_ROOT->middle_area_man) result = ED4_A_MIDDLE_AREA;
510
511        if (result != ED4_A_ERROR && multi_species_manager) {
512            *multi_species_manager = area_man->get_multi_species_manager();
513        }
514    }
515    return result;
516}
517
518
519void ED4_multi_species_manager::update_group_id() {
520    ED4_species_name_terminal *consensus_name_terminal = get_consensus_name_terminal();
521    if (consensus_name_terminal) { // top managers dont show consensus
522        e4_assert(has_valid_counters());
523       
524        const char *cntid = consensus_name_terminal->id;
525        char       *name  = ARB_calloc<char>(strlen(cntid)+10);
526
527        int i;
528        for (i=0; cntid[i] && cntid[i] != '(';   i++) {
529            name[i] = cntid[i];
530        }
531        if (i>0 && cntid[i-1] == ' ') --i; // skip terminal space
532        sprintf(name+i, " (%d)", species);
533
534        freeset(consensus_name_terminal->id, name);
535
536        consensus_name_terminal->request_refresh();
537    }
538}
539
540PosRange ED4_abstract_sequence_terminal::pixel2index(PosRange pixel_range) {
541    int length_of_char = ED4_ROOT->font_group.get_width(ED4_G_SEQUENCES);
542
543    int left_index  = int((pixel_range.start()-CHARACTEROFFSET)/length_of_char);
544    int right_index = int((pixel_range.end()  -CHARACTEROFFSET)/length_of_char) + 1;
545
546    return PosRange(left_index, std::min(right_index, MAXSEQUENCECHARACTERLENGTH-1));
547}
548
549PosRange ED4_abstract_sequence_terminal::calc_interval_displayed_in_rectangle(AW_screen_area *rect) { // rect contains win-coords
550    AW_pos x, y;
551    calc_world_coords(&x, &y);
552    current_ed4w()->world_to_win_coords(&x, &y);
553
554    int rel_left_x  = int(rect->l-x);
555    int rel_right_x = int(rect->r-x);
556
557    return pixel2index(PosRange(rel_left_x, rel_right_x)); // changed behavior: clip at MAXSEQUENCECHARACTERLENGTH-1 (was MAXSEQUENCECHARACTERLENGTH)
558}
559
560PosRange ED4_abstract_sequence_terminal::calc_update_interval() {
561    AW_pos x, y;
562    calc_world_coords(&x, &y);
563
564    const AW_screen_area& clip_rect = current_device()->get_cliprect();
565
566    int scroll_shift = current_ed4w()->coords.window_left_clip_point-x; // Verschiebung der Sequenz (durch Scrollen) == slider Position
567    int rel_left_x   = int(clip_rect.l - x + scroll_shift);                   // Abstand vom linken Terminalrand zum Anfang des Clipping rectangles + scroll_shift
568    int rel_right_x  = int(clip_rect.r - x + scroll_shift);
569
570    return pixel2index(PosRange(rel_left_x, rel_right_x));
571}
572
573void ED4_manager::create_consensus(ED4_abstract_group_manager *upper_group_manager, arb_progress *progress) {
574    // creates consensus
575    // is called by group manager
576
577    ED4_abstract_group_manager *group_manager_for_child = upper_group_manager;
578
579    if (is_abstract_group_manager()) {
580        ED4_abstract_group_manager *group_manager = to_abstract_group_manager();
581
582        group_manager->table().init(MAXSEQUENCECHARACTERLENGTH);
583        group_manager_for_child = group_manager;
584
585        if (progress) progress->inc();
586    }
587
588    for (int i=0; i<members(); i++) {
589        ED4_base *child = member(i);
590
591        if (child->is_species_manager()) {
592            ED4_species_manager *species_manager        = child->to_species_manager();
593            const ED4_terminal  *sequence_data_terminal = species_manager->get_consensus_relevant_terminal();
594
595            if (sequence_data_terminal) {
596                int   db_pointer_len;
597                char *db_pointer = sequence_data_terminal->resolve_pointer_to_string_copy(&db_pointer_len);
598                group_manager_for_child->table().add(db_pointer, db_pointer_len);
599                e4_assert(!group_manager_for_child->table().empty());
600                free(db_pointer);
601
602                if (progress) progress->inc();
603            }
604        }
605        else if (child->is_group_manager()) {
606            ED4_group_manager *sub_group = child->to_group_manager();
607
608            sub_group->create_consensus(sub_group, progress);
609            e4_assert(sub_group!=upper_group_manager);
610            upper_group_manager->table().add(sub_group->table());
611#if defined(TEST_CHAR_TABLE_INTEGRITY)
612            if (!sub_group->table().empty() && !sub_group->table().is_ignored()) {
613                e4_assert(!upper_group_manager->table().empty());
614            }
615#endif
616        }
617        else if (child->is_manager()) {
618            child->to_manager()->create_consensus(group_manager_for_child, progress);
619        }
620    }
621}
622
623const ED4_terminal *ED4_base::get_consensus_relevant_terminal() const {
624    int i;
625
626    if (is_terminal()) {
627        if (has_property(PROP_CONSENSUS_RELEVANT)) {
628            return this->to_terminal();
629        }
630        return NULL;
631    }
632
633    const ED4_manager  *manager           = this->to_manager();
634    const ED4_terminal *relevant_terminal = 0;
635
636    int members = manager->members();
637
638    for (i=0; !relevant_terminal && i<members; ++i) {
639        ED4_base *child  = manager->member(i);
640        relevant_terminal = child->get_consensus_relevant_terminal();
641    }
642
643#if defined(DEBUG)
644    if (relevant_terminal) {
645        for (; i<members; ++i) {
646            ED4_base *child = manager->member(i);
647            e4_assert(!child->get_consensus_relevant_terminal()); // there shall be only 1 consensus relevant terminal, since much code assumes that
648        }
649    }
650#endif // DEBUG
651
652    return relevant_terminal;
653}
654
655int ED4_multi_species_manager::count_visible_children() // is called by a multi_species_manager
656{
657    int counter = 0;
658
659    for (int i=0; i<members(); i++) {
660        ED4_base *child = member(i);
661        if (child->is_species_manager()) {
662            counter ++;
663        }
664        else if (child->is_group_manager()) {
665            ED4_group_manager *group_manager = child->to_group_manager();
666            if (group_manager->has_property(PROP_IS_FOLDED)) {
667                counter ++;
668            }
669            else {
670                ED4_multi_species_manager *multi_species_manager = group_manager->get_multi_species_manager();
671                counter += multi_species_manager->count_visible_children();
672            }
673        }
674    }
675    return counter;
676}
677
678
679
680void ED4_base::unlink_from_parent() {
681    e4_assert(parent);
682    parent->remove_member(this);
683}
684
685char *ED4_base::get_name_of_species() {
686    char                *name        = 0;
687    ED4_species_manager *species_man = get_parent(LEV_SPECIES)->to_species_manager();
688    if (species_man) {
689        ED4_species_name_terminal *species_name = species_man->search_spec_child_rek(LEV_SPECIES_NAME)->to_species_name_terminal();
690        if (species_name) {
691            GBDATA *gb_name   = species_name->get_species_pointer();
692            if (gb_name) {
693                GB_transaction ta(gb_name);
694                name = GB_read_as_string(gb_name);
695            }
696        }
697    }
698    return name;
699}
700
701ED4_base *ED4_manager::get_defined_level(ED4_level lev) const {
702    for (int i=0; i<members(); i++) { // first test direct children ..
703        if (member(i)->spec.level & lev) {
704            return member(i);
705        }
706    }
707
708    for (int i=0; i<members(); i++) { // .. then all containers
709        ED4_base *child = member(i);
710
711        if (child->is_multi_species_manager()) {
712            return child->to_multi_species_manager()->get_defined_level(lev);
713        }
714        else if (child->is_group_manager()) {
715            return child->to_group_manager()->member(1)->to_multi_species_manager()->get_defined_level(lev);
716        }
717        else {
718            e4_assert(!child->is_manager());
719        }
720    }
721    return NULL;
722}
723
724ED4_returncode ED4_base::set_width() {
725    // sets object length of terminals to Consensus_Name_terminal if existing
726    // else to MAXNAME_WIDTH
727
728    if (is_species_manager()) {
729        ED4_species_manager *species_manager = to_species_manager();
730
731        if (!species_manager->is_consensus_manager()) {
732            ED4_multi_name_manager    *multi_name_manager = species_manager->get_defined_level(LEV_MULTI_NAME)->to_multi_name_manager();  // case I'm a species
733            ED4_species_name_terminal *consensus_terminal = parent->to_multi_species_manager()->get_consensus_name_terminal();
734
735            for (int i=0; i<multi_name_manager->members(); i++) {
736                ED4_name_manager *name_manager = multi_name_manager->member(i)->to_name_manager();
737                ED4_base         *nameTerm     = name_manager->member(0);
738                int               width        = consensus_terminal ? consensus_terminal->extension.size[WIDTH] : MAXNAME_WIDTH;
739
740                nameTerm->extension.size[WIDTH] = width;
741                nameTerm->request_resize();
742            }
743
744            for (int i=0; i<species_manager->members(); i++) { // adjust all managers as far as possible
745                ED4_base *smember = species_manager->member(i);
746                if (consensus_terminal) {
747                    ED4_base *kmember = consensus_terminal->parent->member(i);
748                    if (kmember) {
749                        smember->extension.position[X_POS] = kmember->extension.position[X_POS];
750                        ED4_base::touch_world_cache();
751                    }
752                }
753                else { // got no consensus
754                    ED4_species_manager *a_species = parent->get_defined_level(LEV_SPECIES)->to_species_manager();
755                    if (a_species) {
756                        smember->extension.position[X_POS] = a_species->member(i)->extension.position[X_POS];
757                        ED4_base::touch_world_cache();
758                    }
759                }
760                smember->request_resize();
761            }
762        }
763    }
764    else if (is_group_manager()) {
765        ED4_group_manager         *group_manager           = to_group_manager();
766        ED4_multi_species_manager *multi_species_manager   = group_manager->get_multi_species_manager();
767        ED4_species_name_terminal *mark_consensus_terminal = multi_species_manager->get_consensus_name_terminal();
768        ED4_species_name_terminal *consensus_terminal      = parent->to_multi_species_manager()->get_consensus_name_terminal();
769
770        if (consensus_terminal) { // we're a group in another group
771            mark_consensus_terminal->extension.size[WIDTH] = consensus_terminal->extension.size[WIDTH] - BRACKET_WIDTH;
772        }
773        else { // we're at the top (no consensus terminal)
774            mark_consensus_terminal->extension.size[WIDTH] = MAXNAME_WIDTH - BRACKET_WIDTH;
775        }
776
777        mark_consensus_terminal->request_resize();
778
779        for (int i=0; i<multi_species_manager->members(); i++) {
780            multi_species_manager->member(i)->set_width();
781        }
782
783        for (int i=0; i < group_manager->members(); i++) { // for all groups below from us
784            if (group_manager->member(i)->is_group_manager()) {
785                group_manager->member(i)->set_width();
786            }
787        }
788    }
789
790    return ED4_R_OK;
791}
792
793
794short ED4_base::in_border(AW_pos x, AW_pos y, ED4_movemode mode)                                // determines if given world coords x and y
795{                                                                                               // are within borders of current object according to move mode
796    AW_pos    world_x, world_y;
797
798    calc_world_coords(&world_x, &world_y);                                              // calculate absolute extension of current object
799
800    switch (mode)                                                                               // which direction ?
801    {
802        case ED4_M_HORIZONTAL:
803            {
804                if ((x >= world_x) && (x < (world_x + extension.size[WIDTH])))
805                    return (1);                                                 // target location is within the borders of parent
806                break;
807            }
808        case ED4_M_VERTICAL:
809            {
810                if ((y >= world_y) && (y < (world_y + extension.size[HEIGHT])))
811                    return (1);                                                 // target location is within the borders of parent
812                break;
813            }
814        case ED4_M_FREE:
815            {
816                return (in_border(x, y, ED4_M_HORIZONTAL) && in_border(x, y, ED4_M_VERTICAL));
817            }
818        case ED4_M_NO_MOVE:
819            {
820                break;
821            }
822    }
823
824    return (0);
825}
826
827
828void ED4_base::calc_rel_coords(AW_pos *x, AW_pos *y) // calculates coordinates relative to current object from given world coords
829{
830    AW_pos   world_x, world_y;
831
832    calc_world_coords(&world_x, &world_y);          // calculate world coordinates of current object
833
834    *x -= world_x;                                  // calculate relative coordinates by subtracting world
835    *y -= world_y;                                  // coords of current object
836}
837
838void ED4_manager::hide_children() {
839    for (int i=0; i<members(); i++) {
840        ED4_base *child = member(i);
841        if (!child->is_spacer_terminal() && !child->is_consensus_manager()) { // don't hide spacer and Consensus
842            child->flag.hidden = 1;
843        }
844    }
845    request_resize();
846}
847
848
849void ED4_manager::unhide_children() {
850    for (int i=0; i<members(); i++) {
851        member(i)->flag.hidden = 0; // make child visible
852    }
853    request_resize();
854}
855
856void ED4_group_manager::unfold() {
857    for (int i=0; i<members(); i++) {
858        ED4_base *child = member(i);
859
860        if (child->is_multi_species_manager()) {
861            ED4_multi_species_manager *multi_species_manager = child->to_multi_species_manager();
862            multi_species_manager->unhide_children();
863        }
864    }
865
866    clr_property(PROP_IS_FOLDED);
867    ED4_request_relayout();
868}
869
870void ED4_group_manager::fold() {
871    ED4_multi_species_manager *multi_species_manager = get_defined_level(LEV_MULTI_SPECIES)->to_multi_species_manager();
872
873    bool consensus_shown = false;
874    if (!(multi_species_manager->member(1)->is_consensus_manager())) { // if consensus is not at top => move to top
875        ED4_manager *consensus_manager = NULL;
876        int i;
877        for (i=0; i<multi_species_manager->members(); i++) { // search for consensus
878            if (multi_species_manager->member(i)->is_consensus_manager()) {
879                consensus_manager = multi_species_manager->member(i)->to_manager();
880                break;
881            }
882        }
883
884        if (consensus_manager) {
885            multi_species_manager->move_member(i, 1); // move Consensus to top of list
886            consensus_manager->extension.position[Y_POS] = SPACER_HEIGHT;
887            ED4_base::touch_world_cache();
888            consensus_shown = true;
889        }
890    }
891    else {
892        consensus_shown = true;
893    }
894
895    if (consensus_shown && ED4_ROOT->aw_root->awar(ED4_AWAR_CONSENSUS_SHOW)->read_int()==0) {
896        consensus_shown = false;
897    }
898
899    multi_species_manager->hide_children();
900    set_property(PROP_IS_FOLDED);
901
902    ED4_request_relayout();
903}
904
905void ED4_group_manager::toggle_folding() {
906    if (has_property(PROP_IS_FOLDED)) unfold();
907    else fold();
908}
909void ED4_bracket_terminal::toggle_folding() {
910    parent->to_group_manager()->toggle_folding();
911}
912
913void ED4_base::check_all()
914{
915    AW_pos x, y;
916
917    calc_world_coords(&x, &y);
918
919    printf("Typ des Aufrufers :\t\t\t%s\n", is_manager() ? "Manager" : "Terminal");
920    printf("Name des Aufrufers von Check_All : \t%.30s\n", (id) ? id : "Keine ID");
921    printf("Linke obere Ecke x, y : \t\t%f, %f\n", extension.position[0], extension.position[1]);
922    printf("Breite und Hoehe x, y : \t\t%f, %f\n", extension.size[0], extension.size[1]);
923    printf("World Coords     x, y : \t\t%f, %f\n\n", x, y);
924    printf("***********************************************\n\n");
925}
926
927int ED4_base::adjust_clipping_rectangle() {
928    // return 0 if clipping rectangle disappeared (nothing left to draw)
929    AW::Rectangle base_area = get_win_area(current_ed4w());
930    return current_device()->reduceClipBorders(base_area.top(), base_area.bottom(), base_area.left(), base_area.right());
931}
932
933void ED4_base::set_links(ED4_base *width_ref, ED4_base *height_ref) {
934    // links 'this' to (one or two) reference terminal(s)
935    // => 'this' will resize when size of reference changes (maybe more effects?)
936    // (Note: passing NULL means "do not change")
937
938    if (width_ref) {
939        if (width_link) width_link->linked_objects->remove_elem(this);
940        width_link = width_ref;
941        if (!width_ref->linked_objects) width_ref->linked_objects = new ED4_base_list;
942        width_ref->linked_objects->append_elem(this);
943    }
944
945    if (height_ref) {
946        if (height_link) height_link->linked_objects->remove_elem(this);
947        height_link = height_ref;
948        if (!height_ref->linked_objects) height_ref->linked_objects = new ED4_base_list;
949        height_ref->linked_objects->append_elem(this);
950    }
951}
952
953int ED4_base::currTimestamp = 1;
954
955#if defined(DEBUG)
956// #define VISIBLE_AREA_REFRESH
957#endif
958
959ED4_returncode ED4_base::clear_background(int color) {
960    if (current_device()) { // @@@ should clear be done for all windows?
961        AW_pos x, y;
962        calc_world_coords(&x, &y);
963        current_ed4w()->world_to_win_coords(&x, &y);
964
965        current_device()->push_clip_scale();
966        if (adjust_clipping_rectangle()) {
967            if (!color) {
968#if defined(VISIBLE_AREA_REFRESH)
969                // for debugging draw each clear in different color:
970                static int gc_area = ED4_G_FIRST_COLOR_GROUP;
971
972                current_device()->box(gc_area, true, x, y, extension.size[WIDTH], extension.size[HEIGHT]);
973                gc_area = (gc_area == ED4_G_LAST_COLOR_GROUP) ? ED4_G_FIRST_COLOR_GROUP : gc_area+1;
974#else // !defined(VISIBLE_AREA_REFRESH)
975                current_device()->clear_part(x, y, extension.size[WIDTH], extension.size[HEIGHT], AW_ALL_DEVICES);
976#endif
977            }
978            else {
979                // fill range with color for debugging
980                current_device()->box(color, AW::FillStyle::SOLID, x, y, extension.size[WIDTH], extension.size[HEIGHT]);
981            }
982        }
983        current_device()->pop_clip_scale();
984    }
985    return (ED4_R_OK);
986}
987
988void ED4_main_manager::clear_whole_background() {
989    // clear AW_MIDDLE_AREA
990    for (ED4_window *window = ED4_ROOT->first_window; window; window=window->next) {
991        AW_device *device = window->get_device();
992        if (device) {
993            device->push_clip_scale();
994            device->clear(AW_ALL_DEVICES);
995            device->pop_clip_scale();
996        }
997    }
998}
999
1000void ED4_base::draw_bb(int color) {
1001    if (current_device()) {
1002        current_device()->push_clip_scale();
1003        if (adjust_clipping_rectangle()) {
1004            AW_pos x1, y1;
1005            calc_world_coords(&x1, &y1);
1006            current_ed4w()->world_to_win_coords(&x1, &y1);
1007            current_device()->box(color, AW::FillStyle::EMPTY, x1, y1, extension.size[WIDTH]-1, extension.size[HEIGHT]-1);
1008        }
1009        current_device()->pop_clip_scale();
1010    }
1011}
1012
1013ED4_base::ED4_base(const ED4_objspec& spec_, GB_CSTR temp_id, AW_pos width, AW_pos height, ED4_manager *temp_parent)
1014    : spec(spec_)
1015{
1016    index = 0;
1017    dynamic_prop = ED4_properties(PROP_NONE | (spec.static_prop & PROP_DYNA_RESIZE));
1018    timestamp =  0; // invalid - almost always..
1019
1020    e4_assert(temp_id);
1021    if (temp_id) {
1022        id = ARB_alloc<char>(strlen(temp_id)+1);
1023        strcpy(id, temp_id);
1024    }
1025
1026    linked_objects = NULL;
1027
1028    extension.position[X_POS] = -1; // position set here has no effect (will be overwritten by next resize)
1029    extension.position[Y_POS] = -1;
1030
1031    ED4_base::touch_world_cache(); // invalidate position
1032
1033    extension.size[WIDTH]  = width;
1034    extension.size[HEIGHT] = height;
1035
1036    extension.y_folded = 0;
1037    parent             = temp_parent;
1038    width_link         = NULL;
1039    height_link        = NULL;
1040
1041    memset((char*)&update_info, 0, sizeof(update_info));
1042    memset((char*)&flag, 0, sizeof(flag));
1043}
1044
1045
1046ED4_base::~ED4_base() {
1047    // before calling this function the first time, parent has to be set NULL
1048    e4_assert(!parent); // unlink from parent first!
1049
1050    if (linked_objects) {
1051        ED4_base_list_elem *list_elem = linked_objects->head();
1052        while (list_elem) {
1053            ED4_base *object = list_elem->elem();
1054            if (object->width_link == this) {
1055                object->width_link->linked_objects->remove_elem(this);              // delete link and
1056                object->width_link = NULL;
1057            }
1058
1059            if (object->height_link == this) {
1060                object->height_link->linked_objects->remove_elem(this);             // delete link and
1061                object->height_link = NULL;
1062            }
1063
1064            ED4_base_list_elem *old_elem = list_elem;
1065            list_elem = list_elem->next();
1066            linked_objects->remove_elem(old_elem->elem());
1067        }
1068        delete linked_objects;
1069    }
1070
1071    if (update_info.linked_to_scrolled_rectangle)
1072    {
1073        if (ED4_ROOT->main_manager)
1074        {
1075            ED4_base *sequence_terminal = ED4_ROOT->main_manager->search_spec_child_rek(LEV_SEQUENCE_STRING);
1076
1077            if (sequence_terminal)
1078                sequence_terminal->update_info.linked_to_scrolled_rectangle = 1;
1079
1080            update_info.linked_to_scrolled_rectangle = 0;
1081            ED4_ROOT->scroll_links.link_for_hor_slider = sequence_terminal;
1082
1083            ED4_window *ed4w = ED4_ROOT->first_window;
1084            while (ed4w != NULL) {
1085                ed4w->scrolled_rect.replace_x_width_link_to(this, sequence_terminal);
1086                ed4w = ed4w->next;
1087            }
1088        }
1089    }
1090
1091    if (width_link) {
1092        width_link->linked_objects->remove_elem(this);
1093        width_link = NULL;
1094    }
1095
1096    if (height_link) {
1097        height_link->linked_objects->remove_elem(this);
1098        height_link = NULL;
1099    }
1100
1101    set_species_pointer(0);     // clear pointer to database and remove callbacks
1102    free(id);
1103}
1104
Note: See TracBrowser for help on using the repository browser.