source: tags/ms_r16q2/EDIT4/ED4_edit_string.cxx

Last change on this file was 14476, checked in by westram, 7 years ago
  • AlignDataAccess:
    • use factory function (ensures proper initialization; was missing for SINA interface); removed global
    • use callback to get helix-string (only used in island_hopping; optional)
    • store alignment-name
    • add proper ctor, copy-ctor and op=
  • island_hopping
    • store helix-string as copy
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.7 KB
Line 
1#include <arbdbt.h>
2#include <AW_helix.hxx>
3
4#include <fast_aligner.hxx>
5#include <awt_map_key.hxx>
6
7#include "ed4_edit_string.hxx"
8#include "ed4_class.hxx"
9#include "ed4_awars.hxx"
10#include "ed4_seq_colors.hxx"
11
12#include <aw_awar.hxx>
13#include <aw_msg.hxx>
14#include <aw_root.hxx>
15#include <aw_question.hxx>
16#include <aw_advice.hxx>
17#include <cctype>
18
19#define SAFE_EDITING        // undef this to remove sequence test code
20
21int ED4_Edit_String::nrepeat = 0;           // # of times command should be repeated
22int ED4_Edit_String::nrepeat_zero_requested = 0;    // nrepeat should be set to zero
23int ED4_Edit_String::nrepeat_is_already_set = 0;    // nrepeat was zero (and was set to 1)
24
25GB_ERROR  ED4_Edit_String::insert(char *text, long position, int direction, int removeAtNextGap) {
26    long i;
27    int text_len = strlen(text);
28    if (text_len == 0) return 0;
29
30    int rest_len;
31
32    if (direction>=0) {
33        rest_len = seq_len-position;
34    }
35    else {
36        rest_len = position;
37    }
38
39    if (rest_len<=0 || text_len>rest_len) {
40        return GBS_global_string("You can't insert text after the end of the sequence!");
41    }
42
43    if (removeAtNextGap) {
44        int nextGap = get_next_gap(position, direction);
45        if (nextGap==-1) {
46            goto no_gaps;
47        }
48
49        int afterGap = nextGap+direction;
50
51        if (afterGap>=0 && afterGap<seq_len) { // in sequence
52            if (seq[afterGap]!=seq[nextGap]) { // gap type changed -> warn to avoid overwrite of '?'
53                return GBS_global_string("Only one gap %s text => insert aborted", direction>=0 ? "after" : "before");
54            }
55        }
56
57        rest_len = (afterGap-position)*direction;
58    }
59
60    if (direction>=0) {
61        if (text_len + position >= seq_len) {
62            return GBS_global_string("You cannot insert that many characters after cursor!");
63        }
64
65        for (i = rest_len-text_len; i<rest_len; i++) {
66            if (!ED4_is_gap_character(seq[position+i])) {
67                goto no_gaps;
68            }
69        }
70
71        for (i = position+rest_len-text_len-1; i>=position; i--) {
72            seq[i+text_len] = seq[i];
73        }
74
75        for (i = 0; i<text_len; i++) {
76            seq[position+i] = text[i];
77        }
78    }
79    else {
80        if (position - text_len < 0) {
81            return GBS_global_string("You cannot insert that many characters before cursor!");
82        }
83
84        for (i = 0; i<text_len; i++) {
85            if (i<0 || !ED4_is_gap_character(seq[i])) {
86                goto no_gaps;
87            }
88        }
89        for (i = 0; i<position-text_len; i++) {
90            seq[i] = seq[i+text_len];
91        }
92
93        for (i = 0; i<text_len; i++) {
94            seq[position-i-1] = text[i];
95        }
96    }
97
98    return 0;
99
100 no_gaps :
101    return GBS_global_string("There are no/not enough gaps at %s of sequence => can't insert characters%s",
102                             direction >= 0 ? "end" : "start",
103                             direction >= 0 ? "\nMaybe your sequences are not formatted?" : "");
104}
105
106GB_ERROR ED4_Edit_String::remove(int len, long position, int direction, int insertAtNextGap) {
107
108    int rest_len; // bases between cursor-position and the directed sequence end
109
110    if (direction>=0) { // forward
111        if ((len + position) >= seq_len) len = (int)(seq_len-position);
112        rest_len = seq_len-position;
113    }
114    else { // backward
115        position--;
116        if (len>position) len = position;
117        rest_len = position;
118    }
119
120    if ((position >= seq_len) || (len == 0) || (seq_len - len < 0)) {
121        return GBS_global_string("Illegal delete position/length");
122    }
123
124    if (insertAtNextGap) {
125        int nextGap = get_next_gap(position+len*direction, direction);
126
127        if (nextGap!=-1) {
128            rest_len = (nextGap-position)*direction;
129        }
130    }
131
132    int new_len = rest_len-len; // no of bases that will be copied
133    int i;
134
135    if (direction>=0) {
136        for (i=0; i<new_len; i++) {
137            seq[position+i] = seq[position+len+i];
138        }
139        for (; i<rest_len; i++) {
140            seq[position+i] = '.';
141        }
142    }
143    else {
144        for (i=0; i<new_len; i++) {
145            seq[position-i] = seq[position-len-i];
146        }
147        for (; i<rest_len; i++) {
148            seq[position-i] = '.';
149        }
150    }
151
152    e4_assert(seq[seq_len]=='\0');
153
154    return 0;
155}
156
157GB_ERROR ED4_Edit_String::replace(char *text, long position, int direction) {
158    int text_len = strlen(text);
159    int i;
160    if (direction>=0) {
161
162        if ((position + text_len > seq_len) || (position > seq_len)) {
163            return GBS_global_string("Replace after end of sequence !");
164        }
165        for (i = 0; i < text_len;   i ++) {
166            seq[i+position] = text[i];
167        }
168    }
169    else {
170        if ((position - text_len < 0) || (position > seq_len)) {
171            return GBS_global_string("Replace before start of sequence !");
172        }
173        for (i = 0; i < text_len;   i ++) {
174            seq[position - i - 1] = text[i];
175        }
176    }
177    return 0;
178}
179
180GB_ERROR ED4_Edit_String::swap_gaps(long position, char ch) {
181    long i;
182    for (i = position; i < seq_len; i++) {
183        if (!ED4_is_gap_character(seq[i])) break;
184        seq[i] = ch;
185    }
186    for (i = position; i >= 0; i--) {
187        if (!ED4_is_gap_character(seq[i])) break;
188        seq[i] = ch;
189    }
190    return 0;
191}
192
193
194GB_ERROR ED4_Edit_String::moveBase(long source_position, long dest_position, unsigned char gap_to_use)
195{
196    e4_assert(source_position!=dest_position);
197#ifdef SAFE_EDITING
198    if (!legal_seqpos(dest_position) || !legal_seqpos(source_position)) {
199        return "Position out of sequence";
200    }
201#endif
202
203    int direction = dest_position<source_position ? -1 : 1;
204    int base = seq[source_position];
205    e4_assert(!ED4_is_gap_character(base));
206    seq[source_position] = gap_to_use;
207
208    long p = source_position+direction;
209    while (p!=dest_position) {
210#ifdef SAFE_EDITING
211        if (!ED4_is_gap_character(seq[p])) {
212            e4_assert(0);
213            return "Internal error: Tried to change base order in moveBase()";
214        }
215#endif
216        e4_assert(ED4_is_gap_character(seq[p]));
217        seq[p] = gap_to_use;
218        p += direction;
219    }
220
221    seq[dest_position] = base;
222    return 0;
223}
224
225GB_ERROR ED4_Edit_String::shiftBases(long source_pos, long last_source, long dest_pos, int direction, long *last_dest, unsigned char gap_to_use)
226    // shifts bases from source_pos-last_source to dest_pos
227    // last_dest is set to the position after the last dest_pos (direction<0 ? pos. right of bases : pos. left of bases)
228{
229    GB_ERROR err = 0;
230
231    if (direction<0) {
232        e4_assert(dest_pos<source_pos);
233        e4_assert(source_pos<=last_source);
234        while (1) {
235            err = moveBase(source_pos, dest_pos, gap_to_use);
236            if (err || source_pos>=last_source) break;
237            source_pos++;
238            dest_pos++;
239            while (!ED4_is_gap_character(seq[dest_pos])) {
240                dest_pos++;
241            }
242        }
243    }
244    else {
245        e4_assert(source_pos<dest_pos);
246        e4_assert(last_source<=source_pos);
247        while (1) {
248            err = moveBase(source_pos, dest_pos, gap_to_use);
249            if (err || source_pos<=last_source) break;
250            source_pos--;
251            dest_pos--;
252            while (!ED4_is_gap_character(seq[dest_pos])) {
253                dest_pos--;
254            }
255        }
256    }
257
258    if (last_dest) {
259        *last_dest = dest_pos;
260    }
261
262    return err;
263}
264
265long ED4_Edit_String::get_next_base(long position, int direction) {
266    long pos;
267    if (direction < 0) position--;
268    for (pos = position; pos>=0 && pos < seq_len; pos += direction) {
269        if (!ED4_is_gap_character(seq[pos])) break;
270    }
271
272    return pos<0 || pos>=seq_len ? -1 : pos;
273}
274long ED4_Edit_String::get_next_gap(long position, int direction) {
275    long pos;
276    if (direction < 0) position--;
277    for (pos = position; pos >= 0 && pos < seq_len; pos += direction) {
278        if (ED4_is_gap_character(seq[pos])) break;
279    }
280
281    return pos<0 || pos>=seq_len ? -1 : pos;
282}
283long ED4_Edit_String::get_next_visible_base(long position, int direction)
284{
285    long pos;
286    if (direction < 0) position--;
287    for (pos = position; pos>=0 && pos < seq_len; pos += direction) {
288        if (!ED4_is_gap_character(seq[pos]) && remap->is_shown(pos)) {
289            break;
290        }
291    }
292
293    return pos<0 || pos>=seq_len ? -1 : pos;
294}
295long ED4_Edit_String::get_next_visible_gap(long position, int direction) {
296    long pos;
297    if (direction < 0) position--;
298    for (pos = position; pos >= 0 && pos < seq_len; pos += direction) {
299        if (ED4_is_gap_character(seq[pos]) && remap->is_shown(pos)) {
300            break;
301        }
302    }
303
304    return pos<0 || pos>=seq_len ? -1 : pos;
305}
306long ED4_Edit_String::get_next_visible_pos(long position, int direction)
307{
308    long pos;
309    if (direction < 0) position--;
310    for (pos = position; pos >= 0 && pos < seq_len; pos += direction) {
311        if (remap->is_shown(pos)) {
312            break;
313        }
314    }
315    return pos<0 || pos>=seq_len ? -1 : pos;
316}
317
318unsigned char ED4_Edit_String::get_gap_type(long pos, int direction)
319{
320    pos += direction;
321    if (!legal_seqpos(pos)) return '.';
322    char gap = seq[pos];
323    if (ED4_is_gap_character(gap)) return gap;
324    return '-';
325}
326
327static GB_ERROR toggle_cursor_group_folding() {
328    GB_ERROR      error  = NULL;
329    ED4_cursor&   cursor = current_cursor();
330    if (cursor.owner_of_cursor) {
331        ED4_terminal *cursor_term = cursor.owner_of_cursor;
332
333        if (cursor_term->is_in_folded_group()) {
334            // cursor not visible -> unfold group which hides cursor
335            cursor_term->setCursorTo(&cursor, cursor.get_sequence_pos(), true, ED4_JUMP_KEEP_POSITION);
336        }
337        else {
338            ED4_base *group = cursor.owner_of_cursor->get_parent(ED4_L_GROUP);
339            if (group) {
340                ED4_group_manager    *group_man    = group->to_group_manager();
341                ED4_bracket_terminal *bracket_term = group_man->get_defined_level(ED4_L_BRACKET)->to_bracket_terminal();
342
343                if (group_man->dynamic_prop & ED4_P_IS_FOLDED) {
344                    bracket_term->unfold();
345                }
346                else {
347                    ED4_species_manager *consensus_man = group_man->get_multi_species_manager()->get_consensus_manager();
348                    if (consensus_man) consensus_man->setCursorTo(&cursor, cursor.get_sequence_pos(), true, ED4_JUMP_KEEP_POSITION);
349
350                    bracket_term->fold();
351                }
352            }
353        }
354    }
355    return error;
356}
357
358static void toggle_mark_of_specData(GBDATA *gb_data) {
359    // toggle mark of species owning data 'gb_data'
360    GB_transaction  ta(gb_data);
361    GBDATA         *gb_species = GB_get_grandfather(gb_data);
362    if (gb_species) GB_write_flag(gb_species, !GB_read_flag(gb_species));
363}
364
365GB_ERROR ED4_Edit_String::command(AW_key_mod keymod, AW_key_code keycode, char key, int direction, ED4_EDITMODE mode, bool is_consensus,
366                                  long &seq_pos, bool &changed_flag, ED4_CursorJumpType& cursor_jump, bool &cannot_handle, bool &write_fault, GBDATA* gb_data, bool is_sequence)
367{
368    changed_flag = 0;
369    write_fault = 0;
370    if (keymod+keycode+key==0) return 0;
371
372    e4_assert(nrepeat>0);
373
374    long old_seq_pos = seq_pos;
375    int  screen_len  = remap->sequence_to_screen(seq_len);
376    int  cursorpos   = remap->sequence_to_screen(seq_pos);
377
378    char str[2];
379    str[0] = key;
380    str[1] = 0;
381
382    direction = direction>0 ? 1 : -1;
383
384    if ((cursorpos > screen_len) || (cursorpos < 0)) {
385        if (cursorpos<MAXSEQUENCECHARACTERLENGTH && cursorpos>=0) {
386            char *seq2 = new char[MAXSEQUENCECHARACTERLENGTH+1];
387
388            memcpy(seq2, seq, seq_len);
389            memset(seq2+seq_len, '.', MAXSEQUENCECHARACTERLENGTH-seq_len);
390            seq_len = MAXSEQUENCECHARACTERLENGTH;
391            seq2[seq_len] = 0;
392
393            delete seq;
394            seq = seq2;
395
396            changed_flag = 1;
397        }
398        else {
399            return GBS_global_string("Cursor out of sequence at screen_pos #%i!", cursorpos);
400        }
401    }
402
403    GB_ERROR ad_err = 0;
404    long h;
405    bool reinterpret_key = true;
406
407    while (reinterpret_key) {
408        reinterpret_key = false;
409
410        switch (keycode) {
411            case AW_KEY_HOME: {
412                int new_seq_pos = get_next_visible_base(0, 1);
413                if (new_seq_pos>=0) seq_pos = new_seq_pos==seq_pos ? 0 : new_seq_pos;
414                else seq_pos = 0;
415                break;
416            }
417            case AW_KEY_END: {
418                int new_seq_pos = get_next_visible_base(seq_len, -1);
419                if (new_seq_pos>=0) {
420                    int new_gap_pos = get_next_visible_gap(new_seq_pos, 1);
421                    if (new_gap_pos >= 0) {
422                        seq_pos = new_gap_pos==seq_pos ? seq_len : new_gap_pos;
423                    }
424                    else {
425                        seq_pos = seq_len;
426                    }
427                }
428                else {
429                    seq_pos = seq_len;
430                }
431                break;
432            }
433            case AW_KEY_LEFT:
434            case AW_KEY_RIGHT: {
435                direction = keycode==AW_KEY_RIGHT ? 1 : -1;
436
437                // no key modifier -> just move cursor
438
439                int n = nrepeat;
440
441                if (keymod == AW_KEYMODE_NONE) {
442                    while (n--) {
443                        do {
444                            seq_pos += direction;
445                        }
446                        while (legal_curpos(seq_pos) && !remap->is_shown(seq_pos));
447                    }
448                    break;
449                }
450
451                if (mode==AD_NOWRITE) { write_fault = 1; break; }
452
453                int jump_or_fetch = 0;  // 1=jump selected 2=fetch selected (for repeat only)
454                int push_or_pull = 0;   // 1=push selected 2=pull selected (for repeat only)
455
456                // ------------------
457                // loop over nrepeat:
458
459                while (!ad_err && n-->0 && legal_curpos(seq_pos)) {
460                    cursorpos = remap->sequence_to_screen(seq_pos);
461
462                    int adjacent_scr_pos = cursorpos - (direction<0); // screen position next to the cursor
463                    if (adjacent_scr_pos<0 || size_t(adjacent_scr_pos)>remap->get_max_screen_pos()) {
464                        ad_err = GBS_global_string("Action beyond end of screen!");
465                        break;
466                    }
467
468                    int adjacent_seq_pos = remap->screen_to_sequence(adjacent_scr_pos); // _visible_ sequence position next to the cursor
469                    int real_adjacent_seq_pos = seq_pos - (direction<0); // sequence position next to cursor (not necessarily visible)
470
471                    if (adjacent_seq_pos<0 || adjacent_seq_pos>=seq_len) {
472                        ad_err = GBS_global_string("Action beyond end of sequence!");
473                        break;
474                    }
475
476                    // Ctrl+Cursor = move cursor to next end of word (or to end of next word)
477
478                    if (keymod & AW_KEYMODE_CONTROL) {
479                        if (adjacent_scr_pos>=0) {
480                            long pos = adjacent_seq_pos;
481
482                            if (ED4_ROOT->aw_root->awar(ED4_AWAR_FAST_CURSOR_JUMP)->read_int()) { // should cursor jump over next group?
483                                if (ED4_is_gap_character(seq[pos])) {
484                                    pos = get_next_visible_base(pos, direction);
485                                    if (pos>=0) pos = get_next_visible_gap(pos, direction);
486                                }
487                                else {
488                                    pos = get_next_visible_gap(pos, direction);
489                                }
490
491                                seq_pos = (pos>=0
492                                           ? (direction<0 ? pos+1 : pos)
493                                           : (direction<0 ? 0 : seq_len-1));
494                            }
495                            else {
496                                if (ED4_is_gap_character(seq[pos])) { seq_pos = get_next_visible_base(pos, direction); }
497                                else                                { seq_pos = get_next_visible_gap(pos, direction); }
498
499                                if (direction<0) { seq_pos = seq_pos==-1 ? 0       : seq_pos+1; }
500                                else             { seq_pos = seq_pos==-1 ? seq_len : seq_pos; }
501                            }
502                        }
503                        continue;
504                    }
505
506                    // ALT/META+Cursor = jump & fetch
507
508                    if (keymod & (AW_KEYMODE_ALT)) {
509                        if (is_consensus) { cannot_handle = 1; return 0; }
510
511                        if (ED4_is_gap_character(seq[adjacent_seq_pos])) { // there's a _gap_ next to the cursor -> let's fetch
512                            if (jump_or_fetch!=1) {
513                                jump_or_fetch = 2;
514                                long source_pos = get_next_base(adjacent_seq_pos, direction); // position of base to fetch
515                                if (source_pos==-1) { // there is nothing to fetch
516                                    n = 0;
517                                }
518                                else {
519                                    ad_err = moveBase(source_pos, adjacent_seq_pos, get_gap_type(source_pos, direction));
520                                    seq_pos = adjacent_seq_pos + (direction>0);
521                                }
522                            }
523                            else {
524                                n = 0;
525                            }
526                        }
527                        else { // there's a _base_ next to the cursor -> let it jump
528                            if (jump_or_fetch!=2) {
529                                jump_or_fetch = 1;
530                                int next_gap = adjacent_seq_pos - direction;
531
532                                if (ED4_is_gap_character(seq[next_gap])) {
533                                    int dest_pos = get_next_base(next_gap, -direction);
534
535                                    if (dest_pos<0) {
536                                        dest_pos = direction>0 ? 0 : seq_len-1;
537                                    }
538                                    else {
539                                        dest_pos += direction;
540                                    }
541
542                                    if (ED4_is_gap_character(seq[dest_pos])) {
543                                        ad_err = moveBase(adjacent_seq_pos, dest_pos, get_gap_type(adjacent_seq_pos, direction));
544                                        if (!ad_err) {
545                                            seq_pos = get_next_base(seq_pos, direction)+(direction<0);
546                                            if (seq_pos==-1) {
547                                                seq_pos = direction<0 ? 0 : seq_len;
548                                            }
549                                        }
550                                    }
551                                    else {
552                                        e4_assert(0);
553                                    }
554                                }
555                                else {
556                                    ad_err = GBS_global_string("You can only jump single bases.");
557                                }
558                            }
559                            else {
560                                n = 0;
561                            }
562                        }
563
564                        if (!ad_err) {
565                            changed_flag = 1;
566                        }
567
568                        continue;
569                    }
570
571                    // Shift+Cursor = push/pull character
572
573                    if (is_consensus) { cannot_handle = 1; return 0; };
574
575                    if (ED4_is_gap_character(seq[real_adjacent_seq_pos])) { // pull
576                        long dest_pos = real_adjacent_seq_pos;
577                        long source_pos = real_adjacent_seq_pos-direction;
578
579                        if (!ED4_is_gap_character(seq[source_pos]) && push_or_pull!=1) {
580                            push_or_pull = 2;
581
582                            long next_gap = get_next_gap(source_pos, -direction);
583                            long last_source = next_gap>=0 ? next_gap : (direction>0 ? 0 : seq_len-1);
584
585                            if (ED4_is_gap_character(seq[last_source])) {
586                                last_source = get_next_base(last_source, direction);
587                            }
588
589                            ad_err = shiftBases(source_pos, last_source, dest_pos, direction, 0,
590                                                is_sequence ? get_gap_type(last_source, -direction) : '.');
591
592                            if (!ad_err) {
593                                seq_pos = dest_pos + (direction>0);
594                                changed_flag = 1;
595                            }
596                        }
597                        else {
598                            n = 0;
599                        }
600                    }
601                    else { // push
602                        long next_gap = get_next_gap(adjacent_seq_pos, direction);
603
604                        if (next_gap>=0 && push_or_pull!=2) {
605                            push_or_pull = 1;
606                            long dest_pos = next_gap;
607                            long source_pos = get_next_base(next_gap, -direction);
608                            long last_source = adjacent_seq_pos;
609
610                            e4_assert(source_pos>=0);
611                            ad_err = shiftBases(source_pos, last_source, dest_pos, direction, &dest_pos,
612                                                is_sequence ? get_gap_type(last_source, -direction) : '.');
613
614                            if (!ad_err) {
615                                seq_pos = dest_pos + (direction<0);
616                                changed_flag = 1;
617                            }
618                        }
619                        else {
620                            n = 0;
621                        }
622                    }
623                }
624                break;
625            }
626
627            case AW_KEY_BACKSPACE:
628                h = seq_pos;
629
630                if (direction>0) {
631                    seq_pos -= nrepeat;
632                }
633                else {
634                    seq_pos += nrepeat;
635                }
636                if (seq_pos <0 || seq_pos >= seq_len) {
637                    seq_pos = h;
638                    break;
639                }
640                // fall-through
641
642            case AW_KEY_DELETE:
643                h = seq_pos;
644
645                if (is_consensus) { cannot_handle = 1; return 0; };
646                if (keymod) { return 0; }
647
648                if (mode==AD_NOWRITE) { write_fault = 1; break; }
649
650                switch (mode) {
651                    case AD_ALIGN:
652                        {
653                            int len;
654                            int offset;
655
656                            ad_err = 0;
657                            if (direction>=0)   offset = 0;
658                            else        offset = -nrepeat;
659
660                            for (len = nrepeat-1; len>=0; len--) {
661                                if (!ED4_is_gap_character(seq[h+offset+len])) {
662                                    ad_err = GBS_global_string("You cannot remove bases in align mode");
663                                    break;
664                                }
665                            }
666                            if (ad_err) break;
667                        }
668                    case AD_REPLACE:
669                    case AD_INSERT:
670                        ad_err = remove(nrepeat, h, direction, !is_sequence);
671                        if (!ad_err) {
672                            changed_flag = 1;
673                        }
674                        break;
675                    default:
676                        break;
677                }
678
679                break;
680
681            case AW_KEY_RETURN: 
682                ad_err = toggle_cursor_group_folding();
683                break; 
684
685            case AW_KEY_ASCII: {
686
687                //      keyboard layout:
688                //
689                //      - CTRL-A    Align                               ok
690                //      - CTRL-D    Toggle view differences             ok
691                //      - CTRL-E    Toggle edit/align                   ok
692                //      - CTRL-I    Toggle insert/replace               ok
693                //      - CTRL-J    Jump opposite helix position        ok
694                //      - CTRL-K    Toggle compression on/off           ok
695                //      - CTRL-L    Refresh                             ok
696                //      - CTRL-M    Invert mark                         ok
697                //      - CTRL-O    = ALT-LEFT                          ok
698                //      - CTRL-P    = ALT-RIGHT                         ok
699                //      - CTRL-R    Set aligner OR viewDiff reference species       ok
700                //      - CTRL-S    Repeat last search                  ok
701                //      - CTRL-U    Undo                                @@@ crashes! disabled atm!
702
703
704                if (key >0 && key<=26) { // CTRL-Keys
705                    switch (key+'A'-1) {
706                        case 'A': { // CTRL-A = Start Fast-Aligner
707                            AW_window *aw_tmp = current_aww();
708                            if (is_consensus) { cannot_handle = 1; return 0; };
709                            if (mode==AD_NOWRITE) { write_fault = 1; return 0; }
710
711                            AlignDataAccess localDataAccess(*ED4_get_aligner_data_access()); // use local modified copy
712                            localDataAccess.do_refresh = false;
713
714                            FastAligner_set_align_current(ED4_ROOT->aw_root, ED4_ROOT->props_db);
715                            AW_clock_cursor(ED4_ROOT->aw_root);
716                            GB_commit_transaction(localDataAccess.gb_main);
717
718                            FastAligner_start(aw_tmp, &localDataAccess);
719
720                            GB_begin_transaction(localDataAccess.gb_main);
721                            AW_normal_cursor(ED4_ROOT->aw_root);
722
723                            int basesLeftOf = 0;
724                            int pos;
725
726                            for (pos=0; pos < seq_pos && pos<seq_len; pos++) {    // count # of bases left of cursorpos
727                                if (!ED4_is_gap_character(seq[pos])) {
728                                    basesLeftOf++;
729                                }
730                            }
731
732                            char *aligned_seq = GB_read_string(gb_data); // read new sequence
733                            ad_err            = GB_write_string(gb_data, seq); // restore old sequence
734
735                            freeset(seq, aligned_seq); // set new sequence
736                            changed_flag = 1;       // and mark changed
737
738                            {
739                                int basesLeftOf2   = 0;
740                                int lastCorrectPos = -1;
741                                for (pos=0; pos<seq_pos && pos<seq_len; pos++) {    // count # of bases left of cursorpos
742                                    if (!ED4_is_gap_character(seq[pos])) {
743                                        basesLeftOf2++;
744                                        if (basesLeftOf2 == basesLeftOf) lastCorrectPos = pos;
745                                    }
746                                }
747
748                                if (basesLeftOf != basesLeftOf2) { // old cursor-position has different basepos
749                                    if (lastCorrectPos != -1) { // already seen position with same basepos
750                                        seq_len = lastCorrectPos+1;
751                                    }
752                                    else {
753                                        for (; pos<seq_len; pos++) {
754                                            if (!ED4_is_gap_character(seq[pos])) {
755                                                basesLeftOf2++;
756                                                if (basesLeftOf2 == basesLeftOf) {
757                                                    seq_pos = pos+1;
758                                                    break; // stop after first matching position
759                                                }
760                                            }
761                                        }
762                                    }
763                                }
764                            }
765                            break;
766                        }
767                        case 'R': {  // CTRL-R = set aligner reference species OR set reference for diff-mode
768                            ED4_reference *ref = ED4_ROOT->reference;
769                            if (ref->is_set()) { // if "view differences" is active = > set new reference
770                                ED4_viewDifferences_setNewReference();
771                            }
772                            else { // otherwise set aligner reference
773                                if (is_consensus) { cannot_handle = 1; return 0; };
774                                FastAligner_set_reference_species(ED4_ROOT->aw_root);
775                            }
776                            break;
777                        }
778                        case 'D': { // CTRL-D = Toggle view differences
779                            ED4_toggle_viewDifferences(ED4_ROOT->aw_root);
780                            break;
781                        }
782                        case 'E': { // CTRL-E = Toggle Edit/Align-Mode
783                            ED4_ROOT->aw_root->awar(AWAR_EDIT_MODE)->toggle_toggle();
784                            break;
785                        }
786                        case 'I': { // CTRL-I = Toggle Insert/Replace-Mode
787                            ED4_ROOT->aw_root->awar(AWAR_INSERT_MODE)->toggle_toggle();
788                            break;
789                        }
790                        case 'J': { // CTRL-J = Jump to opposite helix position
791                            AW_helix *helix = ED4_ROOT->helix;
792
793                            if (!helix->has_entries()) ad_err = strdup("Got no helix information");
794                            else if (helix->pairtype(seq_pos) != HELIX_NONE) {
795                                seq_pos = helix->opposite_position(seq_pos);
796                                cursor_jump = ED4_JUMP_KEEP_POSITION;
797                            }
798                            else ad_err = strdup("Not at helix position");
799                            break;
800                        }
801                        case 'K': { // Ctrl-K = Compression on/off
802                            static int last_mode;
803                            int current_mode = (ED4_remap_mode)ED4_ROOT->aw_root->awar(ED4_AWAR_COMPRESS_SEQUENCE_GAPS)->read_int();
804                            int next_mode = last_mode;
805
806                            if (current_mode==0) { // if not compressed
807                                if (last_mode==0) next_mode = 2; // force compress
808                            }
809                            else {  // if compressed
810                                next_mode = 0; // force uncompressed
811                            }
812
813                            ED4_ROOT->aw_root->awar(ED4_AWAR_COMPRESS_SEQUENCE_GAPS)->write_int(next_mode);
814
815                            last_mode = current_mode;
816                            break;
817                        }
818                        case 'L': {  // CTRL-L = Refresh
819                            ED4_request_full_refresh();
820                            ED4_request_relayout();
821                            cursor_jump = ED4_JUMP_CENTERED;
822                            break;
823                        }
824                        case 'M': { // CTRL-M = Invert mark(s)
825                            if (is_consensus) { cannot_handle = 1; return 0; }
826                            toggle_mark_of_specData(gb_data);
827                            break;
828                        }
829                        case 'O': { //  for ALT-left
830                            keycode = AW_KEY_LEFT;
831                            keymod = AW_KEYMODE_ALT;
832                            reinterpret_key = true;
833                            break;
834                        }
835                        case 'P': { // for ALT-right
836                            keycode = AW_KEY_RIGHT;
837                            keymod = AW_KEYMODE_ALT;
838                            reinterpret_key = true;
839                            break;
840                        }
841                        case 'S': { // CTRL-S = Repeat last search
842                            ad_err      = ED4_repeat_last_search(current_ed4w());
843                            seq_pos     = current_cursor().get_sequence_pos();
844                            cursor_jump = ED4_JUMP_KEEP_POSITION;
845                            break;
846                        }
847                        case 'U': {
848                            // ad_err = GB_undo(gb_main, GB_UNDO_UNDO); // @@@ stuerzt ab - wahrscheinlich weil Transaktion offen ist
849                            break;
850                        }
851                    }
852                }
853                else { // normal characters
854                    if (is_consensus) { cannot_handle = 1; return 0; }
855                    if (mode==AD_NOWRITE) { write_fault = 1; break; }
856
857                    if (key == ' ') {
858                        if (is_sequence) {
859                            long left = seq_pos>0 ? seq_pos-1 : 0;
860                            int  l    = seq[left];
861                            int  r    = seq[seq_pos];
862
863                            char gapchar_at_pos = ED4_is_gap_character(l) ? l : (ED4_is_gap_character(r) ? r : 0);
864
865                            switch (keymod) {
866                                case AW_KEYMODE_NONE:
867                                    key = gapchar_at_pos ? gapchar_at_pos : '-'; // insert (same) gap
868                                    break;
869
870                                case AW_KEYMODE_CONTROL:
871                                    if (gapchar_at_pos) key = gapchar_at_pos == '-' ? '.' : '-'; // toggle gaptype
872                                    break;
873
874                                default: break;
875                            }
876                        }
877                        str[0] = key;
878                    }
879
880                    if (ED4_is_gap_character(key) && keymod == AW_KEYMODE_CONTROL) { // gap-type change works in all modes
881                        // gap type functions ('.' <-> '-')
882
883                        long left = seq_pos>0 ? seq_pos-1 : 0;
884                        int  l    = seq[left];
885                        int  r    = seq[seq_pos];
886
887                        if      (ED4_is_gap_character(l) && l!=key) { ad_err = swap_gaps(left, key);    changed_flag = 1; }
888                        else if (ED4_is_gap_character(r) && r!=key) { ad_err = swap_gaps(seq_pos, key); changed_flag = 1; }
889                    }
890                    else {
891                        switch (mode) {
892                            case AD_ALIGN: {
893                                if (ED4_is_gap_character(key)) {
894                                    if (keymod == AW_KEYMODE_NONE) {
895                                        if (!ad_err) {
896                                            char *nstr = (char *)GB_calloc(1, nrepeat+1);
897                                            int i;
898
899                                            for (i = 0; i< nrepeat; i++) nstr[i] = key;
900                                            ad_err = insert(nstr, seq_pos, direction, 0);
901                                            if (!ad_err) seq_pos = get_next_visible_pos(seq_pos+(direction>=0 ? nrepeat : 0), direction);
902                                            delete nstr;
903                                        }
904                                        changed_flag = 1;
905                                    }
906                                }
907                                else { // check typed bases against sequence
908                                    while (nrepeat && !ad_err) {
909                                        nrepeat--;
910                                        seq_pos = get_next_visible_base(seq_pos, direction);
911                                        if (seq_pos<0 || seq_pos>=seq_len) {
912                                            ad_err = GBS_global_string("End of sequence reached");
913                                        }
914                                        else if (seq[seq_pos]!=key) {
915                                            ad_err = GBS_global_string("Base '%c' at %li does not match '%c'", seq[seq_pos], seq_pos, key);
916                                        }
917                                        else {
918                                            seq_pos = get_next_visible_pos(seq_pos, direction)+1;
919                                            ad_err = 0;
920                                        }
921                                        if (ad_err) {
922                                            ed4_beep();
923                                        }
924                                    }
925                                }
926                                break;
927                            }
928                            case AD_REPLACE: {
929                                while (nrepeat && !ad_err) {
930                                    nrepeat--;
931                                    if (direction>0) {
932                                        ad_err = replace(str, seq_pos, 1);
933
934                                        if (!ad_err) {
935                                            seq_pos++;
936                                            changed_flag = 1;
937                                        }
938                                    }
939                                    else {
940                                        int left_pos = get_next_visible_pos(seq_pos, -1);
941
942                                        if (left_pos>=0)    ad_err = replace(str, left_pos+1, -1);
943                                        else            ad_err = "End of sequence";
944
945                                        if (!ad_err) {
946                                            seq_pos = left_pos;
947                                            changed_flag = 1;
948                                        }
949                                    }
950                                }
951                                break;
952                            }
953                            case AD_INSERT: {
954                                while (nrepeat && !ad_err) {
955                                    nrepeat--;
956                                    if (direction>0) {
957                                        ad_err = insert(str, seq_pos, 1, !is_sequence);
958
959                                        if (!ad_err) {
960                                            seq_pos++;
961                                            changed_flag = 1;
962                                        }
963                                    }
964                                    else {
965                                        int left_pos = get_next_visible_pos(seq_pos, -1);
966
967                                        if (left_pos>=0) {
968                                            ad_err = insert(str, left_pos+1, -1, !is_sequence);
969                                        }
970                                        else {
971                                            ad_err = "End of sequence";
972                                        }
973
974                                        if (!ad_err) {
975                                            seq_pos = left_pos;
976                                            changed_flag = 1;
977                                        }
978                                    }
979                                }
980                                break;
981                            }
982                            default: {
983                                break;
984                            }
985                        }
986                    }
987
988                }
989                break;
990            }
991            default: {
992                break;
993            }
994
995        }
996    }
997
998    if (ad_err) seq_pos = old_seq_pos;
999    seq_pos = seq_pos<0 ? 0 : (seq_pos>seq_len ? seq_len : seq_pos);    // ensure legal position
1000
1001    return ad_err;
1002}
1003
1004ED4_Edit_String::ED4_Edit_String()
1005{
1006    memset((char *)this, 0, sizeof(*this));
1007    remap = ED4_ROOT->root_group_man->remap();
1008}
1009
1010ED4_Edit_String::~ED4_Edit_String()
1011{
1012    free(old_seq);
1013}
1014
1015GB_ERROR ED4_Edit_String::edit(ED4_work_info *info) {
1016    e4_assert(info->working_terminal != 0);
1017
1018    if (!info->rightward) { // 5'<-3'
1019        info->char_position++;
1020    }
1021
1022    info->out_seq_position = remap->screen_to_sequence(info->char_position);
1023    info->refresh_needed   = false;
1024    info->cursor_jump      = ED4_JUMP_KEEP_VISIBLE;
1025    info->cannot_handle    = false;
1026    old_seq                = 0;
1027
1028    if (info->string) {
1029        seq = info->string;
1030        seq_len = strlen(seq);
1031    }
1032    else {
1033        e4_assert(info->gb_data);
1034        int seq_len_int;
1035        seq = info->working_terminal->resolve_pointer_to_string_copy(&seq_len_int);
1036        seq_len = seq_len_int;
1037    }
1038
1039    int map_key;
1040    if (info->event.keymodifier == AW_KEYMODE_NONE) {
1041        map_key = ED4_ROOT->edk->map_key(info->event.character);
1042        if (map_key != info->event.character) { // remapped
1043            if (info->event.character == ' ') { // space
1044                AW_advice("You have keymapped the space-key!\n"
1045                          "The new functionality assigned to space-key is not available when\n"
1046                          "key-mapping is enabled.\n",
1047                          AW_ADVICE_TOGGLE_AND_HELP, "Obsolete default keymapping", "nekey_map.hlp");
1048            }
1049        }
1050    }
1051    else {
1052        map_key = info->event.character;
1053    }
1054    GB_ERROR err = 0;
1055
1056    nrepeat_zero_requested = 1;
1057    if (!nrepeat) {
1058        nrepeat_is_already_set = 1;
1059        nrepeat = 1;
1060    }
1061
1062    if (info->event.keycode==AW_KEY_ASCII &&
1063        isdigit(map_key) &&
1064        ED4_ROOT->aw_root->awar(ED4_AWAR_DIGITS_AS_REPEAT)->read_int()) { // handle digits for repeated commands
1065
1066        if (nrepeat_is_already_set) { nrepeat = 0; }
1067        nrepeat_zero_requested = 0;
1068
1069        for (int r=0; r<info->repeat_count; r++) {
1070            nrepeat = nrepeat * 10 + (map_key - '0');
1071            if (nrepeat>10000) {
1072                nrepeat = 10000;
1073            }
1074            else if (nrepeat<0) {
1075                nrepeat = 0;
1076            }
1077        }
1078#ifdef DEBUG
1079        if (nrepeat>1) {
1080            printf("nrepeat=%i\n", nrepeat);
1081        }
1082#endif
1083    }
1084    else if (info->event.keymodifier==AW_KEYMODE_NONE && info->event.keycode==AW_KEY_NONE) {
1085        nrepeat_zero_requested = 0;
1086    }
1087    else {
1088        nrepeat += info->repeat_count-1;
1089
1090#ifdef DEBUG
1091        if (nrepeat>1) {
1092            printf("nrepeat is %i\n", nrepeat);
1093        }
1094#endif
1095
1096        int is_remapped_sequence = !info->is_sequence && ED4_ROOT->aw_root->awar(ED4_AWAR_COMPRESS_SEQUENCE_TYPE)->read_int()!=ED4_RM_NONE;
1097        if (info->mode==AD_NOWRITE_IF_COMPRESSED) {
1098            if (is_remapped_sequence) {
1099                info->mode = AD_NOWRITE;
1100            }
1101            else {
1102                info->mode = AD_INSERT;
1103            }
1104        }
1105
1106        bool write_fault = 0;
1107
1108        err = command(info->event.keymodifier,
1109                      info->event.keycode,
1110                      map_key,
1111                      info->rightward,
1112                      info->mode,
1113                      (int)(info->string!=0),
1114                      info->out_seq_position,
1115                      info->refresh_needed,
1116                      info->cursor_jump,
1117                      info->cannot_handle,
1118                      write_fault,
1119                      info->gb_data,
1120                      info->is_sequence);
1121
1122        e4_assert(!(err && info->cannot_handle));
1123
1124        if (write_fault) {
1125            e4_assert(info->mode==AD_NOWRITE);
1126            aw_message(is_remapped_sequence
1127                       ? "Check 'Show all gaps' when editing remarks"
1128                       : "This terminal is write-protected!");
1129        }
1130    }
1131
1132    if (!err) {
1133        if (info->gb_data) {
1134            if (info->refresh_needed) {
1135                e4_assert(info->working_terminal->get_species_pointer() == info->gb_data);
1136
1137                int old_seq_len_int;
1138                old_seq     = info->working_terminal->resolve_pointer_to_string_copy(&old_seq_len_int);
1139                old_seq_len = old_seq_len_int;
1140
1141                err = info->working_terminal->write_sequence(seq, seq_len);
1142                if (err) {
1143                    info->out_seq_position = remap->screen_to_sequence(info->char_position);    // correct cursor_pos if protection error occurred
1144                }
1145            }
1146            freenull(seq);
1147        }
1148    }
1149
1150    if (!info->rightward) {
1151        info->char_position    = remap->sequence_to_screen_PLAIN(info->out_seq_position);
1152        e4_assert(info->char_position >= 0);
1153        info->char_position--;
1154        info->out_seq_position = remap->screen_to_sequence(info->char_position);
1155    }
1156
1157    return err;
1158}
1159
1160void ED4_Edit_String::finish_edit()
1161{
1162    nrepeat_is_already_set = 0;
1163    if (nrepeat_zero_requested) {
1164        nrepeat_zero_requested = 0;
1165        nrepeat = 0;
1166    }
1167}
1168
1169void ED4_Edit_String::init_edit() {
1170    freenull(old_seq);
1171    seq_len = 0;
1172    seq = 0;
1173    gbd = 0;
1174    old_seq_len = 0;
1175    remap = ED4_ROOT->root_group_man->remap();
1176}
1177
Note: See TracBrowser for help on using the repository browser.