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