source: branches/profile/EDIT4/ED4_no_class.cxx

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