root/trunk/EDIT4/ED4_no_class.cxx

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