source: branches/profile/SL/DB_UI/ui_species.cxx

Last change on this file was 12803, checked in by westram, 10 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 58.0 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : ui_species.cxx                                    //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include "dbui.h"
12
13#include <awt_sel_boxes.hxx>
14#include <arb_strbuf.h>
15#include <cmath>
16#include <probe_design.hxx>
17#include <arb_defs.h>
18#include <awtc_next_neighbours.hxx>
19#include <db_scanner.hxx>
20#include <db_query.h>
21#include <AW_rename.hxx>
22#include <aw_awar_defs.hxx>
23#include <aw_awar.hxx>
24#include <aw_root.hxx>
25#include <aw_msg.hxx>
26#include <aw_question.hxx>
27#include <algorithm>
28#include <arb_progress.h>
29#include <item_sel_list.h>
30#include <map>
31#include <info_window.h>
32
33using namespace DBUI;
34using namespace QUERY;
35
36#define ui_assert(cond) arb_assert(cond)
37
38#define AWAR_SPECIES_DEST "tmp/adspec/dest"
39#define AWAR_SPECIES_INFO "tmp/adspec/info"
40#define AWAR_SPECIES_KEY  "tmp/adspec/key"
41
42#define AWAR_FIELD_REORDER_SOURCE "tmp/ad_reorder/source"
43#define AWAR_FIELD_REORDER_DEST   "tmp/ad_reorder/dest"
44#define AWAR_FIELD_REORDER_ORDER  "tmp/ad_reorder/order"
45
46#define AWAR_FIELD_CREATE_NAME "tmp/adfield/name"
47#define AWAR_FIELD_CREATE_TYPE "tmp/adfield/type"
48#define AWAR_FIELD_DELETE      "tmp/adfield/source"
49
50#define AWAR_FIELD_CONVERT_SOURCE "tmp/adconvert/source"
51#define AWAR_FIELD_CONVERT_NAME   "tmp/adconvert/name"
52#define AWAR_FIELD_CONVERT_TYPE   "tmp/adconvert/type"
53
54// next neighbours of listed and selected:
55// more defined in ../../AWTC/awtc_next_neighbours.hxx@AWAR_NN_BASE
56#define AWAR_NN_COMPLEMENT  AWAR_NN_BASE "complement"
57#define AWAR_NN_RANGE_START AWAR_NN_BASE "range_start"
58#define AWAR_NN_RANGE_END   AWAR_NN_BASE "range_end"
59#define AWAR_NN_MIN_SCORE   AWAR_NN_BASE "min_scored"
60#define AWAR_NN_MAX_HITS    AWAR_NN_BASE "max_hits"
61
62// next neighbours of selected only:
63#define AWAR_NN_BASE_SELECTED        AWAR_NN_BASE "selected/"
64#define AWAR_NN_SELECTED_HIT_COUNT   "tmp/" AWAR_NN_BASE_SELECTED "hit_count"
65#define AWAR_NN_SELECTED_AUTO_SEARCH "tmp/" AWAR_NN_BASE_SELECTED "auto_search"
66#define AWAR_NN_SELECTED_AUTO_MARK   "tmp/" AWAR_NN_BASE_SELECTED "auto_mark"
67
68// next neighbours of listed only:
69#define AWAR_NN_BASE_LISTED           AWAR_NN_BASE "listed/"
70#define AWAR_NN_LISTED_DEST_FIELD     AWAR_NN_BASE_LISTED "dest_field"
71#define AWAR_NN_LISTED_SCORED_ENTRIES AWAR_NN_BASE_LISTED "scored_entries"
72
73enum ReorderMode {
74    // real orders
75    ORDER_ALPHA,
76    ORDER_TYPE,
77    ORDER_FREQ,
78   
79    // special modes
80    RIGHT_BEHIND_LEFT,
81    REVERSE_ORDER,
82};
83
84void DBUI::create_dbui_awars(AW_root *aw_root, AW_default aw_def) {
85    aw_root->awar_string(AWAR_SPECIES_DEST,         "",          aw_def);
86    aw_root->awar_string(AWAR_SPECIES_INFO,         "",          aw_def);
87    aw_root->awar_string(AWAR_SPECIES_KEY,          "",          aw_def);
88    aw_root->awar_string(AWAR_FIELD_REORDER_SOURCE, "",          aw_def);
89    aw_root->awar_string(AWAR_FIELD_REORDER_DEST,   "",          aw_def);
90    aw_root->awar_int   (AWAR_FIELD_REORDER_ORDER,  ORDER_ALPHA, aw_def);
91    aw_root->awar_string(AWAR_FIELD_CREATE_NAME,    "",          aw_def);
92    aw_root->awar_int   (AWAR_FIELD_CREATE_TYPE,    GB_STRING,   aw_def);
93    aw_root->awar_string(AWAR_FIELD_DELETE,         "",          aw_def);
94    aw_root->awar_string(AWAR_FIELD_CONVERT_SOURCE, "",          aw_def);
95    aw_root->awar_int   (AWAR_FIELD_CONVERT_TYPE,   GB_STRING,   aw_def);
96    aw_root->awar_string(AWAR_FIELD_CONVERT_NAME,   "",          aw_def);
97}
98
99static void move_species_to_extended(AW_window *aww, AW_CL cl_gb_main, AW_CL) {
100    GBDATA   *gb_main = (GBDATA*)cl_gb_main;
101    char     *source  = aww->get_root()->awar(AWAR_SPECIES_NAME)->read_string();
102    GB_ERROR  error   = GB_begin_transaction(gb_main);
103
104    if (!error) {
105        GBDATA *gb_sai_data     = GBT_get_SAI_data(gb_main);
106        if (!gb_sai_data) error = GB_await_error();
107        else {
108            GBDATA *gb_species = GBT_find_species(gb_main, source);
109            GBDATA *gb_dest    = GBT_find_SAI_rel_SAI_data(gb_sai_data, source);
110
111            if (gb_dest) error = GBS_global_string("SAI '%s' already exists", source);
112            else if (gb_species) {
113                gb_dest             = GB_create_container(gb_sai_data, "extended");
114                if (!gb_dest) error = GB_await_error();
115                else {
116                    error = GB_copy(gb_dest, gb_species);
117                    if (!error) {
118                        error = GB_delete(gb_species);
119                        if (!error) aww->get_root()->awar(AWAR_SPECIES_NAME)->write_string("");
120                    }
121                }
122            }
123            else error = "Please select a species";
124        }
125    }
126    GB_end_transaction_show_error(gb_main, error, aw_message);
127    free(source);
128}
129
130
131static void species_create_cb(AW_window * aww, AW_CL cl_gb_main) {
132    GBDATA   *gb_main = (GBDATA*)cl_gb_main;
133    char     *dest    = aww->get_root()->awar(AWAR_SPECIES_DEST)->read_string();
134    GB_ERROR  error   = GB_begin_transaction(gb_main);
135
136    if (!error) {
137        GBDATA *gb_species_data     = GBT_get_species_data(gb_main);
138        if (!gb_species_data) error = GB_await_error();
139        else {
140            GBDATA *gb_dest = GBT_find_species_rel_species_data(gb_species_data, dest);
141
142            if (gb_dest) error = GBS_global_string("Species '%s' already exists", dest);
143            else {
144                gb_dest             = GBT_find_or_create_species_rel_species_data(gb_species_data, dest);
145                if (!gb_dest) error = GB_await_error();
146                else aww->get_root()->awar(AWAR_SPECIES_NAME)->write_string(dest);
147            }
148        }
149    }
150    GB_end_transaction_show_error(gb_main, error, aw_message);
151    free(dest);
152}
153
154static AW_window *create_species_create_window(AW_root *root, AW_CL cl_gb_main) {
155    AW_window_simple *aws = new AW_window_simple;
156
157    aws->init(root, "CREATE_SPECIES", "SPECIES CREATE");
158    aws->load_xfig("ad_al_si.fig");
159
160    aws->callback((AW_CB0)AW_POPDOWN);
161    aws->at("close");
162    aws->create_button("CLOSE", "Close", "C");
163
164    aws->at("label");
165    aws->create_autosize_button(0, "Please enter the name\nof the new species");
166
167    aws->at("input");
168    aws->create_input_field(AWAR_SPECIES_DEST, 15);
169
170    aws->at("ok");
171    aws->callback(species_create_cb, cl_gb_main);
172    aws->create_button("GO", "Go", "G");
173
174    return (AW_window *)aws;
175}
176
177static GBDATA *expect_species_selected(AW_root *aw_root, GBDATA *gb_main, char **give_name = 0) {
178    GB_transaction  ta(gb_main);
179    char           *name       = aw_root->awar(AWAR_SPECIES_NAME)->read_string();
180    GBDATA         *gb_species = GBT_find_species(gb_main, name);
181
182    if (!gb_species) {
183        if (name && name[0]) aw_message(GBS_global_string("Species '%s' does not exist.", name));
184        else aw_message("Please select a species first");
185    }
186
187    if (give_name) *give_name = name;
188    else free(name);
189
190    return gb_species;
191}
192
193static void species_copy_cb(AW_window *aww, AW_CL cl_gb_main, AW_CL) {
194    AW_root *aw_root    = aww->get_root();
195    GBDATA  *gb_main    = (GBDATA*)cl_gb_main;
196    char    *name;
197    GBDATA  *gb_species = expect_species_selected(aw_root, gb_main, &name);
198
199    if (gb_species) {
200        GB_transaction      ta(gb_main);
201        GBDATA             *gb_species_data = GB_get_father(gb_species);
202        UniqueNameDetector  und(gb_species_data);
203        GB_ERROR            error           = 0;
204        char               *copy_name       = AWTC_makeUniqueShortName(GBS_global_string("c%s", name), und);
205
206        if (!copy_name) error = GB_await_error();
207        else {
208            GBDATA *gb_new_species = GB_create_container(gb_species_data, "species");
209
210            if (!gb_new_species) error = GB_await_error();
211            else {
212                error = GB_copy(gb_new_species, gb_species);
213                if (!error) {
214                    error = GBT_write_string(gb_new_species, "name", copy_name);
215                    if (!error) aw_root->awar(AWAR_SPECIES_NAME)->write_string(copy_name); // set focus
216                }
217            }
218
219            free(copy_name);
220        }
221        if (error) {
222            error = ta.close(error);
223            aw_message(error);
224        }
225    }
226}
227
228static void species_rename_cb(AW_window *aww, AW_CL cl_gb_main, AW_CL) {
229    AW_root *aw_root    = aww->get_root();
230    GBDATA  *gb_main    = (GBDATA*)cl_gb_main;
231    GBDATA  *gb_species = expect_species_selected(aw_root, gb_main);
232    if (gb_species) {
233        GB_transaction  ta(gb_main);
234        GBDATA         *gb_full_name  = GB_search(gb_species, "full_name", GB_STRING);
235        const char     *full_name     = gb_full_name ? GB_read_char_pntr(gb_full_name) : "";
236        char           *new_full_name = aw_input("Enter new 'full_name' of species:", full_name);
237
238        if (new_full_name) {
239            GB_ERROR error = 0;
240
241            if (strcmp(full_name, new_full_name) != 0) {
242                error = GB_write_string(gb_full_name, new_full_name);
243            }
244            if (!error) {
245                bool recreateID = ARB_in_expert_mode(aw_root) && // never re-create ID in novice mode
246                    aw_ask_sure("recreate_name_field",
247                                "Regenerate species identifier ('name')?\n"
248                                "(only do this if you know what you're doing)");
249                if (recreateID) {
250                    arb_progress progress("Regenerating species ID", 1);
251                    error = AWTC_recreate_name(gb_species);
252                    if (!error) aw_root->awar(AWAR_SPECIES_NAME)->write_string(GBT_read_name(gb_species)); // set focus
253                }
254            }
255
256            if (error) {
257                error = ta.close(error);
258                aw_message(error);
259            }
260        }
261    }
262}
263
264static void species_delete_cb(AW_window *aww, AW_CL cl_gb_main, AW_CL) {
265    AW_root  *aw_root    = aww->get_root();
266    GBDATA   *gb_main    = (GBDATA*)cl_gb_main;
267    char     *name;
268    GBDATA   *gb_species = expect_species_selected(aw_root, gb_main, &name);
269    GB_ERROR  error      = 0;
270
271    if (!gb_species) {
272        error = "Please select a species first";
273    }
274    else if (aw_ask_sure("info_delete_species", GBS_global_string("Are you sure to delete the species '%s'?", name))) {
275        GB_transaction ta(gb_main);
276        error = GB_delete(gb_species);
277        error = ta.close(error);
278        if (!error) aw_root->awar(AWAR_SPECIES_NAME)->write_string("");
279    }
280
281    if (error) aw_message(error);
282    free(name);
283}
284
285static long count_field_occurrance(BoundItemSel *bsel, const char *field_name) {
286    QUERY_RANGE   RANGE = QUERY_ALL_ITEMS;
287    long          count = 0;
288    ItemSelector& sel   = bsel->selector;
289
290    for (GBDATA *gb_container = sel.get_first_item_container(bsel->gb_main, NULL, RANGE);
291         gb_container;
292         gb_container = sel.get_next_item_container(gb_container, RANGE))
293    {
294        for (GBDATA *gb_item = sel.get_first_item(gb_container, RANGE);
295             gb_item;
296             gb_item = sel.get_next_item(gb_item, RANGE))
297        {
298            GBDATA *gb_field = GB_entry(gb_item, field_name);
299            if (gb_field) ++count;
300        }
301    }
302    return count;
303}
304
305class KeySorter : virtual Noncopyable {
306    int      key_count;
307    GBDATA **key;
308
309    int field_count; // = key_count - container_count
310
311    bool order_changed;
312
313    // helper variables for sorting
314    static GB_HASH      *order_hash;
315    static BoundItemSel *bitem_selector;
316    static arb_progress *sort_progress;
317
318    bool legal_pos(int p) { return p >= 0 && p<key_count; }
319    bool legal_field_pos(int p) const { return p >= 0 && p<field_count; }
320    bool legal_field_pos(int p1, int p2) const { return legal_field_pos(p1) && legal_field_pos(p2); }
321
322    void swap(int p1, int p2) {
323        ui_assert(legal_pos(p1));
324        ui_assert(legal_pos(p2));
325
326        GBDATA *k = key[p1];
327        key[p1]   = key[p2];
328        key[p2]   = k;
329
330        order_changed = true;
331    }
332
333    const char *field_name(int p) const {
334        GBDATA *gb_key_name = GB_entry(key[p], "key_name");
335        if (gb_key_name) return GB_read_char_pntr(gb_key_name);
336        return NULL;
337    }
338    GB_TYPES field_type(int p) const {
339        GBDATA *gb_key_type = GB_entry(key[p], "key_type");
340        if (gb_key_type) return GB_TYPES(GB_read_int(gb_key_type));
341        return GB_NONE;
342    }
343    int field_freq(int p) const {
344        const char *name            = field_name(p);
345        if (!order_hash) order_hash = GBS_create_hash(key_count, GB_IGNORE_CASE);
346
347        long freq = GBS_read_hash(order_hash, name);
348        if (!freq) {
349            freq = 1+count_field_occurrance(bitem_selector, name);
350            GBS_write_hash(order_hash, name, freq);
351            if (sort_progress) sort_progress->inc();
352        }
353        return freq;
354    }
355
356    int compare(int p1, int p2, ReorderMode mode) {
357        switch (mode) {
358            case RIGHT_BEHIND_LEFT:
359            case REVERSE_ORDER: 
360                ui_assert(0); // illegal ReorderMode
361                break;
362
363            case ORDER_TYPE:  return field_type(p2)-field_type(p1);
364            case ORDER_ALPHA: return strcasecmp(field_name(p1), field_name(p2));
365            case ORDER_FREQ:  return field_freq(p2)-field_freq(p1);
366        }
367        return p2-p1; // keep order
368    }
369
370public:
371    KeySorter(GBDATA *gb_key_data) {
372        key_count   = 0;
373        field_count = 0;
374        key         = NULL;
375
376        for (GBDATA *gb_key = GB_child(gb_key_data); gb_key; gb_key = GB_nextChild(gb_key)) {
377            key_count++;
378        }
379
380        if (key_count) {
381            key = (GBDATA**)malloc(key_count*sizeof(*key));
382           
383            int container_count = 0;
384            for (GBDATA *gb_key = GB_child(gb_key_data); gb_key; gb_key = GB_nextChild(gb_key)) {
385                GBDATA   *gb_type = GB_entry(gb_key, CHANGEKEY_TYPE);
386                GB_TYPES  type    = GB_TYPES(GB_read_int(gb_type));
387
388                if (type == GB_DB) { // move containers behind fields
389                    key[key_count-1-container_count++] = gb_key;
390                }
391                else {
392                    key[field_count++] = gb_key;
393                }
394            }
395            ui_assert((container_count+field_count) == key_count);
396            reverse_order(field_count, key_count-1); // of containers
397        }
398        order_changed = false;
399    }
400    ~KeySorter() {
401        ui_assert(!order_changed); // order changed but not written
402        free(key);
403    }
404
405    int get_field_count() const { return field_count; }
406
407    void bubble_sort(int p1, int p2, ReorderMode mode, BoundItemSel *selector) {
408        if (p1>p2) std::swap(p1, p2);
409        if (legal_field_pos(p1, p2)) {
410            if (mode == ORDER_FREQ) {
411                sort_progress = new arb_progress("Calculating field frequencies", p2-p1+1);
412            }
413            bitem_selector = selector;
414            while (p1<p2) {
415                bool changed = false;
416
417                int i = p2;
418                while (i>p1) {
419                    if (compare(i-1, i, mode)>0) {
420                        swap(i-1, i);
421                        changed = true;
422                    }
423                    --i;
424                }
425                if (!changed) break;
426                ++p1;
427            }
428            if (order_hash) {
429                GBS_free_hash(order_hash);
430                order_hash = NULL;
431            }
432            if (sort_progress) {
433                delete sort_progress;
434                sort_progress = NULL;
435            }
436        }
437    }
438    void reverse_order(int p1, int p2) {
439        if (p1>p2) std::swap(p1, p2);
440        if (legal_field_pos(p1, p2)) while (p1<p2) swap(p1++, p2--);
441    }
442
443    int index_of(GBDATA *gb_key) {
444        int i;
445        for (i = 0; i<key_count; i++) {
446            if (gb_key == key[i]) break;
447        }
448        if (i == key_count) {
449            ui_assert(0);
450            i = -1;
451        }
452        return i;
453    }
454
455    void move_to(int to_move, int wanted_position) {
456        if (legal_field_pos(to_move, wanted_position)) {
457            while (to_move<wanted_position) {
458                swap(to_move, to_move+1);
459                to_move++;
460            }
461            while (to_move>wanted_position) {
462                swap(to_move, to_move-1);
463                to_move--;
464            }
465        }
466    }
467
468    __ATTR__USERESULT GB_ERROR save_changes() {
469        GB_ERROR warning = NULL;
470        if (order_changed) {
471            if (key_count) {
472                GBDATA *gb_main = GB_get_root(key[0]);
473                warning         = GB_resort_data_base(gb_main, key, key_count);
474            }
475            order_changed = false;
476        }
477        return warning;
478    }
479};
480
481GB_HASH      *KeySorter::order_hash     = NULL;
482BoundItemSel *KeySorter::bitem_selector = NULL;
483arb_progress *KeySorter::sort_progress  = NULL;
484
485static void reorder_keys(AW_window *aws, ReorderMode mode, Itemfield_Selection *sel_left, Itemfield_Selection *sel_right) {
486    ItemSelector& selector = sel_left->get_selector();
487    ui_assert(&selector == &sel_right->get_selector());
488   
489    int left_index  = sel_left->get_sellist()->get_index_of_selected();
490    int right_index = sel_right->get_sellist()->get_index_of_selected();
491
492    GB_ERROR warning = 0;
493
494    GBDATA  *gb_main = sel_left->get_gb_main();
495    AW_root *awr     = aws->get_root();
496   
497    GB_begin_transaction(gb_main);
498
499    GBDATA *gb_left_field  = GBT_get_changekey(gb_main, awr->awar(AWAR_FIELD_REORDER_SOURCE)->read_char_pntr(), selector.change_key_path);
500    GBDATA *gb_right_field = GBT_get_changekey(gb_main, awr->awar(AWAR_FIELD_REORDER_DEST)->read_char_pntr(), selector.change_key_path);
501
502    if (!gb_left_field || !gb_right_field || gb_left_field == gb_right_field) {
503        warning = "Please select different fields in both list";
504    }
505    else {
506        GBDATA    *gb_key_data = GB_search(gb_main, selector.change_key_path, GB_CREATE_CONTAINER);
507        KeySorter  sorter(gb_key_data);
508
509        int left_key_idx  = sorter.index_of(gb_left_field);
510        int right_key_idx = sorter.index_of(gb_right_field);
511
512        switch (mode) {
513            case RIGHT_BEHIND_LEFT:
514                sorter.move_to(right_key_idx, left_key_idx+(left_key_idx<right_key_idx));
515                if (right_index>left_index) { left_index++; right_index++; } // make it simple to move several consecutive keys
516                break;
517            case REVERSE_ORDER:
518                sorter.reverse_order(left_key_idx, right_key_idx);
519                std::swap(left_index, right_index);
520                break;
521            default: {
522                BoundItemSel bis(gb_main, selector);
523                sorter.bubble_sort(left_key_idx, right_key_idx, mode, &bis);
524                break;
525            }
526        }
527
528        warning = sorter.save_changes();
529    }
530    GB_commit_transaction(gb_main);
531
532    if (warning) {
533        aw_message(warning);
534    }
535    else {
536        sel_left->get_sellist()->select_element_at(left_index);
537        sel_right->get_sellist()->select_element_at(right_index);
538    }
539}
540
541static void reorder_right_behind_left(AW_window *aws, AW_CL cl_selleft, AW_CL cl_selright) { reorder_keys(aws, RIGHT_BEHIND_LEFT, (Itemfield_Selection*)cl_selleft, (Itemfield_Selection*)cl_selright); }
542static void reverse_key_order        (AW_window *aws, AW_CL cl_selleft, AW_CL cl_selright) { reorder_keys(aws, REVERSE_ORDER,     (Itemfield_Selection*)cl_selleft, (Itemfield_Selection*)cl_selright); }
543
544static void sort_keys(AW_window *aws, AW_CL cl_selleft, AW_CL cl_selright) {
545    ReorderMode mode = ReorderMode(aws->get_root()->awar(AWAR_FIELD_REORDER_ORDER)->read_int());
546    reorder_keys(aws, mode, (Itemfield_Selection*)cl_selleft, (Itemfield_Selection*)cl_selright);
547}
548
549static void reorder_up_down(AW_window *aws, AW_CL cl_selright, AW_CL cl_dir) {
550    int                  dir       = (int)cl_dir;
551    Itemfield_Selection *sel_right = (Itemfield_Selection*)cl_selright;
552    GBDATA              *gb_main   = sel_right->get_gb_main();
553
554    GB_begin_transaction(gb_main);
555    ItemSelector& selector   = sel_right->get_selector();
556    int           list_index = sel_right->get_sellist()->get_index_of_selected();
557
558    const char *field_name = aws->get_root()->awar(AWAR_FIELD_REORDER_DEST)->read_char_pntr();
559    GBDATA     *gb_field   = GBT_get_changekey(gb_main, field_name, selector.change_key_path);
560    GB_ERROR    warning    = 0;
561
562    if (!gb_field) {
563        warning = "Please select the item to move in the right box";
564    }
565    else {
566        GBDATA    *gb_key_data = GB_search(gb_main, selector.change_key_path, GB_CREATE_CONTAINER);
567        KeySorter  sorter(gb_key_data);
568
569        int curr_index = sorter.index_of(gb_field);
570        int dest_index = -1;
571        if (abs(dir) == 1) {
572            dest_index = curr_index+dir;
573            list_index = -1;
574        }
575        else {
576            dest_index = dir<0 ? 0 : sorter.get_field_count()-1;
577        }
578
579        sorter.move_to(curr_index, dest_index);
580        warning = sorter.save_changes();
581
582    }
583
584    GB_commit_transaction(gb_main);
585    if (list_index >= 0) sel_right->get_sellist()->select_element_at(list_index);
586    if (warning) aw_message(warning);
587}
588
589AW_window *DBUI::create_fields_reorder_window(AW_root *root, AW_CL cl_bound_item_selector) {
590    BoundItemSel  *bound_selector = (BoundItemSel*)cl_bound_item_selector;
591    ItemSelector&  selector       = bound_selector->selector;
592
593    static AW_window_simple *awsa[QUERY_ITEM_TYPES];
594    if (!awsa[selector.type]) {
595        AW_window_simple *aws = new AW_window_simple;
596        awsa[selector.type]  = aws;
597
598        aws->init(root, "REORDER_FIELDS", "REORDER FIELDS");
599        aws->load_xfig("ad_kreo.fig");
600
601        aws->callback((AW_CB0)AW_POPDOWN);
602        aws->at("close");
603        aws->create_button("CLOSE", "Close", "C");
604
605        const char *HELPFILE = "spaf_reorder.hlp";
606        aws->callback(makeHelpCallback(HELPFILE));
607        aws->at("help");
608        aws->create_button("HELP", "Help", "H");
609
610        Itemfield_Selection *sel1 = create_selection_list_on_itemfields(bound_selector->gb_main, aws, AWAR_FIELD_REORDER_SOURCE, true, FIELD_FILTER_NDS, "source", 0, selector, 20, 10, SF_STANDARD, NULL);
611        Itemfield_Selection *sel2 = create_selection_list_on_itemfields(bound_selector->gb_main, aws, AWAR_FIELD_REORDER_DEST,   true, FIELD_FILTER_NDS, "dest",   0, selector, 20, 10, SF_STANDARD, NULL);
612
613        aws->button_length(8);
614
615        aws->at("sort");
616        aws->callback(sort_keys, (AW_CL)sel1, (AW_CL)sel2);
617        aws->help_text(HELPFILE);
618        aws->create_button("SORT", "Sort by");
619
620        aws->at("sorttype");
621        aws->create_option_menu(AWAR_FIELD_REORDER_ORDER, true);
622        aws->insert_option("name",      "a", ORDER_ALPHA);
623        aws->insert_option("type",      "t", ORDER_TYPE);
624        aws->insert_option("frequency", "f", ORDER_FREQ);
625        aws->update_option_menu();
626
627        aws->at("leftright");
628        aws->callback(reorder_right_behind_left, (AW_CL)sel1, (AW_CL)sel2);
629        aws->help_text(HELPFILE);
630        aws->create_autosize_button("MOVE_RIGHT_BEHIND_LEFT", "Move right\nbehind left");
631
632        aws->at("reverse");
633        aws->callback(reverse_key_order, (AW_CL)sel1, (AW_CL)sel2);
634        aws->help_text(HELPFILE);
635        aws->create_autosize_button("REVERSE", "Reverse");
636       
637        aws->button_length(6);
638        struct {
639            const char *tag;
640            const char *macro;
641            int         dir;
642        } reorder[4] = {
643            { "Top",    "MOVE_TOP_RIGHT",  -2 },
644            { "Up",     "MOVE_UP_RIGHT",   -1 },
645            { "Down",   "MOVE_DOWN_RIGHT", +1 },
646            { "Bottom", "MOVE_BOT_RIGHT",  +2 },
647        };
648
649        for (int i = 0; i<4; ++i) {
650            aws->at(reorder[i].tag);
651            aws->callback(reorder_up_down, (AW_CL)sel2, reorder[i].dir);
652            aws->help_text(HELPFILE);
653            aws->create_button(reorder[i].macro, reorder[i].tag);
654        }
655    }
656
657    return awsa[selector.type];
658}
659
660static void hide_field_cb(AW_window *aws, AW_CL cl_sel, AW_CL cl_hide) {
661    Itemfield_Selection *item_sel = (Itemfield_Selection*)cl_sel;
662
663    GBDATA   *gb_main = item_sel->get_gb_main();
664    GB_ERROR  error   = GB_begin_transaction(gb_main);
665
666    if (!error) {
667        char          *source    = aws->get_root()->awar(AWAR_FIELD_DELETE)->read_string();
668        ItemSelector&  selector  = item_sel->get_selector();
669        GBDATA        *gb_source = GBT_get_changekey(gb_main, source, selector.change_key_path);
670
671        if (!gb_source) error = "Please select the field you want to (un)hide";
672        else error            = GBT_write_int(gb_source, CHANGEKEY_HIDDEN, int(cl_hide));
673
674        free(source);
675    }
676    GB_end_transaction_show_error(gb_main, error, aw_message);
677    if (!error) item_sel->get_sellist()->move_selection(1);
678}
679
680static void field_delete_cb(AW_window *aws, AW_CL cl_sel) {
681    Itemfield_Selection *item_sel = (Itemfield_Selection*)cl_sel;
682
683    GBDATA   *gb_main = item_sel->get_gb_main();
684    GB_ERROR  error   = GB_begin_transaction(gb_main);
685
686    if (!error) {
687        char              *source     = aws->get_root()->awar(AWAR_FIELD_DELETE)->read_string();
688        ItemSelector&      selector   = item_sel->get_selector();
689        AW_selection_list *sellist    = item_sel->get_sellist();
690        int                curr_index = sellist->get_index_of_selected();
691        GBDATA            *gb_source  = GBT_get_changekey(gb_main, source, selector.change_key_path);
692
693        if (!gb_source) error = "Please select the field you want to delete";
694        else error            = GB_delete(gb_source);
695
696        for (GBDATA *gb_item_container = selector.get_first_item_container(gb_main, aws->get_root(), QUERY_ALL_ITEMS);
697             !error && gb_item_container;
698             gb_item_container = selector.get_next_item_container(gb_item_container, QUERY_ALL_ITEMS))
699        {
700            for (GBDATA * gb_item = selector.get_first_item(gb_item_container, QUERY_ALL_ITEMS);
701                 !error && gb_item;
702                 gb_item = selector.get_next_item(gb_item, QUERY_ALL_ITEMS))
703            {
704                GBDATA *gbd = GB_search(gb_item, source, GB_FIND);
705
706                if (gbd) {
707                    error = GB_delete(gbd);
708                    if (!error) {
709                        // item has disappeared, this selects the next one:
710                        sellist->select_element_at(curr_index);
711                    }
712                }
713            }
714        }
715
716        free(source);
717    }
718
719    GB_end_transaction_show_error(gb_main, error, aw_message);
720}
721
722
723AW_window *DBUI::create_field_delete_window(AW_root *root, AW_CL cl_bound_item_selector) {
724    BoundItemSel  *bound_selector = (BoundItemSel*)cl_bound_item_selector;
725    ItemSelector&  selector       = bound_selector->selector;
726
727    static AW_window_simple *awsa[QUERY_ITEM_TYPES];
728    if (!awsa[selector.type]) {
729        AW_window_simple *aws = new AW_window_simple;
730        awsa[selector.type]  = aws;
731
732        aws->init(root, "DELETE_FIELD", "DELETE FIELD");
733        aws->load_xfig("ad_delof.fig");
734        aws->button_length(6);
735
736        aws->at("close"); aws->callback(AW_POPDOWN);
737        aws->create_button("CLOSE", "Close", "C");
738
739        aws->at("help"); aws->callback(makeHelpCallback("spaf_delete.hlp"));
740        aws->create_button("HELP", "Help", "H");
741
742        Itemfield_Selection *item_sel = create_selection_list_on_itemfields(bound_selector->gb_main, aws, AWAR_FIELD_DELETE, true, -1, "source", 0, selector, 20, 10, SF_HIDDEN, NULL);
743
744        aws->button_length(13);
745        aws->at("hide");
746        aws->callback(hide_field_cb, (AW_CL)item_sel, (AW_CL)1);
747        aws->help_text("rm_field_only.hlp");
748        aws->create_button("HIDE_FIELD", "Hide field", "H");
749
750        aws->at("unhide");
751        aws->callback(hide_field_cb, (AW_CL)item_sel, (AW_CL)0);
752        aws->help_text("rm_field_only.hlp");
753        aws->create_button("UNHIDE_FIELD", "Unhide field", "U");
754
755        aws->at("delf");
756        aws->callback(field_delete_cb, (AW_CL)item_sel);
757        aws->help_text("rm_field_cmpt.hlp");
758        aws->create_button("DELETE_FIELD", "Delete field\n(data deleted)", "C");
759    }
760   
761    return awsa[selector.type];
762}
763
764static void field_create_cb(AW_window *aws, AW_CL cl_bound_item_selector) {
765    BoundItemSel  *bound_selector = (BoundItemSel*)cl_bound_item_selector;
766    ItemSelector&  selector       = bound_selector->selector;
767
768    GB_push_transaction(bound_selector->gb_main);
769    char     *name   = aws->get_root()->awar(AWAR_FIELD_CREATE_NAME)->read_string();
770    GB_ERROR  error  = GB_check_key(name);
771    GB_ERROR  error2 = GB_check_hkey(name);
772    if (error && !error2) {
773        aw_message("Warning: Your key contain a '/' character,\n"
774                   "    that means it is a hierarchical key");
775        error = 0;
776    }
777
778    int type = (int)aws->get_root()->awar(AWAR_FIELD_CREATE_TYPE)->read_int();
779
780    if (!error) error = GBT_add_new_changekey_to_keypath(bound_selector->gb_main, name, type, selector.change_key_path);
781    aws->hide_or_notify(error);
782    free(name);
783    GB_pop_transaction(bound_selector->gb_main);
784}
785
786AW_window *DBUI::create_field_create_window(AW_root *root, AW_CL cl_bound_item_selector) {
787    BoundItemSel  *bound_selector = (BoundItemSel*)cl_bound_item_selector;
788    ItemSelector&  selector       = bound_selector->selector;
789
790    static AW_window_simple *awsa[QUERY_ITEM_TYPES];
791    if (awsa[selector.type]) return (AW_window *)awsa[selector.type];
792
793    AW_window_simple *aws = new AW_window_simple;
794    awsa[selector.type]  = aws;
795
796    aws->init(root, "CREATE_FIELD", "CREATE A NEW FIELD");
797    aws->load_xfig("ad_fcrea.fig");
798
799    aws->callback((AW_CB0)AW_POPDOWN);
800    aws->at("close");
801    aws->create_button("CLOSE", "Close", "C");
802
803    aws->at("input");
804    aws->label("FIELD NAME");
805    aws->create_input_field(AWAR_FIELD_CREATE_NAME, 15);
806
807    aws->at("type");
808    aws->create_toggle_field(AWAR_FIELD_CREATE_TYPE, "FIELD TYPE", "F");
809    aws->insert_toggle("Ascii Text",        "S", (int)GB_STRING);
810    aws->insert_toggle("Link",              "L", (int)GB_LINK);
811    aws->insert_toggle("Rounded Numerical", "N", (int)GB_INT);
812    aws->insert_toggle("Numerical",         "R", (int)GB_FLOAT);
813    aws->insert_toggle("MASK = 01 Text",    "0", (int)GB_BITS);
814    aws->update_toggle_field();
815
816    aws->at("ok");
817    aws->callback(field_create_cb, cl_bound_item_selector);
818    aws->create_button("CREATE", "Create", "C");
819
820    return (AW_window *)aws;
821}
822
823#if defined(WARN_TODO)
824#warning GBT_convert_changekey currently only works for species fields, make it work with genes/exp/... as well (use selector)
825#endif
826
827static void field_convert_commit_cb(AW_window *aws, AW_CL cl_bound_item_selector) {
828    BoundItemSel *bound_selector = (BoundItemSel*)cl_bound_item_selector;
829
830    AW_root *root    = aws->get_root();
831    GBDATA  *gb_main = bound_selector->gb_main;
832
833    GB_push_transaction(gb_main);
834    GB_ERROR error = GBT_convert_changekey(gb_main,
835                                           root->awar(AWAR_FIELD_CONVERT_SOURCE)->read_char_pntr(),
836                                           (GB_TYPES)root->awar(AWAR_FIELD_CONVERT_TYPE)->read_int());
837
838    GB_end_transaction_show_error(gb_main, error, aw_message);
839}
840
841static void field_convert_update_typesel_cb(AW_window *aws, AW_CL cl_bound_item_selector) {
842    BoundItemSel  *bound_selector = (BoundItemSel*)cl_bound_item_selector;
843    ItemSelector&  selector       = bound_selector->selector;
844
845    AW_root *root    = aws->get_root();
846    GBDATA  *gb_main = bound_selector->gb_main;
847
848    GB_push_transaction(gb_main);
849    int type = GBT_get_type_of_changekey(gb_main,
850                                         root->awar(AWAR_FIELD_CONVERT_SOURCE)->read_char_pntr(),
851                                         selector.change_key_path);
852    GB_pop_transaction(gb_main);
853
854    root->awar(AWAR_FIELD_CONVERT_TYPE)->write_int(type);
855}
856
857static AW_window *create_field_convert_window(AW_root *root, AW_CL cl_bound_item_selector) {
858    BoundItemSel  *bound_selector = (BoundItemSel*)cl_bound_item_selector;
859    ItemSelector&  selector       = bound_selector->selector;
860
861    static AW_window_simple *awsa[QUERY_ITEM_TYPES];
862    if (awsa[selector.type]) return (AW_window *)awsa[selector.type];
863
864    AW_window_simple *aws = new AW_window_simple;
865    awsa[selector.type]  = aws;
866
867    aws->init(root, "CONVERT_FIELD", "CONVERT FIELDS");
868    aws->load_xfig("ad_conv.fig");
869
870    aws->at("close");
871    aws->callback((AW_CB0)AW_POPDOWN);
872    aws->create_button("CLOSE", "Close", "C");
873
874    aws->at("help");
875    aws->callback(makeHelpCallback("spaf_convert.hlp"));
876    aws->create_button("HELP", "Help", "H");
877
878    aws->callback(field_convert_update_typesel_cb, cl_bound_item_selector);
879    create_selection_list_on_itemfields(bound_selector->gb_main, aws, AWAR_FIELD_CONVERT_SOURCE, true, -1, "source", 0, selector, 40, 20, SF_HIDDEN, NULL);
880
881    aws->at("typesel");
882    aws->create_toggle_field(AWAR_FIELD_CONVERT_TYPE, NULL, "F");
883    aws->insert_toggle("Ascii Text",        "S", (int)GB_STRING);
884    aws->insert_toggle("Link",              "L", (int)GB_LINK);
885    aws->insert_toggle("Rounded Numerical", "N", (int)GB_INT);
886    aws->insert_toggle("Numerical",         "R", (int)GB_FLOAT);
887    aws->insert_toggle("MASK = 01 Text",    "0", (int)GB_BITS);
888    aws->update_toggle_field();
889
890    aws->at("convert");
891    aws->callback(field_convert_commit_cb, cl_bound_item_selector);
892    aws->create_button("CONVERT", "Convert", "T");
893
894    return (AW_window*)aws;
895}
896
897void DBUI::insert_field_admin_menuitems(AW_window *aws, GBDATA *gb_main) {
898    static BoundItemSel *bis = new BoundItemSel(gb_main, SPECIES_get_selector());
899    ui_assert(bis->gb_main == gb_main);
900   
901    aws->insert_menu_topic("spec_reorder_fields", "Reorder fields ...",     "R", "spaf_reorder.hlp", AWM_ALL, AW_POPUP, (AW_CL)create_fields_reorder_window,  (AW_CL)bis);
902    aws->insert_menu_topic("spec_delete_field",   "Delete/Hide fields ...", "D", "spaf_delete.hlp",  AWM_EXP, AW_POPUP, (AW_CL)create_field_delete_window,  (AW_CL)bis);
903    aws->insert_menu_topic("spec_create_field",   "Create fields ...",      "C", "spaf_create.hlp",  AWM_ALL, AW_POPUP, (AW_CL)create_field_create_window,  (AW_CL)bis);
904    aws->insert_menu_topic("spec_convert_field",  "Convert fields ...",     "t", "spaf_convert.hlp", AWM_EXP, AW_POPUP, (AW_CL)create_field_convert_window, (AW_CL)bis);
905    aws->sep______________();
906    aws->insert_menu_topic("spec_unhide_fields",  "Show all hidden fields", "S", "scandb.hlp", AWM_ALL, makeWindowCallback(species_field_selection_list_unhide_all_cb, gb_main, FIELD_FILTER_NDS));
907    aws->insert_menu_topic("spec_refresh_fields", "Refresh fields",         "f", "scandb.hlp", AWM_ALL, makeWindowCallback(species_field_selection_list_update_cb,     gb_main, FIELD_FILTER_NDS));
908}
909
910inline int get_and_fix_range_from_awar(AW_awar *awar) {
911    const char *input = awar->read_char_pntr();
912    int         bpos = atoi(input);
913    int         ipos;
914
915    if (bpos>0) {
916        awar->write_string(GBS_global_string("%i", bpos));
917        ipos = bio2info(bpos);
918    }
919    else {
920        ipos = -1;
921        awar->write_string("");
922    }
923    return ipos;
924}
925
926class NN_GlobalData {
927    DbQuery           *query;
928    AW_selection_list *resultList;     // result list from create_next_neighbours_selected_window()
929
930public:
931    NN_GlobalData() : query(0), resultList(0) {}
932
933    void set_query(DbQuery *new_query) {
934        if (new_query != query) {
935            ui_assert(!query); // need redesign b4 changing query works
936            query = new_query;
937        }
938    }
939    void set_result_list(AW_selection_list *new_resultList) {
940        if (new_resultList != resultList) {
941            ui_assert(!resultList); // need redesign b4 changing query works
942            resultList = new_resultList;
943        }
944    }
945
946    DbQuery *get_query() const { ui_assert(query); return query; }
947
948    AW_selection_list *get_result_list() const { ui_assert(resultList); return resultList; }
949    GBDATA *get_gb_main() const { return query_get_gb_main(get_query()); }
950};
951static NN_GlobalData NN_GLOBAL;
952
953static PosRange get_nn_range_from_awars(AW_root *aw_root) {
954    int start = get_and_fix_range_from_awar(aw_root->awar(AWAR_NN_RANGE_START));
955    int end   = get_and_fix_range_from_awar(aw_root->awar(AWAR_NN_RANGE_END));
956
957    return PosRange(start, end);
958}
959
960inline char *read_sequence_region(GBDATA *gb_data, const PosRange& range) {
961    return range.dup_corresponding_part(GB_read_char_pntr(gb_data), GB_read_count(gb_data));
962}
963
964static void awtc_nn_search_all_listed(AW_window *aww) {
965    DbQuery *query   = NN_GLOBAL.get_query();
966    GBDATA  *gb_main = query_get_gb_main(query);
967
968    ui_assert(get_queried_itemtype(query).type == QUERY_ITEM_SPECIES);
969
970    GB_begin_transaction(gb_main);
971
972    AW_root *aw_root    = aww->get_root();
973    char    *dest_field = aw_root->awar(AWAR_NN_LISTED_DEST_FIELD)->read_string();
974
975    GB_ERROR error     = 0;
976    GB_TYPES dest_type = GBT_get_type_of_changekey(gb_main, dest_field, CHANGE_KEY_PATH);
977    if (!dest_type) {
978        error = GB_export_error("Please select a valid field");
979    }
980
981    if (strcmp(dest_field, "name")==0) {
982        int answer = aw_question(NULL, "CAUTION! This will destroy all name-fields of the listed species.\n",
983                                 "Continue and destroy all name-fields,Abort");
984
985        if (answer==1) {
986            error = GB_export_error("Aborted by user");
987        }
988    }
989
990    long max = count_queried_items(query, QUERY_ALL_ITEMS);
991    if (!max) {
992        error = "No species listed in query";
993    }
994    else {
995        arb_progress progress("Searching next neighbours", max);
996        progress.auto_subtitles("Species");
997
998        int     pts            = aw_root->awar(AWAR_PROBE_ADMIN_PT_SERVER)->read_int();
999        char   *ali_name       = aw_root->awar(AWAR_DEFAULT_ALIGNMENT)->read_string();
1000        int     oligo_len      = aw_root->awar(AWAR_NN_OLIGO_LEN)->read_int();
1001        int     mismatches     = aw_root->awar(AWAR_NN_MISMATCHES)->read_int();
1002        bool    fast_mode      = aw_root->awar(AWAR_NN_FAST_MODE)->read_int();
1003        bool    rel_matches    = aw_root->awar(AWAR_NN_REL_MATCHES)->read_int();
1004        int     wanted_entries = aw_root->awar(AWAR_NN_MAX_HITS)->read_int();
1005        bool    scored_entries = aw_root->awar(AWAR_NN_LISTED_SCORED_ENTRIES)->read_int();
1006        double  min_score      = aw_root->awar(AWAR_NN_MIN_SCORE)->read_float();
1007
1008        FF_complement        compl_mode  = static_cast<FF_complement>(aw_root->awar(AWAR_NN_COMPLEMENT)->read_int());
1009        RelativeScoreScaling rel_scaling = static_cast<RelativeScoreScaling>(aw_root->awar(AWAR_NN_REL_SCALING)->read_int());
1010
1011        PosRange org_range = get_nn_range_from_awars(aw_root);
1012
1013        for (GBDATA *gb_species = GBT_first_species(gb_main);
1014             !error && gb_species;
1015             gb_species = GBT_next_species(gb_species))
1016        {
1017            if (!IS_QUERIED(gb_species, query)) continue;
1018            GBDATA *gb_data = GBT_find_sequence(gb_species, ali_name);
1019            if (gb_data) {
1020                PosRange         range    = org_range; // modified by read_sequence_region
1021                char            *sequence = read_sequence_region(gb_data, range);
1022                PT_FamilyFinder  ff(gb_main, pts, oligo_len, mismatches, fast_mode, rel_matches, rel_scaling);
1023
1024                ff.restrict_2_region(range);
1025
1026                error = ff.searchFamily(sequence, compl_mode, wanted_entries, min_score); 
1027                if (!error) {
1028                    const FamilyList *fm = ff.getFamilyList();
1029
1030                    GBS_strstruct *value = NULL;
1031                    while (fm) {
1032                        const char *thisValue = 0;
1033                        if (rel_matches) {
1034                            ui_assert((fm->rel_matches*100) >= min_score); // filtered by ptserver
1035                            thisValue = scored_entries
1036                                ? GBS_global_string("%.1f%%:%s", fm->rel_matches*100, fm->name)
1037                                : fm->name;
1038                        }
1039                        else {
1040                            ui_assert(fm->matches >= min_score); // filtered by ptserver
1041                            thisValue = scored_entries
1042                                ? GBS_global_string("%li:%s", fm->matches, fm->name)
1043                                : fm->name;
1044                        }
1045
1046                        if (thisValue) {
1047                            if (value == NULL) { // first entry
1048                                value = GBS_stropen(1000);
1049                            }
1050                            else {
1051                                GBS_chrcat(value, ';');
1052                            }
1053                            GBS_strcat(value, thisValue);
1054                        }
1055
1056                        fm = fm->next;
1057                    }
1058
1059                    if (value) {
1060                        GBDATA *gb_dest = GB_search(gb_species, dest_field, dest_type);
1061
1062                        error = GB_write_as_string(gb_dest, GBS_mempntr(value));
1063                        GBS_strforget(value);
1064                    }
1065                    else {
1066                        GBDATA *gb_dest = GB_search(gb_species, dest_field, GB_FIND);
1067                        if (gb_dest) error = GB_delete(gb_dest);
1068                    }
1069                }
1070                free(sequence);
1071            }
1072            progress.inc_and_check_user_abort(error);
1073        }
1074        free(ali_name);
1075    }
1076    GB_end_transaction_show_error(gb_main, error, aw_message);
1077    free(dest_field);
1078}
1079
1080static void awtc_mark_hits(AW_window *) {
1081    AW_selection_list *resultList = NN_GLOBAL.get_result_list();
1082    GB_HASH           *list_hash  = resultList->to_hash(false);
1083    GBDATA            *gb_main    = NN_GLOBAL.get_gb_main();
1084
1085    GB_transaction ta(gb_main);
1086    for (GBDATA *gb_species = GBT_first_species(gb_main);
1087         gb_species;
1088         gb_species = GBT_next_species(gb_species))
1089    {
1090        int hit = GBS_read_hash(list_hash, GBT_get_name(gb_species));
1091        GB_write_flag(gb_species, hit);
1092    }
1093}
1094
1095static void awtc_nn_search(AW_window *aww) {
1096    AW_root  *aw_root  = aww->get_root();
1097    GBDATA   *gb_main  = NN_GLOBAL.get_gb_main();
1098    GB_ERROR  error    = 0;
1099    PosRange  range    = get_nn_range_from_awars(aw_root);
1100    char     *sequence = 0;
1101    {
1102        GB_transaction  ta(gb_main);
1103
1104        char   *sel_species = aw_root->awar(AWAR_SPECIES_NAME)->read_string();
1105        GBDATA *gb_species  = GBT_find_species(gb_main, sel_species);
1106
1107        if (!gb_species) {
1108            error = "Select a species first";
1109        }
1110        else {
1111            char   *ali_name = aw_root->awar(AWAR_DEFAULT_ALIGNMENT)->read_string();
1112            GBDATA *gb_data  = GBT_find_sequence(gb_species, ali_name);
1113
1114            if (gb_data) {
1115                sequence = read_sequence_region(gb_data, range);
1116            }
1117            else {
1118                error = GBS_global_string("Species '%s' has no sequence '%s'", sel_species, ali_name);
1119            }
1120            free(ali_name);
1121        }
1122        free(sel_species);
1123    }
1124
1125    int    pts         = aw_root->awar(AWAR_PROBE_ADMIN_PT_SERVER)->read_int();
1126    int    oligo_len   = aw_root->awar(AWAR_NN_OLIGO_LEN)->read_int();
1127    int    mismatches  = aw_root->awar(AWAR_NN_MISMATCHES)->read_int();
1128    bool   fast_mode   = aw_root->awar(AWAR_NN_FAST_MODE)->read_int();
1129    bool   rel_matches = aw_root->awar(AWAR_NN_REL_MATCHES)->read_int();
1130    double min_score   = aw_root->awar(AWAR_NN_MIN_SCORE)->read_float();
1131
1132    RelativeScoreScaling rel_scaling = static_cast<RelativeScoreScaling>(aw_root->awar(AWAR_NN_REL_SCALING)->read_int());
1133
1134    PT_FamilyFinder ff(gb_main, pts, oligo_len, mismatches, fast_mode, rel_matches, rel_scaling);
1135
1136    ff.restrict_2_region(range);
1137
1138    int max_hits = 0; // max wanted hits
1139
1140    if (!error) {
1141        FF_complement compl_mode = static_cast<FF_complement>(aw_root->awar(AWAR_NN_COMPLEMENT)->read_int());
1142        max_hits                 = aw_root->awar(AWAR_NN_MAX_HITS)->read_int();
1143
1144        error = ff.searchFamily(sequence, compl_mode, max_hits, min_score);
1145    }
1146
1147    // update result list
1148    {
1149        AW_selection_list* sel = NN_GLOBAL.get_result_list();
1150        sel->clear();
1151
1152        int hits = 0;
1153        if (error) {
1154            aw_message(error);
1155            sel->insert_default("<Error>", "");
1156        }
1157        else {
1158            int count     = 1;
1159            int shownHits = max_hits>0 ? max_hits : ff.getRealHits();
1160            int numWidth  = log(shownHits)/log(10)+1;
1161
1162            for (const FamilyList *fm = ff.getFamilyList(); fm; fm = fm->next) {
1163                const char *dis;
1164                if (rel_matches) {
1165                    dis = GBS_global_string("#%0*i %-12s Rel.hits: %5.1f%%", numWidth, count, fm->name, fm->rel_matches*100);
1166                }
1167                else {
1168                    dis = GBS_global_string("#%0*i %-12s Hits: %4li", numWidth, count, fm->name, fm->matches);
1169                }
1170
1171                sel->insert(dis, fm->name);
1172                count++;
1173            }
1174
1175            sel->insert_default(ff.hits_were_truncated() ? "<List truncated>" : "<No more hits>", "");
1176            hits = ff.getRealHits();
1177        }
1178        aw_root->awar(AWAR_NN_SELECTED_HIT_COUNT)->write_int(hits);
1179        if (aw_root->awar(AWAR_NN_SELECTED_AUTO_MARK)->read_int()) {
1180            awtc_mark_hits(NULL);
1181            aw_root->awar(AWAR_TREE_REFRESH)->touch();
1182        }
1183        sel->update();
1184    }
1185
1186    free(sequence);
1187}
1188
1189static void awtc_move_hits(AW_window *aww) {
1190    AW_root *aw_root         = aww->get_root();
1191    char    *current_species = aw_root->awar(AWAR_SPECIES_NAME)->read_string();
1192
1193    if (!current_species) current_species = strdup("<unknown>");
1194
1195    char *hit_description = GBS_global_string_copy("<neighbour of %s: %%s>", current_species);
1196
1197    copy_selection_list_2_query_box(NN_GLOBAL.get_query(), NN_GLOBAL.get_result_list(), hit_description);
1198
1199    free(hit_description);
1200    free(current_species);
1201}
1202
1203static void nn_do_autosearch_cb(AW_root *) {
1204    awtc_nn_search(NULL);
1205}
1206
1207static void nn_auto_search_changed_cb(AW_root *awr) {
1208    int auto_search = awr->awar(AWAR_NN_SELECTED_AUTO_SEARCH)->read_int();
1209
1210    AW_awar *awar_sel_species = awr->awar(AWAR_SPECIES_NAME);
1211    if (auto_search) {
1212        awar_sel_species->add_callback(nn_do_autosearch_cb);
1213    }
1214    else {
1215        awar_sel_species->remove_callback(nn_do_autosearch_cb);
1216    }
1217}
1218
1219static void create_next_neighbours_vars(AW_root *aw_root) {
1220    static bool created = false;
1221
1222    if (!created) {
1223        aw_root->awar_int(AWAR_PROBE_ADMIN_PT_SERVER);
1224        aw_root->awar_int(AWAR_NN_COMPLEMENT,  FF_FORWARD);
1225
1226        aw_root->awar_string(AWAR_NN_RANGE_START, "");
1227        aw_root->awar_string(AWAR_NN_RANGE_END,   "");
1228        aw_root->awar_int   (AWAR_NN_MAX_HITS,    10);
1229        aw_root->awar_float (AWAR_NN_MIN_SCORE,   80);
1230       
1231        aw_root->awar_int(AWAR_NN_SELECTED_HIT_COUNT,   0);
1232        aw_root->awar_int(AWAR_NN_SELECTED_AUTO_SEARCH, 0)->add_callback(nn_auto_search_changed_cb);
1233        aw_root->awar_int(AWAR_NN_SELECTED_AUTO_MARK,   0);
1234
1235        aw_root->awar_string(AWAR_NN_LISTED_DEST_FIELD,     "tmp");
1236        aw_root->awar_int   (AWAR_NN_LISTED_SCORED_ENTRIES, 1);
1237
1238        AWTC_create_common_next_neighbour_vars(aw_root);
1239
1240        created = true;
1241    }
1242}
1243
1244static void create_common_next_neighbour_fields(AW_window *aws) {
1245    aws->at("pt_server");
1246    awt_create_PTSERVER_selection_button(aws, AWAR_PROBE_ADMIN_PT_SERVER);
1247
1248    AWTC_create_common_next_neighbour_fields(aws);
1249
1250    aws->auto_space(5, 5);
1251   
1252    aws->at("range");
1253    aws->create_input_field(AWAR_NN_RANGE_START, 6);
1254    aws->create_input_field(AWAR_NN_RANGE_END,   6);
1255   
1256    aws->at("compl");
1257    aws->create_option_menu(AWAR_NN_COMPLEMENT, true);
1258    aws->insert_default_option("forward",            "", FF_FORWARD);
1259    aws->insert_option        ("reverse",            "", FF_REVERSE);
1260    aws->insert_option        ("complement",         "", FF_COMPLEMENT);
1261    aws->insert_option        ("reverse-complement", "", FF_REVERSE_COMPLEMENT);
1262    aws->insert_option        ("fwd + rev-compl",    "", FF_FORWARD|FF_REVERSE_COMPLEMENT);
1263    aws->insert_option        ("rev + compl",        "", FF_REVERSE|FF_COMPLEMENT);
1264    aws->insert_option        ("any",                "", FF_FORWARD|FF_REVERSE|FF_COMPLEMENT|FF_REVERSE_COMPLEMENT);
1265    aws->update_option_menu();
1266
1267    aws->at("results");
1268    aws->create_input_field(AWAR_NN_MAX_HITS, 3);
1269   
1270    aws->at("min_score");
1271    aws->create_input_field(AWAR_NN_MIN_SCORE, 6);
1272}
1273
1274static AW_window *create_next_neighbours_listed_window(AW_root *aw_root, AW_CL cl_query) {
1275    static AW_window_simple *aws = 0;
1276    NN_GLOBAL.set_query((DbQuery*)cl_query);
1277    if (!aws) {
1278        create_next_neighbours_vars(aw_root);
1279
1280        aws = new AW_window_simple;
1281        aws->init(aw_root, "SEARCH_NEXT_RELATIVES_OF_LISTED", "Search Next Neighbours of Listed");
1282        aws->load_xfig("ad_spec_nnm.fig");
1283
1284        aws->at("close");
1285        aws->callback((AW_CB0)AW_POPDOWN);
1286        aws->create_button("CLOSE", "Close", "C");
1287
1288        aws->at("help");
1289        aws->callback(makeHelpCallback("next_neighbours_listed.hlp"));
1290        aws->create_button("HELP", "Help", "H");
1291
1292        create_common_next_neighbour_fields(aws);
1293
1294        aws->at("add_score");
1295        aws->create_toggle(AWAR_NN_LISTED_SCORED_ENTRIES);
1296       
1297        aws->at("field");
1298        create_selection_list_on_itemfields(query_get_gb_main((DbQuery*)cl_query), aws, AWAR_NN_LISTED_DEST_FIELD, true, (1<<GB_INT) | (1<<GB_STRING), "field", 0, SPECIES_get_selector(), 20, 10, SF_STANDARD, NULL);
1299
1300        aws->at("go");
1301        aws->callback(awtc_nn_search_all_listed);
1302        aws->create_autosize_button("WRITE_FIELDS", "Write to field");
1303    }
1304    return aws;
1305}
1306
1307static AW_window *create_next_neighbours_selected_window(AW_root *aw_root, AW_CL cl_query) {
1308    static AW_window_simple *aws = 0;
1309    NN_GLOBAL.set_query((DbQuery*)cl_query);
1310    if (!aws) {
1311        create_next_neighbours_vars(aw_root);
1312
1313        aws = new AW_window_simple;
1314        aws->init(aw_root, "SEARCH_NEXT_RELATIVE_OF_SELECTED", "Search Next Neighbours of Selected");
1315        aws->load_xfig("ad_spec_nn.fig");
1316
1317        aws->at("close");
1318        aws->callback((AW_CB0)AW_POPDOWN);
1319        aws->create_button("CLOSE", "Close", "C");
1320
1321        aws->at("help");
1322        aws->callback(makeHelpCallback("next_neighbours.hlp"));
1323        aws->create_button("HELP", "Help", "H");
1324
1325        create_common_next_neighbour_fields(aws);
1326
1327        aws->at("hit_count");
1328        aws->create_button(0, AWAR_NN_SELECTED_HIT_COUNT, 0, "+");
1329
1330        aws->at("hits");
1331        AW_selection_list *resultList = aws->create_selection_list(AWAR_SPECIES_NAME, false);
1332        NN_GLOBAL.set_result_list(resultList);
1333        resultList->insert_default("No hits found", "");
1334        resultList->update();
1335
1336        aws->at("go");
1337        aws->callback(awtc_nn_search);
1338        aws->create_button("SEARCH", "Search");
1339
1340        aws->at("auto_go");
1341        aws->label("Auto on selection change");
1342        aws->create_toggle(AWAR_NN_SELECTED_AUTO_SEARCH);
1343       
1344        aws->at("mark");
1345        aws->callback(awtc_mark_hits);
1346        aws->create_autosize_button("MARK_HITS", "Mark hits");
1347
1348        aws->at("auto_mark");
1349        aws->label("Auto");
1350        aws->create_toggle(AWAR_NN_SELECTED_AUTO_MARK);
1351
1352        aws->at("move");
1353        aws->callback(awtc_move_hits);
1354        aws->create_autosize_button("MOVE_TO_HITLIST", "Move to hitlist");
1355
1356    }
1357    return aws;
1358}
1359
1360// ---------------------------------------------
1361//      species/organism specific callbacks
1362
1363static AW_window *popup_new_speciesOrganismWindow(AW_root *aw_root, GBDATA *gb_main, bool organismWindow, int detach_id);
1364
1365static void popup_detached_speciesOrganismWindow(AW_window *aw_parent, const InfoWindow *infoWin) {
1366    const InfoWindow *reusable = InfoWindowRegistry::infowin.find_reusable_of_same_type_as(*infoWin);
1367    if (reusable) reusable->reuse();
1368    else { // create a new window if none is reusable
1369        popup_new_speciesOrganismWindow(aw_parent->get_root(),
1370                                        infoWin->get_gbmain(),
1371                                        infoWin->mapsOrganism(),
1372                                        InfoWindowRegistry::infowin.allocate_detach_id(*infoWin));
1373    }
1374}
1375
1376static AW_window *popup_new_speciesOrganismWindow(AW_root *aw_root, GBDATA *gb_main, bool organismWindow, int detach_id) { // INFO_WINDOW_CREATOR
1377    // if detach_id is MAIN_WINDOW -> create main window (not detached)
1378
1379    AW_window_simple_menu *aws      = new AW_window_simple_menu;
1380    const ItemSelector&    itemType = organismWindow ? ORGANISM_get_selector() : SPECIES_get_selector();
1381
1382    init_info_window(aw_root, aws, itemType, detach_id);
1383
1384    aws->load_xfig("ad_spec.fig");
1385
1386    aws->button_length(8);
1387
1388    aws->at("close");
1389    aws->callback(AW_POPDOWN);
1390    aws->create_button("CLOSE", "Close", "C");
1391
1392    aws->at("search");
1393    aws->callback(makeCreateWindowCallback(DBUI::create_species_query_window, gb_main));
1394    aws->create_autosize_button("SEARCH", "Search...", "S");
1395
1396    aws->at("help");
1397    aws->callback(makeHelpCallback(detach_id ? "sp_info_locked.hlp" : "sp_info.hlp")); // uses_hlp_res("sp_info_locked.hlp", "sp_info.hlp"); see ../../SOURCE_TOOLS/check_ressources.pl@uses_hlp_res
1398    aws->create_button("HELP", "Help", "H");
1399
1400    DbScanner         *scanner = create_db_scanner(gb_main, aws, "box", 0, "field", "enable", DB_VIEWER, 0, "mark", FIELD_FILTER_NDS, itemType);
1401    const InfoWindow&  infoWin = InfoWindowRegistry::infowin.registerInfoWindow(aws, scanner, detach_id);
1402
1403    if (organismWindow) aws->create_menu("ORGANISM",    "O", AWM_ALL);
1404    else                aws->create_menu("SPECIES",     "S", AWM_ALL);
1405
1406    aws->insert_menu_topic("species_delete",        "Delete",         "D", "spa_delete.hlp",  AWM_ALL, species_delete_cb,        (AW_CL)gb_main,                      0);
1407    aws->insert_menu_topic("species_rename",        "Rename",         "R", "spa_rename.hlp",  AWM_ALL, species_rename_cb,        (AW_CL)gb_main,                      0);
1408    aws->insert_menu_topic("species_copy",          "Copy",           "y", "spa_copy.hlp",    AWM_ALL, species_copy_cb,          (AW_CL)gb_main,                      0);
1409    aws->insert_menu_topic("species_create",        "Create",         "C", "spa_create.hlp",  AWM_ALL, AW_POPUP,                 (AW_CL)create_species_create_window, (AW_CL)gb_main);
1410    aws->insert_menu_topic("species_convert_2_sai", "Convert to SAI", "S", "sp_sp_2_ext.hlp", AWM_ALL, move_species_to_extended, (AW_CL)gb_main,                      0);
1411    aws->sep______________();
1412
1413    aws->create_menu("FIELDS", "F", AWM_ALL);
1414    insert_field_admin_menuitems(aws, gb_main);
1415
1416    aws->at("detach");
1417    infoWin.add_detachOrGet_button(popup_detached_speciesOrganismWindow);
1418
1419    aws->show();
1420    infoWin.attach_selected_item();
1421    return aws;
1422}
1423
1424static void popup_speciesOrganismWindow(AW_root *aw_root, GBDATA *gb_main, bool organismWindow) {
1425    int windowIdx = (int)organismWindow;
1426
1427    static AW_window *AWS[2] = { 0, 0 };
1428    if (!AWS[windowIdx]) {
1429        AWS[windowIdx] = popup_new_speciesOrganismWindow(aw_root, gb_main, organismWindow, InfoWindow::MAIN_WINDOW);
1430    }
1431    else {
1432        AWS[windowIdx]->activate();
1433    }
1434}
1435
1436void DBUI::popup_species_info_window (AW_root *aw_root, GBDATA *gb_main) { popup_speciesOrganismWindow(aw_root, gb_main, false); }
1437void DBUI::popup_organism_info_window(AW_root *aw_root, GBDATA *gb_main) { popup_speciesOrganismWindow(aw_root, gb_main, true);  }
1438
1439static DbQuery *GLOBAL_species_query = NULL; // @@@ fix design
1440
1441void DBUI::unquery_all() {
1442    QUERY::unquery_all(0, GLOBAL_species_query);
1443}
1444
1445void DBUI::query_update_list() {
1446    DbQuery_update_list(GLOBAL_species_query);
1447}
1448
1449AW_window *DBUI::create_species_query_window(AW_root *aw_root, GBDATA *gb_main) {
1450    static AW_window_simple_menu *aws = 0;
1451    if (!aws) {
1452        aws = new AW_window_simple_menu;
1453        aws->init(aw_root, "SPECIES_QUERY", "SEARCH and QUERY");
1454        aws->create_menu("More functions", "f");
1455        aws->load_xfig("ad_query.fig");
1456
1457
1458        query_spec awtqs(SPECIES_get_selector());
1459
1460        awtqs.gb_main             = gb_main;
1461        awtqs.species_name        = AWAR_SPECIES_NAME;
1462        awtqs.tree_name           = AWAR_TREE;
1463        awtqs.select_bit          = GB_USERFLAG_QUERY;
1464        awtqs.use_menu            = 1;
1465        awtqs.ere_pos_fig         = "ere2";
1466        awtqs.by_pos_fig          = "by2";
1467        awtqs.qbox_pos_fig        = "qbox";
1468        awtqs.rescan_pos_fig      = 0;
1469        awtqs.key_pos_fig         = 0;
1470        awtqs.query_pos_fig       = "content";
1471        awtqs.result_pos_fig      = "result";
1472        awtqs.count_pos_fig       = "count";
1473        awtqs.do_query_pos_fig    = "doquery";
1474        awtqs.config_pos_fig      = "doconfig";
1475        awtqs.do_mark_pos_fig     = "domark";
1476        awtqs.do_unmark_pos_fig   = "dounmark";
1477        awtqs.do_delete_pos_fig   = "dodelete";
1478        awtqs.do_set_pos_fig      = "doset";
1479        awtqs.do_refresh_pos_fig  = "dorefresh";
1480        awtqs.open_parser_pos_fig = "openparser";
1481        awtqs.popup_info_window   = popup_species_info_window;
1482
1483        DbQuery *query           = create_query_box(aws, &awtqs, "spec");
1484        GLOBAL_species_query = query;
1485
1486        aws->create_menu("More search",     "s");
1487        aws->insert_menu_topic("spec_search_equal_fields_within_db", "Search For Equal Fields and Mark Duplicates",                "E", "search_duplicates.hlp", AWM_ALL, (AW_CB)search_duplicated_field_content, (AW_CL)query,                                  0);
1488        aws->insert_menu_topic("spec_search_equal_words_within_db",  "Search For Equal Words Between Fields and Mark Duplicates",  "W", "search_duplicates.hlp", AWM_ALL, (AW_CB)search_duplicated_field_content, (AW_CL)query,                                  1);
1489        aws->insert_menu_topic("spec_search_next_relativ_of_sel",    "Search Next Relatives of SELECTED Species in PT_Server ...", "R", 0,                       AWM_ALL, (AW_CB)AW_POPUP,                 (AW_CL)create_next_neighbours_selected_window, (AW_CL)query);
1490        aws->insert_menu_topic("spec_search_next_relativ_of_listed", "Search Next Relatives of LISTED Species in PT_Server ...",   "L", 0,                       AWM_ALL, (AW_CB)AW_POPUP,                 (AW_CL)create_next_neighbours_listed_window,   (AW_CL)query);
1491
1492        aws->button_length(7);
1493
1494        aws->at("close");
1495        aws->callback((AW_CB0)AW_POPDOWN);
1496        aws->create_button("CLOSE", "Close", "C");
1497
1498        aws->at("help");
1499        aws->callback(makeHelpCallback("sp_search.hlp"));
1500        aws->create_button("HELP", "Help", "H");
1501    }
1502    return aws;
1503}
1504
1505
Note: See TracBrowser for help on using the repository browser.