source: tags/ms_r16q3/EDIT4/ED4_edit_string.cxx

Last change on this file was 15223, checked in by westram, 8 years ago
  • reintegrates 'flags' into 'trunk'
    • DRYed
      • group generation code
      • ref-terminal access
    • layout done by managers (removed manual coordinate calculation)
    • dynamic size calculated by terminals themselves
    • fix design issues
      • brackets were used where groups should have been used. fixed
      • fix many bad/spammy names
    • fix broken member-code (only worked with a NULL sentinel present)
    • dynamic indentation (according to visible group-nesting)
  • adds: log:branches/flags@15098:15222
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.6 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(LEV_GROUP);
339            if (group) {
340                ED4_group_manager *group_man = group->to_group_manager();
341                if (group_man->has_property(PROP_IS_FOLDED)) {
342                    group_man->unfold();
343                }
344                else {
345                    ED4_species_manager *consensus_man = group_man->get_multi_species_manager()->get_consensus_manager();
346                    if (consensus_man) consensus_man->setCursorTo(&cursor, cursor.get_sequence_pos(), true, ED4_JUMP_KEEP_POSITION);
347
348                    group_man->fold();
349                }
350            }
351        }
352    }
353    return error;
354}
355
356static void toggle_mark_of_specData(GBDATA *gb_data) {
357    // toggle mark of species owning data 'gb_data'
358    GB_transaction  ta(gb_data);
359    GBDATA         *gb_species = GB_get_grandfather(gb_data);
360    if (gb_species) GB_write_flag(gb_species, !GB_read_flag(gb_species));
361}
362
363GB_ERROR ED4_Edit_String::command(AW_key_mod keymod, AW_key_code keycode, char key, int direction, ED4_EDITMODE mode, bool is_consensus,
364                                  long &seq_pos, bool &changed_flag, ED4_CursorJumpType& cursor_jump, bool &cannot_handle, bool &write_fault, GBDATA* gb_data, bool is_sequence)
365{
366    changed_flag = 0;
367    write_fault = 0;
368    if (keymod+keycode+key==0) return 0;
369
370    e4_assert(nrepeat>0);
371
372    long old_seq_pos = seq_pos;
373    int  screen_len  = remap->sequence_to_screen(seq_len);
374    int  cursorpos   = remap->sequence_to_screen(seq_pos);
375
376    char str[2];
377    str[0] = key;
378    str[1] = 0;
379
380    direction = direction>0 ? 1 : -1;
381
382    if ((cursorpos > screen_len) || (cursorpos < 0)) {
383        if (cursorpos<MAXSEQUENCECHARACTERLENGTH && cursorpos>=0) {
384            char *seq2 = new char[MAXSEQUENCECHARACTERLENGTH+1];
385
386            memcpy(seq2, seq, seq_len);
387            memset(seq2+seq_len, '.', MAXSEQUENCECHARACTERLENGTH-seq_len);
388            seq_len = MAXSEQUENCECHARACTERLENGTH;
389            seq2[seq_len] = 0;
390
391            delete seq;
392            seq = seq2;
393
394            changed_flag = 1;
395        }
396        else {
397            return GBS_global_string("Cursor out of sequence at screen_pos #%i!", cursorpos);
398        }
399    }
400
401    GB_ERROR ad_err = 0;
402    long h;
403    bool reinterpret_key = true;
404
405    while (reinterpret_key) {
406        reinterpret_key = false;
407
408        switch (keycode) {
409            case AW_KEY_HOME: {
410                int new_seq_pos = get_next_visible_base(0, 1);
411                if (new_seq_pos>=0) seq_pos = new_seq_pos==seq_pos ? 0 : new_seq_pos;
412                else seq_pos = 0;
413                break;
414            }
415            case AW_KEY_END: {
416                int new_seq_pos = get_next_visible_base(seq_len, -1);
417                if (new_seq_pos>=0) {
418                    int new_gap_pos = get_next_visible_gap(new_seq_pos, 1);
419                    if (new_gap_pos >= 0) {
420                        seq_pos = new_gap_pos==seq_pos ? seq_len : new_gap_pos;
421                    }
422                    else {
423                        seq_pos = seq_len;
424                    }
425                }
426                else {
427                    seq_pos = seq_len;
428                }
429                break;
430            }
431            case AW_KEY_LEFT:
432            case AW_KEY_RIGHT: {
433                direction = keycode==AW_KEY_RIGHT ? 1 : -1;
434
435                // no key modifier -> just move cursor
436
437                int n = nrepeat;
438
439                if (keymod == AW_KEYMODE_NONE) {
440                    while (n--) {
441                        do {
442                            seq_pos += direction;
443                        }
444                        while (legal_curpos(seq_pos) && !remap->is_shown(seq_pos));
445                    }
446                    break;
447                }
448
449                if (mode==AD_NOWRITE) { write_fault = 1; break; }
450
451                int jump_or_fetch = 0;  // 1=jump selected 2=fetch selected (for repeat only)
452                int push_or_pull = 0;   // 1=push selected 2=pull selected (for repeat only)
453
454                // ------------------
455                // loop over nrepeat:
456
457                while (!ad_err && n-->0 && legal_curpos(seq_pos)) {
458                    cursorpos = remap->sequence_to_screen(seq_pos);
459
460                    int adjacent_scr_pos = cursorpos - (direction<0); // screen position next to the cursor
461                    if (adjacent_scr_pos<0 || size_t(adjacent_scr_pos)>remap->get_max_screen_pos()) {
462                        ad_err = GBS_global_string("Action beyond end of screen!");
463                        break;
464                    }
465
466                    int adjacent_seq_pos = remap->screen_to_sequence(adjacent_scr_pos); // _visible_ sequence position next to the cursor
467                    int real_adjacent_seq_pos = seq_pos - (direction<0); // sequence position next to cursor (not necessarily visible)
468
469                    if (adjacent_seq_pos<0 || adjacent_seq_pos>=seq_len) {
470                        ad_err = GBS_global_string("Action beyond end of sequence!");
471                        break;
472                    }
473
474                    // Ctrl+Cursor = move cursor to next end of word (or to end of next word)
475
476                    if (keymod & AW_KEYMODE_CONTROL) {
477                        if (adjacent_scr_pos>=0) {
478                            long pos = adjacent_seq_pos;
479
480                            if (ED4_ROOT->aw_root->awar(ED4_AWAR_FAST_CURSOR_JUMP)->read_int()) { // should cursor jump over next group?
481                                if (ED4_is_gap_character(seq[pos])) {
482                                    pos = get_next_visible_base(pos, direction);
483                                    if (pos>=0) pos = get_next_visible_gap(pos, direction);
484                                }
485                                else {
486                                    pos = get_next_visible_gap(pos, direction);
487                                }
488
489                                seq_pos = (pos>=0
490                                           ? (direction<0 ? pos+1 : pos)
491                                           : (direction<0 ? 0 : seq_len-1));
492                            }
493                            else {
494                                if (ED4_is_gap_character(seq[pos])) { seq_pos = get_next_visible_base(pos, direction); }
495                                else                                { seq_pos = get_next_visible_gap(pos, direction); }
496
497                                if (direction<0) { seq_pos = seq_pos==-1 ? 0       : seq_pos+1; }
498                                else             { seq_pos = seq_pos==-1 ? seq_len : seq_pos; }
499                            }
500                        }
501                        continue;
502                    }
503
504                    // ALT/META+Cursor = jump & fetch
505
506                    if (keymod & (AW_KEYMODE_ALT)) {
507                        if (is_consensus) { cannot_handle = 1; return 0; }
508
509                        if (ED4_is_gap_character(seq[adjacent_seq_pos])) { // there's a _gap_ next to the cursor -> let's fetch
510                            if (jump_or_fetch!=1) {
511                                jump_or_fetch = 2;
512                                long source_pos = get_next_base(adjacent_seq_pos, direction); // position of base to fetch
513                                if (source_pos==-1) { // there is nothing to fetch
514                                    n = 0;
515                                }
516                                else {
517                                    ad_err = moveBase(source_pos, adjacent_seq_pos, get_gap_type(source_pos, direction));
518                                    seq_pos = adjacent_seq_pos + (direction>0);
519                                }
520                            }
521                            else {
522                                n = 0;
523                            }
524                        }
525                        else { // there's a _base_ next to the cursor -> let it jump
526                            if (jump_or_fetch!=2) {
527                                jump_or_fetch = 1;
528                                int next_gap = adjacent_seq_pos - direction;
529
530                                if (ED4_is_gap_character(seq[next_gap])) {
531                                    int dest_pos = get_next_base(next_gap, -direction);
532
533                                    if (dest_pos<0) {
534                                        dest_pos = direction>0 ? 0 : seq_len-1;
535                                    }
536                                    else {
537                                        dest_pos += direction;
538                                    }
539
540                                    if (ED4_is_gap_character(seq[dest_pos])) {
541                                        ad_err = moveBase(adjacent_seq_pos, dest_pos, get_gap_type(adjacent_seq_pos, direction));
542                                        if (!ad_err) {
543                                            seq_pos = get_next_base(seq_pos, direction)+(direction<0);
544                                            if (seq_pos==-1) {
545                                                seq_pos = direction<0 ? 0 : seq_len;
546                                            }
547                                        }
548                                    }
549                                    else {
550                                        e4_assert(0);
551                                    }
552                                }
553                                else {
554                                    ad_err = GBS_global_string("You can only jump single bases.");
555                                }
556                            }
557                            else {
558                                n = 0;
559                            }
560                        }
561
562                        if (!ad_err) {
563                            changed_flag = 1;
564                        }
565
566                        continue;
567                    }
568
569                    // Shift+Cursor = push/pull character
570
571                    if (is_consensus) { cannot_handle = 1; return 0; };
572
573                    if (ED4_is_gap_character(seq[real_adjacent_seq_pos])) { // pull
574                        long dest_pos = real_adjacent_seq_pos;
575                        long source_pos = real_adjacent_seq_pos-direction;
576
577                        if (!ED4_is_gap_character(seq[source_pos]) && push_or_pull!=1) {
578                            push_or_pull = 2;
579
580                            long next_gap = get_next_gap(source_pos, -direction);
581                            long last_source = next_gap>=0 ? next_gap : (direction>0 ? 0 : seq_len-1);
582
583                            if (ED4_is_gap_character(seq[last_source])) {
584                                last_source = get_next_base(last_source, direction);
585                            }
586
587                            ad_err = shiftBases(source_pos, last_source, dest_pos, direction, 0,
588                                                is_sequence ? get_gap_type(last_source, -direction) : '.');
589
590                            if (!ad_err) {
591                                seq_pos = dest_pos + (direction>0);
592                                changed_flag = 1;
593                            }
594                        }
595                        else {
596                            n = 0;
597                        }
598                    }
599                    else { // push
600                        long next_gap = get_next_gap(adjacent_seq_pos, direction);
601
602                        if (next_gap>=0 && push_or_pull!=2) {
603                            push_or_pull = 1;
604                            long dest_pos = next_gap;
605                            long source_pos = get_next_base(next_gap, -direction);
606                            long last_source = adjacent_seq_pos;
607
608                            e4_assert(source_pos>=0);
609                            ad_err = shiftBases(source_pos, last_source, dest_pos, direction, &dest_pos,
610                                                is_sequence ? get_gap_type(last_source, -direction) : '.');
611
612                            if (!ad_err) {
613                                seq_pos = dest_pos + (direction<0);
614                                changed_flag = 1;
615                            }
616                        }
617                        else {
618                            n = 0;
619                        }
620                    }
621                }
622                break;
623            }
624
625            case AW_KEY_BACKSPACE:
626                h = seq_pos;
627
628                if (direction>0) {
629                    seq_pos -= nrepeat;
630                }
631                else {
632                    seq_pos += nrepeat;
633                }
634                if (seq_pos <0 || seq_pos >= seq_len) {
635                    seq_pos = h;
636                    break;
637                }
638                // fall-through
639
640            case AW_KEY_DELETE:
641                h = seq_pos;
642
643                if (is_consensus) { cannot_handle = 1; return 0; };
644                if (keymod) { return 0; }
645
646                if (mode==AD_NOWRITE) { write_fault = 1; break; }
647
648                switch (mode) {
649                    case AD_ALIGN:
650                        {
651                            int len;
652                            int offset;
653
654                            ad_err = 0;
655                            if (direction>=0)   offset = 0;
656                            else        offset = -nrepeat;
657
658                            for (len = nrepeat-1; len>=0; len--) {
659                                if (!ED4_is_gap_character(seq[h+offset+len])) {
660                                    ad_err = GBS_global_string("You cannot remove bases in align mode");
661                                    break;
662                                }
663                            }
664                            if (ad_err) break;
665                        }
666                    case AD_REPLACE:
667                    case AD_INSERT:
668                        ad_err = remove(nrepeat, h, direction, !is_sequence);
669                        if (!ad_err) {
670                            changed_flag = 1;
671                        }
672                        break;
673                    default:
674                        break;
675                }
676
677                break;
678
679            case AW_KEY_RETURN: 
680                ad_err = toggle_cursor_group_folding();
681                break; 
682
683            case AW_KEY_ASCII: {
684
685                //      keyboard layout:
686                //
687                //      - CTRL-A    Align                               ok
688                //      - CTRL-D    Toggle view differences             ok
689                //      - CTRL-E    Toggle edit/align                   ok
690                //      - CTRL-I    Toggle insert/replace               ok
691                //      - CTRL-J    Jump opposite helix position        ok
692                //      - CTRL-K    Toggle compression on/off           ok
693                //      - CTRL-L    Refresh                             ok
694                //      - CTRL-M    Invert mark                         ok
695                //      - CTRL-O    = ALT-LEFT                          ok
696                //      - CTRL-P    = ALT-RIGHT                         ok
697                //      - CTRL-R    Set aligner OR viewDiff reference species       ok
698                //      - CTRL-S    Repeat last search                  ok
699                //      - CTRL-U    Undo                                @@@ crashes! disabled atm!
700
701
702                if (key >0 && key<=26) { // CTRL-Keys
703                    switch (key+'A'-1) {
704                        case 'A': { // CTRL-A = Start Fast-Aligner
705                            AW_window *aw_tmp = current_aww();
706                            if (is_consensus) { cannot_handle = 1; return 0; };
707                            if (mode==AD_NOWRITE) { write_fault = 1; return 0; }
708
709                            AlignDataAccess localDataAccess(*ED4_get_aligner_data_access()); // use local modified copy
710                            localDataAccess.do_refresh = false;
711
712                            FastAligner_set_align_current(ED4_ROOT->aw_root, ED4_ROOT->props_db);
713                            AW_clock_cursor(ED4_ROOT->aw_root);
714                            GB_commit_transaction(localDataAccess.gb_main);
715
716                            FastAligner_start(aw_tmp, &localDataAccess);
717
718                            GB_begin_transaction(localDataAccess.gb_main);
719                            AW_normal_cursor(ED4_ROOT->aw_root);
720
721                            int basesLeftOf = 0;
722                            int pos;
723
724                            for (pos=0; pos < seq_pos && pos<seq_len; pos++) {    // count # of bases left of cursorpos
725                                if (!ED4_is_gap_character(seq[pos])) {
726                                    basesLeftOf++;
727                                }
728                            }
729
730                            char *aligned_seq = GB_read_string(gb_data); // read new sequence
731                            ad_err            = GB_write_string(gb_data, seq); // restore old sequence
732
733                            freeset(seq, aligned_seq); // set new sequence
734                            changed_flag = 1;       // and mark changed
735
736                            {
737                                int basesLeftOf2   = 0;
738                                int lastCorrectPos = -1;
739                                for (pos=0; pos<seq_pos && pos<seq_len; pos++) {    // count # of bases left of cursorpos
740                                    if (!ED4_is_gap_character(seq[pos])) {
741                                        basesLeftOf2++;
742                                        if (basesLeftOf2 == basesLeftOf) lastCorrectPos = pos;
743                                    }
744                                }
745
746                                if (basesLeftOf != basesLeftOf2) { // old cursor-position has different basepos
747                                    if (lastCorrectPos != -1) { // already seen position with same basepos
748                                        seq_len = lastCorrectPos+1;
749                                    }
750                                    else {
751                                        for (; pos<seq_len; pos++) {
752                                            if (!ED4_is_gap_character(seq[pos])) {
753                                                basesLeftOf2++;
754                                                if (basesLeftOf2 == basesLeftOf) {
755                                                    seq_pos = pos+1;
756                                                    break; // stop after first matching position
757                                                }
758                                            }
759                                        }
760                                    }
761                                }
762                            }
763                            break;
764                        }
765                        case 'R': {  // CTRL-R = set aligner reference species OR set reference for diff-mode
766                            ED4_reference *ref = ED4_ROOT->reference;
767                            if (ref->is_set()) { // if "view differences" is active = > set new reference
768                                ED4_viewDifferences_setNewReference();
769                            }
770                            else { // otherwise set aligner reference
771                                if (is_consensus) { cannot_handle = 1; return 0; };
772                                FastAligner_set_reference_species(ED4_ROOT->aw_root);
773                            }
774                            break;
775                        }
776                        case 'D': { // CTRL-D = Toggle view differences
777                            ED4_toggle_viewDifferences(ED4_ROOT->aw_root);
778                            break;
779                        }
780                        case 'E': { // CTRL-E = Toggle Edit/Align-Mode
781                            ED4_ROOT->aw_root->awar(AWAR_EDIT_MODE)->toggle_toggle();
782                            break;
783                        }
784                        case 'I': { // CTRL-I = Toggle Insert/Replace-Mode
785                            ED4_ROOT->aw_root->awar(AWAR_INSERT_MODE)->toggle_toggle();
786                            break;
787                        }
788                        case 'J': { // CTRL-J = Jump to opposite helix position
789                            AW_helix *helix = ED4_ROOT->helix;
790
791                            if (!helix->has_entries()) ad_err = ARB_strdup("Got no helix information");
792                            else if (helix->pairtype(seq_pos) != HELIX_NONE) {
793                                seq_pos = helix->opposite_position(seq_pos);
794                                cursor_jump = ED4_JUMP_KEEP_POSITION;
795                            }
796                            else ad_err = ARB_strdup("Not at helix position");
797                            break;
798                        }
799                        case 'K': { // Ctrl-K = Compression on/off
800                            static int last_mode;
801                            int current_mode = (ED4_remap_mode)ED4_ROOT->aw_root->awar(ED4_AWAR_COMPRESS_SEQUENCE_GAPS)->read_int();
802                            int next_mode = last_mode;
803
804                            if (current_mode==0) { // if not compressed
805                                if (last_mode==0) next_mode = 2; // force compress
806                            }
807                            else {  // if compressed
808                                next_mode = 0; // force uncompressed
809                            }
810
811                            ED4_ROOT->aw_root->awar(ED4_AWAR_COMPRESS_SEQUENCE_GAPS)->write_int(next_mode);
812
813                            last_mode = current_mode;
814                            break;
815                        }
816                        case 'L': {  // CTRL-L = Refresh
817                            ED4_request_full_refresh();
818                            ED4_request_relayout();
819                            cursor_jump = ED4_JUMP_CENTERED;
820                            break;
821                        }
822                        case 'M': { // CTRL-M = Invert mark(s)
823                            if (is_consensus) { cannot_handle = 1; return 0; }
824                            toggle_mark_of_specData(gb_data);
825                            break;
826                        }
827                        case 'O': { //  for ALT-left
828                            keycode = AW_KEY_LEFT;
829                            keymod = AW_KEYMODE_ALT;
830                            reinterpret_key = true;
831                            break;
832                        }
833                        case 'P': { // for ALT-right
834                            keycode = AW_KEY_RIGHT;
835                            keymod = AW_KEYMODE_ALT;
836                            reinterpret_key = true;
837                            break;
838                        }
839                        case 'S': { // CTRL-S = Repeat last search
840                            ad_err      = ED4_repeat_last_search(current_ed4w());
841                            seq_pos     = current_cursor().get_sequence_pos();
842                            cursor_jump = ED4_JUMP_KEEP_POSITION;
843                            break;
844                        }
845                        case 'U': {
846                            // ad_err = GB_undo(gb_main, GB_UNDO_UNDO); // @@@ stuerzt ab - wahrscheinlich weil Transaktion offen ist
847                            break;
848                        }
849                    }
850                }
851                else { // normal characters
852                    if (is_consensus) { cannot_handle = 1; return 0; }
853                    if (mode==AD_NOWRITE) { write_fault = 1; break; }
854
855                    if (key == ' ') {
856                        if (is_sequence) {
857                            long left = seq_pos>0 ? seq_pos-1 : 0;
858                            int  l    = seq[left];
859                            int  r    = seq[seq_pos];
860
861                            char gapchar_at_pos = ED4_is_gap_character(l) ? l : (ED4_is_gap_character(r) ? r : 0);
862
863                            switch (keymod) {
864                                case AW_KEYMODE_NONE:
865                                    key = gapchar_at_pos ? gapchar_at_pos : '-'; // insert (same) gap
866                                    break;
867
868                                case AW_KEYMODE_CONTROL:
869                                    if (gapchar_at_pos) key = gapchar_at_pos == '-' ? '.' : '-'; // toggle gaptype
870                                    break;
871
872                                default: break;
873                            }
874                        }
875                        str[0] = key;
876                    }
877
878                    if (ED4_is_gap_character(key) && keymod == AW_KEYMODE_CONTROL) { // gap-type change works in all modes
879                        // gap type functions ('.' <-> '-')
880
881                        long left = seq_pos>0 ? seq_pos-1 : 0;
882                        int  l    = seq[left];
883                        int  r    = seq[seq_pos];
884
885                        if      (ED4_is_gap_character(l) && l!=key) { ad_err = swap_gaps(left, key);    changed_flag = 1; }
886                        else if (ED4_is_gap_character(r) && r!=key) { ad_err = swap_gaps(seq_pos, key); changed_flag = 1; }
887                    }
888                    else {
889                        switch (mode) {
890                            case AD_ALIGN: {
891                                if (ED4_is_gap_character(key)) {
892                                    if (keymod == AW_KEYMODE_NONE) {
893                                        if (!ad_err) {
894                                            char *nstr = ARB_calloc<char>(nrepeat+1);
895
896                                            for (int i = 0; i< nrepeat; i++) nstr[i] = key;
897                                            ad_err = insert(nstr, seq_pos, direction, 0);
898                                            if (!ad_err) seq_pos = get_next_visible_pos(seq_pos+(direction>=0 ? nrepeat : 0), direction);
899                                            delete nstr;
900                                        }
901                                        changed_flag = 1;
902                                    }
903                                }
904                                else { // check typed bases against sequence
905                                    while (nrepeat && !ad_err) {
906                                        nrepeat--;
907                                        seq_pos = get_next_visible_base(seq_pos, direction);
908                                        if (seq_pos<0 || seq_pos>=seq_len) {
909                                            ad_err = GBS_global_string("End of sequence reached");
910                                        }
911                                        else if (seq[seq_pos]!=key) {
912                                            ad_err = GBS_global_string("Base '%c' at %li does not match '%c'", seq[seq_pos], seq_pos, key);
913                                        }
914                                        else {
915                                            seq_pos = get_next_visible_pos(seq_pos, direction)+1;
916                                            ad_err = 0;
917                                        }
918                                        if (ad_err) {
919                                            ed4_beep();
920                                        }
921                                    }
922                                }
923                                break;
924                            }
925                            case AD_REPLACE: {
926                                while (nrepeat && !ad_err) {
927                                    nrepeat--;
928                                    if (direction>0) {
929                                        ad_err = replace(str, seq_pos, 1);
930
931                                        if (!ad_err) {
932                                            seq_pos++;
933                                            changed_flag = 1;
934                                        }
935                                    }
936                                    else {
937                                        int left_pos = get_next_visible_pos(seq_pos, -1);
938
939                                        if (left_pos>=0)    ad_err = replace(str, left_pos+1, -1);
940                                        else            ad_err = "End of sequence";
941
942                                        if (!ad_err) {
943                                            seq_pos = left_pos;
944                                            changed_flag = 1;
945                                        }
946                                    }
947                                }
948                                break;
949                            }
950                            case AD_INSERT: {
951                                while (nrepeat && !ad_err) {
952                                    nrepeat--;
953                                    if (direction>0) {
954                                        ad_err = insert(str, seq_pos, 1, !is_sequence);
955
956                                        if (!ad_err) {
957                                            seq_pos++;
958                                            changed_flag = 1;
959                                        }
960                                    }
961                                    else {
962                                        int left_pos = get_next_visible_pos(seq_pos, -1);
963
964                                        if (left_pos>=0) {
965                                            ad_err = insert(str, left_pos+1, -1, !is_sequence);
966                                        }
967                                        else {
968                                            ad_err = "End of sequence";
969                                        }
970
971                                        if (!ad_err) {
972                                            seq_pos = left_pos;
973                                            changed_flag = 1;
974                                        }
975                                    }
976                                }
977                                break;
978                            }
979                            default: {
980                                break;
981                            }
982                        }
983                    }
984
985                }
986                break;
987            }
988            default: {
989                break;
990            }
991
992        }
993    }
994
995    if (ad_err) seq_pos = old_seq_pos;
996    seq_pos = seq_pos<0 ? 0 : (seq_pos>seq_len ? seq_len : seq_pos);    // ensure legal position
997
998    return ad_err;
999}
1000
1001ED4_Edit_String::ED4_Edit_String()
1002{
1003    memset((char *)this, 0, sizeof(*this));
1004    remap = ED4_ROOT->root_group_man->remap();
1005}
1006
1007ED4_Edit_String::~ED4_Edit_String()
1008{
1009    free(old_seq);
1010}
1011
1012GB_ERROR ED4_Edit_String::edit(ED4_work_info *info) {
1013    e4_assert(info->working_terminal != 0);
1014
1015    if (!info->rightward) { // 5'<-3'
1016        info->char_position++;
1017    }
1018
1019    info->out_seq_position = remap->screen_to_sequence(info->char_position);
1020    info->refresh_needed   = false;
1021    info->cursor_jump      = ED4_JUMP_KEEP_VISIBLE;
1022    info->cannot_handle    = false;
1023    old_seq                = 0;
1024
1025    if (info->string) {
1026        seq = info->string;
1027        seq_len = strlen(seq);
1028    }
1029    else {
1030        e4_assert(info->gb_data);
1031        int seq_len_int;
1032        seq = info->working_terminal->resolve_pointer_to_string_copy(&seq_len_int);
1033        seq_len = seq_len_int;
1034    }
1035
1036    int map_key;
1037    if (info->event.keymodifier == AW_KEYMODE_NONE) {
1038        map_key = ED4_ROOT->edk->map_key(info->event.character);
1039        if (map_key != info->event.character) { // remapped
1040            if (info->event.character == ' ') { // space
1041                AW_advice("You have keymapped the space-key!\n"
1042                          "The new functionality assigned to space-key is not available when\n"
1043                          "key-mapping is enabled.\n",
1044                          AW_ADVICE_TOGGLE_AND_HELP, "Obsolete default keymapping", "nekey_map.hlp");
1045            }
1046        }
1047    }
1048    else {
1049        map_key = info->event.character;
1050    }
1051    GB_ERROR err = 0;
1052
1053    nrepeat_zero_requested = 1;
1054    if (!nrepeat) {
1055        nrepeat_is_already_set = 1;
1056        nrepeat = 1;
1057    }
1058
1059    if (info->event.keycode==AW_KEY_ASCII &&
1060        isdigit(map_key) &&
1061        ED4_ROOT->aw_root->awar(ED4_AWAR_DIGITS_AS_REPEAT)->read_int()) { // handle digits for repeated commands
1062
1063        if (nrepeat_is_already_set) { nrepeat = 0; }
1064        nrepeat_zero_requested = 0;
1065
1066        for (int r=0; r<info->repeat_count; r++) {
1067            nrepeat = nrepeat * 10 + (map_key - '0');
1068            if (nrepeat>10000) {
1069                nrepeat = 10000;
1070            }
1071            else if (nrepeat<0) {
1072                nrepeat = 0;
1073            }
1074        }
1075#ifdef DEBUG
1076        if (nrepeat>1) {
1077            printf("nrepeat=%i\n", nrepeat);
1078        }
1079#endif
1080    }
1081    else if (info->event.keymodifier==AW_KEYMODE_NONE && info->event.keycode==AW_KEY_NONE) {
1082        nrepeat_zero_requested = 0;
1083    }
1084    else {
1085        nrepeat += info->repeat_count-1;
1086
1087#ifdef DEBUG
1088        if (nrepeat>1) {
1089            printf("nrepeat is %i\n", nrepeat);
1090        }
1091#endif
1092
1093        int is_remapped_sequence = !info->is_sequence && ED4_ROOT->aw_root->awar(ED4_AWAR_COMPRESS_SEQUENCE_TYPE)->read_int()!=ED4_RM_NONE;
1094        if (info->mode==AD_NOWRITE_IF_COMPRESSED) {
1095            if (is_remapped_sequence) {
1096                info->mode = AD_NOWRITE;
1097            }
1098            else {
1099                info->mode = AD_INSERT;
1100            }
1101        }
1102
1103        bool write_fault = 0;
1104
1105        err = command(info->event.keymodifier,
1106                      info->event.keycode,
1107                      map_key,
1108                      info->rightward,
1109                      info->mode,
1110                      (int)(info->string!=0),
1111                      info->out_seq_position,
1112                      info->refresh_needed,
1113                      info->cursor_jump,
1114                      info->cannot_handle,
1115                      write_fault,
1116                      info->gb_data,
1117                      info->is_sequence);
1118
1119        e4_assert(!(err && info->cannot_handle));
1120
1121        if (write_fault) {
1122            e4_assert(info->mode==AD_NOWRITE);
1123            aw_message(is_remapped_sequence
1124                       ? "Check 'Show all gaps' when editing remarks"
1125                       : "This terminal is write-protected!");
1126        }
1127    }
1128
1129    if (!err) {
1130        if (info->gb_data) {
1131            if (info->refresh_needed) {
1132                e4_assert(info->working_terminal->get_species_pointer() == info->gb_data);
1133
1134                int old_seq_len_int;
1135                old_seq     = info->working_terminal->resolve_pointer_to_string_copy(&old_seq_len_int);
1136                old_seq_len = old_seq_len_int;
1137
1138                err = info->working_terminal->write_sequence(seq, seq_len);
1139                if (err) {
1140                    info->out_seq_position = remap->screen_to_sequence(info->char_position);    // correct cursor_pos if protection error occurred
1141                }
1142            }
1143            freenull(seq);
1144        }
1145    }
1146
1147    if (!info->rightward) {
1148        info->char_position    = remap->sequence_to_screen_PLAIN(info->out_seq_position);
1149        e4_assert(info->char_position >= 0);
1150        info->char_position--;
1151        info->out_seq_position = remap->screen_to_sequence(info->char_position);
1152    }
1153
1154    return err;
1155}
1156
1157void ED4_Edit_String::finish_edit()
1158{
1159    nrepeat_is_already_set = 0;
1160    if (nrepeat_zero_requested) {
1161        nrepeat_zero_requested = 0;
1162        nrepeat = 0;
1163    }
1164}
1165
1166void ED4_Edit_String::init_edit() {
1167    freenull(old_seq);
1168    seq_len = 0;
1169    seq = 0;
1170    gbd = 0;
1171    old_seq_len = 0;
1172    remap = ED4_ROOT->root_group_man->remap();
1173}
1174
Note: See TracBrowser for help on using the repository browser.