source: tags/ms_r16q2/EDIT4/ED4_base.cxx

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