source: branches/port5/SL/DB_SCANNER/db_scanner.cxx

Last change on this file was 6149, checked in by westram, 16 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.6 KB
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
9#include <inline.h>
10#include <arbdb.h>
11#include <arbdbt.h>
12#include <aw_root.hxx>
13#include <aw_device.hxx>
14#include <aw_window.hxx>
15#include <aw_awars.hxx>
16#include <AW_rename.hxx>
17
18#include <awt.hxx>
19#include <awtlocal.hxx>
20
21#include <db_scanner.hxx>
22
23
24
25
26/**************************************************************************
27    create a database scanner
28        the scanned database is displayed in a selection list
29        the gbdata pointer can be read
30***************************************************************************/
31
32
33/* return the selected GBDATA pntr the should be no !!! running transaction and
34   this function will begin a transaction */
35
36static GBDATA *awt_get_arbdb_scanner_gbd_and_begin_trans(AW_CL arbdb_scanid)
37{
38    struct adawcbstruct *cbs = (struct adawcbstruct *)arbdb_scanid;
39    AW_root *aw_root = cbs->aws->get_root();
40    cbs->may_be_an_error = 0;
41    GB_push_transaction(cbs->gb_main);
42    GBDATA *gbd = (GBDATA *)aw_root->awar(cbs->def_gbd)->read_pointer();
43    if (    !cbs->gb_user ||
44            !gbd ||
45            cbs->may_be_an_error) {     // something changed in the database
46        return 0;
47    }
48    return gbd;
49}
50
51
52
53static GB_BOOL awt_check_scanner_key_data(struct adawcbstruct *cbs,GBDATA *gbd)
54{
55    GBDATA *gb_key_data;
56    gb_key_data = GB_search(cbs->gb_main,cbs->selector->change_key_path,GB_CREATE_CONTAINER);
57    return GB_check_father(gbd,gb_key_data);
58}
59
60static void awt_arbdb_scanner_delete(void *dummy, struct adawcbstruct *cbs)
61{
62    AWUSE(dummy);
63    GBDATA *gbd = awt_get_arbdb_scanner_gbd_and_begin_trans((AW_CL)cbs);
64    if (!gbd) {
65        aw_message("Sorry, cannot perform your operation, please redo it");
66    }else if (awt_check_scanner_key_data(cbs,gbd)) {        // already deleted
67        ;
68    }else{
69        GB_ERROR error = GB_delete(gbd);
70        if (error) aw_message((char *)error);
71    }
72    GB_commit_transaction(cbs->gb_main);
73}
74static void awt_edit_changed_cb(GBDATA *dummy, struct adawcbstruct *cbs, GB_CB_TYPE gbtype)
75{
76    AWUSE(dummy);
77    AW_window *aws = cbs->aws;
78    cbs->may_be_an_error = 1;
79
80    if (gbtype == GB_CB_DELETE) {
81        cbs->gb_edit = 0;
82    }
83    if (cbs->gb_edit) {
84        if (awt_check_scanner_key_data(cbs,cbs->gb_edit)) {     // doesnt exist
85            aws->get_root()->awar(cbs->def_dest)->write_string("");
86        }else{
87            char *data;
88            data = GB_read_as_string(cbs->gb_edit);
89            if (!data) {
90                data = strdup("<YOU CANNOT EDIT THIS TYPE>");
91            }
92            cbs->aws->get_root()->awar(cbs->def_dest)->write_string(data);
93            free(data);
94        }
95    }else{
96        aws->get_root()->awar(cbs->def_dest)->write_string("");
97    }
98}
99
100
101static void awt_arbdb_scanner_value_change(void *, struct adawcbstruct *cbs)
102{
103    char *value = cbs->aws->get_root()->awar(cbs->def_dest)->read_string();
104    int   vlen  = strlen(value);
105
106    while (vlen>0 && value[vlen-1] == '\n') vlen--; // remove trailing newlines
107    value[vlen]     = 0;
108
109    // read the value from the window
110    GBDATA   *gbd         = awt_get_arbdb_scanner_gbd_and_begin_trans((AW_CL)cbs);
111    GB_ERROR  error       = 0;
112    bool      update_self = false;
113
114    if (!gbd) {
115        error = "Sorry, cannot perform your operation, please redo it\n(Hint: No item or fields selected or 'enable edit' is unchecked)";
116        if (!cbs->aws->get_root()->awar(cbs->def_filter)->read_int()) { // edit disabled
117            cbs->aws->get_root()->awar(cbs->def_dest)->write_string("");
118        }
119    }
120    else {
121        awt_assert(cbs->aws->get_root()->awar(cbs->def_filter)->read_int() != 0); // edit is enabled (disabled causes gdb to be 0)
122
123        GBDATA *gb_key_name;
124        char   *key_name = 0;
125
126        if (awt_check_scanner_key_data(cbs,gbd)) {  // not exist, create new element
127            gb_key_name         = GB_entry(gbd,CHANGEKEY_NAME);
128            key_name            = GB_read_string(gb_key_name);
129            GBDATA *gb_key_type = GB_entry(gbd,CHANGEKEY_TYPE);
130
131            if (strlen(value)) {
132                GBDATA *gb_new     = GB_search(cbs->gb_user, key_name,GB_read_int(gb_key_type));
133                if (!gb_new) error = GB_await_error();
134                else    error      = GB_write_as_string(gb_new,value);
135
136                cbs->aws->get_root()->awar(cbs->def_gbd)->write_pointer(gb_new); // remap arbdb
137            }
138        }
139        else { // change old element
140            key_name = GB_read_key(gbd);
141            if (GB_get_father(gbd) == cbs->gb_user && strcmp(key_name, "name") == 0) { // This is a real rename !!!
142                const struct ad_item_selector *selector = cbs->selector;
143
144                if (selector->type == AWT_QUERY_ITEM_SPECIES) { // species
145                    char *name = nulldup(GBT_read_name(cbs->gb_user));
146                    aw_openstatus("Renaming species");
147
148                    if (strlen(value)) {
149                        GBT_begin_rename_session(cbs->gb_main,0);
150
151                        error = GBT_rename_species(name, value, GB_FALSE);
152
153                        if (error) GBT_abort_rename_session();
154                        else GBT_commit_rename_session(aw_status, aw_status);
155                    }
156                    else {
157                        error = AWTC_recreate_name(cbs->gb_user, true);
158                    }
159
160                    aw_closestatus();
161                    free(name);
162                }
163                else { // non-species (gene, experiment, etc.)
164                    if (strlen(value)) {
165                        GBDATA *gb_exists    = 0;
166                        GBDATA *gb_item_data = GB_get_father(cbs->gb_user);
167
168                        for (gb_exists = selector->get_first_item(gb_item_data);
169                             gb_exists;
170                             gb_exists = selector->get_next_item(gb_exists))
171                        {
172                            if (ARB_stricmp(GBT_read_name(gb_exists), value) == 0) break;
173                        }
174
175                        if (gb_exists) error = GBS_global_string("There is already a %s named '%s'", selector->item_name, value);
176                        else error           = GB_write_as_string(gbd, value);
177                    }
178                    else {
179                        error = "The 'name' field can't be empty.";
180                    }
181                }
182
183                if (!error) update_self = true;
184            }
185            else {
186                if (strlen(value)) {
187                    error = GB_write_as_string(gbd, value);
188                }
189                else {
190                    GBDATA *gb_key = GBT_get_changekey(cbs->gb_main, key_name,
191                            cbs->selector->change_key_path);
192                    if (GB_child(gbd)) {
193                        error = "Sorry, cannot perform a deletion.\n(The selected entry has child entries. Delete them first.)";
194                    } else {
195                        error = GB_delete(gbd);
196                        if (!error) {
197                            cbs->aws->get_root()->awar(cbs->def_gbd)->write_pointer(gb_key);
198                        }
199                    }
200                }
201            }
202
203            // if (error) awt_edit_changed_cb(0, cbs, GB_CB_CHANGED); // refresh old value
204        }
205        free(key_name);
206    }
207
208    awt_edit_changed_cb(0, cbs, GB_CB_CHANGED); // refresh edit field
209
210    if (error){
211        aw_message(error);
212        GB_abort_transaction(cbs->gb_main);
213    }
214    else {
215        GB_touch(cbs->gb_user); // change of linked object does not change source of link, so do it by hand
216        GB_commit_transaction(cbs->gb_main);
217    }
218
219    if (update_self) { // if the name changed -> rewrite awars AFTER transaction was closed
220        GB_transaction ta(cbs->gb_main);
221
222        char *my_id = cbs->selector->generate_item_id(cbs->gb_main, cbs->gb_user);
223        cbs->selector->update_item_awars(cbs->gb_main, cbs->awr, my_id); // update awars (e.g. AWAR_SPECIES_NAME)
224        free(my_id);
225    }
226
227    free(value);
228}
229
230/***************** change the flag in cbs->gb_user *****************************/
231
232static void awt_mark_changed_cb(AW_window *aws, struct adawcbstruct *cbs, char *awar_name)
233{
234    cbs->may_be_an_error = 0;
235    long flag = aws->get_root()->awar(awar_name)->read_int();
236    GB_push_transaction(cbs->gb_main);
237    if ( (!cbs->gb_user) || cbs->may_be_an_error) {     // something changed in the database
238    }
239    else{
240        GB_write_flag(cbs->gb_user,flag);
241    }
242    GB_pop_transaction(cbs->gb_main);
243}
244
245static void awt_map_arbdb_edit_box(GBDATA *dummy, struct adawcbstruct *cbs)
246{
247    AWUSE(dummy);
248    GBDATA *gbd;
249    cbs->may_be_an_error = 0;
250    GB_push_transaction(cbs->gb_main);
251    if (cbs->may_be_an_error) {     // sorry
252        cbs->aws->get_root()->awar(cbs->def_gbd)->write_pointer(NULL);
253    }
254    gbd = (GBDATA *)cbs->aws->get_root()->awar(cbs->def_gbd)->read_pointer();
255
256    if (cbs->gb_edit) {
257        GB_remove_callback(cbs->gb_edit,(GB_CB_TYPE)(GB_CB_CHANGED|GB_CB_DELETE),
258                           (GB_CB)awt_edit_changed_cb, (int *)cbs);
259    }
260
261    if (cbs->aws->get_root()->awar(cbs->def_filter)->read_int()) {      // edit enabled
262        cbs->gb_edit = gbd;
263    }else{
264        cbs->gb_edit = 0;       // disable map
265    }
266    if (cbs->gb_edit) {
267        GB_add_callback(cbs->gb_edit,(GB_CB_TYPE)(GB_CB_CHANGED|GB_CB_DELETE),
268                        (GB_CB)awt_edit_changed_cb, (int *)cbs);
269    }
270    awt_edit_changed_cb(gbd,cbs,GB_CB_CHANGED);
271
272    GB_pop_transaction(cbs->gb_main);
273}
274
275
276
277static void awt_scanner_changed_cb(GBDATA *dummy, struct adawcbstruct *cbs, GB_CB_TYPE gbtype);
278/* create an unmapped scanner box and optional some buttons,
279   the return value is the id to further scanner functions */
280
281AW_CL awt_create_arbdb_scanner(GBDATA                 *gb_main, AW_window *aws,
282                               const char             *box_pos_fig, /* the position for the box in the xfig file */
283                               const char             *delete_pos_fig,
284                               const char             *edit_pos_fig,
285                               const char             *edit_enable_pos_fig,
286                               AWT_SCANNERMODE         scannermode,
287                               const char             *rescan_pos_fig, // AWT_VIEWER
288                               const char             *mark_pos_fig,
289                               long                    type_filter,
290                               const ad_item_selector *selector)
291{
292    static int           scanner_id = 0;
293    struct adawcbstruct *cbs        = new adawcbstruct;
294    memset(cbs, 0, sizeof(*cbs));
295
296    char                 buffer[256];
297    AW_root             *aw_root    = aws->get_root();
298
299    GB_push_transaction(gb_main);
300    /*************** Create local AWARS *******************/
301    sprintf(buffer,"tmp/arbdb_scanner_%i/list",scanner_id);
302    cbs->def_gbd = strdup(buffer);
303    aw_root->awar_pointer(cbs->def_gbd, 0, AW_ROOT_DEFAULT);
304
305    sprintf(buffer,"tmp/arbdb_scanner_%i/find",scanner_id);
306    cbs->def_source = strdup(buffer);
307    aw_root->awar_string( cbs->def_source,"", AW_ROOT_DEFAULT);
308
309    sprintf(buffer,"tmp/arbdb_scanner_%i/edit_enable",scanner_id);
310    cbs->def_filter = strdup(buffer);
311    aw_root->awar_int( cbs->def_filter,GB_TRUE, AW_ROOT_DEFAULT);
312
313    sprintf(buffer,"tmp/arbdb_scanner_%i/mark",scanner_id);
314    cbs->def_dir = strdup(buffer);
315    aw_root->awar_int( cbs->def_dir,GB_TRUE, AW_ROOT_DEFAULT);
316
317    aws->at(box_pos_fig);
318
319    cbs->id          = aws->create_selection_list(cbs->def_gbd, 0, "", 20, 10);
320    cbs->aws         = aws;
321    cbs->awr         = aw_root;
322    cbs->gb_main     = gb_main;
323    cbs->gb_user     = 0;
324    cbs->gb_edit     = 0;
325    cbs->scannermode = (char) scannermode;
326    cbs->selector    = selector;
327
328    /*************** Create the delete button ****************/
329    if (delete_pos_fig) {
330        aws->at(delete_pos_fig);
331        aws->callback((AW_CB)awt_arbdb_scanner_delete,(AW_CL)cbs,0);
332        aws->create_button("DELETE_DB_FIELD", "DELETE","D");
333    }
334
335    /*************** Create the enable edit selector ****************/
336    if (edit_enable_pos_fig) {
337        aws->at(edit_enable_pos_fig);
338        aws->callback((AW_CB1)awt_map_arbdb_edit_box,(AW_CL)cbs);
339        aws->create_toggle(cbs->def_filter);
340    }
341
342    if (mark_pos_fig) {
343        aws->at(mark_pos_fig);
344        aws->callback((AW_CB)awt_mark_changed_cb,(AW_CL)cbs,(AW_CL)cbs->def_dir);
345        aws->create_toggle(cbs->def_dir);
346    }
347
348    cbs->def_dest = 0;
349    if (edit_pos_fig) {
350        aw_root->awar(cbs->def_gbd)->add_callback((AW_RCB1)awt_map_arbdb_edit_box,(AW_CL)cbs);
351        if (edit_enable_pos_fig) {
352            aw_root->awar(cbs->def_filter)->add_callback((AW_RCB1)awt_map_arbdb_edit_box,(AW_CL)cbs);
353        }
354        sprintf(buffer,"tmp/arbdb_scanner_%i/edit",scanner_id);
355        cbs->def_dest = strdup(buffer);
356        aw_root->awar_string( cbs->def_dest,"", AW_ROOT_DEFAULT);
357
358        aws->at(edit_pos_fig);
359        aws->callback((AW_CB1)awt_arbdb_scanner_value_change,(AW_CL)cbs);
360        aws->create_text_field(cbs->def_dest,20,10);
361    }
362
363    /*************** Create the rescan button ****************/
364    if (rescan_pos_fig) {
365        aws->at(rescan_pos_fig);
366        aws->callback(cbs->selector->selection_list_rescan_cb, (AW_CL)cbs->gb_main,(AW_CL)type_filter);
367        aws->create_button("RESCAN_DB", "RESCAN","R");
368    }
369
370    scanner_id++;
371    GB_pop_transaction(gb_main);
372    aws->set_popup_callback((AW_CB)awt_scanner_changed_cb,(AW_CL)cbs, GB_CB_CHANGED);
373    return (AW_CL)cbs;
374}
375
376static void awt_scanner_scan_rek(GBDATA *gbd,struct adawcbstruct *cbs,int deep, AW_selection_list *id)
377{
378    GB_TYPES  type = GB_read_type(gbd);
379    char     *key  = GB_read_key(gbd);
380
381    GBS_strstruct *out = GBS_stropen(1000);
382    for (int i = 0; i < deep; i++) GBS_strcat(out, ": ");
383    GBS_strnprintf(out, 30, "%-12s", key);
384
385    switch (type) {
386        case GB_DB: {
387            GBS_strcat(out, "<CONTAINER>:");
388            cbs->aws->insert_selection(cbs->id, GBS_mempntr(out), gbd);
389            GBS_strforget(out);
390
391            for (GBDATA *gb2 = GB_child(gbd); gb2; gb2 = GB_nextChild(gb2)) {
392                awt_scanner_scan_rek(gb2, cbs, deep + 1, id);
393            }
394            break;
395        }
396        case GB_LINK: {
397            GBS_strnprintf(out, 100, "LINK TO '%s'", GB_read_link_pntr(gbd));
398            cbs->aws->insert_selection(cbs->id, GBS_mempntr(out), gbd);
399            GBS_strforget(out);
400
401            GBDATA *gb_al = GB_follow_link(gbd);
402            if (gb_al) {
403                for (GBDATA *gb2 = GB_child(gb_al); gb2; gb2 = GB_nextChild(gb2)) {
404                    awt_scanner_scan_rek(gb2, cbs, deep + 1, id);
405                }
406            }
407            break;
408        }
409        default: {
410            char *data = GB_read_as_string(gbd);
411
412            if (data) {
413                GBS_strcat(out, data);
414                free(data);
415            }
416            else {
417                GBS_strcat(out, "<unprintable>");
418            }
419            cbs->aws->insert_selection(cbs->id, GBS_mempntr(out), gbd);
420            GBS_strforget(out);
421            break;
422        }
423    }
424    free(key);
425}
426
427static void awt_scanner_scan_list(GBDATA *dummy, struct adawcbstruct *cbs)
428{
429#define INFO_WIDTH 1000
430 refresh_again:
431    char buffer[INFO_WIDTH+1];
432    memset(buffer,0,INFO_WIDTH+1);
433
434    static int last_max_name_width;
435    int        max_name_width = 0;
436
437    if (last_max_name_width == 0) last_max_name_width = 15;
438
439    AWUSE(dummy);
440    cbs->aws->clear_selection_list(cbs->id);
441
442    GBDATA *gb_key_data = GB_search(cbs->gb_main, cbs->selector->change_key_path, GB_CREATE_CONTAINER);
443
444    for (int existing = 1; existing >= 0; --existing) {
445        for (GBDATA *gb_key = GB_entry(gb_key_data,CHANGEKEY); gb_key; gb_key = GB_nextEntry(gb_key)) {
446            GBDATA *gb_key_hidden = GB_entry(gb_key,CHANGEKEY_HIDDEN);
447            if (gb_key_hidden && GB_read_int(gb_key_hidden)) continue; // dont show hidden fields in 'species information' window
448
449            GBDATA *gb_key_name = GB_entry(gb_key,CHANGEKEY_NAME);
450            if (!gb_key_name) continue;
451
452            GBDATA *gb_key_type = GB_entry(gb_key,CHANGEKEY_TYPE);
453
454            const char *name = GB_read_char_pntr(gb_key_name);
455            GBDATA     *gbd  = GB_search(cbs->gb_user,name,GB_FIND);
456
457            if ((!existing) == (!gbd)) { // first print only existing; then non-existing entries
458                char *p      = buffer;
459                int   len    = sprintf(p,"%-*s %c", last_max_name_width, name, GB_TYPE_2_CHAR[GB_read_int(gb_key_type)]);
460
461                p += len;
462
463                int name_width = strlen(name);
464                if (name_width>max_name_width) max_name_width = name_width;
465
466                if (gbd) {      // existing entry
467                    *(p++) = GB_read_security_write(gbd)+'0';
468                    *(p++) = ':';
469                    *(p++) = ' ';
470                    *p     = 0;
471
472                    {
473                        char *data = GB_read_as_string(gbd);
474                        int   ssize;
475
476                        if (data) {
477                            int rest = INFO_WIDTH-(p-buffer);
478                            ssize    = strlen(data);
479
480                            if (ssize > rest) {
481                                ssize = GBS_shorten_repeated_data(data);
482                                if (ssize > rest) {
483                                    if (ssize>5) strcpy(data+rest-5, "[...]");
484                                    ssize = rest;
485                                }
486                            }
487
488                            memcpy(p,data,ssize);
489                            p[ssize] = 0;
490
491                            free(data);
492                        }
493                    }
494                    cbs->aws->insert_selection(cbs->id, buffer, gbd);
495                }
496                else { // non-existing entry
497                    p[0] = ' '; p[1] = ':'; p[2] = 0;
498                    cbs->aws->insert_selection(cbs->id, buffer, gb_key);
499                }
500            }
501        }
502    }
503
504    if (last_max_name_width < max_name_width) {
505        last_max_name_width = max_name_width;
506        goto refresh_again;
507    }
508#undef INFO_WIDTH
509}
510
511static void awt_scanner_changed_cb(GBDATA *dummy, struct adawcbstruct *cbs, GB_CB_TYPE gbtype)
512{
513    AWUSE(dummy);
514    AW_window *aws = cbs->aws;
515
516    cbs->may_be_an_error = 1;
517
518    if (gbtype == GB_CB_DELETE) {
519        cbs->gb_user = 0;
520    }
521    if (cbs->gb_user && !cbs->aws->is_shown()) {
522        // unmap invisible window
523        //awt_map_arbdb_scanner((AW_CL)cbs,0,cbs->show_only_marked);
524        // recalls this function !!!!
525        return;
526    }
527    aws->clear_selection_list(cbs->id);
528    if (cbs->gb_user) {
529        GB_transaction ta(cbs->gb_main);
530
531        switch (cbs->scannermode) {
532            case AWT_SCANNER:
533                awt_scanner_scan_rek(cbs->gb_user,cbs,0,cbs->id);
534                break;
535            case AWT_VIEWER:
536                awt_scanner_scan_list(cbs->gb_user,cbs);
537                break;
538        }
539    }
540    aws->insert_default_selection( cbs->id, "", (void*)NULL);
541    aws->update_selection_list( cbs->id );
542    if (cbs->gb_user) {
543        GB_transaction ta(cbs->gb_main);
544
545        long flag = GB_read_flag(cbs->gb_user);
546        aws->get_root()->awar(cbs->def_dir)->write_int(flag);
547    }
548}
549/************ Unmap edit field if 'key_data' has been changed (maybe entries deleted)
550 *********/
551static void awt_scanner_changed_cb2(GBDATA *dummy, struct adawcbstruct *cbs, GB_CB_TYPE gbtype)
552{
553    cbs->aws->get_root()->awar(cbs->def_gbd)->write_pointer(NULL);
554    // unmap edit field
555    awt_scanner_changed_cb(dummy,cbs,gbtype);
556}
557
558void awt_map_arbdb_scanner(AW_CL arbdb_scanid, GBDATA *gb_pntr, int show_only_marked_flag, const char *key_path)
559{
560    struct adawcbstruct *cbs         = (struct adawcbstruct *)arbdb_scanid;
561    GB_push_transaction(cbs->gb_main);
562    GBDATA              *gb_key_data = GB_search(cbs->gb_main,key_path,GB_CREATE_CONTAINER);
563
564    if (cbs->gb_user) {
565        GB_remove_callback(cbs->gb_user,(GB_CB_TYPE)(GB_CB_CHANGED|GB_CB_DELETE), (GB_CB)awt_scanner_changed_cb, (int *)cbs);
566        if (cbs->scannermode == AWT_VIEWER) {
567            GB_remove_callback(gb_key_data,(GB_CB_TYPE)(GB_CB_CHANGED), (GB_CB)awt_scanner_changed_cb2, (int *)cbs);
568        }
569    }
570
571    cbs->show_only_marked = show_only_marked_flag;
572    cbs->gb_user          = gb_pntr;
573
574    if (gb_pntr) {
575        GB_add_callback(gb_pntr,(GB_CB_TYPE)(GB_CB_CHANGED|GB_CB_DELETE), (GB_CB)awt_scanner_changed_cb, (int *)cbs);
576        if (cbs->scannermode == AWT_VIEWER) {
577            GB_add_callback(gb_key_data,(GB_CB_TYPE)(GB_CB_CHANGED), (GB_CB)awt_scanner_changed_cb2, (int *)cbs);
578        }
579    }
580
581    cbs->aws->get_root()->awar(cbs->def_gbd)->write_pointer(NULL);
582    awt_scanner_changed_cb(gb_pntr,cbs,GB_CB_CHANGED);
583
584    GB_pop_transaction(cbs->gb_main);
585}
Note: See TracBrowser for help on using the repository browser.