source: trunk/EDIT4/ED4_base.cxx

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