source: tags/arb_5.1/EDIT4/ED4_edit_string.cxx

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