source: branches/nameserver/EDIT4/ED4_base.cxx

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