source: tags/ms_r16q2/EDIT4/ED4_no_class.cxx

Last change on this file was 14786, checked in by westram, 8 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 82.1 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : ED4_no_class.cxx                                  //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include <ed4_extern.hxx>
12
13#include "ed4_awars.hxx"
14#include "ed4_class.hxx"
15#include "ed4_edit_string.hxx"
16#include "ed4_nds.hxx"
17#include "ed4_list.hxx"
18#include "ed4_seq_colors.hxx"
19
20#include <iupac.h>
21#include <consensus_config.h>
22#include <item_sel_list.h>
23#include <macros.hxx>
24
25#include <awt.hxx>
26#include <awt_config_manager.hxx>
27#include <awt_misc.hxx>
28#include <awt_sel_boxes.hxx>
29
30#include <aw_awars.hxx>
31#include <AW_helix.hxx>
32#include <aw_msg.hxx>
33#include <AW_rename.hxx>
34#include <aw_root.hxx>
35
36#include <ad_config.h>
37
38#include <arb_defs.h>
39#include <arb_global_defs.h>
40#include <arb_progress.h>
41
42#include <cctype>
43#include <limits.h>
44
45#include <vector>
46
47using namespace std;
48
49void ED4_calc_terminal_extentions() {
50    AW_device *device = ED4_ROOT->first_window->get_device(); // any device
51
52    const AW_font_limits& seq_font_limits  = device->get_font_limits(ED4_G_SEQUENCES, 0);
53    const AW_font_limits& seq_equal_limits = device->get_font_limits(ED4_G_SEQUENCES, '=');
54    const AW_font_limits& info_font_limits = device->get_font_limits(ED4_G_STANDARD, 0);
55
56    int info_char_width = info_font_limits.width;
57    int seq_term_descent;
58
59    if (ED4_ROOT->helix->is_enabled() || ED4_ROOT->protstruct) { // display helix ?
60        ED4_ROOT->helix_spacing =
61            seq_equal_limits.ascent // the ascent of '='
62            + ED4_ROOT->helix_add_spacing; // xtra user-defined spacing
63
64        seq_term_descent = ED4_ROOT->helix_spacing;
65    }
66    else {
67        ED4_ROOT->helix_spacing = 0;
68        seq_term_descent  = seq_font_limits.descent;
69    }
70
71    // for wanted_seq_term_height ignore descent, because it additionally allocates 'ED4_ROOT->helix_spacing' space:
72    int wanted_seq_term_height = seq_font_limits.ascent + seq_term_descent + ED4_ROOT->terminal_add_spacing;
73    int wanted_seq_info_height = info_font_limits.height + ED4_ROOT->terminal_add_spacing;
74
75    TERMINALHEIGHT = (wanted_seq_term_height>wanted_seq_info_height) ? wanted_seq_term_height : wanted_seq_info_height;
76
77    {
78        int maxchars;
79        int maxbrackets;
80
81        ED4_get_NDS_sizes(&maxchars, &maxbrackets);
82        MAXSPECIESWIDTH =
83            (maxchars+1)*info_char_width + // width defined in NDS window plus 1 char for marked-box
84            maxbrackets*BRACKETWIDTH; // brackets defined in NDS window
85    }
86    MAXINFOWIDTH = CHARACTEROFFSET + info_char_width*ED4_ROOT->aw_root->awar(ED4_AWAR_NDS_INFO_WIDTH)->read_int() + 1;
87
88    INFO_TERM_TEXT_YOFFSET = info_font_limits.ascent - 1;
89    SEQ_TERM_TEXT_YOFFSET  = seq_font_limits.ascent - 1;
90
91    if (INFO_TERM_TEXT_YOFFSET<SEQ_TERM_TEXT_YOFFSET) INFO_TERM_TEXT_YOFFSET = SEQ_TERM_TEXT_YOFFSET;
92
93#if defined(DEBUG) && 0
94    printf("seq_term_descent= %i\n", seq_term_descent);
95    printf("TERMINALHEIGHT  = %i\n", TERMINALHEIGHT);
96    printf("MAXSPECIESWIDTH = %i\n", MAXSPECIESWIDTH);
97    printf("MAXINFOWIDTH    = %i\n", MAXINFOWIDTH);
98    printf("INFO_TERM_TEXT_YOFFSET= %i\n", INFO_TERM_TEXT_YOFFSET);
99    printf("SEQ_TERM_TEXT_YOFFSET= %i\n", SEQ_TERM_TEXT_YOFFSET);
100#endif // DEBUG
101}
102
103static ARB_ERROR update_terminal_extension(ED4_base *this_object) {
104    if (this_object->is_terminal()) {
105        if (this_object->is_spacer_terminal()) {
106            if (this_object->parent->is_device_manager()) { // the rest is managed by reference links
107                ;
108                //      this_object->extension.size[HEIGHT] = TERMINALHEIGHT / 2;   // @@@ Zeilenabstand verringern hier?
109            }
110        }
111        else if (this_object->is_species_name_terminal()) {
112            this_object->extension.size[WIDTH] = MAXSPECIESWIDTH - BRACKETWIDTH * this_object->calc_group_depth();
113        }
114        else if (this_object->is_sequence_info_terminal()) {
115            this_object->extension.size[WIDTH] = MAXINFOWIDTH;
116        }
117        else if (this_object->is_line_terminal()) { // thought for line terminals which are direct children of the device manager
118            this_object->extension.size[WIDTH] =
119                TREETERMINALSIZE + MAXSPECIESWIDTH +
120                ED4_ROOT->ref_terminals.get_ref_sequence_info()->extension.size[WIDTH] +
121                ED4_ROOT->ref_terminals.get_ref_sequence()->extension.size[WIDTH];
122        }
123    }
124
125    this_object->request_resize();
126
127    return NULL;
128}
129
130void ED4_expose_recalculations() {
131    ED4_ROOT->recalc_font_group();
132    ED4_calc_terminal_extentions();
133
134#if defined(WARN_TODO)
135#warning below calculations have to be done at startup as well
136#endif
137
138    ED4_ROOT->ref_terminals.get_ref_sequence_info()->extension.size[HEIGHT] = TERMINALHEIGHT;
139    ED4_ROOT->ref_terminals.get_ref_sequence()->extension.size[HEIGHT]      = TERMINALHEIGHT;
140    ED4_ROOT->ref_terminals.get_ref_sequence_info()->extension.size[WIDTH]  = MAXINFOWIDTH;
141
142    int screenwidth = ED4_ROOT->root_group_man->remap()->shown_sequence_to_screen(MAXSEQUENCECHARACTERLENGTH);
143    while (1) {
144        ED4_ROOT->ref_terminals.get_ref_sequence()->extension.size[WIDTH] =
145            ED4_ROOT->font_group.get_width(ED4_G_SEQUENCES) *
146            (screenwidth+3);
147
148        ED4_terminal *top_middle_line_terminal = ED4_ROOT->main_manager->get_top_middle_line_terminal();
149
150        ED4_ROOT->main_manager->get_top_middle_spacer_terminal()->extension.size[HEIGHT] = TERMINALHEIGHT - top_middle_line_terminal->extension.size[HEIGHT];
151        ED4_ROOT->main_manager->route_down_hierarchy(makeED4_route_cb(update_terminal_extension)).expect_no_error();
152
153        ED4_ROOT->resize_all(); // may change mapping
154
155        int new_screenwidth = ED4_ROOT->root_group_man->remap()->shown_sequence_to_screen(MAXSEQUENCECHARACTERLENGTH);
156        if (new_screenwidth == screenwidth) { // mapping did not change
157            break;
158        }
159        // @@@ request resize for all terminals ?
160        screenwidth = new_screenwidth;
161    }
162}
163
164static ARB_ERROR call_edit(ED4_base *object, ED4_work_info *work_info) {
165    // called after editing consensus to edit single sequences
166    GB_ERROR error = NULL;
167
168    if (object->is_species_seq_terminal()) {
169        int expected_prop = ED4_P_CURSOR_ALLOWED|ED4_P_ALIGNMENT_DATA;
170
171        if ((object->dynamic_prop & expected_prop) == expected_prop) {
172            ED4_work_info new_work_info;
173
174            new_work_info.event            = work_info->event;
175            new_work_info.char_position    = work_info->char_position;
176            new_work_info.out_seq_position = work_info->out_seq_position;
177            new_work_info.refresh_needed   = false;
178            new_work_info.cursor_jump      = ED4_JUMP_KEEP_VISIBLE;
179            new_work_info.out_string       = NULL;
180            new_work_info.mode             = work_info->mode;
181            new_work_info.rightward        = work_info->rightward;
182            new_work_info.cannot_handle    = false;
183            new_work_info.is_sequence      = work_info->is_sequence;
184            new_work_info.working_terminal = object->to_terminal();
185
186            if (object->get_species_pointer()) {
187                new_work_info.gb_data   = object->get_species_pointer();
188                new_work_info.string    = NULL;
189            }
190            else {
191                new_work_info.gb_data = NULL;
192                new_work_info.string  = object->id; // @@@ looks obsolete (see [8402] for previous code)
193                e4_assert(0); // assume we never come here
194            }
195
196            new_work_info.repeat_count = 1;
197
198            ED4_ROOT->edit_string->init_edit();
199            error = ED4_ROOT->edit_string->edit(&new_work_info);
200
201            e4_assert(error || !new_work_info.out_string); 
202               
203            if (new_work_info.refresh_needed) {
204                object->request_refresh();
205                if (object->is_sequence_terminal()) {
206                    ED4_sequence_terminal *seq_term = object->to_sequence_terminal();
207                    seq_term->results().searchAgain();
208                }
209            }
210
211            if (move_cursor) {
212                current_cursor().jump_sequence_pos(new_work_info.out_seq_position, ED4_JUMP_KEEP_VISIBLE);
213                move_cursor = 0;
214            }
215        }
216    }
217    return error;
218}
219
220static void executeKeystroke(AW_event *event, int repeatCount) {
221    e4_assert(repeatCount>0);
222
223    if (event->keycode!=AW_KEY_NONE) {
224        ED4_cursor *cursor = &current_cursor();
225        if (cursor->owner_of_cursor && !cursor->owner_of_cursor->flag.hidden) {
226            if (event->keycode == AW_KEY_UP || event->keycode == AW_KEY_DOWN ||
227                ((event->keymodifier & AW_KEYMODE_CONTROL) &&
228                 (event->keycode == AW_KEY_HOME || event->keycode == AW_KEY_END)))
229            {
230                GB_transaction ta(GLOBAL_gb_main);
231                while (repeatCount--) {
232                    cursor->move_cursor(event);
233                }
234            }
235            else {
236                ED4_work_info *work_info = new ED4_work_info;
237       
238                work_info->cannot_handle    = false;
239                work_info->event            = *event;
240                work_info->char_position    = cursor->get_screen_pos();
241                work_info->out_seq_position = cursor->get_sequence_pos();
242                work_info->refresh_needed   = false;
243                work_info->cursor_jump      = ED4_JUMP_KEEP_VISIBLE;
244                work_info->out_string       = NULL;         // nur falls new malloc
245                work_info->repeat_count     = repeatCount;
246
247                ED4_terminal *terminal = cursor->owner_of_cursor;
248                e4_assert(terminal->is_text_terminal());
249
250                work_info->working_terminal = terminal;
251
252                if (terminal->is_sequence_terminal()) {
253                    work_info->mode        = awar_edit_mode;
254                    work_info->rightward   = awar_edit_rightward;
255                    work_info->is_sequence = 1;
256                }
257                else {
258                    work_info->rightward   = true;
259                    work_info->is_sequence = 0;
260
261                    if (terminal->is_pure_text_terminal()) {
262                        work_info->mode = awar_edit_mode;
263                    }
264                    else if (terminal->is_columnStat_terminal()) {
265                        work_info->mode = AD_NOWRITE;
266                    }
267                    else {
268                        e4_assert(0);
269                    }
270                }
271
272                work_info->string  = NULL;
273                work_info->gb_data = NULL;
274
275                if (terminal->get_species_pointer()) {
276                    work_info->gb_data = terminal->get_species_pointer();
277                }
278                else if (terminal->is_columnStat_terminal()) {
279                    work_info->gb_data = terminal->to_columnStat_terminal()->corresponding_sequence_terminal()->get_species_pointer();
280                }
281                else {
282                    e4_assert(terminal->is_consensus_terminal());
283                    ED4_consensus_sequence_terminal *cterm = terminal->to_consensus_sequence_terminal();
284                    work_info->string                      = cterm->temp_cons_seq;
285                }
286
287                ED4_Edit_String *edit_string = new ED4_Edit_String;
288                ARB_ERROR        error       = NULL;
289
290                GB_push_transaction(GLOBAL_gb_main);
291
292                if (terminal->is_consensus_terminal()) {
293                    ED4_consensus_sequence_terminal *cterm         = terminal->to_consensus_sequence_terminal();
294                    ED4_group_manager               *group_manager = terminal->get_parent(ED4_L_GROUP)->to_group_manager();
295
296                    e4_assert(cterm->temp_cons_seq == 0);
297                    work_info->string = cterm->temp_cons_seq = group_manager->build_consensus_string();
298
299                    error = edit_string->edit(work_info);
300
301                    cursor->jump_sequence_pos(work_info->out_seq_position, ED4_JUMP_KEEP_VISIBLE);
302
303                    work_info->string = 0;
304
305                    if (work_info->cannot_handle) {
306                        e4_assert(!error); // see ED4_Edit_String::edit()
307                        move_cursor = 1;
308                        if (!ED4_ROOT->edit_string) {
309                            ED4_ROOT->edit_string = new ED4_Edit_String;
310                        }
311                        error = group_manager->route_down_hierarchy(makeED4_route_cb(call_edit, work_info));
312                        group_manager->rebuild_consensi(group_manager, ED4_U_UP_DOWN);
313                    }
314
315                    freenull(cterm->temp_cons_seq);
316                }
317                else {
318                    error = edit_string->edit(work_info);
319                    cursor->jump_sequence_pos(work_info->out_seq_position, work_info->cursor_jump);
320                }
321
322                edit_string->finish_edit();
323
324                if (error) work_info->refresh_needed = true;
325
326                GB_end_transaction_show_error(GLOBAL_gb_main, error, aw_message);
327
328                if (work_info->refresh_needed) {
329                    GB_transaction ta(GLOBAL_gb_main);
330
331                    terminal->request_refresh();
332                    if (terminal->is_sequence_terminal()) {
333                        ED4_sequence_terminal *seq_term = terminal->to_sequence_terminal();
334                        seq_term->results().searchAgain();
335                    }
336                }
337
338                delete edit_string;
339                delete work_info;
340            }
341        }
342    }
343}
344
345void ED4_remote_event(AW_event *faked_event) { // keystrokes forwarded from SECEDIT
346    ED4_MostRecentWinContext context;
347    executeKeystroke(faked_event, 1);
348}
349
350static int get_max_slider_xpos() {
351    const AW_screen_area& rect = current_device()->get_area_size();
352
353    AW_pos x, y;
354    ED4_base *horizontal_link = ED4_ROOT->scroll_links.link_for_hor_slider;
355    horizontal_link->calc_world_coords(&x, &y);
356
357    AW_pos max_xpos = horizontal_link->extension.size[WIDTH] // overall width of virtual scrolling area
358        - (rect.r - x); // minus width of visible scroll-area (== relative width of horizontal scrollbar)
359
360    if (max_xpos<0) max_xpos = 0; // happens when window-content is smaller than window (e.g. if (folded) alignment is narrow)
361    return int(max_xpos+0.5);
362}
363
364static int get_max_slider_ypos() {
365    const AW_screen_area& rect = current_device()->get_area_size(); 
366
367    AW_pos x, y;
368    ED4_base *vertical_link = ED4_ROOT->scroll_links.link_for_ver_slider;
369    vertical_link->calc_world_coords(&x, &y);
370
371    AW_pos max_ypos = vertical_link->extension.size[HEIGHT] // overall height of virtual scrolling area
372        - (rect.b - y); // minus height of visible scroll-area (== relative height of vertical scrollbar)
373
374    if (max_ypos<0) max_ypos = 0; // happens when window-content is smaller than window (e.g. if ARB_EDIT4 is not filled)
375    return int(max_ypos+0.5);
376}
377
378static void ed4_scroll(AW_window *aww, int xdiff, int ydiff) {
379    int new_xpos = aww->slider_pos_horizontal + (xdiff*ED4_ROOT->aw_root->awar(ED4_AWAR_SCROLL_SPEED_X)->read_int())/10;
380    int new_ypos = aww->slider_pos_vertical   + (ydiff*ED4_ROOT->aw_root->awar(ED4_AWAR_SCROLL_SPEED_Y)->read_int())/10;
381
382    if (xdiff<0) { // scroll left
383        if (new_xpos<0) new_xpos = 0;
384    }
385    else if (xdiff>0) { // scroll right
386        int max_xpos = get_max_slider_xpos();
387        if (max_xpos<0) max_xpos = 0;
388        if (new_xpos>max_xpos) new_xpos = max_xpos;
389    }
390
391    if (ydiff<0) { // scroll up
392        if (new_ypos<0) new_ypos = 0;
393    }
394    else if (ydiff>0) { // scroll down
395        int max_ypos = get_max_slider_ypos();
396        if (max_ypos<0) max_ypos = 0;
397        if (new_ypos>max_ypos) new_ypos = max_ypos;
398    }
399
400    if (new_xpos!=aww->slider_pos_horizontal) {
401        aww->set_horizontal_scrollbar_position(new_xpos);
402        ED4_horizontal_change_cb(aww);
403    }
404
405    if (new_ypos!=aww->slider_pos_vertical) {
406        aww->set_vertical_scrollbar_position(new_ypos);
407        ED4_vertical_change_cb(aww);
408    }
409}
410
411void ED4_input_cb(AW_window *aww) {
412    AW_event event;
413    static AW_event lastEvent;
414    static int repeatCount;
415
416    ED4_LocalWinContext uses(aww);
417
418    aww->get_event(&event);
419
420
421#if defined(DEBUG) && 0
422    printf("event.type=%i event.keycode=%i event.character='%c' event.keymodifier=%i\n", event.type, event.keycode, event.character, event.keymodifier);
423#endif
424
425    switch (event.type) {
426        case AW_Keyboard_Press: {
427            if (repeatCount==0) { // first key event?
428                lastEvent = event;
429                repeatCount = 1;
430            }
431            else {
432                if (lastEvent.keycode==event.keycode &&
433                    lastEvent.character==event.character &&
434                    lastEvent.keymodifier==event.keymodifier) { // same key as last?
435                    repeatCount++;
436                }
437                else { // other key => execute now
438                    executeKeystroke(&lastEvent, repeatCount);
439                    lastEvent = event;
440                    repeatCount = 1;
441                }
442            }
443
444            if (repeatCount) {
445#if defined(DARWIN) || 1
446                // sth goes wrong with OSX -> always execute keystroke
447                // Xfree 4.3 has problems as well, so repeat counting is disabled completely
448                executeKeystroke(&lastEvent, repeatCount);
449                repeatCount                       = 0;
450#else
451                AW_ProcessEventType nextEventType = ED4_ROOT->aw_root->peek_key_event(aww);
452
453                if (nextEventType!=KEY_RELEASED) { // no key waiting => execute now
454                    executeKeystroke(&lastEvent, repeatCount);
455                    repeatCount = 0;
456                }
457#endif
458            }
459            break;
460        }
461        case AW_Keyboard_Release: {
462            AW_ProcessEventType nextEventType = ED4_ROOT->aw_root->peek_key_event(aww);
463
464            if (nextEventType!=KEY_PRESSED && repeatCount) { // no key follows => execute keystrokes (if any)
465                executeKeystroke(&lastEvent, repeatCount);
466                repeatCount = 0;
467            }
468
469            break;
470        }
471        default: {
472            if (event.button == AW_WHEEL_UP || event.button == AW_WHEEL_DOWN) {
473                if (event.type == AW_Mouse_Press) {
474                    bool horizontal = event.keymodifier & AW_KEYMODE_ALT;
475                    int  direction  = event.button == AW_WHEEL_UP ? -1 : 1;
476
477                    int dx = horizontal ? direction*ED4_ROOT->font_group.get_max_width() : 0;
478                    int dy = horizontal ? 0 : direction*ED4_ROOT->font_group.get_max_height();
479               
480                    ed4_scroll(aww, dx, dy);
481                }
482                return;
483            }
484
485            if (event.button == AW_BUTTON_MIDDLE) {
486                if (event.type == AW_Mouse_Press) {
487                    ED4_ROOT->scroll_picture.scroll = 1;
488                    ED4_ROOT->scroll_picture.old_y = event.y;
489                    ED4_ROOT->scroll_picture.old_x = event.x;
490                    return;
491                }
492                if (event.type == AW_Mouse_Release) {
493                    ED4_ROOT->scroll_picture.scroll = 0;
494                    return;
495                }
496            }
497
498#if defined(DEBUG) && 0
499            if (event.button==AW_BUTTON_LEFT) {
500                printf("[ED4_input_cb]  type=%i x=%i y=%i ", (int)event.type, (int)event.x, (int)event.y);
501            }
502#endif
503
504            AW_pos win_x = event.x;
505            AW_pos win_y = event.y;
506            current_ed4w()->win_to_world_coords(&(win_x), &(win_y));
507            event.x = (int) win_x;
508            event.y = (int) win_y;
509
510#if defined(DEBUG) && 0
511            if (event.button==AW_BUTTON_LEFT) {
512                printf("-> x=%i y=%i\n", (int)event.type, (int)event.x, (int)event.y);
513            }
514#endif
515
516            GB_transaction ta(GLOBAL_gb_main);
517            ED4_ROOT->main_manager->event_sent_by_parent(&event, aww);
518            break;
519        }
520    }
521
522    ED4_trigger_instant_refresh();
523}
524
525void ED4_vertical_change_cb(AW_window *aww) {
526    ED4_LocalWinContext uses(aww);
527
528    GB_push_transaction(GLOBAL_gb_main);
529
530    ED4_window *win = current_ed4w();
531    int old_slider_pos = win->slider_pos_vertical;
532
533    { // correct slider_pos if necessary
534        int max_slider_ypos = get_max_slider_ypos();
535
536        if (aww->slider_pos_vertical>max_slider_ypos) aww->set_vertical_scrollbar_position(max_slider_ypos);
537        if (aww->slider_pos_vertical<0)               aww->set_vertical_scrollbar_position(0);
538    }
539
540    int slider_diff = aww->slider_pos_vertical - old_slider_pos;
541
542    win->coords.window_upper_clip_point += slider_diff;
543    win->coords.window_lower_clip_point += slider_diff;
544
545    win->scroll_rectangle(0, -slider_diff);
546    win->slider_pos_vertical = aww->slider_pos_vertical;
547
548    GB_pop_transaction(GLOBAL_gb_main);
549    win->update_window_coords();
550}
551
552void ED4_horizontal_change_cb(AW_window *aww) {
553    ED4_LocalWinContext uses(aww);
554
555    GB_push_transaction(GLOBAL_gb_main);
556
557    ED4_window *win = current_ed4w();
558    int old_slider_pos = win->slider_pos_horizontal;
559
560    { // correct slider_pos if necessary
561        int max_slider_xpos = get_max_slider_xpos();
562
563        if (aww->slider_pos_horizontal>max_slider_xpos) aww->set_horizontal_scrollbar_position(max_slider_xpos);
564        if (aww->slider_pos_horizontal<0)               aww->set_horizontal_scrollbar_position(0);
565    }
566
567    int slider_diff = aww->slider_pos_horizontal - old_slider_pos;
568
569    win->coords.window_left_clip_point  += slider_diff;
570    win->coords.window_right_clip_point += slider_diff;
571
572    win->scroll_rectangle(-slider_diff, 0);
573    win->slider_pos_horizontal = aww->slider_pos_horizontal;
574
575    GB_pop_transaction(GLOBAL_gb_main);
576    win->update_window_coords();
577}
578
579void ED4_scrollbar_change_cb(AW_window *aww) {
580    ED4_LocalWinContext uses(aww);
581
582    GB_push_transaction(GLOBAL_gb_main);
583
584    ED4_window *win = current_ed4w();
585
586    int old_hslider_pos = win->slider_pos_horizontal;
587    int old_vslider_pos = win->slider_pos_vertical;
588
589    {
590        // correct slider_pos if necessary
591        int max_slider_xpos = get_max_slider_xpos();
592        int max_slider_ypos = get_max_slider_ypos();
593
594        if (aww->slider_pos_horizontal>max_slider_xpos) aww->set_horizontal_scrollbar_position(max_slider_xpos);
595        if (aww->slider_pos_horizontal<0)               aww->set_horizontal_scrollbar_position(0);
596
597        if (aww->slider_pos_vertical>max_slider_ypos) aww->set_vertical_scrollbar_position(max_slider_ypos);
598        if (aww->slider_pos_vertical<0)               aww->set_vertical_scrollbar_position(0);
599    }
600
601    int slider_hdiff = aww->slider_pos_horizontal - old_hslider_pos;
602    int slider_vdiff = aww->slider_pos_vertical   - old_vslider_pos;
603
604    ED4_coords *coords = &win->coords;
605    coords->window_left_clip_point  += slider_hdiff;
606    coords->window_right_clip_point += slider_hdiff;
607    coords->window_upper_clip_point += slider_vdiff;
608    coords->window_lower_clip_point += slider_vdiff;
609
610    win->scroll_rectangle(-slider_hdiff, -slider_vdiff);
611
612    win->slider_pos_vertical   = aww->slider_pos_vertical;
613    win->slider_pos_horizontal = aww->slider_pos_horizontal;
614
615    GB_pop_transaction(GLOBAL_gb_main);
616    win->update_window_coords();
617}
618
619void ED4_motion_cb(AW_window *aww) {
620    AW_event event;
621
622    ED4_LocalWinContext uses(aww);
623
624    aww->get_event(&event);
625
626    if (event.type == AW_Mouse_Drag && event.button == AW_BUTTON_MIDDLE) {
627        if (ED4_ROOT->scroll_picture.scroll) {
628            int xdiff = ED4_ROOT->scroll_picture.old_x - event.x;
629            int ydiff = ED4_ROOT->scroll_picture.old_y - event.y;
630
631            ed4_scroll(aww, xdiff, ydiff);
632
633            ED4_ROOT->scroll_picture.old_x = event.x;
634            ED4_ROOT->scroll_picture.old_y = event.y;
635        }
636    }
637    else {
638
639#if defined(DEBUG) && 0
640        if (event.button==AW_BUTTON_LEFT) {
641            printf("[ED4_motion_cb] type=%i x=%i y=%i ", (int)event.type, (int)event.x, (int)event.y);
642        }
643#endif
644
645        AW_pos win_x = event.x;
646        AW_pos win_y = event.y;
647        current_ed4w()->win_to_world_coords(&win_x, &win_y);
648        event.x = (int) win_x;
649        event.y = (int) win_y;
650
651#if defined(DEBUG) && 0
652        if (event.button==AW_BUTTON_LEFT) {
653            printf("-> x=%i y=%i\n", (int)event.type, (int)event.x, (int)event.y);
654        }
655#endif
656
657        GB_transaction ta(GLOBAL_gb_main);
658        ED4_ROOT->main_manager->event_sent_by_parent(&event, aww);
659    }
660}
661
662void ED4_remote_set_cursor_cb(AW_root *awr) {
663    AW_awar *awar = awr->awar(AWAR_SET_CURSOR_POSITION);
664    long     pos  = awar->read_int();
665
666    if (pos != -1) {
667        ED4_MostRecentWinContext context;
668        ED4_cursor *cursor = &current_cursor();
669        cursor->jump_sequence_pos(pos, ED4_JUMP_CENTERED);
670        awar->write_int(-1);
671    }
672}
673
674void ED4_jump_to_cursor_position(AW_window *aww, const char *awar_name, PositionType posType) {
675    ED4_LocalWinContext  uses(aww);
676    ED4_cursor          *cursor = &current_cursor();
677    GB_ERROR             error  = 0;
678
679    long pos = aww->get_root()->awar(awar_name)->read_int();
680
681    if (pos>0) pos = bio2info(pos);
682    else if (pos<0) { // jump negative (count from back)
683        int last_pos = -1; // [1..]
684
685        switch (posType) {
686            case ED4_POS_SEQUENCE: {
687                last_pos = MAXSEQUENCECHARACTERLENGTH;
688                break;
689            }
690            case ED4_POS_ECOLI: {
691                BI_ecoli_ref *ecoli = ED4_ROOT->ecoli_ref;
692                if (ecoli->gotData()) {
693                    last_pos = ecoli->abs_2_rel(INT_MAX);
694                }
695                else {
696                    last_pos = 0; // doesnt matter (error below)
697                }
698                break;
699            }
700            case ED4_POS_BASE: {
701                last_pos = cursor->sequence2base_position(INT_MAX);
702                break;
703            }
704        }
705
706        e4_assert(last_pos != -1);
707        pos = bio2info(last_pos+1+pos);
708    }
709
710    switch (posType) {
711        case ED4_POS_SEQUENCE: {
712            e4_assert(strcmp(awar_name, current_ed4w()->awar_path_for_cursor)==0);
713            break;
714        }
715        case ED4_POS_ECOLI: {
716            e4_assert(strcmp(awar_name, current_ed4w()->awar_path_for_Ecoli)==0);
717
718            BI_ecoli_ref *ecoli = ED4_ROOT->ecoli_ref;
719            if (ecoli->gotData()) pos = ecoli->rel_2_abs(pos);
720            else error = "No ecoli reference";
721            break;
722        }
723        case ED4_POS_BASE: {
724            e4_assert(strcmp(awar_name, current_ed4w()->awar_path_for_basePos)==0);
725            pos = cursor->base2sequence_position(pos); 
726            break;
727        }
728    }
729
730    // now position is absolute [0..N-1]
731
732    // limit to screen
733    {
734        ED4_remap *remap = ED4_ROOT->root_group_man->remap();
735        long       max   = remap->screen_to_sequence(remap->get_max_screen_pos());
736
737        if (pos > max) pos  = max;
738        else if (pos<0) pos = 0;
739    }
740
741    if (error) {
742        aw_message(error);
743    }
744    else {
745        cursor->jump_sequence_pos(pos, ED4_JUMP_CENTERED);
746    }
747}
748
749void ED4_set_helixnr(AW_window *aww, const char *awar_name) {
750    ED4_LocalWinContext uses(aww);
751    ED4_cursor *cursor = &current_cursor();
752
753    if (cursor->owner_of_cursor) {
754        AW_root  *root     = aww->get_root();
755        char     *helix_nr = root->awar(awar_name)->read_string();
756        BI_helix *helix    = ED4_ROOT->helix;
757
758        if (helix->has_entries()) {
759            long pos = helix->first_position(helix_nr);
760
761            if (pos == -1) {
762                aw_message(GBS_global_string("No helix '%s' found", helix_nr));
763            }
764            else {
765                cursor->jump_sequence_pos(pos, ED4_JUMP_CENTERED);
766            }
767        }
768        else {
769            aw_message("Got no helix information");
770        }
771        free(helix_nr);
772    }
773}
774
775void ED4_set_iupac(AW_window *aww, const char *awar_name) {
776    ED4_LocalWinContext uses(aww);
777    ED4_cursor *cursor = &current_cursor();
778
779    if (cursor->owner_of_cursor) {
780        if (cursor->in_consensus_terminal()) {
781            aw_message("You cannot change the consensus");
782        }
783        else {
784            int   len;
785            char *seq     = cursor->owner_of_cursor->resolve_pointer_to_string_copy(&len);
786            int   seq_pos = cursor->get_sequence_pos();
787
788            e4_assert(seq);
789
790            if (seq_pos<len) {
791                char *iupac    = ED4_ROOT->aw_root->awar(awar_name)->read_string();
792                char  new_char = iupac::encode(iupac, ED4_ROOT->alignment_type);
793
794                seq[seq_pos] = new_char;
795                cursor->owner_of_cursor->write_sequence(seq, len);
796
797                free(iupac);
798            }
799
800            free(seq);
801        }
802    }
803}
804
805void ED4_exit() {
806    ED4_ROOT->aw_root->unlink_awars_from_DB(GLOBAL_gb_main);
807
808    ED4_window *ed4w = ED4_ROOT->first_window;
809
810    while (ed4w) {
811        ed4w->aww->hide();
812        ed4w->cursor.prepare_shutdown(); // removes any callbacks
813        ed4w = ed4w->next;
814    }
815
816    while (ED4_ROOT->first_window)
817        ED4_ROOT->first_window->delete_window(ED4_ROOT->first_window);
818
819
820    shutdown_macro_recording(ED4_ROOT->aw_root);
821
822    delete ED4_ROOT;
823
824    GBDATA *gb_main = GLOBAL_gb_main;
825    GLOBAL_gb_main  = NULL;
826#if defined(DEBUG)
827    AWT_browser_forget_db(gb_main);
828#endif // DEBUG
829    GB_close(gb_main);
830
831    ::exit(EXIT_SUCCESS);
832}
833
834void ED4_quit_editor(AW_window *aww) {
835    ED4_LocalWinContext uses(aww); // @@@ dont use context here
836
837    if (ED4_ROOT->first_window == current_ed4w()) { // quit button has been pressed in first window
838        ED4_exit();
839    }
840    // case : in another window close has been pressed
841    current_aww()->hide();
842    current_ed4w()->is_hidden = true;
843}
844
845static int timer_calls           = 0;
846static int timer_calls_triggered = 0;
847
848static unsigned ED4_timer(AW_root *) {
849    timer_calls++;
850
851#if defined(TRACE_REFRESH)
852    fprintf(stderr, "ED4_timer\n"); fflush(stderr);
853#endif
854    // get all changes from server
855    GB_begin_transaction(GLOBAL_gb_main);
856    GB_tell_server_dont_wait(GLOBAL_gb_main);
857    GB_commit_transaction(GLOBAL_gb_main);
858
859    ED4_ROOT->refresh_all_windows(0);
860
861    if (timer_calls == timer_calls_triggered) {
862        timer_calls_triggered++;
863        return 2000; // trigger callback after 2s
864    }
865    return 0; // do not trigger callback
866}
867
868void ED4_trigger_instant_refresh() {
869#if defined(TRACE_REFRESH)
870    fprintf(stderr, "ED4_trigger_instant_refresh\n"); fflush(stderr);
871#endif
872    timer_calls_triggered++;
873    ED4_ROOT->aw_root->add_timed_callback(1, makeTimedCallback(ED4_timer)); // trigger instant callback
874}
875void ED4_request_full_refresh() {
876    ED4_ROOT->main_manager->request_refresh();
877}
878void ED4_request_full_instant_refresh() {
879    ED4_request_full_refresh();
880    ED4_trigger_instant_refresh();
881}
882
883void ED4_request_relayout() {
884    ED4_expose_recalculations();
885    ED4_ROOT->main_manager->request_resize();
886    ED4_trigger_instant_refresh();
887}
888
889#define SIGNIFICANT_FIELD_CHARS 30 // length used to compare field contents (in createGroupFromSelected)
890
891static void createGroupFromSelected(GB_CSTR group_name, GB_CSTR field_name, GB_CSTR field_content) {
892    // creates a new group named group_name
893    // if field_name==0 -> all selected species & subgroups are moved to this new group
894    // if field_name!=0 -> all selected species containing field_content in field field_name are moved to this new group
895
896    ED4_group_manager *new_group_manager = NULL;
897    ED4_ROOT->main_manager->create_group(&new_group_manager, group_name);
898
899    {
900        ED4_multi_species_manager *multi_species_manager = ED4_ROOT->top_area_man->get_multi_species_manager();
901
902        new_group_manager->extension.position[Y_POS] = 2;
903        ED4_base::touch_world_cache();
904        multi_species_manager->children->append_member(new_group_manager);
905        new_group_manager->parent = (ED4_manager *) multi_species_manager;
906    }
907
908    ED4_multi_species_manager *new_multi_species_manager = new_group_manager->get_multi_species_manager();
909    bool lookingForNoContent = field_content==0 || field_content[0]==0;
910
911    ED4_selected_elem *list_elem = ED4_ROOT->selected_objects->head();
912    while (list_elem) {
913        ED4_base *object = list_elem->elem()->object;
914        object = object->get_parent(ED4_L_SPECIES);
915
916        bool move_object = true;
917        if (object->is_consensus_manager()) {
918            object = object->get_parent(ED4_L_GROUP);
919            if (field_name) move_object = false; // don't move groups if moving by field_name
920        }
921        else {
922            e4_assert(object->is_species_manager());
923            if (field_name) {
924                GBDATA *gb_species = object->get_species_pointer();
925                GBDATA *gb_field = GB_search(gb_species, field_name, GB_FIND);
926
927                move_object = lookingForNoContent;
928                if (gb_field) { // field was found
929                    char *found_content = GB_read_as_string(gb_field);
930                    if (found_content) {
931                        move_object = strncmp(found_content, field_content, SIGNIFICANT_FIELD_CHARS)==0;
932                        free(found_content);
933                    }
934                }
935            }
936        }
937
938        if (move_object) {
939            ED4_base *base = object->get_parent(ED4_L_MULTI_SPECIES);
940            if (base && base->is_multi_species_manager()) {
941                ED4_multi_species_manager *old_multi = base->to_multi_species_manager();
942                old_multi->invalidate_species_counters();
943            }
944           
945            object->parent->children->remove_member(object);
946            new_multi_species_manager->children->append_member(object);
947
948            object->parent = (ED4_manager *)new_multi_species_manager;
949            object->set_width();
950        }
951
952        list_elem = list_elem->next();
953    }
954
955    new_group_manager->create_consensus(new_group_manager, NULL);
956    new_multi_species_manager->invalidate_species_counters();
957   
958    {
959        ED4_bracket_terminal *bracket = new_group_manager->get_defined_level(ED4_L_BRACKET)->to_bracket_terminal();
960        if (bracket) bracket->fold();
961    }
962
963    new_multi_species_manager->resize_requested_by_child();
964}
965
966static void group_species(bool use_field, AW_window *use_as_main_window) {
967    GB_ERROR error = 0;
968    GB_push_transaction(GLOBAL_gb_main);
969
970    ED4_LocalWinContext uses(use_as_main_window);
971
972    if (!use_field) {
973        char *group_name = aw_input("Enter name for new group:");
974
975        if (group_name) {
976            if (strlen(group_name)>GB_GROUP_NAME_MAX) {
977                group_name[GB_GROUP_NAME_MAX] = 0;
978                aw_message("Truncated overlong group name");
979            }
980            createGroupFromSelected(group_name, 0, 0);
981            free(group_name);
982        }
983    }
984    else {
985        char   *field_name   = ED4_ROOT->aw_root->awar(AWAR_FIELD_CHOSEN)->read_string();
986        char   *doneContents = strdup(";");
987        size_t  doneLen      = 1;
988
989        bool tryAgain     = true;
990        bool foundField   = false;
991        bool foundSpecies = false;
992
993        if (strcmp(field_name, NO_FIELD_SELECTED) == 0) {
994            error = "Please select a field to use for grouping.";
995        }
996
997        while (tryAgain && !error) {
998            tryAgain = false;
999            ED4_selected_elem *list_elem = ED4_ROOT->selected_objects->head();
1000            while (list_elem && !error) {
1001                ED4_base *object = list_elem->elem()->object;
1002                object = object->get_parent(ED4_L_SPECIES);
1003                if (!object->is_consensus_manager()) {
1004                    GBDATA *gb_species = object->get_species_pointer();
1005                    GBDATA *gb_field   = NULL;
1006
1007                    if (gb_species) {
1008                        foundSpecies = true;
1009                        gb_field     = GB_search(gb_species, field_name, GB_FIND);
1010                    }
1011
1012                    if (gb_field) {
1013                        char *field_content = GB_read_as_string(gb_field);
1014                        if (field_content) {
1015                            size_t field_content_len = strlen(field_content);
1016
1017                            foundField = true;
1018                            if (field_content_len>SIGNIFICANT_FIELD_CHARS) {
1019                                field_content[SIGNIFICANT_FIELD_CHARS] = 0;
1020                                field_content_len                      = SIGNIFICANT_FIELD_CHARS;
1021                            }
1022
1023                            char with_semi[SIGNIFICANT_FIELD_CHARS+2+1];
1024                            sprintf(with_semi, ";%s;", field_content);
1025
1026                            if (strstr(doneContents, with_semi)==0) { // field_content was not used yet
1027                                createGroupFromSelected(field_content, field_name, field_content);
1028                                tryAgain = true;
1029
1030                                int   newlen  = doneLen + field_content_len + 1;
1031                                char *newDone = (char*)malloc(newlen+1);
1032
1033                                GBS_global_string_to_buffer(newDone, newlen+1, "%s%s;", doneContents, field_content);
1034                                freeset(doneContents, newDone);
1035                                doneLen = newlen;
1036                            }
1037                            free(field_content);
1038                        }
1039                        else {
1040                            error = "Incompatible field type";
1041                        }
1042                    }
1043                    else {
1044                        if (GB_have_error()) error = GB_await_error();
1045                    }
1046                }
1047                list_elem = list_elem->next();
1048            }
1049        }
1050
1051        if (!error) {
1052            if      (!foundSpecies) error = "Please select some species in order to insert them into new groups";
1053            else if (!foundField)   error = GBS_global_string("Field not found: '%s'%s", field_name, error ? GBS_global_string(" (Reason: %s)", error) : "");
1054        }
1055
1056        free(doneContents);
1057        free(field_name);
1058    }
1059
1060    GB_end_transaction_show_error(GLOBAL_gb_main, error, aw_message);
1061}
1062
1063static void group_species_by_field_content(AW_window*, AW_window *use_as_main_window, AW_window *window_to_hide) {
1064    group_species(true, use_as_main_window);
1065    window_to_hide->hide();
1066}
1067
1068static AW_window *create_group_species_by_field_window(AW_root *aw_root, AW_window *use_as_main_window) {
1069    AW_window_simple *aws = new AW_window_simple;
1070
1071    aws->init(aw_root, "CREATE_GROUP_USING_FIELD_CONTENT", "Create groups using field");
1072    aws->auto_space(10, 10);
1073
1074    aws->button_length(10);
1075    aws->at_newline();
1076
1077    aws->callback(AW_POPDOWN);
1078    aws->create_button("CLOSE", "CLOSE", "C");
1079
1080    aws->callback(makeHelpCallback("group_by_field.hlp"));
1081    aws->create_button("HELP", "HELP", "H");
1082
1083    aws->at_newline();
1084    aws->label("Use content of field");
1085    create_itemfield_selection_button(aws, FieldSelDef(AWAR_FIELD_CHOSEN, GLOBAL_gb_main, SPECIES_get_selector(), FIELD_FILTER_STRING_READABLE, "group-field"), NULL);
1086
1087    aws->at_newline();
1088    aws->callback(makeWindowCallback(group_species_by_field_content, use_as_main_window, static_cast<AW_window*>(aws)));
1089    aws->create_autosize_button("USE_FIELD", "Group selected species by content", "");
1090
1091    return aws;
1092}
1093
1094void group_species_cb(AW_window *aww, bool use_fields) {
1095    if (!use_fields) {
1096        group_species(false, aww);
1097    }
1098    else {
1099        static AW_window *ask_field_window;
1100
1101        if (!ask_field_window) ask_field_window = create_group_species_by_field_window(ED4_ROOT->aw_root, aww);
1102        ask_field_window->activate();
1103    }
1104}
1105
1106static GB_ERROR ED4_load_new_config(char *name) {
1107    GB_ERROR error;
1108    GBT_config cfg(GLOBAL_gb_main, name, error);
1109    if (cfg.exists()) {
1110        ED4_ROOT->main_manager->clear_whole_background();
1111        ED4_calc_terminal_extentions();
1112
1113        max_seq_terminal_length = 0;
1114
1115        ED4_init_notFoundMessage();
1116
1117        if (ED4_ROOT->selected_objects->size() > 0) {
1118            ED4_ROOT->deselect_all();
1119        }
1120
1121        ED4_ROOT->remove_all_callbacks();
1122
1123        ED4_ROOT->scroll_picture.scroll = 0;
1124        ED4_ROOT->scroll_picture.old_x  = 0;
1125        ED4_ROOT->scroll_picture.old_y  = 0;
1126
1127        ED4_ROOT->ref_terminals.clear();
1128
1129        for (ED4_window *window = ED4_ROOT->first_window; window; window=window->next) {
1130            window->cursor.init();
1131            window->aww->set_horizontal_scrollbar_position (0);
1132            window->aww->set_vertical_scrollbar_position (0);
1133        }
1134
1135        ED4_ROOT->scroll_links.link_for_hor_slider = NULL;
1136        ED4_ROOT->scroll_links.link_for_ver_slider = NULL;
1137        ED4_ROOT->middle_area_man                  = NULL;
1138        ED4_ROOT->top_area_man                     = NULL;
1139
1140        delete ED4_ROOT->main_manager;
1141        ED4_ROOT->main_manager = NULL;
1142        delete ED4_ROOT->ecoli_ref;
1143
1144        ED4_ROOT->first_window->reset_all_for_new_config();
1145        ED4_ROOT->create_hierarchy(cfg.get_definition(GBT_config::MIDDLE_AREA), cfg.get_definition(GBT_config::TOP_AREA));
1146    }
1147
1148    return error;
1149}
1150
1151static ED4_EDITMODE ED4_get_edit_mode(AW_root *root) {
1152    if (!root->awar(AWAR_EDIT_MODE)->read_int()) return AD_ALIGN;
1153    return root->awar(AWAR_INSERT_MODE)->read_int() ? AD_INSERT : AD_REPLACE;
1154}
1155
1156void ed4_changesecurity(AW_root *root) {
1157    ED4_EDITMODE  mode      = ED4_get_edit_mode(root);
1158    const char   *awar_name = 0;
1159
1160    switch (mode) {
1161        case AD_ALIGN:
1162            awar_name = AWAR_EDIT_SECURITY_LEVEL_ALIGN;
1163            break;
1164        default:
1165            awar_name = AWAR_EDIT_SECURITY_LEVEL_CHANGE;
1166    }
1167
1168    ED4_ROOT->aw_root->awar(AWAR_EDIT_SECURITY_LEVEL)->map(awar_name);
1169
1170    long level = ED4_ROOT->aw_root->awar(awar_name)->read_int();
1171    GB_change_my_security(GLOBAL_gb_main, level);
1172}
1173
1174void ed4_change_edit_mode(AW_root *root) {
1175    awar_edit_mode = ED4_get_edit_mode(root);
1176    ed4_changesecurity(root);
1177}
1178
1179ARB_ERROR rebuild_consensus(ED4_base *object) {
1180    if (object->is_consensus_manager()) {
1181        ED4_species_manager *spec_man = object->to_species_manager();
1182        spec_man->do_callbacks();
1183
1184        ED4_base *sequence_data_terminal = object->search_spec_child_rek(ED4_L_SEQUENCE_STRING);
1185        sequence_data_terminal->request_refresh();
1186    }
1187    return NULL;
1188}
1189
1190void ED4_new_editor_window(AW_window *aww) {
1191    ED4_LocalWinContext uses(aww);
1192
1193    AW_device  *device;
1194    ED4_window *new_window = 0;
1195
1196    if (ED4_ROOT->generate_window(&device, &new_window) != ED4_R_BREAK) {
1197        ED4_LocalWinContext now_uses(new_window);
1198
1199        new_window->set_scrolled_rectangle(ED4_ROOT->scroll_links.link_for_hor_slider,
1200                                           ED4_ROOT->scroll_links.link_for_ver_slider,
1201                                           ED4_ROOT->scroll_links.link_for_hor_slider,
1202                                           ED4_ROOT->scroll_links.link_for_ver_slider);
1203
1204        new_window->aww->show();
1205        new_window->update_scrolled_rectangle();
1206    }
1207}
1208
1209
1210
1211static void ED4_start_editor_on_configuration(AW_window *aww) {
1212    aww->hide();
1213
1214    GB_ERROR error;
1215    {
1216        char *name = aww->get_root()->awar(AWAR_EDIT_CONFIGURATION)->read_string();
1217        error      = ED4_load_new_config(name);
1218        free(name);
1219    }
1220
1221    if (error) {
1222        aw_message(error);
1223        aww->show(); // show old window
1224    }
1225}
1226
1227struct cursorpos {
1228    ED4_cursor& cursor;
1229    int screen_rel;
1230    int seq;
1231
1232    cursorpos(ED4_window *win)
1233        : cursor(win->cursor),
1234          screen_rel(cursor.get_screen_relative_pos()),
1235          seq(cursor.get_sequence_pos())
1236    {}
1237    cursorpos(const cursorpos& other)
1238        : cursor(other.cursor),
1239          screen_rel(other.screen_rel),
1240          seq(other.seq)
1241    {}
1242    DECLARE_ASSIGNMENT_OPERATOR(cursorpos);
1243};
1244
1245
1246void ED4_compression_changed_cb(AW_root *awr) {
1247    ED4_remap_mode mode    = (ED4_remap_mode)awr->awar(ED4_AWAR_COMPRESS_SEQUENCE_TYPE)->read_int();
1248    int            percent = awr->awar(ED4_AWAR_COMPRESS_SEQUENCE_PERCENT)->read_int();
1249    GB_transaction ta(GLOBAL_gb_main);
1250
1251    if (ED4_ROOT->root_group_man) {
1252        vector<cursorpos> pos;
1253
1254        for (ED4_window *win = ED4_ROOT->first_window; win; win = win->next) {
1255            pos.push_back(cursorpos(win));
1256        }
1257
1258        ED4_ROOT->root_group_man->remap()->set_mode(mode, percent);
1259        ED4_expose_recalculations();
1260
1261        for (vector<cursorpos>::const_iterator i = pos.begin(); i != pos.end(); ++i) {
1262            ED4_cursor&  cursor = const_cast<ED4_cursor&>(i->cursor);
1263            ED4_window  *win    = cursor.window();
1264
1265            win->update_scrolled_rectangle(); // @@@ needed ?
1266
1267            cursor.jump_sequence_pos(i->seq, ED4_JUMP_KEEP_POSITION);
1268            cursor.set_screen_relative_pos(i->screen_rel);
1269        }
1270
1271        ED4_request_full_instant_refresh();
1272    }
1273}
1274
1275void ED4_compression_toggle_changed_cb(AW_root *root, bool hideChanged) {
1276    int gaps = root->awar(ED4_AWAR_COMPRESS_SEQUENCE_GAPS)->read_int();
1277    int hide = root->awar(ED4_AWAR_COMPRESS_SEQUENCE_HIDE)->read_int();
1278
1279    ED4_remap_mode mode = ED4_remap_mode(root->awar(ED4_AWAR_COMPRESS_SEQUENCE_TYPE)->read_int()); // @@@ mode is overwritten below
1280
1281    if (hideChanged) {
1282        // ED4_AWAR_COMPRESS_SEQUENCE_HIDE changed
1283        if (hide!=0 && gaps!=2) {
1284            root->awar(ED4_AWAR_COMPRESS_SEQUENCE_GAPS)->write_int(2);
1285            return;
1286        }
1287    }
1288    else {
1289        // ED4_AWAR_COMPRESS_SEQUENCE_GAPS changed
1290        if (gaps!=2 && hide!=0) {
1291            root->awar(ED4_AWAR_COMPRESS_SEQUENCE_HIDE)->write_int(0);
1292            return;
1293        }
1294    }
1295
1296    mode = ED4_RM_NONE;
1297    switch (gaps) {
1298        case 0: mode = ED4_RM_NONE; break;
1299        case 1: mode = ED4_RM_DYNAMIC_GAPS; break;
1300        case 2: {
1301            switch (hide) {
1302                case 0: mode = ED4_RM_MAX_ALIGN; break;
1303                case 1: mode = ED4_RM_SHOW_ABOVE; break;
1304                default: e4_assert(0); break;
1305            }
1306            break;
1307        }
1308        default: e4_assert(0); break;
1309    }
1310
1311    root->awar(ED4_AWAR_COMPRESS_SEQUENCE_TYPE)->write_int(int(mode));
1312}
1313
1314static AWT_config_mapping_def editor_options_config_mapping[] = {
1315    { ED4_AWAR_COMPRESS_SEQUENCE_GAPS,    "compressgaps" },
1316    { ED4_AWAR_COMPRESS_SEQUENCE_HIDE,    "hidenucs" },
1317    { ED4_AWAR_COMPRESS_SEQUENCE_PERCENT, "hidepercent" },
1318    { AWAR_EDIT_HELIX_SPACING,            "helixspacing" },
1319    { AWAR_EDIT_TERMINAL_SPACING,         "terminalspacing" },
1320    { ED4_AWAR_SCROLL_SPEED_X,            "scrollspeedx" },
1321    { ED4_AWAR_SCROLL_SPEED_Y,            "scrollspeedy" },
1322    { ED4_AWAR_SCROLL_MARGIN,             "scrollmargin" },
1323    { ED4_AWAR_GAP_CHARS,                 "gapchars" },
1324    { ED4_AWAR_DIGITS_AS_REPEAT,          "digitsasrepeat" },
1325    { ED4_AWAR_FAST_CURSOR_JUMP,          "fastcursorjump" },
1326    { ED4_AWAR_ANNOUNCE_CHECKSUM_CHANGES, "announcechecksumchanges" },
1327
1328    { 0, 0 }
1329};
1330
1331AW_window *ED4_create_editor_options_window(AW_root *root) {
1332    AW_window_simple *aws = new AW_window_simple;
1333
1334    aws->init(root, "EDIT4_PROPS", "EDIT4 Options");
1335    aws->load_xfig("edit4/options.fig");
1336
1337    aws->auto_space(5, 5);
1338
1339    const int SCALEDCOLUMNS = 4;
1340    const int SCALERLEN     = 200;
1341
1342    aws->callback(AW_POPDOWN);
1343    aws->at("close");
1344    aws->create_button("CLOSE", "CLOSE", "C");
1345
1346    aws->callback(makeHelpCallback("e4_options.hlp"));
1347    aws->at("help");
1348    aws->create_button("HELP", "HELP", "H");
1349
1350    //  -----------------------------------
1351    //      Online Sequence Compression
1352
1353    aws->at("gaps");
1354    aws->create_toggle_field(ED4_AWAR_COMPRESS_SEQUENCE_GAPS);
1355    aws->insert_default_toggle("Show all gaps", "A", 0);
1356    aws->insert_toggle("Show some gaps", "S", 1);
1357    aws->insert_toggle("Hide all gaps", "H", 2);
1358    aws->update_toggle_field();
1359
1360    aws->at("hide");
1361    aws->create_toggle_field(ED4_AWAR_COMPRESS_SEQUENCE_HIDE);
1362    aws->insert_default_toggle("Hide no Nucleotides", "0", 0);
1363    aws->insert_toggle("Hide columns with less than...", "1", 1);
1364    aws->update_toggle_field();
1365
1366    aws->at("percent");
1367    aws->create_input_field_with_scaler(ED4_AWAR_COMPRESS_SEQUENCE_PERCENT, SCALEDCOLUMNS, SCALERLEN, AW_SCALER_LINEAR);
1368
1369    //  --------------
1370    //      Layout
1371
1372    aws->at("seq_helix"); aws->create_input_field_with_scaler(AWAR_EDIT_HELIX_SPACING,    SCALEDCOLUMNS, SCALERLEN, AW_SCALER_EXP_CENTER);
1373    aws->at("seq_seq");   aws->create_input_field_with_scaler(AWAR_EDIT_TERMINAL_SPACING, SCALEDCOLUMNS, SCALERLEN, AW_SCALER_EXP_CENTER);
1374
1375    //  --------------------
1376    //      Scroll-Speed
1377
1378    aws->at("scroll_x");
1379    aws->create_input_field(ED4_AWAR_SCROLL_SPEED_X);
1380
1381    aws->at("scroll_y");
1382    aws->create_input_field(ED4_AWAR_SCROLL_SPEED_Y);
1383
1384    aws->at("margin");
1385    aws->create_input_field(ED4_AWAR_SCROLL_MARGIN);
1386
1387    //  ---------------
1388    //      Editing
1389
1390    aws->at("gapchars");
1391    aws->create_input_field(ED4_AWAR_GAP_CHARS);
1392
1393    aws->at("repeat");
1394    aws->create_toggle(ED4_AWAR_DIGITS_AS_REPEAT);
1395
1396    aws->at("fast");
1397    aws->create_toggle(ED4_AWAR_FAST_CURSOR_JUMP);
1398
1399    aws->at("checksum");
1400    aws->create_toggle(ED4_AWAR_ANNOUNCE_CHECKSUM_CHANGES);
1401
1402    aws->at("config");
1403    AWT_insert_config_manager(aws, AW_ROOT_DEFAULT, "options", editor_options_config_mapping);
1404
1405    return aws;
1406}
1407
1408static AWT_config_mapping_def consensus_config_mapping[] = {
1409    { ED4_AWAR_CONSENSUS_COUNTGAPS,   CONSENSUS_CONFIG_COUNTGAPS },
1410    { ED4_AWAR_CONSENSUS_GAPBOUND,    CONSENSUS_CONFIG_GAPBOUND },
1411    { ED4_AWAR_CONSENSUS_GROUP,       CONSENSUS_CONFIG_GROUP },
1412    { ED4_AWAR_CONSENSUS_CONSIDBOUND, CONSENSUS_CONFIG_CONSIDBOUND },
1413    { ED4_AWAR_CONSENSUS_UPPER,       CONSENSUS_CONFIG_UPPER },
1414    { ED4_AWAR_CONSENSUS_LOWER,       CONSENSUS_CONFIG_LOWER },
1415
1416    { 0, 0 }
1417};
1418
1419AW_window *ED4_create_consensus_definition_window(AW_root *root) {
1420    // keep in sync with ../NTREE/AP_consensus.cxx@AP_create_con_expert_window
1421
1422    static AW_window_simple *aws = 0;
1423
1424    if (!aws) {
1425        aws = new AW_window_simple;
1426
1427        aws->init(root, "EDIT4_CONSENSUS_DEFm", "EDIT4 Consensus Definition");
1428        aws->load_xfig("edit4/consensus.fig");
1429
1430        aws->auto_space(5, 5);
1431
1432        const int SCALEDCOLUMNS = 3;
1433        const int SCALERSIZE    = 150;
1434
1435        // top part of window:
1436        aws->button_length(9);
1437
1438        aws->callback(AW_POPDOWN);
1439        aws->at("close");
1440        aws->create_button("CLOSE", "CLOSE", "C");
1441
1442        aws->callback(makeHelpCallback("e4_consensus.hlp"));
1443        aws->at("help");
1444        aws->create_button("HELP", "HELP", "H");
1445
1446        // center part of window (same as in NTREE):
1447        aws->at("countgaps");
1448        aws->create_toggle_field(ED4_AWAR_CONSENSUS_COUNTGAPS);
1449        aws->insert_toggle("on", "1", 1);
1450        aws->insert_default_toggle("off", "0", 0);
1451        aws->update_toggle_field();
1452
1453        aws->at("gapbound");
1454        aws->create_input_field_with_scaler(ED4_AWAR_CONSENSUS_GAPBOUND, SCALEDCOLUMNS, SCALERSIZE, AW_SCALER_LINEAR);
1455
1456        aws->at("group");
1457        aws->create_toggle_field(ED4_AWAR_CONSENSUS_GROUP);
1458        aws->insert_toggle("on", "1", 1);
1459        aws->insert_default_toggle("off", "0", 0);
1460        aws->update_toggle_field();
1461
1462        aws->at("considbound");
1463        aws->create_input_field_with_scaler(ED4_AWAR_CONSENSUS_CONSIDBOUND, SCALEDCOLUMNS, SCALERSIZE, AW_SCALER_LINEAR);
1464
1465        aws->at("showgroups");
1466        aws->callback(AWT_create_IUPAC_info_window);
1467        aws->create_autosize_button("SHOW_IUPAC", "Show IUPAC groups", "S");
1468
1469        aws->at("upper");
1470        aws->create_input_field_with_scaler(ED4_AWAR_CONSENSUS_UPPER, SCALEDCOLUMNS, SCALERSIZE, AW_SCALER_LINEAR);
1471
1472        aws->at("lower");
1473        aws->create_input_field_with_scaler(ED4_AWAR_CONSENSUS_LOWER, SCALEDCOLUMNS, SCALERSIZE, AW_SCALER_LINEAR);
1474
1475        // bottom part of window:
1476        aws->at("show");
1477        aws->label("Display consensus?");
1478        aws->create_toggle(ED4_AWAR_CONSENSUS_SHOW);
1479
1480        aws->at("config");
1481        AWT_insert_config_manager(aws, AW_ROOT_DEFAULT, CONSENSUS_CONFIG_ID, consensus_config_mapping);
1482    }
1483
1484    return aws;
1485}
1486
1487static void consensus_upper_lower_changed_cb(AW_root *awr, bool upper_changed) {
1488    AW_awar *awar_lower = awr->awar(ED4_AWAR_CONSENSUS_LOWER);
1489    AW_awar *awar_upper = awr->awar(ED4_AWAR_CONSENSUS_UPPER);
1490
1491    int lower = awar_lower->read_int();
1492    int upper = awar_upper->read_int();
1493
1494    if (upper<lower) {
1495        if (upper_changed) awar_lower->write_int(upper);
1496        else               awar_upper->write_int(lower);
1497    }
1498    ED4_consensus_definition_changed(awr);
1499}
1500
1501void ED4_create_consensus_awars(AW_root *aw_root) {
1502    GB_transaction ta(GLOBAL_gb_main);
1503
1504    aw_root->awar_int(ED4_AWAR_CONSENSUS_COUNTGAPS,   1) ->add_callback(ED4_consensus_definition_changed);
1505    aw_root->awar_int(ED4_AWAR_CONSENSUS_GROUP,       1) ->add_callback(ED4_consensus_definition_changed);
1506    aw_root->awar_int(ED4_AWAR_CONSENSUS_GAPBOUND,    60)->set_minmax(0, 100)->add_callback(ED4_consensus_definition_changed);
1507    aw_root->awar_int(ED4_AWAR_CONSENSUS_CONSIDBOUND, 30)->set_minmax(0, 100)->add_callback(ED4_consensus_definition_changed);
1508    aw_root->awar_int(ED4_AWAR_CONSENSUS_UPPER,       95)->set_minmax(0, 100)->add_callback(makeRootCallback(consensus_upper_lower_changed_cb, true));
1509    aw_root->awar_int(ED4_AWAR_CONSENSUS_LOWER,       70)->set_minmax(0, 100)->add_callback(makeRootCallback(consensus_upper_lower_changed_cb, false));
1510
1511    AW_awar *cons_show = aw_root->awar_int(ED4_AWAR_CONSENSUS_SHOW, 1);
1512
1513    cons_show->write_int(1);
1514    cons_show->add_callback(ED4_consensus_display_changed);
1515}
1516
1517void ED4_reloadConfiguration(AW_window *aww) {
1518    ED4_start_editor_on_configuration(aww);
1519}
1520
1521AW_window *ED4_create_loadConfiguration_window(AW_root *awr) {
1522    static AW_window_simple *aws = 0;
1523    if (!aws) {
1524        aws = new AW_window_simple;
1525        aws->init(awr, "LOAD_CONFIGURATION", "Load existing configuration");
1526        aws->load_xfig("edit4/load_config.fig");
1527
1528        aws->at("close");
1529        aws->callback(AW_POPDOWN);
1530        aws->create_button("CLOSE", "CLOSE", "C");
1531
1532        aws->at("help");
1533        aws->callback(makeHelpCallback("species_configs_saveload.hlp"));
1534        aws->create_button("HELP", "HELP");
1535
1536        aws->at("confs");
1537        awt_create_CONFIG_selection_list(GLOBAL_gb_main, aws, AWAR_EDIT_CONFIGURATION, false);
1538
1539        aws->at("go");
1540        aws->callback(ED4_start_editor_on_configuration);
1541        aws->create_button("LOAD", "LOAD");
1542
1543        aws->window_fit();
1544    }
1545    return aws;
1546}
1547
1548void ED4_saveConfiguration(AW_window *aww, bool hide_aww) {
1549    if (hide_aww) aww->hide();
1550
1551    char *name = aww->get_root()->awar(AWAR_EDIT_CONFIGURATION)->read_string();
1552    ED4_ROOT->database->save_current_config(name);
1553    free(name);
1554}
1555
1556AW_window *ED4_create_saveConfigurationAs_window(AW_root *awr) {
1557    static AW_window_simple *aws = 0;
1558    if (!aws) {
1559        aws = new AW_window_simple;
1560        aws->init(awr, "SAVE_CONFIGURATION", "Save current configuration as");
1561        aws->load_xfig("edit4/save_config.fig");
1562
1563        aws->at("close");
1564        aws->callback(AW_POPDOWN);
1565        aws->create_button("CLOSE", "CLOSE");
1566
1567        aws->at("help");
1568        aws->callback(makeHelpCallback("species_configs_saveload.hlp"));
1569        aws->create_button("HELP", "HELP");
1570
1571        aws->at("save");
1572        aws->create_input_field(AWAR_EDIT_CONFIGURATION);
1573
1574        aws->at("confs");
1575        awt_create_CONFIG_selection_list(GLOBAL_gb_main, aws, AWAR_EDIT_CONFIGURATION, false);
1576
1577        aws->at("go");
1578        aws->callback(makeWindowCallback(ED4_saveConfiguration, true));
1579        aws->create_button("SAVE", "SAVE");
1580    }
1581    return aws;
1582}
1583
1584static char *filter_loadable_SAIs(GBDATA *gb_sai) {
1585    GBDATA *gb_ali = GB_search(gb_sai, ED4_ROOT->alignment_name, GB_FIND);
1586    if (gb_ali) {
1587        GBDATA *gb_data = GB_search(gb_ali, "data", GB_FIND);
1588        if (gb_data) {
1589            const char *sai_name = GBT_get_name(gb_sai);
1590            if (!ED4_find_SAI_name_terminal(sai_name)) { // if not loaded yet
1591                return strdup(sai_name);
1592            }
1593        }
1594    }
1595    return NULL;
1596}
1597
1598AW_window *ED4_create_loadSAI_window(AW_root *awr) {
1599    static AW_window_simple *aws = 0;
1600    if (!aws) {
1601        aws = new AW_window_simple;
1602        aws->init(awr, "LOAD_SAI", "Load additional SAI");
1603        aws->load_xfig("edit4/load_sai.fig");
1604
1605        aws->at("close");
1606        aws->callback(AW_POPDOWN);
1607        aws->create_button("CLOSE", "CLOSE");
1608
1609        aws->at("help");
1610        aws->callback(makeHelpCallback("e4_get_species.hlp"));
1611        aws->create_button("HELP", "HELP");
1612
1613        aws->at("sai");
1614        awt_create_SAI_selection_list(GLOBAL_gb_main, aws, AWAR_SAI_NAME, false, makeSaiSelectionlistFilterCallback(filter_loadable_SAIs));
1615        ED4_ROOT->loadable_SAIs = LSAI_UPTODATE;
1616
1617        aws->at("go");
1618        aws->callback(ED4_get_and_jump_to_selected_SAI);
1619        aws->create_button("LOAD", "LOAD");
1620    }
1621    return aws;
1622}
1623
1624static GB_ERROR createDataFromConsensus(GBDATA *gb_species, ED4_group_manager *group_man) {
1625    GB_ERROR error = 0;
1626
1627    int   len;
1628    char *consensus = group_man->build_consensus_string(&len);
1629
1630    char *equal_to = ED4_ROOT->aw_root->awar(ED4_AWAR_CREATE_FROM_CONS_REPL_EQUAL)->read_string();
1631    char *point_to = ED4_ROOT->aw_root->awar(ED4_AWAR_CREATE_FROM_CONS_REPL_POINT)->read_string();
1632    int   allUpper = ED4_ROOT->aw_root->awar(ED4_AWAR_CREATE_FROM_CONS_ALL_UPPER)->read_int();
1633
1634    for (int p=0; p<len; p++) {
1635        switch (consensus[p]) {
1636            case '=': consensus[p] = equal_to[0]; break;
1637            case '.': consensus[p] = point_to[0]; break;
1638            default: {
1639                if (allUpper) {
1640                    consensus[p] = toupper(consensus[p]);
1641                }
1642                break;
1643            }
1644        }
1645    }
1646
1647    if (ED4_ROOT->aw_root->awar(ED4_AWAR_CREATE_FROM_CONS_CREATE_POINTS)) { // points at start & end of sequence?
1648        for (int p=0; p<len; p++) {
1649            if (!ED4_is_gap_character(consensus[p])) break;
1650            consensus[p] = '.';
1651        }
1652        for (int p=len-1; p>=0; p--) {
1653            if (!ED4_is_gap_character(consensus[p])) break;
1654            consensus[p] = '.';
1655        }
1656    }
1657
1658    GB_CSTR ali = GBT_get_default_alignment(GLOBAL_gb_main);
1659    GBDATA *gb_ali = GB_search(gb_species, ali, GB_DB);
1660    if (gb_ali) {
1661        GBDATA *gb_data = GB_search(gb_ali, "data", GB_STRING);
1662        error = GB_write_pntr(gb_data, consensus, len+1, len);
1663    }
1664    else {
1665        error = GB_export_errorf("Can't find alignment '%s'", ali);
1666    }
1667    free(consensus);
1668    return error;
1669}
1670
1671// --------------------------------------------------------------------------------
1672
1673struct SpeciesMergeList {
1674    GBDATA *species;
1675    char   *species_name;
1676
1677    SpeciesMergeList *next;
1678};
1679
1680static ARB_ERROR add_species_to_merge_list(ED4_base *base, SpeciesMergeList **smlp, GBDATA *gb_species_data) {
1681    GB_ERROR error = NULL;
1682
1683    if (base->is_species_name_terminal()) {
1684        ED4_species_name_terminal *name_term = base->to_species_name_terminal();
1685
1686        if (!name_term->inside_consensus_manager()) {
1687            char   *species_name    = name_term->resolve_pointer_to_string_copy();
1688            GBDATA *gb_species      = GBT_find_species_rel_species_data(gb_species_data, species_name);
1689
1690            if (gb_species) {
1691                SpeciesMergeList *sml = new SpeciesMergeList;
1692
1693                sml->species      = gb_species;
1694                sml->species_name = strdup(species_name);
1695                sml->next         = *smlp;
1696                *smlp             = sml;
1697            }
1698            else {
1699                error = GB_append_exportedError(GBS_global_string("can't find species '%s'", species_name));
1700            }
1701
1702            free(species_name);
1703        }
1704    }
1705    return error;
1706}
1707static int SpeciesMergeListLength(SpeciesMergeList *sml)
1708{
1709    int length = 0;
1710
1711    while (sml) {
1712        length++;
1713        sml = sml->next;
1714    }
1715
1716    return length;
1717}
1718static void freeSpeciesMergeList(SpeciesMergeList *sml) {
1719    while (sml) {
1720        free(sml->species_name);
1721        freeset(sml, sml->next);
1722    }
1723}
1724
1725// --------------------------------------------------------------------------------
1726
1727inline bool nameIsUnique(const char *short_name, GBDATA *gb_species_data) {
1728    return GBT_find_species_rel_species_data(gb_species_data, short_name)==0;
1729}
1730
1731
1732static void create_new_species(AW_window *, SpeciesCreationMode creation_mode) {
1733    char      *new_species_full_name = ED4_ROOT->aw_root->awar(ED4_AWAR_SPECIES_TO_CREATE)->read_string(); // this contains the full_name now!
1734    ARB_ERROR  error                 = 0;
1735
1736    e4_assert(creation_mode>=0 && creation_mode<=2);
1737
1738    if (!new_species_full_name || new_species_full_name[0]==0) {
1739        error = "Please enter a full_name for the new species";
1740    }
1741    else {
1742        ED4_MostRecentWinContext context;
1743
1744        error = GB_begin_transaction(GLOBAL_gb_main);
1745
1746        GBDATA *gb_species_data  = GBT_get_species_data(GLOBAL_gb_main);
1747        char   *new_species_name = 0;
1748        char   *acc              = 0;
1749        char   *addid            = 0;
1750
1751        enum e_dataSource { MERGE_FIELDS, COPY_FIELDS } dataSource = (enum e_dataSource)ED4_ROOT->aw_root ->awar(ED4_AWAR_CREATE_FROM_CONS_DATA_SOURCE)->read_int();
1752        enum { NOWHERE, ON_SPECIES, ON_CONSENSUS } where_we_are = NOWHERE;
1753        ED4_terminal *cursor_terminal = 0;
1754
1755        if (!error) {
1756            if (creation_mode==CREATE_FROM_CONSENSUS || creation_mode==COPY_SPECIES) {
1757                ED4_cursor *cursor = &current_cursor();
1758
1759                if (cursor->owner_of_cursor) {
1760                    cursor_terminal = cursor->owner_of_cursor;
1761                    where_we_are    = cursor_terminal->is_consensus_terminal() ? ON_CONSENSUS : ON_SPECIES;
1762                }
1763            }
1764
1765            if (creation_mode==COPY_SPECIES || (creation_mode==CREATE_FROM_CONSENSUS && dataSource==COPY_FIELDS)) {
1766                if (where_we_are==ON_SPECIES) {
1767                    ED4_species_name_terminal *spec_name   = cursor_terminal->to_sequence_terminal()->corresponding_species_name_terminal();
1768                    const char                *source_name = spec_name->resolve_pointer_to_char_pntr();
1769                    GBDATA                    *gb_source   = GBT_find_species_rel_species_data(gb_species_data, source_name);
1770
1771                    if (!gb_source) error = GBS_global_string("No such species: '%s'", source_name);
1772                    else {
1773                        GBDATA *gb_acc  = GB_search(gb_source, "acc", GB_FIND);
1774                        if (gb_acc) acc = GB_read_string(gb_acc); // if has accession
1775
1776                        const char *add_field = AW_get_nameserver_addid(GLOBAL_gb_main);
1777                        GBDATA     *gb_addid  = add_field[0] ? GB_search(gb_source, add_field, GB_FIND) : 0;
1778                        if (gb_addid) addid   = GB_read_as_string(gb_addid);
1779                    }
1780                }
1781                else {
1782                    error = "Please place cursor on a species";
1783                }
1784            }
1785        }
1786
1787        if (!error) {
1788            UniqueNameDetector *existingNames = 0;
1789
1790            if (creation_mode==0) {
1791                error = "It's no good idea to create the short-name for a new species using the nameserver! (has no acc yet)";
1792            }
1793            else {
1794                error = AWTC_generate_one_name(GLOBAL_gb_main, new_species_full_name, acc, addid, new_species_name);
1795                if (!error) {   // name was created
1796                    if (!nameIsUnique(new_species_name, gb_species_data)) {
1797                        if (!existingNames) existingNames = new UniqueNameDetector(gb_species_data);
1798                        freeset(new_species_name, AWTC_makeUniqueShortName(new_species_name, *existingNames));
1799                        if (!new_species_name) error = GB_await_error();
1800                    }
1801                }
1802            }
1803
1804            if (error) {        // try to make a random name
1805                const char *msg = GBS_global_string("%s\nGenerating a random name instead.", error.deliver());
1806                aw_message(msg);
1807                error           = 0;
1808
1809                if (!existingNames) existingNames = new UniqueNameDetector(gb_species_data);
1810                new_species_name = AWTC_generate_random_name(*existingNames);
1811
1812                if (!new_species_name) {
1813                    error = GBS_global_string("Failed to create a new name for '%s'", new_species_full_name);
1814                }
1815            }
1816
1817            if (existingNames) delete existingNames;
1818        }
1819
1820        if (!error) {
1821            if (!error) {
1822                if (creation_mode==CREATE_NEW_SPECIES) {
1823                    GBDATA *gb_created_species = GBT_find_or_create_species(GLOBAL_gb_main, new_species_name);
1824                    if (!gb_created_species) {
1825                        error = GBS_global_string("Failed to create new species '%s'", new_species_name);
1826                    }
1827                    else {
1828                        GB_CSTR  ali    = GBT_get_default_alignment(GLOBAL_gb_main);
1829                        GBDATA  *gb_ali = GB_search(gb_created_species, ali, GB_DB);
1830
1831                        if (gb_ali) error = GBT_write_string(gb_ali, "data", ".......");
1832                        else error        = GBS_global_string("Can't create alignment '%s' (Reason: %s)", ali, GB_await_error());
1833                    }
1834                    if (!error) error = GBT_write_string(gb_created_species, "full_name", new_species_full_name);
1835                }
1836                else if (creation_mode==CREATE_FROM_CONSENSUS && dataSource==MERGE_FIELDS)
1837                { // create from consensus (merge fields from all species in container)
1838                    if (where_we_are==NOWHERE) {
1839                        error = "Please place cursor on any sequence/consensus of group";
1840                    }
1841                    else {
1842                        ED4_group_manager *group_man = cursor_terminal->get_parent(ED4_L_GROUP)->to_group_manager();
1843                        SpeciesMergeList  *sml       = 0;  // list of species in group
1844
1845                        error = group_man->route_down_hierarchy(makeED4_route_cb(add_species_to_merge_list, &sml, gb_species_data));
1846                        if (!error && !sml) {
1847                            error = "Please choose a none empty group!";
1848                        }
1849
1850                        GBDATA *gb_new_species = 0;
1851                        if (!error) {
1852                            GBDATA *gb_source = sml->species;
1853                            gb_new_species = GB_create_container(gb_species_data, "species");
1854                            error = GB_copy(gb_new_species, gb_source); // copy first found species to create a new species
1855                        }
1856                        if (!error) error = GBT_write_string(gb_new_species, "name", new_species_name); // insert new 'name'
1857                        if (!error) error = GBT_write_string(gb_new_species, "full_name", new_species_full_name); // insert new 'full_name'
1858                        if (!error) error = createDataFromConsensus(gb_new_species, group_man); // insert consensus as 'data'
1859
1860                        if (!error) {
1861                            char             *doneFields = strdup(";name;full_name;"); // all fields which are already merged
1862                            int               doneLen    = strlen(doneFields);
1863                            SpeciesMergeList *sl         = sml;
1864                            int               sl_length  = SpeciesMergeListLength(sml);
1865                            int              *fieldStat  = new int[sl_length];         // 0 = not used yet ; -1 = don't has field ; 1..n = field content, same number means same content
1866
1867                            arb_progress progress("Merging fields", sl_length);
1868
1869                            while (sl && !error) { // with all species do..
1870                                char *newFields = GB_get_subfields(sl->species);
1871                                char *fieldStart = newFields; // points to ; before next field
1872
1873                                while (fieldStart[1] && !error) { // with all subfields of the species do..
1874                                    char *fieldEnd = strchr(fieldStart+1, ';');
1875
1876                                    e4_assert(fieldEnd);
1877                                    char behind = fieldEnd[1];
1878                                    fieldEnd[1] = 0;
1879
1880                                    if (strstr(doneFields, fieldStart)==0) { // field is not merged yet
1881                                        char *fieldName = fieldStart+1;
1882                                        int fieldLen = int(fieldEnd-fieldName);
1883
1884                                        e4_assert(fieldEnd[0]==';');
1885                                        fieldEnd[0] = 0;
1886
1887                                        GBDATA *gb_field = GB_search(sl->species, fieldName, GB_FIND);
1888                                        e4_assert(gb_field); // field has to exist, cause it was found before
1889
1890                                        GB_TYPES type = GB_read_type(gb_field);
1891                                        if (type==GB_STRING) { // we only merge string fields
1892                                            int i;
1893                                            int doneSpecies = 0;
1894                                            int nextStat = 1;
1895
1896                                            for (i=0; i<sl_length; i++) { // clear field status
1897                                                fieldStat[i] = 0;
1898                                            }
1899
1900                                            while (doneSpecies<sl_length) { // since all species in list were handled
1901                                                SpeciesMergeList *sl2 = sml;
1902                                                i = 0;
1903
1904                                                while (sl2) {
1905                                                    if (fieldStat[i]==0) {
1906                                                        gb_field = GB_search(sl2->species, fieldName, GB_FIND);
1907                                                        if (gb_field) {
1908                                                            char *content = GB_read_as_string(gb_field);
1909                                                            SpeciesMergeList *sl3 = sl2->next;
1910
1911                                                            fieldStat[i] = nextStat;
1912                                                            doneSpecies++;
1913                                                            int j = i+1;
1914                                                            while (sl3) {
1915                                                                if (fieldStat[j]==0) {
1916                                                                    gb_field = GB_search(sl3->species, fieldName, GB_FIND);
1917                                                                    if (gb_field) {
1918                                                                        char *content2 = GB_read_as_string(gb_field);
1919
1920                                                                        if (strcmp(content, content2)==0) { // if contents are the same, they get the same status
1921                                                                            fieldStat[j] = nextStat;
1922                                                                            doneSpecies++;
1923                                                                        }
1924                                                                        free(content2);
1925                                                                    }
1926                                                                    else {
1927                                                                        fieldStat[j] = -1;
1928                                                                        doneSpecies++;
1929                                                                    }
1930                                                                }
1931                                                                sl3 = sl3->next;
1932                                                                j++;
1933                                                            }
1934
1935                                                            free(content);
1936                                                            nextStat++;
1937                                                        }
1938                                                        else {
1939                                                            fieldStat[i] = -1; // field does not exist here
1940                                                            doneSpecies++;
1941                                                        }
1942                                                    }
1943                                                    sl2 = sl2->next;
1944                                                    i++;
1945                                                }
1946                                            }
1947
1948                                            e4_assert(nextStat!=1); // this would mean that none of the species contained the field
1949
1950                                            {
1951                                                char *new_content = 0;
1952                                                int new_content_len = 0;
1953
1954                                                if (nextStat==2) { // all species contain same field content or do not have the field
1955                                                    SpeciesMergeList *sl2 = sml;
1956
1957                                                    while (sl2) {
1958                                                        gb_field = GB_search(sl2->species, fieldName, GB_FIND);
1959                                                        if (gb_field) {
1960                                                            new_content = GB_read_as_string(gb_field);
1961                                                            new_content_len = strlen(new_content); // @@@ new_content_len never used
1962                                                            break;
1963                                                        }
1964                                                        sl2 = sl2->next;
1965                                                    }
1966                                                }
1967                                                else { // different field contents
1968                                                    int currStat;
1969                                                    for (currStat=1; currStat<nextStat; currStat++) {
1970                                                        int names_len = 1; // open bracket
1971                                                        SpeciesMergeList *sl2 = sml;
1972                                                        i = 0;
1973                                                        char *content = 0;
1974
1975                                                        while (sl2) {
1976                                                            if (fieldStat[i]==currStat) {
1977                                                                names_len += strlen(sl2->species_name)+1;
1978                                                                if (!content) {
1979                                                                    gb_field = GB_search(sl2->species, fieldName, GB_FIND);
1980                                                                    e4_assert(gb_field);
1981                                                                    content = GB_read_as_string(gb_field);
1982                                                                }
1983                                                            }
1984                                                            sl2 = sl2->next;
1985                                                            i++;
1986                                                        }
1987
1988                                                        e4_assert(content);
1989                                                        int add_len = names_len+1+strlen(content);
1990                                                        char *whole = (char*)malloc(new_content_len+1+add_len+1);
1991                                                        e4_assert(whole);
1992                                                        char *add = new_content ? whole+sprintf(whole, "%s ", new_content) : whole;
1993                                                        sl2 = sml;
1994                                                        i = 0;
1995                                                        int first = 1;
1996                                                        while (sl2) {
1997                                                            if (fieldStat[i]==currStat) {
1998                                                                add += sprintf(add, "%c%s", first ? '{' : ';', sl2->species_name);
1999                                                                first = 0;
2000                                                            }
2001                                                            sl2 = sl2->next;
2002                                                            i++;
2003                                                        }
2004                                                        add += sprintf(add, "} %s", content);
2005
2006                                                        free(content);
2007
2008                                                        freeset(new_content, whole);
2009                                                        new_content_len = strlen(new_content);
2010                                                    }
2011                                                }
2012
2013                                                if (new_content) {
2014                                                    error = GBT_write_string(gb_new_species, fieldName, new_content);
2015                                                    free(new_content);
2016                                                }
2017                                            }
2018                                        }
2019
2020                                        // mark field as done:
2021                                        char *new_doneFields = (char*)malloc(doneLen+fieldLen+1+1);
2022                                        sprintf(new_doneFields, "%s%s;", doneFields, fieldName);
2023                                        doneLen += fieldLen+1;
2024                                        freeset(doneFields, new_doneFields);
2025
2026                                        fieldEnd[0] = ';';
2027                                    }
2028
2029                                    fieldEnd[1] = behind;
2030                                    fieldStart = fieldEnd;
2031                                }
2032                                free(newFields);
2033                                sl = sl->next;
2034                                progress.inc_and_check_user_abort(error);
2035                            }
2036                            free(doneFields);
2037                            delete [] fieldStat;
2038                        }
2039                        freeSpeciesMergeList(sml); sml = 0;
2040                    }
2041                }
2042                else { // copy species or create from consensus (copy fields from one species)
2043                    e4_assert(where_we_are==ON_SPECIES);
2044
2045                    ED4_species_name_terminal *spec_name   = cursor_terminal->to_sequence_terminal()->corresponding_species_name_terminal();
2046                    const char                *source_name = spec_name->resolve_pointer_to_char_pntr();
2047                    GBDATA                    *gb_source   = GBT_find_species_rel_species_data(gb_species_data, source_name);
2048
2049                    if (gb_source) {
2050                        GBDATA *gb_new_species = GB_create_container(gb_species_data, "species");
2051                        error                  = GB_copy(gb_new_species, gb_source);
2052                        if (!error) error      = GBT_write_string(gb_new_species, "name", new_species_name);
2053                        if (!error) error      = GBT_write_string(gb_new_species, "full_name", new_species_full_name); // insert new 'full_name'
2054                        if (!error && creation_mode==CREATE_FROM_CONSENSUS) {
2055                            ED4_group_manager *group_man = cursor_terminal->get_parent(ED4_L_GROUP)->to_group_manager();
2056                            error = createDataFromConsensus(gb_new_species, group_man);
2057                        }
2058                    }
2059                    else {
2060                        error = GBS_global_string("Can't find species '%s'", source_name);
2061                    }
2062                }
2063            }
2064
2065            error = GB_end_transaction(GLOBAL_gb_main, error);
2066            if (!error) ED4_get_and_jump_to_species(new_species_name);
2067        }
2068        else {
2069            GB_abort_transaction(GLOBAL_gb_main);
2070        }
2071
2072        free(addid);
2073        free(acc);
2074        free(new_species_name);
2075    }
2076
2077    aw_message_if(error);
2078    free(new_species_full_name);
2079}
2080
2081AW_window *ED4_create_new_seq_window(AW_root *root, SpeciesCreationMode creation_mode) {
2082    e4_assert(valid(creation_mode));
2083
2084    AW_window_simple *aws = new AW_window_simple;
2085    switch (creation_mode) {
2086        case CREATE_NEW_SPECIES:    aws->init(root, "create_species",                "Create species");                break;
2087        case CREATE_FROM_CONSENSUS: aws->init(root, "create_species_from_consensus", "Create species from consensus"); break;
2088        case COPY_SPECIES:          aws->init(root, "copy_species",                  "Copy current species");          break;
2089    }
2090   
2091    if (creation_mode==CREATE_FROM_CONSENSUS) {
2092        aws->load_xfig("edit4/create_seq_fc.fig");
2093    }
2094    else {
2095        aws->load_xfig("edit4/create_seq.fig");
2096    }
2097
2098    aws->callback(AW_POPDOWN);
2099    aws->at("close");
2100    aws->create_button("CLOSE", "CLOSE", "C");
2101
2102    aws->at("label");
2103    aws->create_autosize_button(0, "Please enter the FULL_NAME\nof the new species");
2104
2105    aws->at("input");
2106    aws->create_input_field(ED4_AWAR_SPECIES_TO_CREATE, 30);
2107
2108    aws->at("ok");
2109    aws->callback(makeWindowCallback(create_new_species, creation_mode));
2110    aws->create_button("GO", "GO", "g");
2111
2112    if (creation_mode==CREATE_FROM_CONSENSUS) {
2113        aws->at("replace_equal");
2114        aws->label("Replace '=' by ");
2115        aws->create_input_field(ED4_AWAR_CREATE_FROM_CONS_REPL_EQUAL, 1);
2116
2117        aws->at("replace_point");
2118        aws->label("Replace '.' by ");
2119        aws->create_input_field(ED4_AWAR_CREATE_FROM_CONS_REPL_POINT, 1);
2120
2121        aws->at("replace_start_end");
2122        aws->label("Create ... at ends of sequence?");
2123        aws->create_toggle(ED4_AWAR_CREATE_FROM_CONS_CREATE_POINTS);
2124
2125        aws->at("upper");
2126        aws->label("Convert all chars to upper?");
2127        aws->create_toggle(ED4_AWAR_CREATE_FROM_CONS_ALL_UPPER);
2128
2129        aws->at("data");
2130        aws->label("Other fields");
2131        aws->create_option_menu(ED4_AWAR_CREATE_FROM_CONS_DATA_SOURCE, true);
2132        aws->insert_default_option("Merge from all in group", "", 0);
2133        aws->insert_option("Copy from current species", "", 1);
2134        aws->update_option_menu();
2135    }
2136
2137    return aws;
2138}
2139
Note: See TracBrowser for help on using the repository browser.