root/branches/stable_5.0/AWT/AWT_query_and_functions.cxx

Revision 7061, 113.6 KB (checked in by westram, 19 months ago)
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <time.h>
5#include <string.h>
6// #include <malloc.h>
7#include <memory.h>
8#include <ctype.h>
9
10#include <list>
11#include <string>
12
13#include <arbdb.h>
14#include <arbdbt.h>
15#include <aw_root.hxx>
16#include <aw_device.hxx>
17#include <aw_window.hxx>
18#include <aw_awars.hxx>
19#include <aw_preset.hxx>
20#include <aw_color_groups.hxx>
21#include "awt.hxx"
22#include "awtlocal.hxx"
23#include "awt_config_manager.hxx"
24#include "awt_item_sel_list.hxx"
25#include "awt_sel_boxes.hxx"
26#include "awt_advice.hxx"
27
28#include "GEN.hxx"
29
30using namespace std;
31
32#define AWT_MAX_QUERY_LIST_LEN  100000
33#define AWT_MAX_SHOWN_DATA_SIZE 500
34
35/***************** Create the database query box and functions *************************/
36
37#define AWAR_COLORIZE "tmp/dbquery_all/colorize"
38
39inline void SET_QUERIED(GBDATA *gb_species, adaqbsstruct *cbs, const char *hitInfo, size_t hitInfoLen = 0) {
40    awt_assert(hitInfo);
41
42    GB_write_usr_private(gb_species, cbs->select_bit | GB_read_usr_private(gb_species));
43
44    char *name = cbs->selector->generate_item_id(cbs->gb_main, gb_species);
45    char *info;
46
47    if (hitInfoLen == 0) hitInfoLen = strlen(hitInfo);
48    if (hitInfoLen>AWT_MAX_SHOWN_DATA_SIZE) {
49        char *dupInfo = strdup(hitInfo);
50        hitInfoLen    = GBS_shorten_repeated_data(dupInfo);
51        if (hitInfoLen>AWT_MAX_SHOWN_DATA_SIZE) {
52            strcpy(dupInfo+hitInfoLen-5, "[...]");
53        }
54        info = strdup(dupInfo);
55        free(dupInfo);
56    }
57    else {
58        info = strdup(hitInfo);
59    }
60
61    long  toFree = GBS_write_hash(cbs->hit_description, name, reinterpret_cast<long>(info));
62    if (toFree) free(reinterpret_cast<char*>(toFree)); // free old value (from hash)
63    free(name);
64}
65
66inline void CLEAR_QUERIED(GBDATA *gb_species, adaqbsstruct *cbs) {
67    GB_write_usr_private(gb_species, (~cbs->select_bit) & GB_read_usr_private(gb_species));
68
69    char *name   = cbs->selector->generate_item_id(cbs->gb_main, gb_species);
70    long  toFree = GBS_write_hash(cbs->hit_description, name, 0); // delete hit info
71    if (toFree) free(reinterpret_cast<char*>(toFree));
72    free(name);
73}
74
75inline const char *getHitInfo(GBDATA *gb_species, adaqbsstruct *cbs) {
76    char *name = cbs->selector->generate_item_id(cbs->gb_main, gb_species);
77    long  info = GBS_read_hash(cbs->hit_description, name);
78    free(name);
79    return reinterpret_cast<const char*>(info);
80}
81
82static void awt_query_create_global_awars(AW_root *aw_root, AW_default aw_def) {
83    aw_root->awar_int(AWAR_COLORIZE, 0, aw_def);
84}
85
86enum AWT_EXT_QUERY_TYPES {
87    AWT_EXT_QUERY_NONE,
88    AWT_EXT_QUERY_COMPARE_LINES,
89    AWT_EXT_QUERY_COMPARE_WORDS
90};
91
92awt_query_struct::awt_query_struct(void){
93    memset((char *)this,0,sizeof(awt_query_struct));
94    select_bit = 1;
95}
96
97long awt_count_queried_items(struct adaqbsstruct *cbs, AWT_QUERY_RANGE range) {
98    GBDATA                 *gb_main  = cbs->gb_main;
99    const ad_item_selector *selector = cbs->selector;
100
101    long count = 0;
102
103    for (GBDATA *gb_item_container = selector->get_first_item_container(gb_main, cbs->aws->get_root(), range);
104         gb_item_container;
105         gb_item_container = selector->get_next_item_container(gb_item_container, range))
106    {
107        for (GBDATA *gb_item = selector->get_first_item(gb_item_container);
108             gb_item;
109             gb_item = selector->get_next_item(gb_item))
110        {
111            if (IS_QUERIED(gb_item,cbs)) count++;
112        }
113    }
114    return count;
115}
116
117#if defined(DEVEL_RALF)
118#warning replace awt_count_items by "method" of selector
119#endif // DEVEL_RALF
120
121static int awt_count_items(struct adaqbsstruct *cbs, AWT_QUERY_RANGE range) {
122    int                     count    = 0;
123    GBDATA                 *gb_main  = cbs->gb_main;
124    const ad_item_selector *selector = cbs->selector;
125    GB_transaction          ta(gb_main);
126
127    for (GBDATA *gb_item_container = selector->get_first_item_container(gb_main, cbs->aws->get_root(), range);
128         gb_item_container;
129         gb_item_container = selector->get_next_item_container(gb_item_container, range))
130    {
131        for (GBDATA *gb_item = selector->get_first_item(gb_item_container);
132             gb_item;
133             gb_item = selector->get_next_item(gb_item))
134        {
135            count++;
136        }
137    }
138    return count;
139}
140
141const int MAX_CRITERIA = int(sizeof(unsigned long)*8/AWT_QUERY_SORT_CRITERIA_BITS);
142
143static AWT_QUERY_RESULT_ORDER split_sort_mask(unsigned long sort_mask, AWT_QUERY_RESULT_ORDER *order) {
144    // splits the sort order bit mask 'sort_mask' into single sort criteria
145    // (order[0] contains the primary sort criteria)
146    //
147    // Returns the first criteria matching
148    // AWT_QUERY_SORT_BY_1STFIELD_CONTENT or AWT_QUERY_SORT_BY_HIT_DESCRIPTION
149    // (or AWT_QUERY_SORT_NONE if no sort order defined)
150
151    AWT_QUERY_RESULT_ORDER first = AWT_QUERY_SORT_NONE;
152
153    for (int o = 0; o<MAX_CRITERIA; o++) {
154        order[o] = AWT_QUERY_RESULT_ORDER(sort_mask&AWT_QUERY_SORT_CRITERIA_MASK);
155        awt_assert(order[o] == (order[o]&AWT_QUERY_SORT_CRITERIA_MASK));
156
157        if (first == AWT_QUERY_SORT_NONE) {
158            if (order[o] & (AWT_QUERY_SORT_BY_1STFIELD_CONTENT|AWT_QUERY_SORT_BY_HIT_DESCRIPTION)) {
159                first = order[o];
160            }
161        }
162
163        sort_mask = sort_mask>>AWT_QUERY_SORT_CRITERIA_BITS;
164    }
165    return first;
166}
167
168static void awt_first_searchkey_changed_cb(AW_root *, AW_CL cl_cbs) {
169    struct adaqbsstruct *cbs = reinterpret_cast<struct adaqbsstruct*>(cl_cbs);
170
171    AWT_QUERY_RESULT_ORDER order[MAX_CRITERIA];
172    AWT_QUERY_RESULT_ORDER first = split_sort_mask(cbs->sort_mask, order);
173
174    if (first != AWT_QUERY_SORT_BY_HIT_DESCRIPTION) { // do we display values?
175        awt_query_update_list(NULL, cbs);
176    }
177}
178
179inline bool keep_criteria(AWT_QUERY_RESULT_ORDER old_criteria, AWT_QUERY_RESULT_ORDER new_criteria) {
180    return
181        old_criteria  != AWT_QUERY_SORT_NONE &&     // do not keep 'unsorted' (it is no real criteria)
182        (old_criteria != new_criteria        ||     // do not keep new criteria (added later)
183         old_criteria == AWT_QUERY_SORT_REVERSE);   // reverse may occur several times -> always keep
184}
185
186static void awt_sort_order_changed_cb(AW_root *aw_root, AW_CL cl_cbs) {
187    // adds the new selected sort order to the sort order mask
188    // (removes itself, if previously existed in sort order mask)
189    //
190    // if 'unsorted' is selected -> delete sort order
191
192    struct adaqbsstruct    *cbs          = reinterpret_cast<struct adaqbsstruct*>(cl_cbs);
193    AWT_QUERY_RESULT_ORDER  new_criteria = (AWT_QUERY_RESULT_ORDER)aw_root->awar(cbs->awar_sort)->read_int();
194
195    if (new_criteria == AWT_QUERY_SORT_NONE) {
196        cbs->sort_mask = AWT_QUERY_SORT_NONE; // clear sort_mask
197    }
198    else {
199        AWT_QUERY_RESULT_ORDER order[MAX_CRITERIA];
200        split_sort_mask(cbs->sort_mask, order);
201
202        int empty_or_same = 0;
203        for (int o = 0; o<MAX_CRITERIA; o++) {
204            if (!keep_criteria(order[o], new_criteria)) {
205                empty_or_same++; // these criteria will be skipped below
206            }
207        }
208
209        unsigned long new_sort_mask = 0;
210        for (int o = MAX_CRITERIA-(empty_or_same>0 ? 1 : 2); o >= 0; o--) {
211            if (keep_criteria(order[o], new_criteria)) {
212                new_sort_mask = (new_sort_mask<<AWT_QUERY_SORT_CRITERIA_BITS)|order[o];
213            }
214        }
215        cbs->sort_mask = (new_sort_mask<<AWT_QUERY_SORT_CRITERIA_BITS)|new_criteria; // add new primary key
216    }
217    awt_query_update_list(NULL, cbs);
218}
219
220struct awt_sort_query_hits_param {
221    struct adaqbsstruct    *cbs;
222    char                   *first_key;
223    AWT_QUERY_RESULT_ORDER  order[MAX_CRITERIA];
224};
225
226inline int strNULLcmp(const char *str1, const char *str2) {
227    return
228        str1
229        ? (str2 ? strcmp(str1, str2) : -1)
230        : (str2 ? 1 : 0);
231}
232
233static int awt_sort_query_hits(const void *cl_item1, const void *cl_item2, void *cl_param) {
234    awt_sort_query_hits_param *param = static_cast<awt_sort_query_hits_param*>(cl_param);
235
236    GBDATA *gb_item1 = (GBDATA*)cl_item1;
237    GBDATA *gb_item2 = (GBDATA*)cl_item2;
238
239    struct adaqbsstruct    *cbs      = param->cbs;
240    const ad_item_selector *selector = cbs->selector;
241
242    int cmp = 0;
243
244    for (int o = 0; o<MAX_CRITERIA && cmp == 0; o++) {
245        AWT_QUERY_RESULT_ORDER criteria = param->order[o];
246
247        switch (criteria) {
248            case AWT_QUERY_SORT_NONE:
249                o = MAX_CRITERIA; // don't sort further
250                break;
251
252            case AWT_QUERY_SORT_BY_1STFIELD_CONTENT: {
253                char *field1 = GBT_read_as_string(gb_item1, param->first_key);
254                char *field2 = GBT_read_as_string(gb_item2, param->first_key);
255
256                cmp = strNULLcmp(field1, field2);
257
258                free(field2);
259                free(field1);
260                break;
261            }
262            case AWT_QUERY_SORT_BY_NESTED_PID: {
263                if (selector->parent_selector) {
264                    GBDATA *gb_parent1 = selector->get_parent(gb_item1);
265                    GBDATA *gb_parent2 = selector->get_parent(gb_item2);
266                    char   *pid1       = AWT_get_item_id(cbs->gb_main, selector, gb_parent1);
267                    char   *pid2       = AWT_get_item_id(cbs->gb_main, selector, gb_parent2);
268
269                    cmp = strNULLcmp(pid1, pid2);
270
271                    free(pid2);
272                    free(pid1);
273                }
274                break;
275            }
276            case AWT_QUERY_SORT_BY_ID: {
277                const char *id1 = GBT_read_char_pntr(gb_item1, selector->id_field);
278                const char *id2 = GBT_read_char_pntr(gb_item2, selector->id_field);
279
280                cmp = strcmp(id1, id2);
281                break;
282            }
283            case AWT_QUERY_SORT_BY_MARKED:
284                cmp = GB_read_flag(gb_item2)-GB_read_flag(gb_item1);
285                break;
286
287            case AWT_QUERY_SORT_BY_HIT_DESCRIPTION: {
288                const char *id1   = GBT_read_char_pntr(gb_item1, selector->id_field);
289                const char *id2   = GBT_read_char_pntr(gb_item2, selector->id_field);
290                const char *info1 = reinterpret_cast<const char *>(GBS_read_hash(cbs->hit_description, id1));
291                const char *info2 = reinterpret_cast<const char *>(GBS_read_hash(cbs->hit_description, id2));
292                cmp = strNULLcmp(info1, info2);
293                break;
294            }
295            case AWT_QUERY_SORT_REVERSE: {
296                GBDATA *tmp = gb_item1; // swap items for following compares (this is a prefix revert!)
297                gb_item1    = gb_item2;
298                gb_item2    = tmp;;
299                break;
300            }
301        }
302    }
303
304    return cmp;
305}
306
307static long detectMaxNameLength(const char *key, long val, void *cl_len) {
308    int *len  = (int*)cl_len;
309    int  klen = strlen(key);
310
311    if (klen>*len) *len = klen;
312    return val;
313}
314
315long awt_query_update_list(void *dummy, struct adaqbsstruct *cbs) {
316    AWUSE(dummy);
317    GB_push_transaction(cbs->gb_main);
318
319    // clear
320    cbs->aws->clear_selection_list(cbs->result_id);
321
322    AW_root         *aw_root = cbs->aws->get_root();
323    AWT_QUERY_RANGE  range   = (AWT_QUERY_RANGE)aw_root->awar(cbs->awar_where)->read_int();
324
325    // create array of hits
326    long     count  = awt_count_queried_items(cbs, range);
327    GBDATA **sorted = static_cast<GBDATA**>(malloc(count*sizeof(*sorted)));
328    {
329        long s = 0;
330
331        for (GBDATA *gb_item_container = cbs->selector->get_first_item_container(cbs->gb_main, aw_root, range);
332             gb_item_container;
333             gb_item_container = cbs->selector->get_next_item_container(gb_item_container, range))
334        {
335            for (GBDATA *gb_item = cbs->selector->get_first_item(gb_item_container);
336                 gb_item;
337                 gb_item = cbs->selector->get_next_item(gb_item))
338            {
339                if (IS_QUERIED(gb_item,cbs)) sorted[s++] = gb_item;
340            }
341        }
342    }
343
344    // sort hits
345
346    bool show_value = true; // default
347    awt_sort_query_hits_param param = { cbs, NULL, {} };
348    param.first_key = cbs->aws->get_root()->awar(cbs->awar_keys[0])->read_string();
349
350    if (cbs->sort_mask != AWT_QUERY_SORT_NONE) {    // unsorted -> don't sort
351        AWT_QUERY_RESULT_ORDER main_criteria = split_sort_mask(cbs->sort_mask, param.order);
352
353        if (main_criteria == AWT_QUERY_SORT_BY_HIT_DESCRIPTION) {
354            show_value = false;
355        }
356        GB_sort((void**)sorted, 0, count, awt_sort_query_hits, &param);
357    }
358
359    // display hits
360
361    int name_len = cbs->selector->item_name_length;
362    if (name_len == -1) { // if name_len is unknown -> detect
363        GBS_hash_do_loop(cbs->hit_description, detectMaxNameLength, &name_len);
364    }
365
366    long i;
367    for (i = 0; i<count && i<AWT_MAX_QUERY_LIST_LEN; i++) {
368        char *name = cbs->selector->generate_item_id(cbs->gb_main, sorted[i]);
369        if (name) {
370            char       *toFree = 0;
371            const char *info;
372
373            if (show_value) {
374                toFree = GBT_read_as_string(sorted[i], param.first_key);
375                if (toFree) {
376                    if (strlen(toFree)>AWT_MAX_SHOWN_DATA_SIZE) {
377                        size_t shortened_len = GBS_shorten_repeated_data(toFree);
378                        if (shortened_len>AWT_MAX_SHOWN_DATA_SIZE) {
379                            strcpy(toFree+AWT_MAX_SHOWN_DATA_SIZE-5, "[...]");
380                        }
381                    }
382                }
383                else {
384                    toFree = GBS_global_string_copy("<%s has no data>", param.first_key);
385                }
386                info = toFree;
387            }
388            else {
389                info = reinterpret_cast<const char *>(GBS_read_hash(cbs->hit_description, name));
390                if (!info) info = "<no hit info>";
391            }
392
393            awt_assert(info);
394            const char *line = GBS_global_string("%c %-*s :%s",
395                                                 GB_read_flag(sorted[i]) ? '*' : ' ',
396                                                 name_len, name,
397                                                 info);
398
399            cbs->aws->insert_selection(cbs->result_id, line, name);
400            free(toFree);
401            free(name);
402        }
403    }
404
405    if (count>AWT_MAX_QUERY_LIST_LEN) {
406        cbs->aws->insert_selection(cbs->result_id, "*****  List truncated  *****", "");
407    }
408
409    free(sorted);
410   
411    cbs->aws->insert_default_selection( cbs->result_id, "End of list", "" );
412    cbs->aws->update_selection_list( cbs->result_id );
413    cbs->aws->get_root()->awar(cbs->awar_count)->write_int( (long)count);
414    GB_pop_transaction(cbs->gb_main);
415
416    return count;
417}
418// Mark listed species
419// mark = 1 -> mark listed
420// mark | 8 -> don't change rest
421void awt_do_mark_list(void *dummy, struct adaqbsstruct *cbs, long mark)
422{
423    AWUSE(dummy);
424    GB_push_transaction(cbs->gb_main);
425
426    for (GBDATA *gb_item_container = cbs->selector->get_first_item_container(cbs->gb_main, cbs->aws->get_root(), AWT_QUERY_ALL_SPECIES);
427         gb_item_container;
428         gb_item_container = cbs->selector->get_next_item_container(gb_item_container, AWT_QUERY_ALL_SPECIES))
429        {
430            for (GBDATA *gb_item = cbs->selector->get_first_item(gb_item_container);
431                 gb_item;
432                 gb_item = cbs->selector->get_next_item(gb_item))
433                {
434                    if (IS_QUERIED(gb_item, cbs)) {
435                        GB_write_flag(gb_item, mark&1);
436                    }
437                    else if ((mark&8) == 0) {
438                        GB_write_flag(gb_item, 1-(mark&1));
439                    }
440                }
441        }
442
443    awt_query_update_list(0,cbs);
444    GB_pop_transaction(cbs->gb_main);
445}
446
447void awt_unquery_all(void *dummy, struct adaqbsstruct *cbs){
448    AWUSE(dummy);
449    GB_push_transaction(cbs->gb_main);
450    GBDATA *gb_species;
451    for (       gb_species = GBT_first_species(cbs->gb_main);
452                gb_species;
453                gb_species = GBT_next_species(gb_species)){
454        CLEAR_QUERIED(gb_species,cbs);
455    }
456    awt_query_update_list(0,cbs);
457    GB_pop_transaction(cbs->gb_main);
458}
459
460void awt_delete_species_in_list(void *dummy, struct adaqbsstruct *cbs)
461{
462    GB_begin_transaction(cbs->gb_main);
463    long cnt = 0;
464
465    for (GBDATA *gb_item_container = cbs->selector->get_first_item_container(cbs->gb_main, cbs->aws->get_root(), AWT_QUERY_ALL_SPECIES);
466         gb_item_container;
467         gb_item_container = cbs->selector->get_next_item_container(gb_item_container, AWT_QUERY_ALL_SPECIES))
468        {
469            for (GBDATA *gb_item = cbs->selector->get_first_item(gb_item_container);
470                 gb_item;
471                 gb_item = cbs->selector->get_next_item(gb_item))
472                {
473                    if (IS_QUERIED(gb_item, cbs)) cnt++;
474                }
475        }
476
477    sprintf(AW_ERROR_BUFFER,"Are you sure to delete %li %s",cnt, cbs->selector->items_name);
478    if (aw_question(AW_ERROR_BUFFER,"OK,CANCEL")){
479        GB_abort_transaction(cbs->gb_main);
480        return;
481    }
482
483    GB_ERROR error = 0;
484
485    for (GBDATA *gb_item_container = cbs->selector->get_first_item_container(cbs->gb_main, cbs->aws->get_root(), AWT_QUERY_ALL_SPECIES);
486         !error && gb_item_container;
487         gb_item_container = cbs->selector->get_next_item_container(gb_item_container, AWT_QUERY_ALL_SPECIES))
488        {
489            for (GBDATA *gb_item = cbs->selector->get_first_item(gb_item_container);
490                 !error && gb_item;
491                 gb_item = cbs->selector->get_next_item(gb_item))
492                {
493                    if (IS_QUERIED(gb_item,cbs)) {
494                        error = GB_delete(gb_item);
495                    }
496                }
497        }
498
499    if (error) {
500        GB_abort_transaction(cbs->gb_main);
501        aw_message(error);
502    }else{
503        awt_query_update_list(dummy,cbs);
504        GB_commit_transaction(cbs->gb_main);
505    }
506}
507
508static GB_HASH *awt_create_ref_hash(const struct adaqbsstruct *cbs, const char *key, bool split_words) {
509    GBDATA  *gb_ref       = cbs->gb_ref;
510    bool     queried_only = cbs->expect_hit_in_ref_list;
511    GB_HASH *hash         = GBS_create_hash(GBT_get_species_hash_size(gb_ref), GB_IGNORE_CASE);
512
513    for (GBDATA  *gb_species = GBT_first_species(gb_ref);
514         gb_species;
515         gb_species = GBT_next_species(gb_species))
516    {
517        if (!queried_only || IS_QUERIED(gb_species, cbs)) {
518            GBDATA *gb_name = GB_search(gb_species,key,GB_FIND);
519            if (gb_name) {
520                char *keyas = GB_read_as_string(gb_name);
521                if (keyas && strlen(keyas)) {
522                    if (split_words) {
523                        char *t;
524                        for (t = strtok(keyas," "); t; t = strtok(0," ")) {
525                            if (t[0]) GBS_write_hash(hash, t, (long)gb_species);
526                        }
527                    }
528                    else {
529                        GBS_write_hash(hash, keyas, (long)gb_species);
530                    }
531                }
532                free(keyas);
533            }
534        }
535    }
536    return hash;
537}
538
539//  ------------------------
540//      class awt_query
541//  ------------------------
542typedef enum { ILLEGAL, AND, OR } awt_query_operator;
543
544typedef enum {
545    AQT_INVALID,
546    AQT_EMPTY,
547    AQT_NON_EMPTY,
548    AQT_LOWER,
549    AQT_GREATER,
550    AQT_EXACT_MATCH,
551    AQT_OCCURS,
552    AQT_STARTS_WITH,
553    AQT_ENDS_WITH,
554    AQT_WILDCARD,
555    AQT_REGEXPR,
556    AQT_ACI,
557} awt_query_type;
558
559typedef enum {
560    AQFT_EXPLICIT,                                  // query should match one explicit field
561    AQFT_ANY_FIELD,                                 // query should match one field (no matter which)
562    AQFT_ALL_FIELDS,                                // query should match all fields
563} awt_query_field_type;
564
565class awt_query {
566    awt_query_operator  op;                         // operator (AND or OR)
567    char               *key;                        // search key
568    bool                Not;                        // true means "don't match"
569    char               *query;                      // search expression
570
571    GBDATA     *gb_main;
572    const char *tree;                               // name of current default tree (needed for ACI)
573
574    bool                 rek;                       // is 'key' hierarchical ?
575    awt_query_field_type match_field;               // type of search key
576    GBQUARK              keyquark;                  // valid only if match_field == AQFT_EXPLICIT
577    awt_query_type       type;                      // type of 'query'
578    struct {                                        // used for some values of 'type'
579        string     str;
580        GBS_REGEX *regexp;
581        float      number;
582    } xquery;
583
584    mutable char *error;                            // set by matches(), once set all future matches fail
585    mutable char *lastACIresult;                    // result of last ACI query
586
587    awt_query *next;
588    int        index;                               // number of query (0 = first query, 1 = second query); not always consecutive!
589
590    // --------------------
591
592    void initFields(struct adaqbsstruct *cbs, int idx, awt_query_operator aqo, AW_root *aw_root);
593    awt_query() {}
594
595    void       detect_query_type();
596    awt_query *remove_tail();
597    void       append(awt_query *tail);
598
599public:
600
601    awt_query(struct adaqbsstruct *cbs);
602
603    ~awt_query() {
604        free(key);
605        free(query);
606        free(lastACIresult);
607        if (xquery.regexp) GBS_free_regexpr(xquery.regexp);
608        free(error);
609        delete next;
610    }
611
612    awt_query_operator getOperator() const { return op; }
613    const char *getKey() const { return key; }
614    bool applyNot(bool matched) const { return Not ? !matched : matched; }
615    bool shallMatch() const { return !Not; }
616    awt_query_type getType() const { return type; }
617    int getIndex() const { return index; }
618
619    bool matches(const char *data, GBDATA *gb_item) const;
620    GB_ERROR getError(int count = 0) const;
621    const char *get_last_ACI_result() const { return type == AQT_ACI ? lastACIresult : 0; }
622
623    awt_query *getNext() { return next; }
624
625    bool is_rek() const { return rek; }
626    awt_query_field_type get_match_field() const { return match_field; }
627    GBQUARK getKeyquark() const { return keyquark; }
628
629    GBDATA *get_first_key(GBDATA *gb_item) const {
630        GBDATA *gb_key = 0;
631
632        if (is_rek()) {
633            gb_key = GB_search(gb_item, getKey(), GB_FIND);
634        }
635        else if (match_field != AQFT_EXPLICIT) {
636            gb_key = GB_child(gb_item);
637            while (gb_key && GB_read_type(gb_key) == GB_DB) {
638                gb_key = GB_nextChild(gb_key);
639            }
640        }
641        else {
642            gb_key = GB_find_sub_by_quark(gb_item, getKeyquark(), 0);
643        }
644
645        return gb_key;
646    }
647
648    void negate();
649
650    bool prefers_sort_by_hit() {
651        return
652            match_field == AQFT_ALL_FIELDS ||
653            match_field == AQFT_ANY_FIELD ||
654            (next && next->prefers_sort_by_hit());
655    }
656
657#if defined(DEBUG)
658    string dump_str() const { return string(key)+(Not ? "!=" : "==")+query; }
659    void dump(string *prev = 0) const {
660        string mine = dump_str();
661        if (prev) {
662            string both = *prev+' ';
663            switch (op) {
664                case AND: both += "&&"; break;
665                case OR: both  += "||"; break;
666                default : awt_assert(0); break;
667            }
668            both += ' '+mine;
669            mine  = both;
670
671            if (next) mine = '('+mine+')';
672        }
673
674        if (next) next->dump(&mine);
675        else fputs(mine.c_str(), stdout);
676    }
677#endif // DEBUG
678};
679
680void awt_query::initFields(struct adaqbsstruct *cbs, int idx, awt_query_operator aqo, AW_root *aw_root) {
681    awt_assert(aqo == OR || aqo == AND);
682
683    error         = 0;
684    lastACIresult = 0;
685    next          = 0;
686    index         = idx;
687    xquery.regexp = 0;
688
689    op    = aqo;
690    key   = aw_root->awar(cbs->awar_keys[idx])->read_string();
691    Not   = aw_root->awar(cbs->awar_not[idx])->read_int() != 0;
692    query = aw_root->awar(cbs->awar_queries[idx])->read_string();
693
694    gb_main = cbs->gb_main;
695    tree    = cbs->tree_name;
696
697    rek         = false;
698    match_field = AQFT_EXPLICIT;;
699    keyquark    = -1;   
700    if (GB_first_non_key_char(key)) {
701        if (strcmp(key, PSEUDO_FIELD_ANY_FIELD) == 0) match_field = AQFT_ANY_FIELD;
702        else if (strcmp(key, PSEUDO_FIELD_ALL_FIELDS) == 0) match_field = AQFT_ALL_FIELDS;
703        else rek = true;
704    }
705    else {
706        keyquark = GB_key_2_quark(gb_main, key);
707    }
708
709    detect_query_type();
710}
711
712awt_query::awt_query(struct adaqbsstruct *cbs) {
713    AW_root *aw_root = cbs->aws->get_root();
714
715    initFields(cbs, 0, OR, aw_root);                // initial value is false, (false OR QUERY1) == QUERY1
716
717    awt_query *tail = this;
718    for (size_t keyidx = 1; keyidx<AWT_QUERY_SEARCHES; ++keyidx) {
719        char *opstr = aw_root->awar(cbs->awar_operator[keyidx])->read_string();
720
721        if (strcmp(opstr, "ign") != 0) {            // not ignore
722            awt_query_operator next_op = ILLEGAL;
723
724            if (strcmp(opstr, "and")     == 0) next_op = AND;
725            else if (strcmp(opstr, "or") == 0) next_op = OR;
726#if defined(ASSERTION_USED)
727            else aw_assert(0);
728#endif // ASSERTION_USED
729
730            if (next_op != ILLEGAL) {
731                awt_query *next_query = new awt_query;
732
733                next_query->initFields(cbs, keyidx, next_op, aw_root);
734
735                tail->next = next_query;
736                tail       = next_query;
737            }
738        }
739        free(opstr);
740    }
741}
742
743awt_query *awt_query::remove_tail() {
744    awt_query *tail = 0;
745    if (next) {
746        awt_query *body_last = this;
747        while (body_last->next && body_last->next->next) {
748            body_last = body_last->next;
749        }
750        awt_assert(body_last->next);
751        awt_assert(body_last->next->next == 0);
752       
753        tail            = body_last->next;
754        body_last->next = 0;
755    }
756    return tail;
757}
758
759void awt_query::append(awt_query *tail) {
760    awt_assert(this != tail);
761    if (next) next->append(tail);
762    else next = tail;
763}
764
765void awt_query::negate() {
766    if (next) {
767        awt_query *tail = remove_tail();
768
769        negate();
770        tail->negate();
771
772        switch (tail->op) {
773            case AND: tail->op = OR; break;
774            case OR: tail->op  = AND; break;
775            default : awt_assert(0); break;
776        }
777
778        append(tail);
779    }
780    else {
781        Not = !Not;
782        switch (match_field) {
783            case AQFT_EXPLICIT: break;
784            case AQFT_ALL_FIELDS: match_field = AQFT_ANY_FIELD; break; // not match allFields <=> mismatch anyField
785            case AQFT_ANY_FIELD: match_field  = AQFT_ALL_FIELDS; break; // not match anyField <=> mismatch allFields
786        }
787    }
788}
789
790GB_ERROR awt_query::getError(int count) const {
791    GB_ERROR err = error;
792    error        = NULL;
793
794    if (err) {
795        err = GBS_global_string("%s (in query #%i)", err, count+1);
796    }
797
798    if (next) {
799        if (err) {
800            char *dup = strdup(err);
801
802            err = next->getError(count+1);
803            if (err) err = GBS_global_string("%s\n%s", dup, err);
804            else err = GBS_global_string("%s", dup);
805            free(dup);
806        }
807        else {
808            err = next->getError(count+1);
809        }
810    }
811
812    return err;
813}
814
815
816inline bool containsWildcards(const char *str) { return strpbrk(str, "*?") != 0; }
817inline bool containsWildcards(const string& str) { return str.find_first_of("*?") != string::npos; }
818
819void awt_query::detect_query_type() {
820    char    first = query[0];
821    string& str   = xquery.str;
822    str           = query;
823
824    type = AQT_INVALID;
825
826    if (!first)            type = AQT_EMPTY;
827    else if (first == '/') {
828        GB_CASE     case_flag;
829        GB_ERROR    err       = 0;
830        const char *unwrapped = GBS_unwrap_regexpr(query, &case_flag, &err);
831        if (unwrapped) {
832            xquery.regexp = GBS_compile_regexpr(unwrapped, case_flag, &err);
833            if (xquery.regexp) type = AQT_REGEXPR;
834        }
835        if (err) freedup(error, err);
836    }
837    else if (first == '|') type = AQT_ACI;
838    else if (first == '<' || first == '>') {
839        const char *rest = query+1;
840        const char *end;
841        float       f    = strtof(rest, const_cast<char**>(&end));
842
843        if (end != rest) { // did convert part or all of rest to float
844            if (end[0] == 0) { // all of rest has been converted
845                type          = query[0] == '<' ? AQT_LOWER : AQT_GREATER;
846                xquery.number = f;
847            }
848            else {
849                freeset(error, GBS_global_string_copy("Could not convert '%s' to number (unexpected content '%s')", rest, end));
850            }
851        }
852        // otherwise handle as non-special search string
853    }
854
855    if (type == AQT_INVALID && !error) {            // no type detected above
856        if (containsWildcards(query)) {
857            size_t qlen = strlen(query);
858            char   last = query[qlen-1];
859
860            if (first == '*') {
861                if (last == '*') {
862                    str  = string(str, 1, str.length()-2); // cut off first and last
863                    type = str.length() ? AQT_OCCURS : AQT_NON_EMPTY;
864                }
865                else {
866                    str  = string(str, 1);          // cut of first
867                    type = AQT_ENDS_WITH;
868                }
869            }
870            else {
871                if (last == '*') {
872                    str  = string(str, 0, str.length()-1); // cut of last
873                    type = AQT_STARTS_WITH;
874                }
875                else type = AQT_WILDCARD;
876            }
877
878            if (type != AQT_WILDCARD && containsWildcards(str)) { // still contains wildcards -> fallback
879                str  = query; 
880                type = AQT_WILDCARD;
881            }
882        }
883        else type = AQT_EXACT_MATCH;
884    }
885
886    awt_assert(type != AQT_INVALID || error);
887}
888
889bool awt_query::matches(const char *data, GBDATA *gb_item) const {
890    // 'data' is the content of the searched field (read as string)
891    // 'gb_item' is the DB item (e.g. species, gene). Used in ACI-search only.
892
893    bool hit = false;
894
895    awt_assert(data);
896    awt_assert(gb_item);
897
898    if (error) hit = false;
899    else switch (type) {
900        case AQT_EMPTY: {
901            hit = (data[0] == 0);
902            break;
903        }
904        case AQT_NON_EMPTY: { 
905            hit = (data[0] != 0);
906            break;
907        }
908        case AQT_EXACT_MATCH: {                     // exact match (but ignoring case)
909            hit = strcasecmp(data, query) == 0;
910            break;
911        }
912        case AQT_OCCURS: {                          // query expression occurs in data (equiv to '*expr*')
913            // hit = GBS_find_string(xquery.str.c_str(), data, 1) != 0;
914            hit = GBS_find_string(data, xquery.str.c_str(), 1) != 0;
915            break;
916        }
917        case AQT_STARTS_WITH: {                     // data starts with query expression (equiv to 'expr*')
918            hit = strncasecmp(data, xquery.str.c_str(), xquery.str.length()) == 0;
919            break;
920        }
921        case AQT_ENDS_WITH: {                       // data ends with query expression (equiv to '*expr')
922            int dlen = strlen(data);
923            hit = strcasecmp(data+dlen-xquery.str.length(), xquery.str.c_str()) == 0;
924            break;
925        }
926        case AQT_WILDCARD: {                        // expr contains wildcards (use GBS_string_matches for compare)
927            hit = GBS_string_matches(data,query,GB_IGNORE_CASE);
928            break;
929        }
930        case AQT_GREATER:                           // data is greater than query
931        case AQT_LOWER: {                           // data is lower than query
932            const char *start = data;
933            while (start[0] == ' ') ++start;
934
935            const char *end;
936            float       f = strtof(start, const_cast<char**>(&end));
937
938            if (end == start) { // nothing was converted
939                hit = false;
940            }
941            else {
942                bool is_numeric = (end[0] == 0);
943
944                if (!is_numeric) {
945                    while (end[0] == ' ') ++end;
946                    is_numeric = (end[0] == 0);
947                }
948                if (is_numeric) {
949                    hit = (type == AQT_GREATER)
950                        ? f > xquery.number
951                        : f < xquery.number;
952                }
953                else {
954                    hit = false;
955                }
956            }
957            break;
958        }
959        case AQT_REGEXPR: {                         // expr is a regexpr ('/.../')
960            hit = GBS_regmatch_compiled(data, xquery.regexp, NULL) != 0;
961            break;
962        }
963        case AQT_ACI: {                             // expr is a ACI ('|...'); result = "0" -> no hit; otherwise hit
964            char *aci_result = GB_command_interpreter(gb_main, data, query, gb_item, tree);
965            if (!aci_result) {
966                freedup(error, GB_await_error());
967                hit   = false;
968            }
969            else {
970                hit = strcmp(aci_result, "0") != 0;
971            }
972            freeset(lastACIresult, aci_result);
973            break;
974        }
975        case AQT_INVALID: {                     // invalid
976            awt_assert(0);
977            freedup(error, "Invalid search expression");
978            hit   = false;
979            break;
980        }
981    }
982    return applyNot(hit);
983}
984
985static void awt_do_query(void *dummy, struct adaqbsstruct *cbs, AW_CL cl_ext_query) {
986    AWUSE(dummy);
987
988    GB_push_transaction(cbs->gb_main);
989
990    AWT_EXT_QUERY_TYPES  ext_query = (AWT_EXT_QUERY_TYPES)cl_ext_query;
991    AW_root             *aw_root   = cbs->aws->get_root();
992    awt_query            query(cbs);
993
994    AWT_QUERY_MODES mode  = (AWT_QUERY_MODES)aw_root->awar(cbs->awar_ere)->read_int();
995    AWT_QUERY_RANGE range = (AWT_QUERY_RANGE)aw_root->awar(cbs->awar_where)->read_int();
996    AWT_QUERY_TYPES type  = (AWT_QUERY_TYPES)aw_root->awar(cbs->awar_by)->read_int();
997
998    if (cbs->gb_ref && type != AWT_QUERY_MARKED) {  // special for merge tool!
999        char *first_query = aw_root->awar(cbs->awar_queries[0])->read_string();
1000        if (strlen(first_query) == 0) {
1001            if (!ext_query) ext_query  = AWT_EXT_QUERY_COMPARE_LINES;
1002        }
1003        free(first_query);
1004    }
1005
1006    GB_ERROR error = query.getError();
1007
1008    if (!error) {
1009        size_t   item_count     = awt_count_items(cbs, range);
1010        size_t   searched_count = 0;
1011
1012        aw_openstatus("Searching");
1013        aw_status(0.0);
1014
1015        if (cbs->gb_ref && // merge tool only
1016            (ext_query == AWT_EXT_QUERY_COMPARE_LINES || ext_query == AWT_EXT_QUERY_COMPARE_WORDS))
1017        {
1018            GB_push_transaction(cbs->gb_ref);
1019            const char *first_key = query.getKey();
1020            GB_HASH    *ref_hash  = awt_create_ref_hash(cbs, first_key, ext_query == AWT_EXT_QUERY_COMPARE_WORDS);
1021
1022#if defined(DEBUG)
1023            printf("query: search identical %s in field %s%s\n",
1024                   (ext_query == AWT_EXT_QUERY_COMPARE_WORDS ? "words" : "values"),
1025                   first_key,
1026                   cbs->expect_hit_in_ref_list ? " of species listed in other hitlist" : "");
1027#endif // DEBUG
1028
1029            for (GBDATA *gb_item_container = cbs->selector->get_first_item_container(cbs->gb_main, aw_root, range);
1030                 gb_item_container && !error;
1031                 gb_item_container = cbs->selector->get_next_item_container(gb_item_container, range))
1032            {
1033                for (GBDATA *gb_item = cbs->selector->get_first_item(gb_item_container);
1034                     gb_item && !error;
1035                     gb_item = cbs->selector->get_next_item(gb_item))
1036                {
1037                    switch (mode) {
1038                        case AWT_QUERY_GENERATE: CLEAR_QUERIED(gb_item, cbs); break;
1039                        case AWT_QUERY_ENLARGE:  if (IS_QUERIED(gb_item, cbs)) continue; break;
1040                        case AWT_QUERY_REDUCE:   if (!IS_QUERIED(gb_item, cbs)) continue; break;
1041                    }
1042                   
1043                    GBDATA *gb_key = query.get_first_key(gb_item);
1044
1045                    if (gb_key) {
1046                        char   *data        = GB_read_as_string(gb_key);
1047                        GBDATA *gb_ref_pntr = 0;
1048
1049                        if (data && data[0]) {
1050                            string hit_reason;
1051                            bool   this_hit = false;
1052
1053                            if (ext_query == AWT_EXT_QUERY_COMPARE_WORDS){
1054                                for (char *t = strtok(data," "); t; t = strtok(0," ")) {
1055                                    gb_ref_pntr = (GBDATA *)GBS_read_hash(ref_hash,t);
1056                                    if (gb_ref_pntr) { // found item in other DB, with 'first_key' containing word from 'gb_key'
1057                                        this_hit   = true;
1058                                        hit_reason = GBS_global_string("%s%s has word '%s' in %s",
1059                                                                       cbs->expect_hit_in_ref_list ? "Hit " : "",
1060                                                                       cbs->selector->generate_item_id(cbs->gb_ref, gb_ref_pntr),
1061                                                                       t, first_key);
1062                                    }
1063                                }
1064                            }
1065                            else {
1066                                gb_ref_pntr = (GBDATA *)GBS_read_hash(ref_hash,data); 
1067                                if (gb_ref_pntr) { // found item in other DB, with identical 'first_key'
1068                                    this_hit   = true;
1069                                    hit_reason = GBS_global_string("%s%s matches %s",
1070                                                                   cbs->expect_hit_in_ref_list ? "Hit " : "",
1071                                                                   cbs->selector->generate_item_id(cbs->gb_ref, gb_ref_pntr),
1072                                                                   first_key);
1073                                }
1074                            }
1075
1076                            if (type == AWT_QUERY_DONT_MATCH) {
1077                                this_hit = !this_hit;
1078                                if (this_hit) hit_reason = "<no matching entry>";
1079                            }
1080
1081                            if (this_hit) {
1082                                awt_assert(!hit_reason.empty());
1083                                SET_QUERIED(gb_item, cbs, hit_reason.c_str(), hit_reason.length());
1084                            }
1085                            else CLEAR_QUERIED(gb_item, cbs);
1086                        }
1087                        free(data);
1088                    }
1089
1090                    if (aw_status(searched_count++/double(item_count))) error = "aborted";
1091                }
1092            }
1093
1094            GBS_free_hash(ref_hash);
1095            GB_pop_transaction(cbs->gb_ref);
1096        }
1097        else {                                          // "normal" query
1098            if (type == AWT_QUERY_DONT_MATCH) {
1099#if defined(DEBUG)
1100                fputs("query: !(", stdout); query.dump();
1101#endif // DEBUG
1102
1103                query.negate();
1104                type = AWT_QUERY_MATCH;
1105
1106#if defined(DEBUG)
1107                fputs(") => query: ", stdout); query.dump(); fputc('\n', stdout);
1108#endif // DEBUG
1109            }
1110#if defined(DEBUG)
1111            else { fputs("query: ", stdout); query.dump(); fputc('\n', stdout); }
1112#endif // DEBUG
1113
1114            if (query.prefers_sort_by_hit()) {
1115                // automatically switch to sorting 'by hit' if 'any field' or 'all fields' is selected
1116                aw_root->awar(cbs->awar_sort)->write_int(AWT_QUERY_SORT_BY_HIT_DESCRIPTION);
1117            }
1118
1119            for (GBDATA *gb_item_container = cbs->selector->get_first_item_container(cbs->gb_main, aw_root, range);
1120                 gb_item_container && !error;
1121                 gb_item_container = cbs->selector->get_next_item_container(gb_item_container, range))
1122            {
1123                for (GBDATA *gb_item = cbs->selector->get_first_item(gb_item_container);
1124                     gb_item && !error;
1125                     gb_item = cbs->selector->get_next_item(gb_item))
1126                {
1127                    string hit_reason;
1128
1129                    switch (mode) {
1130                        case AWT_QUERY_GENERATE: CLEAR_QUERIED(gb_item,cbs); break;
1131                        case AWT_QUERY_ENLARGE:  if (IS_QUERIED(gb_item,cbs)) continue; break;
1132                        case AWT_QUERY_REDUCE:   if (!IS_QUERIED(gb_item,cbs)) continue; break;
1133                    }
1134
1135                    bool hit = false;
1136
1137                    switch(type) {
1138                        case AWT_QUERY_MARKED: {
1139                            hit        = GB_read_flag(gb_item);
1140                            hit_reason = "<marked>";
1141                            break;
1142                        }
1143                        case AWT_QUERY_MATCH: {
1144                            for (awt_query *this_query = &query; this_query;  this_query = this_query ? this_query->getNext() : 0) { // iterate over all single queries
1145                                awt_query_operator this_op = this_query->getOperator();
1146
1147                                if ((this_op == OR) == hit) {
1148                                    continue; // skip query Q for '1 OR Q' and for '0 AND Q' (result can't change)
1149                                }
1150
1151                                string this_hit_reason;
1152
1153                                GBDATA               *gb_key      = this_query->get_first_key(gb_item);
1154                                awt_query_field_type  match_field = this_query->get_match_field();
1155                                bool                  this_hit    = (match_field == AQFT_ALL_FIELDS);
1156
1157                                char *data       = gb_key ? GB_read_as_string(gb_key) : strdup(""); // assume "" for explicit fields that don't exist
1158                                if (!data) error = GB_await_error();
1159
1160                                while (data) {
1161                                    awt_assert(ext_query == AWT_EXT_QUERY_NONE);
1162                                    bool        matched    = this_query->matches(data, gb_item); // includes not-op
1163                                    const char *reason_key = 0;
1164
1165                                    switch (match_field) {
1166                                        case AQFT_EXPLICIT:
1167                                            this_hit   = matched;
1168                                            reason_key = this_query->getKey();
1169                                            break;
1170
1171                                        case AQFT_ANY_FIELD:
1172                                            if (matched) {
1173                                                this_hit   = true;
1174                                                reason_key = GB_read_key_pntr(gb_key);
1175                                            }
1176                                            break;
1177
1178                                        case AQFT_ALL_FIELDS:
1179                                            if (!matched) {
1180                                                this_hit   = false;
1181                                                reason_key = GB_read_key_pntr(gb_key);
1182                                            }
1183                                            break;
1184                                    }
1185
1186                                    if (reason_key) {
1187                                        if (strlen(data)>AWT_MAX_SHOWN_DATA_SIZE) {
1188                                            size_t shortened_len = GBS_shorten_repeated_data(data);
1189                                            if (shortened_len>AWT_MAX_SHOWN_DATA_SIZE) {
1190                                                strcpy(data+AWT_MAX_SHOWN_DATA_SIZE-5, "[...]");
1191                                            }
1192                                        }
1193                                        this_hit_reason       = string(reason_key)+"="+data;
1194                                        const char *ACIresult = this_query->get_last_ACI_result();
1195                                        if (ACIresult) {
1196                                            this_hit_reason = string("[ACI=")+ACIresult+"] "+this_hit_reason;
1197                                        }
1198                                        gb_key = NULL; // stop!
1199                                    }
1200
1201                                    freeset(data, NULL);
1202                                    if (gb_key) {
1203                                        do { gb_key = GB_nextChild(gb_key); }
1204                                        while (gb_key && GB_read_type(gb_key) == GB_DB);
1205
1206                                        if (gb_key) {
1207                                            data = GB_read_as_string(gb_key);
1208                                            awt_assert(data);
1209                                        }
1210                                    }
1211                                }
1212
1213                                if (this_hit && match_field == AQFT_ALL_FIELDS) {
1214                                    awt_assert(this_hit_reason.empty());
1215                                    this_hit_reason = this_query->shallMatch() ? "<matched all fields>" : "<matched no field>";
1216                                }
1217
1218                           
1219                                if (this_hit) {
1220                                    awt_assert(!this_hit_reason.empty()); // if we got a hit, we also need a reason
1221                                    const char *prefix = GBS_global_string("%c%c", '1'+this_query->getIndex(), this_query->shallMatch() ? ' ' : '!');
1222                                    this_hit_reason    = string(prefix)+this_hit_reason;
1223                                }
1224
1225                                // calculate result
1226                                // (Note: the operator of the 1st query is always OR)
1227                                switch (this_op) {
1228                                    case AND: {
1229                                        awt_assert(hit); // otherwise there was no need to run this sub-query
1230                                        hit        = this_hit;
1231                                        hit_reason = hit_reason.empty() ? this_hit_reason : hit_reason+" & "+this_hit_reason;
1232                                        break;
1233                                    }
1234                                    case OR: {
1235                                        awt_assert(!hit); // otherwise there was no need to run this sub-query
1236                                        hit        = this_hit;
1237                                        hit_reason = this_hit_reason;
1238                                        break;
1239                                    }
1240                                    default :
1241                                        awt_assert(0);
1242                                        break;
1243                                }
1244                                awt_assert(!hit || !hit_reason.empty()); // if we got a hit, we also need a reason
1245                            }
1246                            break;
1247                        }
1248                        default : awt_assert(0); break;
1249                    }
1250
1251                    if (hit) {
1252                        awt_assert(!hit_reason.empty());
1253
1254                        if (mode == AWT_QUERY_REDUCE) {
1255                            string prev_info = getHitInfo(gb_item, cbs);
1256                            hit_reason = prev_info+" (kept cause "+hit_reason+")";
1257                        }
1258
1259                        SET_QUERIED(gb_item, cbs, hit_reason.c_str(), hit_reason.length());
1260                    }
1261                    else CLEAR_QUERIED(gb_item, cbs);
1262
1263                    if (error) {
1264                        error = GB_failedTo_error("query", GBT_get_name(gb_item), error);
1265                    }
1266                    else {
1267                        if (aw_status(searched_count++/double(item_count))) error = "aborted";
1268                    }
1269                }
1270            }
1271        }
1272
1273        aw_closestatus();
1274    }
1275
1276    if (!error) error = query.getError(); // check for query error
1277
1278    if (error) aw_message(error);
1279    else awt_query_update_list(0,cbs);
1280
1281    GB_pop_transaction(cbs->gb_main);
1282}
1283
1284void awt_copy_selection_list_2_queried_species(struct adaqbsstruct *cbs, AW_selection_list *id, const char *hit_description) {
1285    GB_transaction ta(cbs->gb_main);
1286
1287    awt_assert(strstr(hit_description, "%s")); // hit_description needs '%s' (which is replaced by visible content of 'id')
1288
1289    GB_ERROR         error     = 0;
1290    AW_window       *aww       = cbs->aws;
1291    AW_root         *aw_root   = aww->get_root();
1292    GB_HASH         *list_hash = aww->selection_list_to_hash(id, false);
1293    AWT_QUERY_MODES  mode      = (AWT_QUERY_MODES)aw_root->awar(cbs->awar_ere)->read_int();
1294    AWT_QUERY_TYPES  type      = (AWT_QUERY_TYPES)aw_root->awar(cbs->awar_by)->read_int();
1295
1296    if (type == AWT_QUERY_MARKED) {
1297        error = "Query mode 'that are marked' does not apply here.\nEither select 'that match the query' or 'that don't match the q.'";
1298    }
1299
1300    if (type != AWT_QUERY_MATCH || mode != AWT_QUERY_GENERATE) { // different behavior as in the past -> advice
1301        AWT_advice("'Move to hitlist' now depends on the values selected for\n"
1302                   " * 'Search/Add/Keep species' and\n"
1303                   " * 'that match/don't match the query'\n"
1304                   "in the search tool.",
1305                   AWT_ADVICE_TOGGLE|AWT_ADVICE_HELP,
1306                   "Behavior changed",
1307                   "next_neighbours.hlp");
1308    }
1309
1310    long inHitlist = GBS_hash_count_elems(list_hash);
1311    long seenInDB  = 0;
1312
1313    for (GBDATA *gb_species = GBT_first_species(cbs->gb_main);
1314         gb_species && !error;
1315         gb_species = GBT_next_species(gb_species))
1316    {
1317        switch (mode) {
1318            case AWT_QUERY_GENERATE: CLEAR_QUERIED(gb_species, cbs); break;
1319            case AWT_QUERY_ENLARGE:  if (IS_QUERIED(gb_species, cbs)) continue; break;
1320            case AWT_QUERY_REDUCE:   if (!IS_QUERIED(gb_species, cbs)) continue; break;
1321        }
1322
1323        const char *name      = GBT_get_name(gb_species);
1324        const char *displayed = reinterpret_cast<const char*>(GBS_read_hash(list_hash, name));
1325
1326        if (displayed) seenInDB++;
1327
1328        if ((displayed == 0) == (type == AWT_QUERY_DONT_MATCH)) {
1329            string hit_reason = GBS_global_string(hit_description, displayed ? displayed : "<no near neighbour>");
1330           
1331            if (mode == AWT_QUERY_REDUCE) {
1332                string prev_info = getHitInfo(gb_species, cbs);
1333                hit_reason = prev_info+" (kept cause "+hit_reason+")";
1334            }
1335            SET_QUERIED(gb_species, cbs, hit_reason.c_str(), hit_reason.length());
1336        }
1337        else {
1338            CLEAR_QUERIED(gb_species, cbs);
1339        }
1340    }
1341
1342    if (seenInDB < inHitlist) {
1343        aw_message(GBS_global_string("%li of %li hits were found in database", seenInDB, inHitlist));
1344    }
1345
1346    GBS_free_hash(list_hash);
1347    if (error) aw_message(error);
1348    awt_query_update_list(0,cbs);
1349}
1350
1351
1352void awt_search_equal_entries(AW_window *,struct adaqbsstruct *cbs, bool tokenize){
1353    char     *key   = cbs->aws->get_root()->awar(cbs->awar_keys[0])->read_string();
1354    GB_ERROR  error = 0;
1355
1356    if (strlen(key) == 0) {
1357        error = "Please select a key (in the first query expression)";
1358    }
1359    else {
1360        GB_transaction dumy(cbs->gb_main);
1361
1362        GBDATA          *gb_species_data = GB_search(cbs->gb_main, "species_data", GB_CREATE_CONTAINER);
1363        AW_root         *aw_root         = cbs->aws->get_root();
1364        long             hashsize;
1365        AWT_QUERY_RANGE  range           = AWT_QUERY_ALL_SPECIES;
1366        AWT_QUERY_TYPES  type            = (AWT_QUERY_TYPES)aw_root->awar(cbs->awar_by)->read_int();;
1367
1368        switch (cbs->selector->type) {
1369            case AWT_QUERY_ITEM_SPECIES:  {
1370                hashsize = GB_number_of_subentries(gb_species_data);
1371                break;
1372            }
1373            case AWT_QUERY_ITEM_EXPERIMENTS:
1374            case AWT_QUERY_ITEM_GENES: {
1375                // handle species sub-items
1376                hashsize = 0;
1377
1378                for (GBDATA *gb_item_container = cbs->selector->get_first_item_container(cbs->gb_main, cbs->aws->get_root(), range);
1379                     gb_item_container;
1380                     gb_item_container = cbs->selector->get_next_item_container(gb_item_container, range))
1381                {
1382                    hashsize += GB_number_of_subentries(gb_item_container);
1383                }
1384
1385                break;
1386            }
1387            default: {
1388                awt_assert(0);
1389                hashsize = 0;
1390                break;
1391            }
1392        }
1393
1394        if (!hashsize) {
1395            error = "No items exist";
1396        }
1397        else if (type == AWT_QUERY_MARKED) {
1398            error = "'that are marked' is not applicable here";
1399        }
1400
1401        if (!error) {
1402            GB_HASH *hash = GBS_create_hash(hashsize, GB_IGNORE_CASE);
1403
1404            for (GBDATA *gb_item_container = cbs->selector->get_first_item_container(cbs->gb_main, aw_root, range);
1405                 gb_item_container;
1406                 gb_item_container = cbs->selector->get_next_item_container(gb_item_container, range))
1407            {
1408                for (GBDATA *gb_item = cbs->selector->get_first_item(gb_item_container);
1409                     gb_item;
1410                     gb_item = cbs->selector->get_next_item(gb_item))
1411                {
1412                    CLEAR_QUERIED(gb_item,cbs);
1413                    GB_write_flag(gb_item,0);
1414
1415                    GBDATA *gb_key = GB_search(gb_item,key,GB_FIND);    if (!gb_key) continue;
1416                    char   *data   = GB_read_as_string(gb_key);         if (!data) continue;
1417
1418                    if (tokenize){
1419                        char *s;
1420                        for (s=strtok(data,",; \t."); s ; s = strtok(0,",; \t.")){
1421                            GBDATA *gb_old = (GBDATA *)GBS_read_hash(hash,s);
1422                            if (gb_old) {
1423                                const char *oldInfo   = 0;
1424                                char       *firstInfo = GBS_global_string_copy("1st=%s", s);
1425
1426                                if (IS_QUERIED(gb_old, cbs)) {
1427                                    const char *prevInfo = getHitInfo(gb_old, cbs);
1428
1429                                    if (strstr(prevInfo, firstInfo) == 0) { // not already have 1st-entry here
1430                                        oldInfo = GBS_global_string("%s %s", prevInfo, firstInfo);
1431                                    }
1432                                }
1433                                else {
1434                                    oldInfo = firstInfo;
1435                                }
1436                               
1437                                if (oldInfo) SET_QUERIED(gb_old, cbs, oldInfo);
1438                                SET_QUERIED(gb_item, cbs, GBS_global_string("dup=%s", s));
1439                                GB_write_flag(gb_item, 1);
1440
1441                                free(firstInfo);
1442                            }
1443                            else {
1444                                GBS_write_hash(hash,s,(long)gb_item);
1445                            }
1446                        }
1447                    }
1448                    else {
1449                        GBDATA *gb_old = (GBDATA *)GBS_read_hash(hash,data);
1450                        if (gb_old) {
1451                            if (!IS_QUERIED(gb_old, cbs)) {
1452                                SET_QUERIED(gb_old, cbs, GBS_global_string("%s (1st)", data));
1453                            }
1454                            SET_QUERIED(gb_item, cbs, GBS_global_string("%s (duplicate)", data));
1455                            GB_write_flag(gb_item, 1);
1456                        }
1457                        else {
1458                            GBS_write_hash(hash,data,(long)gb_item);
1459                        }
1460                    }
1461
1462                    free(data);
1463                }
1464
1465                if (type == AWT_QUERY_DONT_MATCH) {
1466                    for (GBDATA *gb_item = cbs->selector->get_first_item(gb_item_container);
1467                         gb_item;
1468                         gb_item = cbs->selector->get_next_item(gb_item))
1469                    {
1470                        if (IS_QUERIED(gb_item, cbs)) {
1471                            CLEAR_QUERIED(gb_item, cbs);
1472                            GB_write_flag(gb_item, 0); // unmark
1473                        }
1474                        else {
1475                            SET_QUERIED(gb_item, cbs, tokenize ? "<entry with unique words>" : "<unique entry>");
1476                        }
1477                    }
1478                }
1479            }
1480
1481            GBS_free_hash(hash);
1482        }
1483
1484        if (type != AWT_QUERY_MATCH) {
1485            AWT_advice("'Find equal entries' now depends on the values selected for\n"
1486                       " * 'that match/don't match the query'\n"
1487                       "in the search tool.",
1488                       AWT_ADVICE_TOGGLE|AWT_ADVICE_HELP,
1489                       "Behavior changed",
1490                       "search_duplicates.hlp");
1491        }
1492    }
1493
1494    free(key);
1495
1496    if (error) aw_message(error);
1497    awt_query_update_list(0,cbs);
1498}
1499
1500/***************** Pars fields *************************/
1501
1502void awt_do_pars_list(void *dummy, struct adaqbsstruct *cbs)
1503{
1504    AWUSE(dummy);
1505    GB_ERROR  error = 0;
1506    char     *key   = cbs->aws->get_root()->awar(cbs->awar_parskey)->read_string();
1507
1508    if (!strcmp(key,"name")){
1509        switch (cbs->selector->type)  {
1510            case AWT_QUERY_ITEM_SPECIES: {
1511                if (aw_question("WARNING WARNING WARNING!!! You now try to rename the species\n"
1512                                "    The name is used to link database entries and trees\n"
1513                                "    ->  ALL TREES WILL BE LOST\n"
1514                                "    ->  The new name MUST be UNIQUE"
1515                                "        if not you will corrupt the database!" ,
1516                                "Let's Go,Cancel")) return;
1517                break;
1518            }
1519            case AWT_QUERY_ITEM_GENES: {
1520                if (aw_question("WARNING! You now try to rename the gene\n"
1521                                "    ->  Pseudo-species will loose their link to the gene"
1522                                "    ->  The new name MUST be UNIQUE"
1523                                "        if not you will corrupt the database!" ,
1524                                "Let's Go,Cancel")) return;
1525                break;
1526            }
1527            case AWT_QUERY_ITEM_EXPERIMENTS: {
1528                if (aw_question("WARNING! You now try to rename the experiment\n"
1529                                "    ->  The new name MUST be UNIQUE"
1530                                "        if not you will corrupt the database!" ,
1531                                "Let's Go,Cancel")) return;
1532                break;
1533            }
1534            default: {
1535                awt_assert(0);
1536                return;
1537            }
1538        }
1539    }
1540
1541
1542    if (!strlen(key)) error = "Please select a valid key";
1543
1544    char *command = cbs->aws->get_root()->awar(cbs->awar_parsvalue)->read_string();
1545    if (!error && !strlen(command)) {
1546        error = "Please enter your command";
1547    }
1548    if (!error) {
1549        GB_begin_transaction(cbs->gb_main);
1550       
1551        GBDATA *gb_key_name;
1552        {
1553            GBDATA *gb_key_data = GB_search(cbs->gb_main, cbs->selector->change_key_path, GB_CREATE_CONTAINER);
1554            while (!error && !(gb_key_name = GB_find_string(gb_key_data,CHANGEKEY_NAME,key,GB_IGNORE_CASE,down_2_level))) {
1555                const char *question = GBS_global_string("The destination field '%s' does not exists", key);
1556                if (aw_question(question, "Create Field (Type STRING),Cancel")) {
1557                    error = "Aborted by user";
1558                }
1559                else {
1560                    error = GBT_add_new_changekey_to_keypath(cbs->gb_main,key,GB_STRING, cbs->selector->change_key_path);
1561                }
1562            }
1563        }
1564
1565        GBDATA *gb_key_type;
1566        if (!error) {
1567            gb_key_type = GB_brother(gb_key_name,CHANGEKEY_TYPE);
1568           
1569            if (!gb_key_type) error = GB_await_error();
1570            else {
1571                if (GB_read_int(gb_key_type)!=GB_STRING &&
1572                    aw_question("Writing to a non-STRING database field may lead to conversion problems.", "Abort,Continue")==0)
1573                {
1574                    error = "Aborted by user";
1575                }
1576            }
1577        }
1578
1579        if (!error) {
1580            long  count  = 0;
1581            long  ncount = cbs->aws->get_root()->awar(cbs->awar_count)->read_int();
1582            char *deftag = cbs->aws->get_root()->awar(cbs->awar_deftag)->read_string();
1583            char *tag    = cbs->aws->get_root()->awar(cbs->awar_tag)->read_string();
1584
1585            {
1586                long use_tag = cbs->aws->get_root()->awar(cbs->awar_use_tag)->read_int();
1587                if (!use_tag || !strlen(tag)) {
1588                    freeset(tag, 0);
1589                }
1590            }
1591            int double_pars = cbs->aws->get_root()->awar(cbs->awar_double_pars)->read_int();
1592
1593            aw_openstatus("Pars Fields");
1594
1595            AW_root         *aw_root = cbs->aws->get_root();
1596            AWT_QUERY_RANGE  range   = (AWT_QUERY_RANGE)aw_root->awar(cbs->awar_where)->read_int();
1597
1598            for (GBDATA *gb_item_container = cbs->selector->get_first_item_container(cbs->gb_main, aw_root, range);
1599                 !error && gb_item_container;
1600                 gb_item_container = cbs->selector->get_next_item_container(gb_item_container, range))
1601            {
1602                for (GBDATA *gb_item = cbs->selector->get_first_item(gb_item_container);
1603                     !error && gb_item;
1604                     gb_item = cbs->selector->get_next_item(gb_item))
1605                {
1606                    if (IS_QUERIED(gb_item,cbs)) {
1607                        if (aw_status((count++)/(double)ncount)) {
1608                            error = "Aborted by user";
1609                            break;
1610                        }
1611                        GBDATA *gb_new = GB_search(gb_item, key,GB_FIND);
1612                        char   *str    = gb_new ? GB_read_as_string(gb_new) : strdup("");
1613                        char   *parsed = 0;
1614
1615                        if (double_pars) {
1616                            char *com2 = GB_command_interpreter(cbs->gb_main, str,command,gb_item, cbs->tree_name);
1617                            if (com2) {
1618                                if (tag) parsed = GBS_string_eval_tagged_string(cbs->gb_main, "", deftag, tag, 0, com2, gb_item);
1619                                else parsed     = GB_command_interpreter       (cbs->gb_main, "", com2, gb_item, cbs->tree_name);
1620                            }
1621                            free(com2);
1622                        }
1623                        else {
1624                            if (tag) parsed = GBS_string_eval_tagged_string(cbs->gb_main, str, deftag, tag, 0, command,gb_item);
1625                            else parsed     = GB_command_interpreter       (cbs->gb_main, str, command, gb_item, cbs->tree_name);
1626                        }
1627
1628                        if (!parsed) error = GB_await_error();
1629                        else {
1630                            if (strcmp(parsed, str) != 0) { // any change?
1631                                if (gb_new && parsed[0] == 0) { // empty result -> delete field
1632                                    error = GB_delete(gb_new);
1633                                }
1634                                else {
1635                                    if (!gb_new) {
1636                                        gb_new = GB_search(gb_item, key, GB_read_int(gb_key_type));
1637                                        if (!gb_new) error = GB_await_error();
1638                                    }
1639                                    if (!error) error = GB_write_as_string(gb_new, parsed);
1640                                }
1641                            }
1642                            free(parsed);
1643                        }
1644                        free(str);
1645                    }
1646                }
1647            }
1648
1649
1650            aw_closestatus();
1651            delete tag;
1652            free(deftag);
1653        }
1654
1655        error = GB_end_transaction(cbs->gb_main, error);
1656    }
1657   
1658    if (error) aw_message(error);
1659
1660    free(key);
1661    free(command);
1662}
1663
1664void awt_predef_prg(AW_root *aw_root, struct adaqbsstruct *cbs){
1665    char *str = aw_root->awar(cbs->awar_parspredefined)->read_string();
1666    char *brk = strchr(str,'#');
1667    if (brk) {
1668        *(brk++) = 0;
1669        char *kv = str;
1670        if (!strcmp(str,"ali_*/data")){
1671            GB_transaction valid_transaction(cbs->gb_main);
1672            char *use = GBT_get_default_alignment(cbs->gb_main);
1673            kv = GBS_global_string_copy("%s/data",use);
1674            free(use);
1675        }
1676        aw_root->awar(cbs->awar_parskey)->write_string( kv);
1677        if (kv != str) free(kv);
1678        aw_root->awar(cbs->awar_parsvalue)->write_string( brk);
1679    }else{
1680        aw_root->awar(cbs->awar_parsvalue)->write_string( str);
1681    }
1682    free(str);
1683}
1684
1685char *AWT_get_item_id(GBDATA *gb_main, const ad_item_selector *sel, GBDATA *gb_item) {
1686    return sel->generate_item_id(gb_main, gb_item);
1687}
1688
1689GBDATA *AWT_get_item_with_id(GBDATA *gb_main, const ad_item_selector *sel, const char *id) {
1690    return sel->find_item_by_id(gb_main, id);
1691}
1692
1693static void awt_colorize_listed(AW_window */*dummy*/, AW_CL cl_cbs) {
1694    struct adaqbsstruct *cbs         = (struct adaqbsstruct *)cl_cbs;
1695    GB_transaction       trans_dummy(cbs->gb_main);
1696    GB_ERROR             error       = 0;
1697    AW_root             *aw_root     = cbs->aws->get_root();
1698    int                  color_group = aw_root->awar(AWAR_COLORIZE)->read_int();
1699    AWT_QUERY_RANGE      range       = (AWT_QUERY_RANGE)aw_root->awar(cbs->awar_where)->read_int();
1700
1701    for (GBDATA *gb_item_container = cbs->selector->get_first_item_container(cbs->gb_main, aw_root, range);
1702         !error && gb_item_container;
1703         gb_item_container = cbs->selector->get_next_item_container(gb_item_container, range))
1704        {
1705            for (GBDATA *gb_item = cbs->selector->get_first_item(gb_item_container);
1706                 !error && gb_item;
1707                 gb_item       = cbs->selector->get_next_item(gb_item))
1708                {
1709                    if (IS_QUERIED(gb_item,cbs)) {
1710                        error = AW_set_color_group(gb_item, color_group);
1711                    }
1712                }
1713        }
1714
1715    if (error) GB_export_error(error);
1716}
1717
1718struct color_mark_data {
1719    const ad_item_selector *sel;
1720    GBDATA                 *gb_main;
1721};
1722
1723static void awt_colorize_marked(AW_window *aww, AW_CL cl_cmd) {
1724    const color_mark_data  *cmd         = (struct color_mark_data *)cl_cmd;
1725    const ad_item_selector *sel         = cmd->sel;
1726    GB_transaction          trans_dummy(cmd->gb_main);
1727    GB_ERROR                error       = 0;
1728    AW_root                *aw_root     = aww->get_root();
1729    int                     color_group = aw_root->awar(AWAR_COLORIZE)->read_int();
1730    AWT_QUERY_RANGE         range       = AWT_QUERY_ALL_SPECIES; // @@@ FIXME: make customizable
1731
1732    for (GBDATA *gb_item_container = sel->get_first_item_container(cmd->gb_main, aw_root, range);
1733         !error && gb_item_container;
1734         gb_item_container = sel->get_next_item_container(gb_item_container, range))
1735        {
1736            for (GBDATA *gb_item = sel->get_first_item(gb_item_container);
1737                 !error && gb_item;
1738                 gb_item       = sel->get_next_item(gb_item))
1739                {
1740                    if (GB_read_flag(gb_item)) {
1741                        error = AW_set_color_group(gb_item, color_group);
1742                    }
1743                }
1744        }
1745
1746    if (error) GB_export_error(error);
1747}
1748
1749// @@@ awt_mark_colored is obsolete! (will be replaced by dynamic coloring in the future)
1750static void awt_mark_colored(AW_window *aww, AW_CL cl_cmd, AW_CL cl_mode)
1751{
1752    const color_mark_data  *cmd         = (struct color_mark_data *)cl_cmd;
1753    const ad_item_selector *sel         = cmd->sel;
1754    int                     mode        = int(cl_mode); // 0 = unmark 1 = mark 2 = invert
1755    GB_ERROR                error       = 0;
1756    AW_root                *aw_root     = aww->get_root();
1757    int                     color_group = aw_root->awar(AWAR_COLORIZE)->read_int();
1758    AWT_QUERY_RANGE         range       = AWT_QUERY_ALL_SPECIES; // @@@ FIXME: make customizable
1759
1760    GB_transaction trans_dummy(cmd->gb_main);
1761
1762    for (GBDATA *gb_item_container = sel->get_first_item_container(cmd->gb_main, aw_root, range);
1763         !error && gb_item_container;
1764         gb_item_container = sel->get_next_item_container(gb_item_container, range))
1765        {
1766            for (GBDATA *gb_item = sel->get_first_item(gb_item_container);
1767                 !error && gb_item;
1768                 gb_item       = sel->get_next_item(gb_item))
1769                {
1770                    long my_color = AW_find_color_group(gb_item, true);
1771                    if (my_color == color_group) {
1772                        bool marked = GB_read_flag(gb_item);
1773
1774                        switch (mode) {
1775                        case 0: marked = 0; break;
1776                        case 1: marked = 1; break;
1777                        case 2: marked = !marked; break;
1778                        default : awt_assert(0); break;
1779                        }
1780
1781                        error = GB_write_flag(gb_item, marked);
1782                    }
1783                }
1784        }
1785
1786    if (error) GB_export_error(error);
1787}
1788
1789// --------------------------------------------------------------------------------
1790// color sets
1791
1792struct color_save_data {
1793    color_mark_data   *cmd;
1794    const char        *items_name;
1795    AW_window         *aww; // window of selection list
1796    AW_selection_list *sel_id;
1797};
1798
1799#define AWT_COLOR_LOADSAVE_NAME "tmp/colorset/name"
1800
1801static GBDATA *get_colorset_root(const color_save_data *csd) {
1802    GBDATA *gb_main      = csd->cmd->gb_main;
1803    GBDATA *gb_colorsets = GB_search(gb_main, "colorsets", GB_CREATE_CONTAINER);
1804    GBDATA *gb_item_root = GB_search(gb_colorsets, csd->items_name, GB_CREATE_CONTAINER);
1805
1806    awt_assert(gb_item_root);
1807    return gb_item_root;
1808}
1809
1810static void update_colorset_selection_list(const color_save_data *csd) {
1811    GB_transaction  ta(csd->cmd->gb_main);
1812    AW_window      *aww = csd->aww;
1813
1814    aww->clear_selection_list(csd->sel_id);
1815    GBDATA *gb_item_root = get_colorset_root(csd);
1816
1817    for (GBDATA *gb_colorset = GB_entry(gb_item_root, "colorset");
1818         gb_colorset;
1819         gb_colorset = GB_nextEntry(gb_colorset))
1820    {
1821        const char *name = GBT_read_name(gb_colorset);
1822        aww->insert_selection(csd->sel_id, name, name);
1823    }
1824    aww->insert_default_selection(csd->sel_id, "<new colorset>", "");
1825
1826    aww->update_selection_list(csd->sel_id);
1827}
1828
1829static void colorset_changed_cb(GBDATA*, int *cl_csd, GB_CB_TYPE cbt) {
1830    if (cbt&GB_CB_CHANGED) {
1831        const color_save_data *csd = (const color_save_data*)cl_csd;
1832        update_colorset_selection_list(csd);
1833    }
1834}
1835
1836static char *create_colorset_representation(const color_save_data *csd, GB_ERROR& error) {
1837    const color_mark_data  *cmd     = csd->cmd;
1838    const ad_item_selector *sel     = cmd->sel;
1839    AWT_QUERY_RANGE         range   = AWT_QUERY_ALL_SPECIES;
1840    AW_root                *aw_root = csd->aww->get_root();
1841    GBDATA                 *gb_main = cmd->gb_main;
1842
1843    typedef list<string> ColorList;
1844    ColorList             cl;
1845
1846    for (GBDATA *gb_item_container = sel->get_first_item_container(cmd->gb_main, aw_root, range);
1847         !error && gb_item_container;
1848         gb_item_container = sel->get_next_item_container(gb_item_container, range))
1849    {
1850        for (GBDATA *gb_item = sel->get_first_item(gb_item_container);
1851             !error && gb_item;
1852             gb_item = sel->get_next_item(gb_item))
1853        {
1854            long        color     = AW_find_color_group(gb_item, true);
1855            char       *id        = sel->generate_item_id(gb_main, gb_item);
1856            const char *color_def = GBS_global_string("%s=%li", id, color);
1857            cl.push_front(color_def);
1858            free(id);
1859        }
1860    }
1861
1862    char *result = 0;
1863    if (cl.empty()) {
1864        error = GBS_global_string("Could not find any %s", sel->items_name);
1865    }
1866    else {
1867        string res;
1868        for (ColorList::iterator ci = cl.begin(); ci != cl.end(); ++ci) {
1869            res += (*ci) + ';';
1870        }
1871
1872        result               = (char*)malloc(res.length());
1873        memcpy(result, res.c_str(), res.length()-1); // skip trailing ';'
1874        result[res.length()] = 0;
1875    }
1876    return result;
1877}
1878
1879static GB_ERROR clear_all_colors(const color_save_data *csd) {
1880    const color_mark_data  *cmd     = csd->cmd;
1881    const ad_item_selector *sel     = cmd->sel;
1882    AWT_QUERY_RANGE         range   = AWT_QUERY_ALL_SPECIES;
1883    AW_root                *aw_root = csd->aww->get_root();
1884    GB_ERROR                error   = 0;
1885
1886    for (GBDATA *gb_item_container = sel->get_first_item_container(cmd->gb_main, aw_root, range);
1887         !error && gb_item_container;
1888         gb_item_container = sel->get_next_item_container(gb_item_container, range))
1889    {
1890        for (GBDATA *gb_item = sel->get_first_item(gb_item_container);
1891             !error && gb_item;
1892             gb_item = sel->get_next_item(gb_item))
1893        {
1894            error = AW_set_color_group(gb_item, 0); // clear colors
1895        }
1896    }
1897
1898    return error;
1899}
1900
1901static void awt_clear_all_colors(AW_window *, AW_CL cl_csd) {
1902    const color_save_data *csd   = (const color_save_data*)cl_csd;
1903    GB_transaction         ta(csd->cmd->gb_main);
1904    GB_ERROR               error = clear_all_colors(csd);
1905
1906    if (error) {
1907        error = ta.close(error);
1908        aw_message(error);
1909    }
1910}
1911
1912static GB_ERROR restore_colorset_representation(const color_save_data *csd, const char *colorset) {
1913    const color_mark_data  *cmd     = csd->cmd;
1914    const ad_item_selector *sel     = cmd->sel;
1915    GBDATA                 *gb_main = cmd->gb_main;
1916
1917    int   buffersize = 200;
1918    char *buffer     = (char*)malloc(buffersize);
1919
1920    while (colorset) {
1921        const char *equal = strchr(colorset, '=');
1922        awt_assert(equal);
1923        const char *semi  = strchr(equal, ';');
1924
1925        int size = equal-colorset;
1926        if (size >= buffersize) {
1927            buffersize = int(size*1.5);
1928            freeset(buffer, (char*)malloc(buffersize));
1929        }
1930
1931        awt_assert(buffer && buffersize>size);
1932        memcpy(buffer, colorset, size);
1933        buffer[size] = 0;       // now buffer contains the item id
1934
1935        GBDATA *gb_item = AWT_get_item_with_id(gb_main, sel, buffer);
1936        if (!gb_item) {
1937            aw_message(GBS_global_string("No such %s: '%s'", sel->item_name, buffer));
1938        }
1939        else {
1940            int color_group = atoi(equal+1);
1941            AW_set_color_group(gb_item, color_group);
1942        }
1943        colorset = semi ? semi+1 : 0;
1944    }
1945
1946    free(buffer);
1947    return 0;
1948}
1949
1950static void awt_loadsave_colorset(AW_window *aws, AW_CL cl_csd, AW_CL cl_mode) {
1951    const color_save_data *csd     = (const color_save_data*)cl_csd;
1952    int                    mode    = (int)cl_mode;  // 0 = save; 1 = load; 2 = overlay; 3 = delete;
1953    AW_root               *aw_root = aws->get_root();
1954    char                  *name    = aw_root->awar(AWT_COLOR_LOADSAVE_NAME)->read_string();
1955    GB_ERROR               error   = 0;
1956
1957    if (name[0] == 0) {
1958        error = "Please enter a name for the colorset.";
1959    }
1960    else {
1961        GB_transaction ta(csd->cmd->gb_main);
1962        GBDATA *gb_colorset_root = get_colorset_root(csd);
1963        awt_assert(gb_colorset_root);
1964
1965        GBDATA *gb_colorset_name = GB_find_string(gb_colorset_root, "name", name, GB_IGNORE_CASE, down_2_level);
1966        GBDATA *gb_colorset      = gb_colorset_name ? GB_get_father(gb_colorset_name) : 0;
1967        if (mode == 0) {        // save-mode
1968            if (!gb_colorset) { // create new (otherwise overwrite w/o comment)
1969                gb_colorset             = GB_create_container(gb_colorset_root, "colorset");
1970                if (!gb_colorset) error = GB_await_error();
1971                else error              = GBT_write_string(gb_colorset, "name", name);
1972            }
1973            if (!error) {
1974                char *colorset = create_colorset_representation(csd, error);
1975                if (colorset) {
1976                    error = GBT_write_string(gb_colorset, "color_set", colorset);
1977                    free(colorset);
1978                }
1979            }
1980        }
1981        else { // load/delete
1982            if (!gb_colorset) {
1983                error = GBS_global_string("Colorset '%s' not found", name);
1984            }
1985            else {
1986                if (mode == 1 || mode == 2) { // load- and overlay-mode
1987                    GBDATA *gb_set = GB_entry(gb_colorset, "color_set");
1988                    if (!gb_set) {
1989                        error = "colorset is empty (oops)";
1990                    }
1991                    else {
1992                        const char *colorset = GB_read_char_pntr(gb_set);
1993                        if (!colorset) error = GB_await_error();
1994                        else {
1995                            if (mode == 1) { // load => clear all colors
1996                                error = clear_all_colors(csd);
1997                            }
1998                            if (!error) {
1999                                error = restore_colorset_representation(csd, colorset);
2000                            }
2001                        }
2002                    }
2003                }
2004                else {
2005                    awt_assert(mode == 3); // delete-mode
2006                    error = GB_delete(gb_colorset);
2007                }
2008            }
2009        }
2010
2011        error = ta.close(error);
2012    }
2013    free(name);
2014
2015    if (error) aw_message(error);
2016}
2017
2018static AW_window *awt_create_loadsave_colored_window(AW_root *aw_root, AW_CL cl_csd) {
2019    static AW_window **aw_loadsave = 0;
2020    if (!aw_loadsave) {
2021        // init data
2022        aw_root->awar_string(AWT_COLOR_LOADSAVE_NAME, "", AW_ROOT_DEFAULT);
2023        aw_loadsave = (AW_window**)GB_calloc(AWT_QUERY_ITEM_TYPES, sizeof(*aw_loadsave)); // contains loadsave windows for each item type
2024    }
2025
2026    color_save_data     *csd  = (color_save_data*)cl_csd;
2027    AWT_QUERY_ITEM_TYPE  type = csd->cmd->sel->type;
2028
2029    awt_assert(type<AWT_QUERY_ITEM_TYPES);
2030
2031    if (!aw_loadsave[type]) {
2032        // init window
2033        AW_window_simple *aws = new AW_window_simple;
2034        {
2035            char *window_id = GBS_global_string_copy("colorset_loadsave_%s", csd->items_name);
2036            aws->init(aw_root, window_id, GBS_global_string("Load/Save %s colorset", csd->items_name));
2037            free(window_id);
2038        }
2039
2040        aws->load_xfig("color_loadsave.fig");
2041
2042        aws->at("close");
2043        aws->callback((AW_CB0) AW_POPDOWN);
2044        aws->create_button("CLOSE","CLOSE", "C");
2045
2046        aws->at("help");
2047        aws->callback(AW_POPUP_HELP,(AW_CL)"color_loadsave.hlp");
2048        aws->create_button("HELP","HELP","H");
2049
2050        aws->at("name");
2051        aws->create_input_field(AWT_COLOR_LOADSAVE_NAME, 60);
2052
2053        awt_assert(csd->sel_id == 0);
2054        aws->at("list");
2055        csd->sel_id = aws->create_selection_list(AWT_COLOR_LOADSAVE_NAME, 0, 0, 0, 0);
2056        csd->aww    = aws;
2057
2058        update_colorset_selection_list(csd);
2059
2060        aws->at("save");
2061        aws->callback(awt_loadsave_colorset, (AW_CL)csd, (AW_CL)0); // 0 = save
2062        aws->create_button("save", "Save", "S");
2063
2064        aws->at("load");
2065        aws->callback(awt_loadsave_colorset, (AW_CL)csd, (AW_CL)1); // 1 = load
2066        aws->create_button("load", "Load", "L");
2067
2068        aws->at("overlay");
2069        aws->callback(awt_loadsave_colorset, (AW_CL)csd, (AW_CL)2); // 2 = overlay
2070        aws->create_button("overlay", "Overlay", "O");
2071
2072        aws->at("delete");
2073        aws->callback(awt_loadsave_colorset, (AW_CL)csd, (AW_CL)3); // 3 = delete
2074        aws->create_button("delete", "Delete", "D");
2075
2076        aws->at("reset");
2077        aws->callback(awt_clear_all_colors, (AW_CL)csd);
2078        aws->create_button("reset", "Reset", "R");
2079
2080        // callbacks
2081        {
2082            GB_transaction  ta(csd->cmd->gb_main);
2083            GBDATA         *gb_colorset = get_colorset_root(csd);
2084            GB_add_callback(gb_colorset, GB_CB_CHANGED, colorset_changed_cb, (int*)csd);
2085        }
2086
2087        aw_loadsave[type] = aws;
2088    }
2089
2090    return aw_loadsave[type];
2091}
2092
2093static const char *color_group_name(int color_group) {
2094    static char buf[30];
2095
2096    if (color_group) {
2097        sprintf(buf, "color group %i", color_group);
2098    }
2099    else {
2100        strcpy(buf, "no color group");
2101    }
2102
2103    return buf;
2104}
2105
2106static AW_window *create_awt_colorizer_window(AW_root *aw_root, GBDATA *gb_main, struct adaqbsstruct *cbs, const ad_item_selector *sel) {
2107    // invoked by   'colorize listed'                   (sel != 0)
2108    // and          'colorize marked/mark colored'      (cbs != 0)
2109
2110    enum { AWT_COL_INVALID, AWT_COL_COLORIZE_LISTED, AWT_COL_COLORIZE_MARKED } mode = AWT_COL_INVALID;
2111
2112    awt_query_create_global_awars(aw_root, AW_ROOT_DEFAULT);
2113
2114    AW_window_simple *aws = new AW_window_simple;
2115
2116    if (cbs) {
2117        awt_assert(mode == AWT_COL_INVALID);
2118        mode = AWT_COL_COLORIZE_LISTED;
2119    }
2120    if (sel) {
2121        awt_assert(mode == AWT_COL_INVALID);
2122        mode = AWT_COL_COLORIZE_MARKED;
2123    }
2124    awt_assert(!(mode == AWT_COL_INVALID));
2125
2126    const ad_item_selector *Sel  = mode == AWT_COL_COLORIZE_LISTED ? cbs->selector : sel;
2127    const char             *what = mode == AWT_COL_COLORIZE_LISTED ? "listed" : "marked";
2128
2129    {
2130        char *macro_name  = GBS_global_string_copy("COLORIZE_%s_%s", what, Sel->items_name);
2131        char *window_name = GBS_global_string_copy("Colorize %s %s", what, Sel->items_name);
2132
2133        aws->init( aw_root, macro_name, window_name);
2134
2135        free(window_name);
2136        free(macro_name);
2137    }
2138
2139    aws->load_xfig("colorize.fig");
2140
2141    aws->auto_space(10, 10);
2142
2143    aws->at("close");
2144    aws->callback((AW_CB0) AW_POPDOWN);
2145    aws->create_button("CLOSE","CLOSE", "C");
2146
2147    aws->at("help");
2148    aws->callback(AW_POPUP_HELP,(AW_CL)(mode == AWT_COL_COLORIZE_LISTED ? "set_color_of_listed.hlp" : "colorize.hlp"));
2149    aws->create_button("HELP","HELP","H");
2150
2151    aws->at("colorize");
2152
2153    color_mark_data *cmd = new color_mark_data; // do not free!
2154    cmd->sel             = (mode == AWT_COL_COLORIZE_MARKED) ? sel : cbs->selector;
2155    cmd->gb_main = gb_main;
2156
2157    if (mode == AWT_COL_COLORIZE_LISTED)    aws->callback(awt_colorize_listed, (AW_CL)cbs);
2158    else                                    aws->callback(awt_colorize_marked, (AW_CL)cmd);
2159
2160    aws->create_autosize_button("COLORIZE", GBS_global_string_copy("Set color of %s %s to ...", what, Sel->items_name), "S", 2);
2161
2162    {
2163        int color_group;
2164
2165        aws->create_option_menu(AWAR_COLORIZE);
2166        aws->insert_default_option(color_group_name(0), "none", 0);
2167        for (color_group = 1; color_group <= AW_COLOR_GROUPS; ++color_group) {
2168            aws->insert_option(color_group_name(color_group), "", color_group);
2169        }
2170        aws->update_option_menu();
2171    }
2172
2173    color_save_data *csd = new color_save_data; // do not free!
2174    csd->cmd             = cmd;
2175    csd->items_name      = Sel->items_name;
2176    csd->aww             = 0;
2177    csd->sel_id          = 0;
2178
2179    aws->at("loadsave");
2180    aws->callback(AW_POPUP, (AW_CL)awt_create_loadsave_colored_window, (AW_CL)csd);
2181    aws->create_autosize_button("LOADSAVE_COLORED", "Load/Save", "L");
2182
2183    if (mode == AWT_COL_COLORIZE_MARKED) {
2184        aws->at("mark");
2185        aws->callback(awt_mark_colored, (AW_CL)cmd, (AW_CL)1);
2186        aws->create_autosize_button("MARK_COLORED", GBS_global_string_copy("Mark all %s of ...", Sel->items_name), "M", 2);
2187
2188        aws->at("unmark");
2189        aws->callback(awt_mark_colored, (AW_CL)cmd, (AW_CL)0);
2190        aws->create_autosize_button("UNMARK_COLORED", GBS_global_string_copy("Unmark all %s of ...", Sel->items_name), "U", 2);
2191
2192        aws->at("invert");
2193        aws->callback(awt_mark_colored, (AW_CL)cmd, (AW_CL)2);
2194        aws->create_autosize_button("INVERT_COLORED", GBS_global_string_copy("Invert all %s of ...", Sel->items_name), "I", 2);
2195    }
2196
2197    aws->at_newline();
2198    aws->window_fit();
2199
2200    return aws;
2201}
2202
2203AW_window *create_awt_listed_items_colorizer(AW_root *aw_root, struct adaqbsstruct *cbs) {
2204    return create_awt_colorizer_window(aw_root, cbs->gb_main, cbs, 0);
2205}
2206
2207AW_window *awt_create_item_colorizer(AW_root *aw_root, GBDATA *gb_main, const ad_item_selector *sel) {
2208    return create_awt_colorizer_window(aw_root, gb_main, 0, sel);
2209}
2210
2211AW_window *create_awt_open_parser(AW_root *aw_root, struct adaqbsstruct *cbs)
2212{
2213    AW_window_simple *aws = 0;
2214    aws                   = new AW_window_simple;
2215
2216    {
2217        char *macro_name = GBS_global_string_copy("MODIFY_DATABASE_FIELD_%s", cbs->selector->items_name);
2218        char *window_name = GBS_global_string_copy("MODIFY DATABASE FIELD of listed %s", cbs->selector->items_name);
2219
2220        aws->init( aw_root, macro_name, window_name);
2221
2222        free(window_name);
2223        free(macro_name);
2224    }
2225
2226    aws->load_xfig("awt/parser.fig");
2227
2228    aws->at("close");
2229    aws->callback( (AW_CB0)AW_POPDOWN);
2230    aws->create_button("CLOSE","CLOSE","C");
2231
2232    aws->at("help");
2233    aws->callback(AW_POPUP_HELP,(AW_CL)"mod_field_list.hlp");
2234    aws->create_button("HELP","HELP","H");
2235
2236    aws->at("helptags");
2237    aws->callback(AW_POPUP_HELP,(AW_CL)"tags.hlp");
2238    aws->create_button("HELP_TAGS", "HELP TAGS","H");
2239
2240    aws->at("usetag");  aws->create_toggle(cbs->awar_use_tag);
2241    aws->at("deftag");  aws->create_input_field(cbs->awar_deftag);
2242    aws->at("tag");     aws->create_input_field(cbs->awar_tag);
2243
2244    aws->at("double");  aws->create_toggle(cbs->awar_double_pars);
2245
2246    awt_create_selection_list_on_scandb(cbs->gb_main,aws,cbs->awar_parskey,AWT_PARS_FILTER, "field",0, cbs->selector, 20, 10);
2247
2248    aws->at("go");
2249    aws->callback((AW_CB1)awt_do_pars_list,(AW_CL)cbs);
2250    aws->create_button("GO", "GO","G");
2251
2252    aws->at("parser");
2253    aws->create_text_field(cbs->awar_parsvalue);
2254
2255    aws->at("pre");
2256    AW_selection_list *id = aws->create_selection_list(cbs->awar_parspredefined);
2257
2258    char *filename = 0;
2259    switch (cbs->selector->type) {
2260    case AWT_QUERY_ITEM_SPECIES:
2261        filename = AWT_unfold_path("lib/sellists/mod_fields*.sellst","ARBHOME");
2262        break;
2263    case AWT_QUERY_ITEM_GENES:
2264        filename = AWT_unfold_path("lib/sellists/mod_gene_fields*.sellst","ARBHOME");
2265        break;
2266    case AWT_QUERY_ITEM_EXPERIMENTS:
2267        filename = AWT_unfold_path("lib/sellists/mod_experiment_fields*.sellst","ARBHOME");
2268        break;
2269    default:
2270        gb_assert(0);
2271        break;
2272    }
2273
2274    GB_ERROR error = filename ? aws->load_selection_list(id,filename) : "No default selection list for query-type";
2275    free(filename);
2276    if (error) {
2277        aw_message(error);
2278    }
2279    else{
2280        aws->get_root()->awar(cbs->awar_parspredefined)->add_callback((AW_RCB1)awt_predef_prg,(AW_CL)cbs);
2281    }
2282    return (AW_window *)aws;
2283}
2284
2285
2286/***************** Multi set fields *************************/
2287
2288void awt_do_set_list(void *, struct adaqbsstruct *cbs, long append) {
2289    GB_ERROR  error = 0;
2290    char     *key   = cbs->aws->get_root()->awar(cbs->awar_setkey)->read_string();
2291    if (strcmp(key,"name") == 0) {
2292        error = "You cannot set the name field";
2293    }
2294
2295    char *value = cbs->aws->get_root()->awar(cbs->awar_setvalue)->read_string();
2296    if (value[0] == 0) freeset(value, 0);
2297
2298    GB_begin_transaction(cbs->gb_main);
2299
2300    GBDATA *gb_key_type = 0;
2301    {
2302        GBDATA *gb_key_data     = GB_search(cbs->gb_main, cbs->selector->change_key_path, GB_CREATE_CONTAINER);
2303        if (!gb_key_data) error = GB_await_error();
2304        else {
2305            GBDATA *gb_key_name = GB_find_string(gb_key_data,CHANGEKEY_NAME,key,GB_IGNORE_CASE,down_2_level);
2306            if (!gb_key_name) {
2307                error = GBS_global_string("The destination field '%s' does not exists", key);
2308            }
2309            else {
2310                gb_key_type = GB_brother(gb_key_name,CHANGEKEY_TYPE);
2311                if (!gb_key_type) error = GB_await_error();
2312            }
2313        }
2314    }
2315
2316    for (GBDATA *gb_item_container = cbs->selector->get_first_item_container(cbs->gb_main, cbs->aws->get_root(), AWT_QUERY_ALL_SPECIES);
2317         !error && gb_item_container;
2318         gb_item_container = cbs->selector->get_next_item_container(gb_item_container, AWT_QUERY_ALL_SPECIES))
2319    {
2320        for (GBDATA *gb_item = cbs->selector->get_first_item(gb_item_container);
2321             !error && gb_item;
2322             gb_item = cbs->selector->get_next_item(gb_item))
2323        {
2324            if (IS_QUERIED(gb_item,cbs)) {
2325                GBDATA *gb_new = GB_search(gb_item, key,GB_FIND);
2326                if (gb_new) {
2327                    if (value){
2328                        if (append){
2329                            char *old = GB_read_as_string(gb_new);
2330                            if (old) {
2331                                GBS_strstruct *strstr = GBS_stropen(strlen(old)+strlen(value)+2);
2332                                GBS_strcat(strstr,old);
2333                                GBS_strcat(strstr,value);
2334                                char *v = GBS_strclose(strstr);
2335                                error = GB_write_as_string(gb_new,v);
2336                                free(v);
2337                            }
2338                            else {
2339                                char *name = GBT_read_string(gb_item,"name");
2340                                error = GB_export_errorf("Field '%s' of %s '%s' has incompatible type", key, cbs->selector->item_name, name);
2341                                free(name);
2342                            }
2343                        }
2344                        else { 
2345                            error = GB_write_as_string(gb_new,value);
2346                        }
2347                    }
2348                    else {
2349                        if (!append) error = GB_delete(gb_new);
2350                    }
2351                }
2352                else {
2353                    gb_new = GB_search(gb_item, key, GB_read_int(gb_key_type));
2354
2355                    if (!gb_new) error = GB_await_error();
2356                    else error         = GB_write_as_string(gb_new,value);
2357                }
2358            }
2359        }
2360    }
2361
2362    GB_end_transaction_show_error(cbs->gb_main, error, aw_message);
2363   
2364    free(key);
2365    free(value);
2366}
2367
2368AW_window *create_awt_do_set_list(AW_root *aw_root, struct adaqbsstruct *cbs)
2369{
2370    AW_window_simple *aws = 0;
2371    aws = new AW_window_simple;
2372    aws->init( aw_root, "SET_DATABASE_FIELD_OF_LISTED","SET MANY FIELDS");
2373    aws->load_xfig("ad_mset.fig");
2374
2375    aws->at("close");
2376    aws->callback( (AW_CB0)AW_POPDOWN);
2377    aws->create_button("CLOSE", "CLOSE","C");
2378
2379    aws->at("help");
2380    aws->callback( AW_POPUP_HELP,(AW_CL)"write_field_list.hlp");
2381    aws->create_button("HELP", "HELP","H");
2382
2383    awt_create_selection_list_on_scandb(cbs->gb_main,aws,cbs->awar_setkey, AWT_NDS_FILTER, "box",0, cbs->selector, 20, 10);
2384    aws->at("create");
2385    aws->callback((AW_CB)awt_do_set_list,(AW_CL)cbs,0);
2386    aws->create_button("SET_SINGLE_FIELD_OF_LISTED","WRITE");
2387    aws->at("do");
2388    aws->callback((AW_CB)awt_do_set_list,(AW_CL)cbs,1);
2389    aws->create_button("APPEND_SINGLE_FIELD_OF_LISTED","APPEND");
2390
2391    aws->at("val");
2392    aws->create_text_field(cbs->awar_setvalue,2,2);
2393    return (AW_window *)aws;
2394
2395}
2396
2397/***************** Multi set fields *************************/
2398
2399void awt_do_set_protection(void *, struct adaqbsstruct *cbs) {
2400    GB_ERROR  error = 0;
2401    char     *key   = cbs->aws->get_root()->awar(cbs->awar_setkey)->read_string();
2402
2403    GB_begin_transaction(cbs->gb_main);
2404    GBDATA *gb_key_data = GB_search(cbs->gb_main, cbs->selector->change_key_path, GB_CREATE_CONTAINER);
2405    GBDATA *gb_key_name = GB_find_string(gb_key_data,CHANGEKEY_NAME,key,GB_IGNORE_CASE,down_2_level);
2406    if (!gb_key_name) {
2407        error = GBS_global_string("The destination field '%s' does not exists", key);
2408    }
2409    else {
2410        int              level   = cbs->aws->get_root()->awar(cbs->awar_setprotection)->read_int();
2411        AW_root         *aw_root = cbs->aws->get_root();
2412        AWT_QUERY_RANGE  range   = (AWT_QUERY_RANGE)aw_root->awar(cbs->awar_where)->read_int();
2413
2414        for (GBDATA *gb_item_container = cbs->selector->get_first_item_container(cbs->gb_main, aw_root, range);
2415             !error && gb_item_container;
2416             gb_item_container = cbs->selector->get_next_item_container(gb_item_container, range))
2417        {
2418            for (GBDATA *gb_item = cbs->selector->get_first_item(gb_item_container);
2419                 !error && gb_item;
2420                 gb_item = cbs->selector->get_next_item(gb_item))
2421            {
2422                if (IS_QUERIED(gb_item,cbs)) {
2423                    GBDATA *gb_new = GB_search(gb_item, key,GB_FIND);
2424                    if (!gb_new) continue;
2425                    error = GB_write_security_delete(gb_new,level);
2426                    error = GB_write_security_write(gb_new,level);
2427                }
2428            }
2429        }
2430    }
2431    GB_end_transaction_show_error(cbs->gb_main, error, aw_message);
2432   
2433    free(key);
2434}
2435
2436AW_window *create_awt_set_protection(AW_root *aw_root, struct adaqbsstruct *cbs)
2437{
2438    AW_window_simple *aws = 0;
2439    aws = new AW_window_simple;
2440    aws->init( aw_root, "SET_PROTECTION_OF_FIELD_OF_LISTED", "SET PROTECTIONS OF FIELDS");
2441    aws->load_xfig("awt/set_protection.fig");
2442
2443    aws->at("close");
2444    aws->callback( (AW_CB0)AW_POPDOWN);
2445    aws->create_button("CLOSE","CLOSE","C");
2446
2447    aws->at("help");
2448    aws->callback( AW_POPUP_HELP,(AW_CL)"set_protection.hlp");
2449    aws->create_button("HELP", "HELP","H");
2450
2451
2452    aws->at("prot");
2453    aws->create_toggle_field(cbs->awar_setprotection,0);
2454    aws->insert_toggle("0 Temporary","0",0);
2455    aws->insert_toggle("1 Checked","1",1);
2456    aws->insert_toggle("2","2",2);
2457    aws->insert_toggle("3","3",3);
2458    aws->insert_toggle("4 normal","4",4);
2459    aws->insert_toggle("5 ","5",5);
2460    aws->insert_toggle("6 the truth","5",6);
2461
2462    awt_create_selection_list_on_scandb(cbs->gb_main,aws,cbs->awar_setkey, AWT_NDS_FILTER, "list",0, cbs->selector, 20, 10);
2463
2464    aws->at("go");
2465    aws->callback((AW_CB1)awt_do_set_protection,(AW_CL)cbs);
2466    aws->create_button("SET_PROTECTION_OF_FIELD_OF_LISTED", "SET PROTECTION");
2467
2468    return (AW_window *)aws;
2469}
2470
2471void awt_toggle_flag(AW_window *aww, struct adaqbsstruct *cbs) {
2472    GB_transaction dummy(cbs->gb_main);
2473    GBDATA *gb_item = cbs->selector->get_selected_item(cbs->gb_main, aww->get_root());
2474    if (gb_item) {
2475        long flag = GB_read_flag(gb_item);
2476        GB_write_flag(gb_item, 1-flag);
2477    }
2478    awt_query_update_list(aww,cbs);
2479
2480    //  GB_transaction dummy(cbs->gb_main);
2481    //  char *sname = aww->get_root()->awar(cbs->species_name)->read_string();
2482    //  if (sname[0]){
2483    //      GBDATA *gb_species = GBT_find_species(cbs->gb_main,sname);
2484    //      if (gb_species) {
2485    //          long flag = GB_read_flag(gb_species);
2486    //          GB_write_flag(gb_species,1-flag);
2487    //      }
2488    //  }
2489
2490    //  delete sname;
2491    //  awt_query_update_list(aww,cbs);
2492}
2493
2494//  -----------------------------------------------------
2495//      struct ad_item_selector AWT_species_selector
2496//  -----------------------------------------------------
2497
2498static GBDATA *awt_get_first_species_data(GBDATA *gb_main, AW_root *, AWT_QUERY_RANGE) {
2499    return GBT_get_species_data(gb_main);
2500}
2501static GBDATA *awt_get_next_species_data(GBDATA *, AWT_QUERY_RANGE) {
2502    return 0; // there is only ONE species_data
2503}
2504
2505static void awt_select_species(GBDATA* , AW_root *aw_root, const char *item_name) {
2506    aw_root->awar(AWAR_SPECIES_NAME)->write_string(item_name);
2507}
2508
2509static GBDATA* awt_get_selected_species(GBDATA *gb_main, AW_root *aw_root) {
2510    char   *species_name = aw_root->awar(AWAR_SPECIES_NAME)->read_string();
2511    GBDATA *gb_species   = 0;
2512    if (species_name[0]) {
2513        gb_species = GBT_find_species(gb_main, species_name);
2514    }
2515    free(species_name);
2516    return gb_species;
2517}
2518
2519static char* awt_get_species_id(GBDATA *, GBDATA *gb_species) {
2520    // awt_get_species_id creates the label that occurs in the search and query result list
2521    GBDATA *gb_name = GB_entry(gb_species, "name");
2522    if (!gb_name) return 0;     // species w/o name -> skip
2523    return GB_read_as_string(gb_name);
2524}
2525
2526static GBDATA *awt_find_species_by_id(GBDATA *gb_main, const char *id) {
2527    return GBT_find_species(gb_main, id); // id is 'name' field
2528}
2529
2530struct ad_item_selector AWT_species_selector = {
2531    AWT_QUERY_ITEM_SPECIES,
2532    awt_select_species,
2533    awt_get_species_id,
2534    awt_find_species_by_id,
2535    (AW_CB)awt_selection_list_update_cb,
2536    12,
2537    CHANGE_KEY_PATH,
2538    "species",
2539    "species",
2540    "name",
2541    awt_get_first_species_data,
2542    awt_get_next_species_data,
2543    GBT_first_species_rel_species_data,
2544    GBT_next_species,
2545    awt_get_selected_species,
2546    0, 0, 
2547};
2548
2549struct ad_item_selector AWT_organism_selector = {
2550    AWT_QUERY_ITEM_SPECIES,
2551    awt_select_species,
2552    awt_get_species_id,
2553    awt_find_species_by_id,
2554    (AW_CB)awt_selection_list_update_cb,
2555    12,
2556    CHANGE_KEY_PATH,
2557    "organism",
2558    "organism",
2559    "name",
2560    awt_get_first_species_data,
2561    awt_get_next_species_data,
2562    GBT_first_species_rel_species_data,
2563    GBT_next_species,
2564    awt_get_selected_species,
2565    0, 0, 
2566};
2567
2568static void awt_new_selection_made(AW_root *aw_root, AW_CL cl_awar_selection, AW_CL cl_cbs) {
2569    const char          *awar_selection = (const char *)cl_awar_selection;
2570    struct adaqbsstruct *cbs            = (struct adaqbsstruct *)cl_cbs;
2571
2572    char *item_name = aw_root->awar(awar_selection)->read_as_string();
2573    cbs->selector->update_item_awars(cbs->gb_main, aw_root, item_name);
2574    free(item_name);
2575}
2576
2577static void query_box_init_config(AWT_config_definition& cdef, struct adaqbsstruct *cbs) { // this defines what is saved/restored to/from configs
2578    //  don't save these
2579    //     cdef.add(cbs->awar_ere, "action");
2580    //     cdef.add(cbs->awar_where, "range");
2581    //     cdef.add(cbs->awar_by, "by");
2582
2583    for (int key_id = 0; key_id<AWT_QUERY_SEARCHES; ++key_id) {
2584        cdef.add(cbs->awar_keys[key_id], "key", key_id);
2585        cdef.add(cbs->awar_queries[key_id], "query", key_id);
2586        cdef.add(cbs->awar_not[key_id], "not", key_id);
2587        cdef.add(cbs->awar_operator[key_id], "operator", key_id);
2588    }
2589}
2590static char *query_box_store_config(AW_window *aww, AW_CL cl_cbs, AW_CL) {
2591    AWT_config_definition cdef(aww->get_root());
2592    query_box_init_config(cdef, (struct adaqbsstruct *)cl_cbs);
2593    return cdef.read();
2594}
2595static void query_box_restore_config(AW_window *aww, const char *stored, AW_CL cl_cbs, AW_CL ) {
2596    AWT_config_definition cdef(aww->get_root());
2597    query_box_init_config(cdef, (struct adaqbsstruct *)cl_cbs);
2598    cdef.write(stored);
2599}
2600
2601
2602typedef AW_window *(*window_generator)(AW_root *);
2603
2604static void query_box_popup_view_window(AW_window *aww, AW_CL cl_create_window, AW_CL) {
2605    window_generator  create_window = (window_generator)cl_create_window;
2606    AW_window        *aw_viewer     = create_window(aww->get_root());
2607    aw_viewer->show();
2608}
2609
2610/***************** Create the database query box and functions *************************/
2611
2612static void query_rel_menu_entry(AW_window *aws, const char *id, const char *query_id, AW_label label, const char *mnemonic, const char *helpText, AW_active Mask, void (*f)(AW_window*,AW_CL,AW_CL), AW_CL cd1, AW_CL cd2) {
2613    char *rel_id = GBS_global_string_copy("%s_%s", query_id, id);
2614    aws->insert_menu_topic(rel_id, label, mnemonic, helpText, Mask, f, cd1, cd2);
2615    free(rel_id);
2616}
2617
2618struct adaqbsstruct *awt_create_query_box(AW_window *aws, awt_query_struct *awtqs, const char *query_id) // create the query box
2619{
2620    char                 buffer[256];
2621    AW_root             *aw_root = aws->get_root();
2622    GBDATA              *gb_main = awtqs->gb_main;
2623    struct adaqbsstruct *cbs     = (struct adaqbsstruct *)calloc(1, sizeof(struct adaqbsstruct));
2624
2625    cbs->gb_main                = awtqs->gb_main;
2626    cbs->aws                    = aws;
2627    cbs->gb_ref                 = awtqs->gb_ref;
2628    cbs->expect_hit_in_ref_list = awtqs->expect_hit_in_ref_list;
2629    cbs->select_bit             = awtqs->select_bit;
2630    cbs->species_name           = strdup(awtqs->species_name);
2631    cbs->tree_name              = awtqs->tree_name ? aw_root->awar(awtqs->tree_name)->read_string() : 0;
2632    cbs->selector               = awtqs->selector;
2633    cbs->hit_description        = GBS_create_hash(2*awt_count_items(cbs, AWT_QUERY_ALL_SPECIES), GB_IGNORE_CASE);
2634
2635    GB_push_transaction(gb_main);
2636    /*************** Create local AWARS *******************/
2637
2638    awt_query_create_global_awars(aw_root, AW_ROOT_DEFAULT);
2639
2640    {
2641        const char *default_key[AWT_QUERY_SEARCHES+1] = { "name", "name", "name", 0};
2642
2643        for (int key_id = 0; key_id<AWT_QUERY_SEARCHES; ++key_id) {
2644            sprintf(buffer,"tmp/dbquery_%s/key_%i",query_id, key_id);
2645            cbs->awar_keys[key_id] = strdup(buffer);
2646            awt_assert(default_key[key_id] != 0);
2647            aw_root->awar_string( cbs->awar_keys[key_id], default_key[key_id], AW_ROOT_DEFAULT);
2648
2649            sprintf(buffer,"tmp/dbquery_%s/query_%i",query_id, key_id);
2650            cbs->awar_queries[key_id] = strdup(buffer);
2651            aw_root->awar_string( cbs->awar_queries[key_id], "*", AW_ROOT_DEFAULT);
2652
2653            sprintf(buffer,"tmp/dbquery_%s/not_%i",query_id, key_id);
2654            cbs->awar_not[key_id] = strdup(buffer);
2655            aw_root->awar_int( cbs->awar_not[key_id], 0, AW_ROOT_DEFAULT);
2656
2657            sprintf(buffer,"tmp/dbquery_%s/operator_%i",query_id, key_id);
2658            cbs->awar_operator[key_id] = strdup(buffer);
2659            aw_root->awar_string( cbs->awar_operator[key_id], "ign", AW_ROOT_DEFAULT);
2660        }
2661        aw_root->awar(cbs->awar_keys[0])->add_callback(awt_first_searchkey_changed_cb, (AW_CL)cbs);
2662    }
2663
2664    sprintf(buffer,"tmp/dbquery_%s/ere",query_id);
2665    cbs->awar_ere = strdup(buffer);
2666    aw_root->awar_int( cbs->awar_ere, AWT_QUERY_GENERATE);
2667
2668    sprintf(buffer,"tmp/dbquery_%s/where",query_id);
2669    cbs->awar_where = strdup(buffer);
2670    aw_root->awar_int( cbs->awar_where, AWT_QUERY_ALL_SPECIES);
2671
2672    sprintf(buffer,"tmp/dbquery_%s/count",query_id);
2673    cbs->awar_count = strdup(buffer);
2674    aw_root->awar_int( cbs->awar_count, 0);
2675
2676    sprintf(buffer,"tmp/dbquery_%s/sort",query_id);
2677    cbs->awar_sort = strdup(buffer);
2678    aw_root->awar_int( cbs->awar_sort, AWT_QUERY_SORT_NONE)->add_callback(awt_sort_order_changed_cb, (AW_CL)cbs);
2679    cbs->sort_mask = AWT_QUERY_SORT_NONE; // default to unsorted
2680
2681    sprintf(buffer,"tmp/dbquery_%s/by",query_id);
2682    cbs->awar_by = strdup(buffer);
2683    aw_root->awar_int( cbs->awar_by, AWT_QUERY_MATCH);
2684
2685    if (awtqs->ere_pos_fig){
2686        aws->at(awtqs->ere_pos_fig);
2687        aws->create_toggle_field(cbs->awar_ere,"","");
2688
2689        aws->insert_toggle(GBS_global_string("Search %s", cbs->selector->items_name),"G",(int)AWT_QUERY_GENERATE);
2690        aws->insert_toggle(GBS_global_string("Add %s", cbs->selector->items_name),"E",(int)AWT_QUERY_ENLARGE);
2691        aws->insert_toggle(GBS_global_string("Keep %s", cbs->selector->items_name),"R",(int)AWT_QUERY_REDUCE);
2692
2693        aws->update_toggle_field();
2694    }
2695    if (awtqs->where_pos_fig) {
2696        aws->at(awtqs->where_pos_fig);
2697        aws->create_toggle_field(cbs->awar_where,"","");
2698        aws->insert_toggle("of current organism","C",(int)AWT_QUERY_CURRENT_SPECIES);
2699        aws->insert_toggle("of marked organisms","M",(int)AWT_QUERY_MARKED_SPECIES);
2700        aws->insert_toggle("of all organisms","A",(int)AWT_QUERY_ALL_SPECIES);
2701        aws->update_toggle_field();
2702
2703    }
2704    if (awtqs->by_pos_fig){
2705        aws->at(awtqs->by_pos_fig);
2706        aws->create_toggle_field(cbs->awar_by,"","");
2707        aws->insert_toggle("that match the query","M",(int)AWT_QUERY_MATCH);
2708        aws->insert_toggle("that don't match the q.","D",(int)AWT_QUERY_DONT_MATCH);
2709        aws->insert_toggle("that are marked","A",(int)AWT_QUERY_MARKED);
2710        aws->update_toggle_field();
2711    }
2712
2713    // distances for multiple queries :
2714
2715#define KEY_Y_OFFSET 32
2716
2717    int xpos_calc[3] = { -1, -1, -1 }; // X-positions for elements in search expressions
2718
2719    if (awtqs->qbox_pos_fig){
2720        AW_at_size at_size;
2721        int        xpos, ypos;
2722
2723        aws->auto_space(1, 1);
2724
2725        aws->at(awtqs->qbox_pos_fig);
2726        aws->store_at_size_and_attach(&at_size);
2727        aws->get_at_position(&xpos, &ypos);
2728
2729        int ypos_dummy;
2730
2731        for (int key = AWT_QUERY_SEARCHES-1;  key >= 0; --key) {
2732            if (key) {
2733                aws->at(xpos, ypos+key*KEY_Y_OFFSET);
2734                aws->create_option_menu(cbs->awar_operator[key], 0, "");
2735                aws->insert_option("and", "", "and");
2736                aws->insert_option("or", "", "or");
2737                aws->insert_option("ign", "", "ign");
2738                aws->update_option_menu();
2739
2740                if (xpos_calc[0] == -1) aws->get_at_position(&xpos_calc[0], &ypos_dummy);
2741            }
2742
2743            aws->at(xpos_calc[0], ypos+key*KEY_Y_OFFSET);
2744            aws->restore_at_size_and_attach(&at_size);
2745
2746            {
2747                char *button_id = GBS_global_string_copy("field_sel_%s_%i", query_id, key);
2748                awt_create_selection_list_on_scandb(gb_main,aws,cbs->awar_keys[key], AWT_NDS_FILTER,
2749                                                    0, awtqs->rescan_pos_fig,
2750                                                    awtqs->selector, 22, 20, AWT_SF_PSEUDO, button_id);
2751                free(button_id);
2752            }
2753
2754            if (xpos_calc[1] == -1) aws->get_at_position(&xpos_calc[1], &ypos_dummy);
2755
2756            aws->at(xpos_calc[1], ypos+key*KEY_Y_OFFSET);
2757            aws->create_toggle(cbs->awar_not[key], "#equal.xpm", "#notEqual.xpm");
2758
2759            if (xpos_calc[2] == -1) aws->get_at_position(&xpos_calc[2], &ypos_dummy);
2760        }
2761    }
2762    if (awtqs->key_pos_fig){
2763        aws->at(awtqs->key_pos_fig);
2764        aws->create_input_field(cbs->awar_keys[0],12);
2765    }
2766
2767    if (awtqs->query_pos_fig){
2768        aws->at(awtqs->query_pos_fig);
2769
2770        AW_at_size at_size;
2771        int        xpos, ypos;
2772        aws->store_at_size_and_attach(&at_size);
2773        aws->get_at_position(&xpos, &ypos);
2774
2775        for (int key = 0; key<AWT_QUERY_SEARCHES; ++key) {
2776            aws->at(xpos_calc[2], ypos+key*KEY_Y_OFFSET);
2777            aws->restore_at_size_and_attach(&at_size);
2778            aws->d_callback((AW_CB)awt_do_query,(AW_CL)cbs,AWT_EXT_QUERY_NONE); // enable ENTER in searchfield to start search
2779            aws->create_input_field(cbs->awar_queries[key],12);
2780        }
2781    }
2782
2783    if (awtqs->result_pos_fig){
2784        aws->at(awtqs->result_pos_fig);
2785        if(awtqs->create_view_window) {
2786            aws->callback(query_box_popup_view_window,(AW_CL)awtqs->create_view_window, 0);
2787        }
2788        aws->d_callback((AW_CB1)awt_toggle_flag,(AW_CL)cbs);
2789
2790        {
2791            char    *this_awar_name = GBS_global_string_copy("tmp/dbquery_%s/select", query_id);
2792            AW_awar *awar           = aw_root->awar_string( this_awar_name, "", AW_ROOT_DEFAULT);
2793
2794            cbs->result_id = aws->create_selection_list(this_awar_name,"","",5,5);
2795            awar->add_callback(awt_new_selection_made, (AW_CL)this_awar_name, (AW_CL)cbs);
2796
2797            //free(this_awar_name); do not free this, cause it's passed to awt_new_selection_made
2798        }
2799        aws->insert_default_selection( cbs->result_id, "end of list", "" );
2800        aws->update_selection_list( cbs->result_id );
2801    }
2802    if (awtqs->count_pos_fig){
2803        aws->at(awtqs->count_pos_fig);
2804        aws->label("Hits:");
2805        aws->create_button(0,cbs->awar_count,0,"+");
2806    }
2807
2808    if (awtqs->config_pos_fig){
2809        aws->button_length(0);
2810        aws->at(awtqs->config_pos_fig);
2811        char *macro_id = GBS_global_string_copy("SAVELOAD_CONFIG_%s", query_id);
2812        AWT_insert_config_manager(aws, AW_ROOT_DEFAULT, "query_box",
2813                                  query_box_store_config, query_box_restore_config, (AW_CL)cbs, 0,
2814                                  macro_id);
2815        free(macro_id);
2816    }
2817
2818    aws->button_length(18);
2819    if (awtqs->do_query_pos_fig){
2820        aws->at(awtqs->do_query_pos_fig);
2821        aws->callback((AW_CB)awt_do_query,(AW_CL)cbs,AWT_EXT_QUERY_NONE);
2822        char *macro_id = GBS_global_string_copy("SEARCH_%s", query_id);
2823        aws->create_button(macro_id, "Search");
2824        free(macro_id);
2825    }
2826    if (awtqs->do_refresh_pos_fig){
2827        aws->at(awtqs->do_refresh_pos_fig);
2828        aws->create_option_menu(cbs->awar_sort);
2829        aws->insert_default_option("unsorted",  "u", AWT_QUERY_SORT_NONE);
2830        aws->insert_option        ("by value",  "v", AWT_QUERY_SORT_BY_1STFIELD_CONTENT);
2831        aws->insert_option        ("by id",     "n", AWT_QUERY_SORT_BY_ID);
2832        if (cbs->selector->parent_selector) {
2833            aws->insert_option    ("by parent", "p", AWT_QUERY_SORT_BY_NESTED_PID);
2834        }
2835        aws->insert_option        ("by marked", "m", AWT_QUERY_SORT_BY_MARKED);
2836        aws->insert_option        ("by hit",    "h", AWT_QUERY_SORT_BY_HIT_DESCRIPTION);
2837        aws->insert_option        ("reverse",   "r", AWT_QUERY_SORT_REVERSE);
2838        aws->update_option_menu();
2839    }
2840    else {
2841        awt_assert(0); // hmm - no sort button here. -> tell ralf where this happens
2842    }
2843
2844    if (awtqs->do_mark_pos_fig){
2845        aws->at(awtqs->do_mark_pos_fig);
2846        aws->help_text("mark_list.hlp");
2847        aws->callback((AW_CB)awt_do_mark_list,(AW_CL)cbs,1);
2848        aws->create_button("MARK_LISTED_UNMARK_REST", "Mark Listed\nUnmark Rest","M");
2849    }
2850    if (awtqs->do_unmark_pos_fig){
2851        aws->at(awtqs->do_unmark_pos_fig);
2852        aws->help_text("unmark_list.hlp");
2853        aws->callback((AW_CB)awt_do_mark_list,(AW_CL)cbs,0);
2854        aws->create_button("UNMARK_LISTED_MARK_REST","Unmark Listed\nMark Rest","U");
2855    }
2856    if (awtqs->do_delete_pos_fig){
2857        aws->at(awtqs->do_delete_pos_fig);
2858        aws->help_text("del_list.hlp");
2859        aws->callback((AW_CB)awt_delete_species_in_list,(AW_CL)cbs,0);
2860        char *macro_id = GBS_global_string_copy("DELETE_LISTED_%s", query_id);
2861        aws->create_button(macro_id, "Delete Listed", "D");
2862        free(macro_id);
2863    }
2864    if (awtqs->do_set_pos_fig){
2865        sprintf(buffer,"tmp/dbquery_%s/set_key",query_id);
2866        cbs->awar_setkey = strdup(buffer);
2867        aw_root->awar_string( cbs->awar_setkey);
2868
2869        sprintf(buffer,"tmp/dbquery_%s/set_protection",query_id);
2870        cbs->awar_setprotection = strdup(buffer);
2871        aw_root->awar_int( cbs->awar_setprotection, 4);
2872
2873        sprintf(buffer,"tmp/dbquery_%s/set_value",query_id);
2874        cbs->awar_setvalue = strdup(buffer);
2875        aw_root->awar_string( cbs->awar_setvalue);
2876
2877        aws->at(awtqs->do_set_pos_fig);
2878        aws->help_text("mod_field_list.hlp");
2879        aws->callback(AW_POPUP,(AW_CL)create_awt_do_set_list,(AW_CL)cbs);
2880        char *macro_id = GBS_global_string_copy("WRITE_TO_FIELDS_OF_LISTED_%s", query_id);
2881        aws->create_button(macro_id, "Write to Fields\nof Listed","S");
2882        free(macro_id);
2883    }
2884
2885    char *Items = strdup(cbs->selector->items_name);
2886    Items[0]    = toupper(Items[0]);
2887
2888    if ( ( awtqs->use_menu || awtqs->open_parser_pos_fig)){
2889        sprintf(buffer, "tmp/dbquery_%s/tag",                 query_id); cbs->awar_tag            = strdup(buffer); aw_root->awar_string(cbs->awar_tag);
2890        sprintf(buffer, "tmp/dbquery_%s/use_tag",             query_id); cbs->awar_use_tag        = strdup(buffer); aw_root->awar_int   (cbs->awar_use_tag);
2891        sprintf(buffer, "tmp/dbquery_%s/deftag",              query_id); cbs->awar_deftag         = strdup(buffer); aw_root->awar_string(cbs->awar_deftag);
2892        sprintf(buffer, "tmp/dbquery_%s/double_pars",         query_id); cbs->awar_double_pars    = strdup(buffer); aw_root->awar_int   (cbs->awar_double_pars);
2893        sprintf(buffer, "tmp/dbquery_%s/parskey",             query_id); cbs->awar_parskey        = strdup(buffer); aw_root->awar_string(cbs->awar_parskey);
2894        sprintf(buffer, "tmp/dbquery_%s/parsvalue",           query_id); cbs->awar_parsvalue      = strdup(buffer); aw_root->awar_string(cbs->awar_parsvalue);
2895        sprintf(buffer, "tmp/dbquery_%s/awar_parspredefined", query_id); cbs->awar_parspredefined = strdup(buffer); aw_root->awar_string(cbs->awar_parspredefined);
2896
2897        if (awtqs->use_menu){
2898            sprintf(buffer, "Modify Fields of Listed %s", Items); query_rel_menu_entry(aws, "mod_fields_of_listed", query_id, buffer, "F", "mod_field_list.hlp", AWM_ALL, AW_POPUP,(AW_CL)create_awt_open_parser,(AW_CL)cbs);
2899        }else{
2900            aws->at(awtqs->open_parser_pos_fig);
2901            aws->callback(AW_POPUP,(AW_CL)create_awt_open_parser,(AW_CL)cbs);
2902            aws->create_button("MODIFY_FIELDS_OF_LISTED", "MODIFY FIELDS\nOF LISTED","F");
2903        }
2904    }
2905    if (awtqs->use_menu) {
2906        sprintf(buffer, "Set Protection of Fields of Listed %s", Items); query_rel_menu_entry(aws, "s_prot_of_listed", query_id, buffer, "P", "set_protection.hlp", AWM_ALL, AW_POPUP, (AW_CL)create_awt_set_protection, (AW_CL)cbs);
2907        aws->insert_separator();
2908        sprintf(buffer, "Mark Listed %s, don't Change Rest",   Items); query_rel_menu_entry(aws, "mark_listed",             query_id, buffer, "M", "mark.hlp", AWM_ALL, (AW_CB)awt_do_mark_list, (AW_CL)cbs, (AW_CL)1 | 8);
2909        sprintf(buffer, "Mark Listed %s, Unmark Rest",         Items); query_rel_menu_entry(aws, "mark_listed_unmark_rest", query_id, buffer, "L", "mark.hlp", AWM_ALL, (AW_CB)awt_do_mark_list, (AW_CL)cbs, (AW_CL)1);
2910        sprintf(buffer, "Unmark Listed %s, don't Change Rest", Items); query_rel_menu_entry(aws, "unmark_listed",           query_id, buffer, "U", "mark.hlp", AWM_ALL, (AW_CB)awt_do_mark_list, (AW_CL)cbs, (AW_CL)0 | 8);
2911        sprintf(buffer, "Unmark Listed %s, Mark Rest",         Items); query_rel_menu_entry(aws, "unmark_listed_mark_rest", query_id, buffer, "R", "mark.hlp", AWM_ALL, (AW_CB)awt_do_mark_list, (AW_CL)cbs, (AW_CL)0);
2912        aws->insert_separator();
2913
2914
2915        sprintf(buffer, "Set Color of Listed %s", Items);    query_rel_menu_entry(aws, "set_color_of_listed", query_id, buffer,"C","set_color_of_listed.hlp", AWM_ALL, AW_POPUP, (AW_CL)create_awt_listed_items_colorizer, (AW_CL)cbs);
2916
2917        if (cbs->gb_ref){
2918            awt_assert(cbs->selector->type == AWT_QUERY_ITEM_SPECIES); // stuff below works only for species
2919            aws->insert_separator();
2920            if (cbs->expect_hit_in_ref_list) {
2921                aws->insert_menu_topic("search_equal_fields_and_listed_in_I", "Search entries existing in both DBs and listed in the DB I hitlist","S",
2922                                       "search_equal_fields.hlp", AWM_ALL, (AW_CB)awt_do_query,(AW_CL)cbs,AWT_EXT_QUERY_COMPARE_LINES);
2923                aws->insert_menu_topic("search_equal_words_and_listed_in_I",  "Search words existing in entries of both DBs and listed in the DB I hitlist","W",
2924                                       "search_equal_fields.hlp", AWM_ALL, (AW_CB)awt_do_query,(AW_CL)cbs,AWT_EXT_QUERY_COMPARE_WORDS);
2925            }else{
2926                aws->insert_menu_topic("search_equal_field_in_both_db", "Search entries existing in both DBs","S",
2927                                       "search_equal_fields.hlp", AWM_ALL, (AW_CB)awt_do_query,(AW_CL)cbs,AWT_EXT_QUERY_COMPARE_LINES);
2928                aws->insert_menu_topic("search_equal_word_in_both_db","Search words existing in entries of both DBs","W",
2929                                       "search_equal_fields.hlp", AWM_ALL, (AW_CB)awt_do_query,(AW_CL)cbs,AWT_EXT_QUERY_COMPARE_WORDS);
2930            }
2931        }
2932    }
2933
2934    free(Items);
2935
2936    GB_pop_transaction(gb_main);
2937    return cbs;
2938}
Note: See TracBrowser for help on using the browser.