source: tags/arb_5.2/EDIT4/ED4_block.cxx

Last change on this file was 5885, checked in by westram, 15 years ago
  • moved fast-aligner to separate library
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.1 KB
Line 
1#include <cstdio>
2#include <cstdlib>
3#include <cstring>
4#include <climits>
5#include <cctype>
6#include <cmath>
7
8#include <arbdb.h>
9#include <arbdbt.h>
10#include <aw_root.hxx>
11#include <aw_keysym.hxx>
12#include <aw_window.hxx>
13#include <aw_awars.hxx>
14#include <fast_aligner.hxx>
15
16#include "ed4_awars.hxx"
17#include "ed4_class.hxx"
18#include "ed4_tools.hxx"
19#include "ed4_block.hxx"
20#include "ed4_edit_string.hxx"
21
22// --------------------------------------------------------------------------------
23
24static ED4_blocktype blocktype = ED4_BT_NOBLOCK;
25
26// linerange for COLUMNBLOCK is stored in EDIT4 marks,
27// columnrange for COLUMNBLOCK is stored here:
28
29static int range_col1, range_col2;
30static int columnBlockUsed = 0;
31
32// --------------------------------------------------------------------------------
33
34static void col_block_refresh_on_seq_term(ED4_sequence_terminal *seq_term) {
35    seq_term->set_refresh(1);
36    seq_term->parent->refresh_requested_by_child();
37
38    ED4_columnStat_terminal *colStatTerm = seq_term->corresponding_columnStat_terminal();
39    if (colStatTerm) {
40        const char *probe_match_pattern = colStatTerm->build_probe_match_string(range_col1, range_col2);
41        int len = strlen(probe_match_pattern);
42
43        if (len>=4) {
44            colStatTerm->set_refresh(1);
45            colStatTerm->parent->refresh_requested_by_child();
46
47            // automatically set probe-match awars to appropriate values:
48
49            ED4_ROOT->aw_root->awar(ED4_AWAR_PROBE_SEARCH_MAX_MISMATCHES)->write_int(0); // no mismatches
50            ED4_ROOT->aw_root->awar(ED4_AWAR_PROBE_SEARCH_AUTO_JUMP)->write_int(0); // disable auto jump
51            ED4_ROOT->aw_root->awar(AWAR_MAX_MISMATCHES)->write_int(0); // probe search w/o mismatches
52            ED4_ROOT->aw_root->awar(AWAR_ITARGET_STRING)->write_string(probe_match_pattern); // set probe search string
53        }
54    }
55}
56// --------------------------------------------------------------------------------
57
58// if block_operation() returns NULL => no changes will be made to database
59// otherwise the changed sequence(part) will be written to the database
60
61static GB_ERROR perform_block_operation_on_whole_sequence(ED4_blockoperation block_operation, ED4_sequence_terminal *term, int repeat) {
62    GBDATA *gbd = term->get_species_pointer();
63    GB_ERROR error = 0;
64
65    if (gbd) {
66        char *seq = GB_read_string(gbd);
67        int len = GB_read_string_count(gbd);
68
69        int new_len;
70        char *new_seq = block_operation(seq, len, repeat, &new_len, &error);
71
72        if (new_seq) {
73            if (new_len<len) {
74                memcpy(seq, new_seq, new_len);
75                char gap = ADPP_IS_ALIGN_CHARACTER(seq[len-1]) ? seq[len-1] : '.';
76                int l;
77                for (l=new_len; l<len; l++) {
78                    seq[l] = gap;
79                }
80                seq[l] = 0;
81            }
82            else if (new_len>len) {
83                for (int l=new_len-1; l>=len; l--) {
84                    if (!ADPP_IS_ALIGN_CHARACTER(new_seq[l])) {
85                        error = "Result of block-operation to large (not enough gaps at end of sequence data)";
86                        break;
87                    }
88                }
89
90                if (!error) { // there are enough gaps at end of sequence
91                    memcpy(seq, new_seq, len);
92                }
93            }
94            else {
95                memcpy(seq, new_seq, len);
96            }
97            delete new_seq;
98
99            if (!error) {
100                error = GB_write_string(gbd, seq);
101                if (!error) {
102                    term->set_refresh();
103                    term->parent->refresh_requested_by_child();
104                }
105            }
106        }
107
108        delete seq;
109    }
110
111    return error;
112}
113
114// uses range_col1 till range_col2 as range
115static GB_ERROR perform_block_operation_on_part_of_sequence(ED4_blockoperation block_operation, ED4_sequence_terminal *term, int repeat) {
116    GBDATA *gbd = term->get_species_pointer();
117    GB_ERROR error = 0;
118
119    if (gbd) {
120        char *seq = GB_read_string(gbd);
121        int len = GB_read_string_count(gbd);
122
123        if (range_col1>=len || range_col2>=len) {
124            error = "Column-range exceeds sequence length";
125        }
126        else {
127            int len_part = range_col2-range_col1+1;
128            char *seq_part = seq+range_col1;
129            int new_len;
130            char *new_seq_part = block_operation(seq_part, len_part, repeat, &new_len, &error);
131
132            if (new_seq_part) {
133                if (new_len<len_part) {
134                    memcpy(seq_part, new_seq_part, new_len);
135                    char gap = '-';
136                    if (seq_part[len_part-1] == '.' || seq_part[len_part] == '.') gap = '.';
137
138                    for (int l=new_len; l<len_part; l++) {
139                        seq_part[l] = gap;
140                    }
141                }
142                else if (new_len>len_part) {
143                    for (int l=new_len-1; l>=len_part; l--) {
144                        if (!ADPP_IS_ALIGN_CHARACTER(new_seq_part[l])) {
145                            error = "Result of block-operation to large (not enough gaps at end of marked columnblock)";
146                            break;
147                        }
148                    }
149
150                    if (!error) { // there are enough gaps at end of sequence
151                        memcpy(seq_part, new_seq_part, len_part);
152                    }
153                }
154                else {
155                    memcpy(seq_part, new_seq_part, len_part);
156                }
157                delete new_seq_part;
158
159                if (!error) {
160                    error = GB_write_as_string(gbd, seq);
161                    if (!error) {
162                        term->set_refresh();
163                        term->parent->refresh_requested_by_child();
164                    }
165                }
166            }
167        }
168
169        delete seq;
170    }
171
172    return error;
173}
174
175
176
177void ED4_with_whole_block(ED4_blockoperation block_operation, int repeat) {
178    GB_ERROR               error    = GB_begin_transaction(GLOBAL_gb_main);
179    ED4_sequence_terminal *err_term = 0;
180    //    ED4_terminal *term        = ED4_ROOT->root_group_man->get_first_terminal();
181
182    ED4_cursor *cursor   = &ED4_ROOT->get_ed4w()->cursor;
183    int         base_pos = (cursor && cursor->owner_of_cursor != 0) ? cursor->get_base_position() : -1;
184
185    switch (blocktype) {
186        case ED4_BT_NOBLOCK: {
187            aw_message("No block marked -- use right mouse button");
188            break;
189        }
190        case ED4_BT_LINEBLOCK: {
191            ED4_list_elem *listElem = ED4_ROOT->selected_objects.first();
192            while (listElem && !error) {
193                ED4_selection_entry   *selectionEntry = (ED4_selection_entry*)listElem->elem();
194                ED4_sequence_terminal *seqTerm        = selectionEntry->object->get_parent(ED4_L_SPECIES)->search_spec_child_rek(ED4_L_SEQUENCE_STRING)->to_sequence_terminal();
195
196                error               = perform_block_operation_on_whole_sequence(block_operation, seqTerm, repeat);
197                if (error) err_term = seqTerm;
198
199                listElem = listElem->next();
200            }
201            break;
202        }
203        case ED4_BT_MODIFIED_COLUMNBLOCK:
204        case ED4_BT_COLUMNBLOCK: {
205            ED4_list_elem *listElem = ED4_ROOT->selected_objects.first();
206            while (listElem && !error) {
207                ED4_selection_entry *selectionEntry = (ED4_selection_entry*)listElem->elem();
208                ED4_sequence_terminal *seqTerm = selectionEntry->object->get_parent(ED4_L_SPECIES)->search_spec_child_rek(ED4_L_SEQUENCE_STRING)->to_sequence_terminal();
209
210                error = perform_block_operation_on_part_of_sequence(block_operation, seqTerm, repeat);
211                if (error) err_term = seqTerm;
212
213                listElem = listElem->next();
214            }
215            break;
216        }
217        default: {
218            error = "Illegal blocktype";
219            break;
220        }
221    }
222
223    if (error) error = GBS_global_string("[In block operation] %s", error);
224    GB_end_transaction_show_error(GLOBAL_gb_main, error, aw_message);
225
226    if (!error && base_pos != -1) {
227        cursor->jump_base_pos(ED4_ROOT->get_aww(), base_pos, ED4_JUMP_KEEP_VISIBLE); // restore cursor at same base
228    }
229}
230
231int ED4_get_selected_range(ED4_terminal *term, int *first_column, int *last_column) {
232    if (blocktype==ED4_BT_NOBLOCK) return 0;
233
234    if (blocktype==ED4_BT_COLUMNBLOCK || blocktype==ED4_BT_MODIFIED_COLUMNBLOCK) {
235        *first_column = range_col1;
236        *last_column = range_col2;
237    }
238    else {
239        e4_assert(blocktype==ED4_BT_LINEBLOCK);
240        *first_column = 0;
241        *last_column = -1;
242    }
243
244    ED4_species_name_terminal *name_term = term->to_sequence_terminal()->corresponding_species_name_terminal();
245    return name_term->flag.selected;
246}
247
248ED4_blocktype ED4_getBlocktype() {
249    return blocktype;
250}
251void ED4_setBlocktype(ED4_blocktype bt) {
252    if (blocktype!=bt) {
253        blocktype = bt;
254
255        ED4_list_elem *listElem = ED4_ROOT->selected_objects.first();
256        while (listElem) {
257            ED4_selection_entry *selected = (ED4_selection_entry*)listElem->elem();
258            ED4_species_name_terminal *name_term = selected->object->to_species_name_terminal();
259            ED4_sequence_terminal *seq_term = name_term->corresponding_sequence_terminal();
260
261            name_term->set_refresh(1);
262            name_term->parent->refresh_requested_by_child();
263            if (seq_term) col_block_refresh_on_seq_term(seq_term);
264
265            listElem = listElem->next();
266        }
267
268        if (blocktype==ED4_BT_COLUMNBLOCK || blocktype==ED4_BT_MODIFIED_COLUMNBLOCK) {
269            columnBlockUsed = 1;
270        }
271    }
272}
273
274void ED4_toggle_block_type(void) {
275    switch (blocktype) {
276        case ED4_BT_NOBLOCK: {
277            aw_message("No block selected.");
278            break;
279        }
280        case ED4_BT_LINEBLOCK: {
281            if (columnBlockUsed) {
282                ED4_setBlocktype(ED4_BT_MODIFIED_COLUMNBLOCK);
283            }
284            else {
285                aw_message("No columnblock marked so far  - I can't guess the column range");
286            }
287            break;
288        }
289        case ED4_BT_MODIFIED_COLUMNBLOCK:
290        case ED4_BT_COLUMNBLOCK: {
291            ED4_setBlocktype(ED4_BT_LINEBLOCK);
292            break;
293        }
294        default: {
295            e4_assert(0);
296            break;
297        }
298    }
299}
300
301void ED4_correctBlocktypeAfterSelection() { // this has to be called every time the selection has changed
302
303    if (ED4_ROOT->selected_objects.first()==0) { // no objects are selected
304        ED4_setBlocktype(ED4_BT_NOBLOCK);
305    }
306    else {
307        switch (ED4_getBlocktype()) {
308            case ED4_BT_NOBLOCK: {
309                ED4_setBlocktype(ED4_BT_LINEBLOCK);
310                break;
311            }
312            case ED4_BT_COLUMNBLOCK: {
313                ED4_setBlocktype(ED4_BT_MODIFIED_COLUMNBLOCK);
314                break;
315            }
316            case ED4_BT_LINEBLOCK:
317            case ED4_BT_MODIFIED_COLUMNBLOCK: {
318                break;
319            }
320            default: {
321                e4_assert(0);
322                break;
323            }
324        }
325    }
326}
327
328static void select_and_update(ED4_sequence_terminal *term1, ED4_sequence_terminal *term2, ED4_index pos1, ED4_index pos2, int initial_call) {
329    static ED4_sequence_terminal *last_term1, *last_term2;
330    static ED4_index last_pos1, last_pos2;
331
332    if (pos1>pos2) {
333        range_col1 = pos2;
334        range_col2 = pos1;
335    }
336    else {
337        range_col1 = pos1;
338        range_col2 = pos2;
339    }
340
341    if (blocktype==ED4_BT_MODIFIED_COLUMNBLOCK) {
342        ED4_list_elem *listElem = ED4_ROOT->selected_objects.first();
343        while (listElem) {
344            ED4_selection_entry *selectionEntry = (ED4_selection_entry*)listElem->elem();
345            ED4_species_name_terminal *name_term = selectionEntry->object->to_species_name_terminal();
346            ED4_sequence_terminal *seq_term = name_term->corresponding_sequence_terminal();
347
348            if (seq_term) col_block_refresh_on_seq_term(seq_term);
349
350            listElem = listElem->next();
351        }
352    }
353    else {
354        { // ensure term1 is the upper terminal
355            AW_pos dummy, y1, y2;
356
357            term1->calc_world_coords(&dummy, &y1);
358            term2->calc_world_coords(&dummy, &y2);
359
360            if (y1>y2) {
361                ED4_sequence_terminal *t = term1; term1 = term2; term2 = t;
362                AW_pos y = y1; y1 = y2; y2 = y;
363            }
364        }
365
366        int do_above = 1; // we have to update terminals between last_term1 and term1
367        int do_below = 1; // we have to update terminals between term2 and last_term2
368
369        ED4_terminal *term = term1;
370        //      ED4_terminal *start_term = term1;
371        int xRangeChanged = last_pos1!=range_col1 || last_pos2!=range_col2;
372
373        while (term) {
374            if (term->is_sequence_terminal()) {
375                ED4_sequence_terminal *seq_term = term->to_sequence_terminal();
376
377                if (seq_term==last_term1) {
378                    do_above = 0;
379                }
380                if (seq_term==last_term2) {
381                    do_below = 0;
382                }
383
384                ED4_species_name_terminal *name_term = seq_term->corresponding_species_name_terminal();
385                if (name_term->flag.selected) { // already selected
386                    if (xRangeChanged) {
387                        col_block_refresh_on_seq_term(seq_term);
388                    }
389                }
390                else { // select it
391                    ED4_species_manager *species_man = name_term->get_parent(ED4_L_SPECIES)->to_species_manager();
392
393                    if (!species_man->flag.is_consensus) {
394                        ED4_ROOT->add_to_selected(name_term);
395                    }
396                }
397            }
398            if (term==term2) {
399                break;
400            }
401            term = term->get_next_terminal();
402        }
403
404        if (!initial_call) {
405            if (do_below) {
406                while (term) {
407                    if (term->is_species_name_terminal() && term->flag.selected) {
408                        ED4_species_manager *species_man = term->get_parent(ED4_L_SPECIES)->to_species_manager();
409
410                        if (!species_man->flag.is_consensus) {
411                            ED4_ROOT->remove_from_selected(term);
412                        }
413                    }
414                    if (term==last_term2) break;
415                    term = term->get_next_terminal();
416                }
417            }
418
419            if (do_above) {
420                term = last_term1->corresponding_species_name_terminal();
421                while (term && term!=term1) {
422                    if (term->is_species_name_terminal() && term->flag.selected) {
423                        ED4_species_manager *species_man = term->get_parent(ED4_L_SPECIES)->to_species_manager();
424
425                        if (!species_man->flag.is_consensus) {
426                            ED4_ROOT->remove_from_selected(term);
427                        }
428                    }
429                    term = term->get_next_terminal();
430                }
431            }
432        }
433    }
434
435    last_term1 = term1;
436    last_term2 = term2;
437    last_pos1 = range_col1;
438    last_pos2 = range_col2;
439}
440
441// static inline double fabs(double d) {
442// return d<0 ? -d : d;
443// }
444
445void ED4_setColumnblockCorner(AW_event *event, ED4_sequence_terminal *seq_term) {
446    static ED4_sequence_terminal *fix_term = 0;
447    static ED4_index fix_pos = 0;
448
449    ED4_index seq_pos;
450    {
451        AW_pos termw_x, termw_y;
452        seq_term->calc_world_coords(&termw_x, &termw_y);
453
454        ED4_index scr_pos = ED4_ROOT->pixel2pos(event->x - termw_x);
455        ED4_remap *remap = ED4_ROOT->root_group_man->remap();
456        seq_pos = remap->screen_to_sequence(scr_pos);
457    }
458
459    switch (event->type) {
460        case AW_Mouse_Press: {
461            if (blocktype==ED4_BT_NOBLOCK) { // initial columnblock
462                ED4_setBlocktype(ED4_BT_COLUMNBLOCK);
463
464                fix_term = seq_term;
465                fix_pos = seq_pos;
466
467                select_and_update(fix_term, seq_term, fix_pos, seq_pos, 1);
468            }
469            else if (blocktype==ED4_BT_LINEBLOCK) { // change lineblock to columnblock
470                ED4_setBlocktype(ED4_BT_MODIFIED_COLUMNBLOCK);
471
472                fix_term = seq_term;
473                if (seq_pos<(MAXSEQUENCECHARACTERLENGTH/2)) { // in first half of sequence
474                    fix_pos = MAXSEQUENCECHARACTERLENGTH;
475                }
476                else {
477                    fix_pos = 0;
478                }
479
480                select_and_update(fix_term, seq_term, fix_pos, seq_pos, 1);
481            }
482            else { // expand columnblock (search nearest corner/border -> fix opposite corner/border)
483                e4_assert(blocktype==ED4_BT_COLUMNBLOCK || blocktype==ED4_BT_MODIFIED_COLUMNBLOCK);
484
485                ED4_list_elem *listElem = ED4_ROOT->selected_objects.first();
486                e4_assert(listElem);
487
488                if (blocktype==ED4_BT_COLUMNBLOCK) {
489                    AW_pos min_term_y = LONG_MAX;
490                    AW_pos max_term_y = LONG_MIN;
491                    ED4_species_name_terminal *min_term = 0;
492                    ED4_species_name_terminal *max_term = 0;
493                    AW_pos xpos, ypos;
494
495                    while (listElem) {
496                        ED4_selection_entry *selected = (ED4_selection_entry*)listElem->elem();
497                        ED4_species_name_terminal *name_term = selected->object->to_species_name_terminal();
498
499                        name_term->calc_world_coords(&xpos, &ypos);
500
501                        if (ypos<min_term_y) {
502                            min_term_y = ypos;
503                            min_term = name_term;
504                        }
505                        if (ypos>max_term_y) {
506                            max_term_y = ypos;
507                            max_term = name_term;
508                        }
509
510                        listElem = listElem->next();
511                    }
512
513                    seq_term->calc_world_coords(&xpos, &ypos);
514                    ED4_species_name_terminal *fix_name_term;
515                    if (fabs(ypos-min_term_y)<fabs(ypos-max_term_y)) { // seq_term is closer to min_term
516                        fix_name_term = max_term; // select max_term as fixed corner
517                    }
518                    else {
519                        fix_name_term = min_term;
520                    }
521                    fix_term = fix_name_term->corresponding_sequence_terminal();
522                }
523
524                long scr_col1, scr_col2;
525                AW_rectangle area_rect;
526                {
527                    AW_pos ex = event->x;
528                    AW_pos ey = event->y;
529                    ED4_ROOT->world_to_win_coords(ED4_ROOT->get_ed4w()->aww, &ex, &ey);
530
531                    if (ED4_ROOT->get_area_rectangle(&area_rect, ex, ey)!=ED4_R_OK) {
532                        e4_assert(0);
533                        break;
534                    }
535                }
536
537
538                const ED4_remap *rm = ED4_ROOT->root_group_man->remap();
539
540                seq_term->calc_intervall_displayed_in_rectangle(&area_rect, &scr_col1, &scr_col2);
541                rm->clip_screen_range(&scr_col1, &scr_col2);
542
543                int range_scr_col1 = rm->sequence_to_screen(range_col1);
544                int range_scr_col2 = rm->sequence_to_screen(range_col2);
545                int scr_pos = rm->sequence_to_screen(seq_pos);
546
547                int use_scr_col1 = range_scr_col1<scr_col1 ? scr_col1 : range_scr_col1;
548                int use_scr_col2 = range_scr_col2>scr_col2 ? scr_col2 : range_scr_col2;
549
550                if (abs(scr_pos-use_scr_col1) < abs(scr_pos-use_scr_col2)) { // scr_pos is closer to use_scr_col1
551                    fix_pos = range_col2;
552                }
553                else {
554                    fix_pos = range_col1;
555                }
556
557                select_and_update(fix_term, seq_term, fix_pos, seq_pos, 0);
558            }
559            break;
560        }
561        case AW_Mouse_Drag: {
562            select_and_update(fix_term, seq_term, fix_pos, seq_pos, 0);
563            break;
564        }
565        case AW_Mouse_Release: {
566            select_and_update(fix_term, seq_term, fix_pos, seq_pos, 0);
567            break;
568        }
569        default: {
570            e4_assert(0);
571            break;
572        }
573    }
574}
575
576// --------------------------------------------------------------------------------
577//      Replace
578// --------------------------------------------------------------------------------
579
580static int strncmpWithJoker(GB_CSTR s1, GB_CSTR s2, int len) { // s2 contains '?' as joker
581    int cmp = 0;
582
583    while (len-- && !cmp) {
584        int c1 = *s1++;
585        int c2 = *s2++;
586
587        if (!c1) {
588            cmp = -1;
589        }
590        else if (!c2) {
591            cmp = 1;
592        }
593        else if (c2!='?') {
594            cmp = c1-c2;
595        }
596    }
597
598    return cmp;
599}
600
601static char *oldString, *newString;
602static int oldStringContainsJoker;
603
604static char* replace_in_sequence(const char *sequence, int len, int /*repeat*/, int *new_len, GB_ERROR*) {
605    int maxlen;
606    int olen = strlen(oldString);
607    int nlen = strlen(newString);
608
609    if (nlen<=olen) {
610        maxlen = len;
611    }
612    else  {
613        maxlen = (len/olen+1)*nlen;
614    }
615
616    char *new_seq = (char*)GB_calloc(maxlen+1, sizeof(*new_seq));
617    int replaced = 0;
618    int o = 0;
619    int n = 0;
620    char ostart = oldString[0];
621
622    if (oldStringContainsJoker) {
623        while (o<len) {
624            if (strncmpWithJoker(sequence+o, oldString, olen)==0) {
625                memcpy(new_seq+n, newString, nlen);
626                n += nlen;
627                o += olen;
628                replaced++;
629            }
630            else {
631                new_seq[n++] = sequence[o++];
632            }
633        }
634    }
635    else {
636        while (o<len) {
637            if (sequence[o]==ostart && strncmp(sequence+o, oldString, olen)==0) { // occurrence of oldString
638                memcpy(new_seq+n, newString, nlen);
639                n += nlen;
640                o += olen;
641                replaced++;
642            }
643            else {
644                new_seq[n++] = sequence[o++];
645            }
646        }
647    }
648    new_seq[n] = 0;
649
650    if (replaced) {
651        if (new_len) {
652            *new_len = n;
653        }
654    }
655    else {
656        delete new_seq;
657        new_seq = 0;
658    }
659
660    return new_seq;
661}
662
663static void replace_in_block(AW_window*) {
664    oldString = ED4_ROOT->aw_root->awar(ED4_AWAR_REP_SEARCH_PATTERN)->read_string();
665    newString = ED4_ROOT->aw_root->awar(ED4_AWAR_REP_REPLACE_PATTERN)->read_string();
666
667    oldStringContainsJoker = strchr(oldString, '?')!=0;
668    ED4_with_whole_block(replace_in_sequence, 1);
669
670    delete oldString; oldString = 0;
671    delete newString; newString = 0;
672}
673
674AW_window *ED4_create_replace_window(AW_root *root) {
675    AW_window_simple *aws = new AW_window_simple;
676
677    aws->init(root, "REPLACE", "Search & Replace");
678    aws->load_xfig("edit4/replace.fig");
679
680    aws->at("close");
681    aws->callback( (AW_CB0)AW_POPDOWN);
682    aws->create_button("CLOSE", "Close","C");
683
684    aws->at("help");
685    aws->callback( AW_POPUP_HELP,(AW_CL)"e4_replace.hlp");
686    aws->create_button("HELP", "Help","H");
687
688    aws->at("spattern");
689    aws->create_input_field(ED4_AWAR_REP_SEARCH_PATTERN, 30);
690
691    aws->at("rpattern");
692    aws->create_input_field(ED4_AWAR_REP_REPLACE_PATTERN, 30);
693
694    aws->at("go");
695    aws->callback(replace_in_block);
696    aws->create_button("GO", "Go", "G");
697
698    return aws;
699}
700
701// --------------------------------------------------------------------------------
702//      Other block operations
703// --------------------------------------------------------------------------------
704
705static char *sequence_to_upper_case(const char *seq, int len, int /*repeat*/, int *new_len, GB_ERROR*) {
706    char *new_seq = (char*)GB_calloc(len+1, sizeof(*new_seq));
707    int l;
708
709    for (l=0; l<len; l++) {
710        new_seq[l] = toupper(seq[l]);
711    }
712
713    if (new_len) *new_len = len;
714    return new_seq;
715}
716static char *sequence_to_lower_case(const char *seq, int len, int /*repeat*/, int *new_len, GB_ERROR*) {
717    char *new_seq = (char*)GB_calloc(len+1, sizeof(*new_seq));
718    int l;
719
720    for (l=0; l<len; l++) {
721        new_seq[l] = tolower(seq[l]);
722    }
723
724    if (new_len) *new_len = len;
725    return new_seq;
726}
727
728#define EVEN_REPEAT "repeat-count is even -> no changes!"
729
730static char *reverse_sequence(const char *seq, int len, int repeat, int *new_len, GB_ERROR *error) {
731    if ((repeat&1)==0) { *error = GBS_global_string(EVEN_REPEAT); return 0; }
732
733    char *new_seq = GBT_reverseNucSequence(seq, len);
734    if (new_len) *new_len = len;
735    return new_seq;
736}
737static char *complement_sequence(const char *seq, int len, int repeat, int *new_len, GB_ERROR *error) {
738    if ((repeat&1)==0) {
739        *error = GBS_global_string(EVEN_REPEAT);
740        return 0;
741    }
742
743    char T_or_U;
744    *error = GBT_determine_T_or_U(ED4_ROOT->alignment_type, &T_or_U, "complement");
745    if (*error) return 0;
746
747    //     char T_or_U = ED4_ROOT->alignment_type==GB_AT_DNA ? 'T' : 'U';
748
749    char *new_seq         = GBT_complementNucSequence(seq, len, T_or_U);
750    if (new_len) *new_len = len;
751    return new_seq;
752}
753static char *reverse_complement_sequence(const char *seq, int len, int repeat, int *new_len, GB_ERROR *error) {
754    if ((repeat&1) == 0) {
755        *error      = GBS_global_string(EVEN_REPEAT);
756        return 0;
757    }
758
759    char T_or_U;
760    *error = GBT_determine_T_or_U(ED4_ROOT->alignment_type, &T_or_U, "reverse-complement");
761    if (*error) return 0;
762    // char  T_or_U = ED4_ROOT->alignment_type==GB_AT_DNA ? 'T' : 'U';
763    char *new_seq1  = GBT_complementNucSequence(seq, len, T_or_U);
764    char *new_seq2  = GBT_reverseNucSequence(new_seq1, len);
765
766    delete new_seq1;
767    if (new_len) *new_len = len;
768    return new_seq2;
769}
770
771static char *unalign_sequence_internal(const char *seq, int len, int *new_len, bool to_the_right) {
772    char *new_seq   = (char*)GB_calloc(len+1, sizeof(*new_seq));
773    int   o         = 0;
774    int   n         = 0;
775    char  gap       = '-';
776
777    if (to_the_right) {
778        if (ADPP_IS_ALIGN_CHARACTER(seq[0])) gap = seq[0]; // use first position of block if it's a gap
779        else if (ADPP_IS_ALIGN_CHARACTER(seq[-1])) gap = seq[-1]; // WARNING:  might be out-side sequence and undefined behavior
780    }
781    else {
782        if (ADPP_IS_ALIGN_CHARACTER(seq[len-1])) gap = seq[len-1]; // use first position of block if it's a gap
783        else if (ADPP_IS_ALIGN_CHARACTER(seq[len])) gap = seq[len]; // otherwise check position behind
784    }
785
786    while (o<len) {
787        if (!ADPP_IS_ALIGN_CHARACTER(seq[o])) new_seq[n++] = seq[o];
788        o++;
789    }
790
791    if (n<len) {                // (move and) dot rest
792        int gapcount = len-n;
793        if (to_the_right) {
794            memmove(new_seq+gapcount, new_seq, n);
795            memset(new_seq, gap, gapcount);
796        }
797        else {
798            memset(new_seq+n, gap, gapcount);
799        }
800    }
801
802    if (new_len) *new_len = len;
803    return new_seq;
804}
805
806static char *unalign_left_sequence(const char *seq, int len, int /*repeat*/, int *new_len, GB_ERROR *) {
807    return unalign_sequence_internal(seq, len, new_len, false);
808}
809
810static char *unalign_right_sequence(const char *seq, int len, int /*repeat*/, int *new_len, GB_ERROR *) {
811    return unalign_sequence_internal(seq, len, new_len, true);
812}
813
814static char *shift_left_sequence(const char *seq, int len, int repeat, int *new_len, GB_ERROR *error) {
815    char *new_seq = 0;
816
817    if (repeat>=len) {
818        *error = "Repeat count exceeds block length";
819    }
820    else
821    {
822        int enough_space = 1;
823        for (int i=0; enough_space && i<repeat; i++) {
824            if (!ADPP_IS_ALIGN_CHARACTER(seq[i])) {
825                enough_space = 0;
826            }
827        }
828
829        if (enough_space) {
830            char gap = '-';
831
832            new_seq               = (char*)GB_calloc(len+1, sizeof(*new_seq));
833            if (new_len) *new_len = len;
834            memcpy(new_seq, seq+repeat, len-repeat);
835
836            if (ADPP_IS_ALIGN_CHARACTER(seq[len-1])) gap    = seq[len-1];
837            else if (ADPP_IS_ALIGN_CHARACTER(seq[len])) gap = seq[len];
838
839            memset(new_seq+len-repeat, gap, repeat);
840        }
841        else {
842            *error = GBS_global_string("Shift left needs %i gap%s at block start", repeat, repeat==1 ? "" : "s");
843        }
844    }
845
846    return new_seq;
847}
848
849static char *shift_right_sequence(const char *seq, int len, int repeat, int *new_len, GB_ERROR *error) {
850    char *new_seq = 0;
851
852    if (repeat>=len) {
853        *error = "Repeat count exceeds block length";
854    }
855    else
856    {
857        int enough_space = 1;
858        for (int i=0; enough_space && i<repeat; i++) {
859            if (!ADPP_IS_ALIGN_CHARACTER(seq[len-i-1])) {
860                enough_space = 0;
861            }
862        }
863
864        if (enough_space) {
865            char gap = '-';
866
867            new_seq = (char*)GB_calloc(len+1, sizeof(*new_seq));
868            if (new_len) *new_len = len;
869
870            if (ADPP_IS_ALIGN_CHARACTER(seq[0])) gap       = seq[0];
871            else if (ADPP_IS_ALIGN_CHARACTER(seq[-1])) gap = seq[-1]; // a working hack
872
873            memset(new_seq, gap, repeat);
874            memcpy(new_seq+repeat, seq, len-repeat);
875        }
876        else {
877            *error = GBS_global_string("Shift right needs %i gap%s at block end", repeat, repeat==1 ? "" : "s");
878        }
879    }
880
881    return new_seq;
882}
883
884void ED4_perform_block_operation(ED4_blockoperation_type operationType) {
885    int nrepeat = ED4_ROOT->edit_string->use_nrepeat();
886
887    switch (operationType) {
888        case ED4_BO_UPPER_CASE:         ED4_with_whole_block(sequence_to_upper_case, nrepeat);          break;
889        case ED4_BO_LOWER_CASE:         ED4_with_whole_block(sequence_to_lower_case, nrepeat);          break;
890        case ED4_BO_REVERSE:            ED4_with_whole_block(reverse_sequence, nrepeat);                break;
891        case ED4_BO_COMPLEMENT:         ED4_with_whole_block(complement_sequence, nrepeat);             break;
892        case ED4_BO_REVERSE_COMPLEMENT: ED4_with_whole_block(reverse_complement_sequence, nrepeat);     break;
893        case ED4_BO_UNALIGN:            ED4_with_whole_block(unalign_left_sequence, nrepeat);           break;
894        case ED4_BO_UNALIGN_RIGHT:      ED4_with_whole_block(unalign_right_sequence, nrepeat);          break;
895        case ED4_BO_SHIFT_LEFT:         ED4_with_whole_block(shift_left_sequence, nrepeat);             break;
896        case ED4_BO_SHIFT_RIGHT:        ED4_with_whole_block(shift_right_sequence, nrepeat);            break;
897
898        default: {
899            e4_assert(0);
900            break;
901        }
902    }
903}
Note: See TracBrowser for help on using the repository browser.