source: tags/ms_r16q3/SL/REFENTRIES/refentries.cxx

Last change on this file was 15279, checked in by westram, 8 years ago
File size: 13.7 KB
Line 
1// ============================================================ //
2//                                                              //
3//   File      : refentries.cxx                                 //
4//   Purpose   :                                                //
5//                                                              //
6//   Coded by Ralf Westram (coder@reallysoft.de) in June 2011   //
7//   Institute of Microbiology (Technical University Munich)    //
8//   http://www.arb-home.de/                                    //
9//                                                              //
10// ============================================================ //
11
12#include "refentries.h"
13
14#include <awt_config_manager.hxx>
15#include <item_sel_list.h>
16
17#include <aw_root.hxx>
18#include <aw_awars.hxx>
19#include <aw_msg.hxx>
20
21#include <arbdbt.h>
22
23#include <arb_strarray.h>
24
25#include <cctype>
26
27namespace RefEntries {
28
29    static ARB_ERROR generate_item_error(const char *format, ItemSelector& itemtype, GBDATA *gb_item) {
30        GBDATA *gb_main          = GB_get_root(gb_item);
31        char   *item_id          = itemtype.generate_item_id(gb_main, gb_item);
32        char   *item_description = GBS_global_string_copy("%s '%s'", itemtype.item_name, item_id);
33
34        re_assert(strstr(format, "%s"));
35        ARB_ERROR error = GBS_global_string(format, item_description);
36
37        free(item_description);
38        free(item_id);
39
40        return error;
41    }
42
43    const char *RefSelector::get_refs(ItemSelector& itemtype, GBDATA *gb_item) const {
44        const char *refs    = NULL;
45        GBDATA     *gb_refs = GB_entry(gb_item, field);
46        if (gb_refs) {
47            refs = GB_read_char_pntr(gb_refs);
48        }
49        else if (error_if_field_missing) {
50            char *err_format = GBS_global_string_copy("%%s has no field '%s'", field);
51            GB_export_error(generate_item_error(err_format, itemtype, gb_item).deliver());
52            free(err_format);
53        }
54        return refs;
55    }
56
57    char *RefSelector::filter_refs(const char *refs, GBDATA *gb_item) const {
58        return refs ? GB_command_interpreter(GB_get_root(gb_item), refs, aci, gb_item, NULL) : NULL;
59    }
60
61    static ARB_ERROR addRefsTo(DBItemSet& referred, ItemSelector& itemtype, GBDATA *gb_item, const RefSelector& ref) {
62        const char *refs     = ref.get_refs(itemtype, gb_item);
63        char       *filtered = ref.filter_refs(refs, gb_item);
64        ARB_ERROR   error    = GB_incur_error_if(!filtered);
65
66        if (filtered) {
67            re_assert(!error);
68            ConstStrArray refNames;
69            GBT_split_string(refNames, filtered, ";, ", true);
70            size_t   refCount = refNames.size();
71
72            for (size_t r = 0; r<refCount && !error; ++r) {
73                GBDATA *gb_main     = GB_get_root(gb_item);
74                GBDATA *gb_referred = itemtype.find_item_by_id(gb_main, refNames[r]);
75                if (gb_referred) {
76                    referred.insert(gb_referred);
77                }
78                else if (!ref.ignore_unknown_refs()) {
79                    error = generate_item_error(GBS_global_string("%%s refers to unknown %s '%s'\n"
80                                                                  "in content of field '%s'\n"
81                                                                  "(content ='%s',\n"
82                                                                  " filtered='%s')\n",
83                                                                  itemtype.item_name, refNames[r],
84                                                                  ref.get_field(),
85                                                                  refs,
86                                                                  filtered),
87                                                itemtype, gb_item);
88                }
89            }
90
91            free(filtered);
92        }
93
94        return error;
95    }
96
97    ARB_ERROR ReferringEntriesHandler::with_all_referred_items(QUERY_RANGE range, const RefSelector& refsel, referred_item_handler callback) {
98        re_assert(range != QUERY_CURRENT_ITEM); // would need AW_root
99
100        ARB_ERROR  error;
101        DBItemSet referred;
102
103        {
104            GB_transaction ta(gb_main);
105
106            for (GBDATA *gb_container = itemtype.get_first_item_container(gb_main, NULL, QUERY_ALL_ITEMS);
107                 gb_container && !error;
108                 gb_container = itemtype.get_next_item_container(gb_container, QUERY_ALL_ITEMS))
109            {
110                for (GBDATA *gb_item = itemtype.get_first_item(gb_container, range);
111                     gb_item && !error;
112                     gb_item = itemtype.get_next_item(gb_item, range))
113                {
114                    error = addRefsTo(referred, itemtype, gb_item, refsel);
115                }
116            }
117        }
118
119        if (!error) error = callback(gb_main, referred);
120        return error;
121    }
122
123    ARB_ERROR ReferringEntriesHandler::with_all_referred_items(GBDATA *gb_item, const RefSelector& refsel, referred_item_handler callback) {
124        DBItemSet referred;
125        ARB_ERROR  error  = addRefsTo(referred, itemtype, gb_item, refsel);
126        if (!error) error = callback(gb_main, referred);
127        return error;
128    }
129
130
131
132    // ------------------------
133    //      GUI related below
134
135
136#define AWAR_MARKBYREF                "awt/refs/"
137#define AWAR_MARKBYREF_ALL            AWAR_MARKBYREF "which"
138#define AWAR_MARKBYREF_FIELD          AWAR_MARKBYREF "field"
139#define AWAR_MARKBYREF_IGNORE_MISSING AWAR_MARKBYREF "ignore_missing"
140#define AWAR_MARKBYREF_IGNORE_UNKNOWN AWAR_MARKBYREF "ignore_unknown"
141#define AWAR_MARKBYREF_FILTER         AWAR_MARKBYREF "filter"
142
143#define AWAR_MARKBYREF_TEMP "tmp/awt/refs/"
144#define AWAR_MARKBYREF_SELECTED AWAR_MARKBYREF_TEMP "selected"
145#define AWAR_MARKBYREF_CONTENT  AWAR_MARKBYREF_TEMP "content"
146#define AWAR_MARKBYREF_RESULT   AWAR_MARKBYREF_TEMP "result"
147
148    static void perform_refentries(AW_window *aww, ReferringEntriesHandler *reh, referred_item_handler ricb) {
149        AW_root     *aw_root = aww->get_root();
150        QUERY_RANGE  range   = aw_root->awar(AWAR_MARKBYREF_ALL)->read_int() ? QUERY_ALL_ITEMS : QUERY_MARKED_ITEMS;
151
152        RefSelector refsel(aw_root->awar(AWAR_MARKBYREF_FIELD)->read_char_pntr(),
153                           aw_root->awar(AWAR_MARKBYREF_FILTER)->read_char_pntr(),
154                           !aw_root->awar(AWAR_MARKBYREF_IGNORE_MISSING)->read_int(),
155                           !aw_root->awar(AWAR_MARKBYREF_IGNORE_UNKNOWN)->read_int());
156
157        ARB_ERROR error = reh->with_all_referred_items(range, refsel, ricb);
158        aw_message_if(error);
159    }
160
161    static void refresh_result_cb(AW_root *aw_root, ReferringEntriesHandler *reh) {
162        ItemSelector&   itemtype = reh->get_referring_item();
163        GBDATA         *gb_main  = reh->get_gbmain();
164        GB_transaction  ta(gb_main);
165
166        GBDATA  *gb_item       = itemtype.get_selected_item(gb_main, aw_root);
167        AW_awar *awar_selected = aw_root->awar(AWAR_MARKBYREF_SELECTED);
168        AW_awar *awar_result   = aw_root->awar(AWAR_MARKBYREF_RESULT);
169
170        awar_result->write_string("<no result>");
171        if (!gb_item) {
172            awar_selected->write_string(GBS_global_string("<no %s selected>", itemtype.item_name));
173        }
174        else {
175            char *id = itemtype.generate_item_id(gb_main, gb_item);
176            if (!id) {
177                awar_selected->write_string(GB_await_error());
178            }
179            else {
180                awar_selected->write_string(id);
181
182                AW_awar *awar_content = aw_root->awar(AWAR_MARKBYREF_CONTENT);
183
184                RefSelector refsel(aw_root->awar(AWAR_MARKBYREF_FIELD)->read_char_pntr(),
185                                   aw_root->awar(AWAR_MARKBYREF_FILTER)->read_char_pntr(),
186                                   true, true);
187
188                const char *refs = refsel.get_refs(itemtype, gb_item);
189
190                if (!refs) {
191                    char *err = GBS_string_eval(GB_await_error(), "\n=; ", NULL);
192                    awar_content->write_string(err);
193                    free(err);
194                }
195                else {
196                    awar_content->write_string(refs);
197
198                    char *result = refsel.filter_refs(refs, gb_item);
199
200                    if (result) {
201                        awar_result->write_string(result);
202                        free(result);
203                    }
204                    else {
205                        char *err = GBS_string_eval(GB_await_error(), "\n=;", NULL);
206                        awar_result->write_string(err);
207                        free(err);
208                    }
209                }
210
211                free(id);
212            }
213        }
214    }
215
216    static void bind_result_refresh_cbs(AW_root *aw_root, ReferringEntriesHandler *reh) {
217        RootCallback refreshCb = makeRootCallback(refresh_result_cb, reh);
218
219        aw_root->awar(AWAR_MARKBYREF_FIELD) ->add_callback(refreshCb);
220        aw_root->awar(AWAR_MARKBYREF_FILTER)->add_callback(refreshCb);
221        aw_root->awar(AWAR_SPECIES_NAME)    ->add_callback(refreshCb);    // @@@ hack
222    }
223
224    void create_refentries_awars(AW_root *aw_root, AW_default aw_def) {
225        aw_root->awar_string(AWAR_MARKBYREF_FIELD, "used_rels",       aw_def);
226        aw_root->awar_string(AWAR_MARKBYREF_FILTER,   "/[0-9.]+[%]*://", aw_def);
227       
228        aw_root->awar_string(AWAR_MARKBYREF_SELECTED, "<no item>",    aw_def);
229        aw_root->awar_string(AWAR_MARKBYREF_CONTENT,  "<no content>", aw_def);
230        aw_root->awar_string(AWAR_MARKBYREF_RESULT,   "<no result>",  aw_def);
231
232        aw_root->awar_int(AWAR_MARKBYREF_ALL,            0, aw_def);
233        aw_root->awar_int(AWAR_MARKBYREF_IGNORE_MISSING, 0, aw_def);
234        aw_root->awar_int(AWAR_MARKBYREF_IGNORE_UNKNOWN, 0, aw_def);
235    }
236
237    static AWT_config_mapping_def markByRef_config_mapping[] = {
238        { AWAR_MARKBYREF_ALL,            "examine" },
239        { AWAR_MARKBYREF_FIELD,          "field" },
240        { AWAR_MARKBYREF_IGNORE_MISSING, "ignore_missing" },
241        { AWAR_MARKBYREF_FILTER,         "filter" },
242        { AWAR_MARKBYREF_IGNORE_UNKNOWN, "ignore_unknown" },
243
244        { 0, 0 }
245    };
246
247    static AWT_predefined_config markByRef_predefined_config[] = {
248        { "*relatives_used_by_aligner", "For use with 'used_rels' entry as\ngenerated by fast-aligner.",         "field='used_rels';filter='/:[0-9]+//'" },
249        { "*next_relatives_of_listed",  "For use with entries generated by\n'Search next relatives of listed'.", "field='tmp';filter='/[0-9.]+[%]://'" },
250
251        { 0, 0, 0 }
252    };
253
254    AW_window *create_refentries_window(AW_root *aw_root, ReferringEntriesHandler *reh, const char *window_id, const char *title, const char *help, client_area_builder build_client_area, const char *action, referred_item_handler action_cb) {
255        AW_window_simple *aws = new AW_window_simple;
256
257        aws->init(aw_root, window_id, title);
258        aws->at(10, 10);
259        aws->auto_space(10, 10);
260
261        bind_result_refresh_cbs(aw_root, reh);
262
263        aws->callback(AW_POPDOWN);
264        aws->create_button("CLOSE", "CLOSE", "C");
265
266        aws->callback(makeHelpCallback(help));
267        aws->create_button("HELP", "HELP", "H");
268
269        const int LABEL_LENGTH = 27;
270        const int LABEL_SHORTL = 10;
271        aws->label_length(LABEL_LENGTH);
272
273        const int XOFF    = -10; // attached to right border
274        const int YOFF_IF = 32;  // lineheight of attached input field
275        const int YOFF_SB = 25;  // lineheight of attached selection butoon
276        const int YOFF_DF = 18;  // lineheight of attached display field
277
278        ItemSelector& itemtype = reh->get_referring_item();
279
280        char *items_name = strdup(itemtype.items_name);
281        items_name[0]    = toupper(items_name[0]);
282
283        aws->at_newline();
284        aws->label(GBS_global_string("%s to examine", items_name));
285        aws->create_option_menu(AWAR_MARKBYREF_ALL, true);
286        aws->insert_option("Marked", "M", 0);
287        aws->insert_option("All",    "A", 1);
288        aws->update_option_menu();
289
290        aws->at_newline();
291        aws->at_set_to(true, false, XOFF, YOFF_SB);
292        aws->label("Field containing references");
293        create_itemfield_selection_button(aws, FieldSelDef(AWAR_MARKBYREF_FIELD, reh->get_gbmain(), SPECIES_get_selector(), FIELD_FILTER_STRING, "reference field"), NULL);
294
295        aws->at_newline();
296        aws->label("Ignore if field missing?");
297        aws->create_toggle(AWAR_MARKBYREF_IGNORE_MISSING);
298
299        aws->at_newline();
300        aws->at_set_to(true, false, XOFF, YOFF_IF);
301        aws->label("Filter content by ACI");
302        aws->create_input_field(AWAR_MARKBYREF_FILTER, 30);
303
304        aws->label_length(LABEL_SHORTL);
305
306        aws->at_newline();
307        aws->at_set_to(true, false, XOFF, YOFF_DF);
308        aws->label("Selected");
309        aws->create_button(NULL, AWAR_MARKBYREF_SELECTED, 0, "+");
310
311        aws->at_newline();
312        aws->at_set_to(true, false, XOFF, YOFF_DF);
313        aws->label("Content");
314        aws->create_button(NULL, AWAR_MARKBYREF_CONTENT,  0, "+");
315
316        aws->at_newline();
317        aws->at_set_to(true, false, XOFF, YOFF_DF);
318        aws->label("Result");
319        aws->create_button(NULL, AWAR_MARKBYREF_RESULT,   0, "+");
320
321        aws->label_length(LABEL_LENGTH);
322
323        aws->at_newline();
324        aws->label("Ignore unknown references?");
325        aws->create_toggle(AWAR_MARKBYREF_IGNORE_UNKNOWN);
326
327        if (build_client_area) build_client_area(aws);
328
329        aws->at_newline();
330        aws->callback(makeWindowCallback(perform_refentries, reh, action_cb));
331        aws->create_autosize_button("ACTION", action, "");
332
333        AWT_insert_config_manager(aws, AW_ROOT_DEFAULT, "mark_by_ref", markByRef_config_mapping, NULL, markByRef_predefined_config);
334
335        aws->window_fit();
336
337        free(items_name);
338
339        refresh_result_cb(aw_root, reh);
340
341        return aws;
342    }
343
344};
345
Note: See TracBrowser for help on using the repository browser.