source: tags/arb-6.0-rc3/EDIT4/ED4_edit_string.cxx

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