source: tags/arb-6.0.5/AWT/AWT_sel_boxes.cxx

Last change on this file was 12267, checked in by westram, 10 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.1 KB
Line 
1// ================================================================ //
2//                                                                  //
3//   File      : AWT_sel_boxes.cxx                                  //
4//   Purpose   :                                                    //
5//                                                                  //
6//   Institute of Microbiology (Technical University Munich)        //
7//   http://www.arb-home.de/                                        //
8//                                                                  //
9// ================================================================ //
10
11#include "awt.hxx"
12#include "awt_sel_boxes.hxx"
13
14#include <item_sel_list.h>
15
16#include <aw_awars.hxx>
17#include <aw_file.hxx>
18#include <aw_msg.hxx>
19#include <aw_root.hxx>
20#include <aw_edit.hxx>
21
22#include <ad_config.h>
23#include <ad_cb.h>
24
25#include <arbdbt.h>
26#include <arb_strbuf.h>
27#include <arb_strarray.h>
28#include <arb_file.h>
29#include <arb_global_defs.h>
30
31#include <list>
32#include "awt_modules.hxx"
33#include <BufferedFileReader.h>
34
35using namespace std;
36
37
38
39// --------------------------------------
40//      selection boxes on alignments
41
42class AWT_alignment_selection : public AW_DB_selection { // derived from a Noncopyable
43    char *ali_type_match;                           // filter for wanted alignments (GBS_string_eval command)
44public:
45    AWT_alignment_selection(AW_selection_list *sellist_, GBDATA *gb_presets, const char *ali_type_match_)
46        : AW_DB_selection(sellist_, gb_presets)
47        , ali_type_match(nulldup(ali_type_match_))
48    {}
49   
50    void fill() OVERRIDE {
51        GBDATA         *gb_presets = get_gbd();
52        GB_transaction  ta(gb_presets);
53
54        for (GBDATA *gb_alignment = GB_entry(gb_presets, "alignment");
55             gb_alignment;
56             gb_alignment = GB_nextEntry(gb_alignment))
57        {
58            char *alignment_type = GBT_read_string(gb_alignment, "alignment_type");
59            char *alignment_name = GBT_read_string(gb_alignment, "alignment_name");
60            char *str            = GBS_string_eval(alignment_type, ali_type_match, 0);
61
62            if (!*str) insert(alignment_name, alignment_name);
63            free(str);
64            free(alignment_type);
65            free(alignment_name);
66        }
67        insert_default(DISPLAY_NONE, NO_ALI_SELECTED);
68    }
69
70    void reconfigure(const char *new_ali_type_match) {
71        freedup(ali_type_match, new_ali_type_match);
72        refresh();
73    }
74};
75
76AW_DB_selection *awt_create_selection_list_on_alignments(GBDATA *gb_main, AW_window *aws, const char *varname, const char *ali_type_match) {
77    // Create selection lists on alignments
78    //
79    // if 'ali_type_match' is set, then only insert alignments,
80    // where 'ali_type_match' GBS_string_eval's the alignment type
81
82    GBDATA *gb_presets;
83    {
84        GB_transaction ta(gb_main);
85        gb_presets = GBT_get_presets(gb_main);
86    }
87    AW_selection_list       *sellist = aws->create_selection_list(varname, 20, 3, true);
88    AWT_alignment_selection *alisel  = new AWT_alignment_selection(sellist, gb_presets, ali_type_match);
89    alisel->refresh(); // belongs to window now
90    return alisel;
91}
92
93void awt_reconfigure_selection_list_on_alignments(AW_DB_selection *dbsel, const char *ali_type_match) {
94    AWT_alignment_selection *alisel = dynamic_cast<AWT_alignment_selection*>(dbsel);
95    alisel->reconfigure(ali_type_match);
96}
97
98// ---------------------------------
99//      selection boxes on trees
100
101struct AWT_tree_selection: public AW_DB_selection {
102    AWT_tree_selection(AW_selection_list *sellist_, GBDATA *gb_tree_data)
103        : AW_DB_selection(sellist_, gb_tree_data)
104    {}
105
106    void fill() OVERRIDE {
107        GBDATA         *gb_main = get_gb_main();
108        GB_transaction  ta(gb_main);
109
110        ConstStrArray tree_names;
111        GBT_get_tree_names(tree_names, gb_main, true);
112
113        if (!tree_names.empty()) {
114            int maxTreeNameLen = 0;
115            for (int i = 0; tree_names[i]; ++i) {
116                const char *tree = tree_names[i];
117                int         len  = strlen(tree);
118                if (len>maxTreeNameLen) maxTreeNameLen = len;
119            }
120            for (int i = 0; tree_names[i]; ++i) {
121                const char *tree = tree_names[i];
122                const char *info = GBT_tree_info_string(gb_main, tree, maxTreeNameLen);
123                if (info) {
124                    insert(info, tree);
125                }
126                else {
127                    aw_message(GB_await_error());
128                    insert(tree, tree);
129                }
130            }
131        }
132        insert_default(DISPLAY_NONE, NO_TREE_SELECTED); 
133    }
134};
135
136AW_DB_selection *awt_create_selection_list_on_trees(GBDATA *gb_main, AW_window *aws, const char *varname, bool fallback2default) {
137    GBDATA *gb_tree_data;
138    {
139        GB_transaction ta(gb_main);
140        gb_tree_data = GBT_get_tree_data(gb_main);
141    }
142    AW_selection_list  *sellist = aws->create_selection_list(varname, 40, 4, fallback2default);
143    AWT_tree_selection *treesel = new AWT_tree_selection(sellist, gb_tree_data); // owned by nobody
144    treesel->refresh();
145    return treesel;
146}
147
148
149// --------------------------------------
150//      selection boxes on pt-servers
151
152#define PT_SERVERNAME_LENGTH        23              // that's for buttons
153#define PT_SERVERNAME_SELLIST_WIDTH 30              // this for lists
154#define PT_SERVER_TRACKLOG_TIMER    10000           // every 10 seconds
155
156class AWT_ptserver_selection : public AW_selection {
157    typedef list<AWT_ptserver_selection*> PTserverSelections;
158   
159    static PTserverSelections ptserver_selections;
160public:
161    AWT_ptserver_selection(AW_selection_list *sellist_);
162
163    void fill() OVERRIDE;
164
165    static void refresh_all();
166};
167
168AWT_ptserver_selection::PTserverSelections AWT_ptserver_selection::ptserver_selections;
169
170void AWT_ptserver_selection::fill() {
171    const char * const *pt_servers = GBS_get_arb_tcp_entries("ARB_PT_SERVER*");
172
173    int count = 0;
174    while (pt_servers[count]) count++;
175
176    for (int i=0; i<count; i++) {
177        char *choice = GBS_ptserver_id_to_choice(i, 1);
178        if (!choice) {
179            aw_message(GB_await_error());
180            break;
181        }
182        insert(choice, (long)i);
183        free(choice);
184    }
185
186    insert_default("-undefined-", (long)-1);
187}
188
189void AWT_ptserver_selection::refresh_all() {
190    PTserverSelections::iterator end = ptserver_selections.end();
191    for (PTserverSelections::iterator pts_sel = ptserver_selections.begin(); pts_sel != end; ++pts_sel) {
192        (*pts_sel)->refresh();
193    }
194}
195static void awt_refresh_all_pt_server_selection_lists() {
196    AWT_ptserver_selection::refresh_all();
197}
198static unsigned track_log_cb(AW_root *) {
199    static long  last_ptserverlog_mod = 0;
200    const char  *ptserverlog          = GBS_ptserver_logname();
201    long         ptserverlog_mod      = GB_time_of_file(ptserverlog);
202
203    if (ptserverlog_mod != last_ptserverlog_mod) {
204#if defined(DEBUG)
205        fprintf(stderr, "%s modified!\n", ptserverlog);
206#endif // DEBUG
207        AWT_ptserver_selection::refresh_all();
208        last_ptserverlog_mod = ptserverlog_mod;
209    }
210
211    return PT_SERVER_TRACKLOG_TIMER;
212}
213
214AWT_ptserver_selection::AWT_ptserver_selection(AW_selection_list *sellist_)
215    : AW_selection(sellist_)
216{
217    if (ptserver_selections.empty()) {
218        // first pt server selection list -> install log tracker
219        AW_root::SINGLETON->add_timed_callback(PT_SERVER_TRACKLOG_TIMER, makeTimedCallback(track_log_cb));
220    }
221    ptserver_selections.push_back(this);
222}
223
224
225static void arb_tcp_dat_changed_cb(const char * /* path */, bool fileChanged, bool /* editorTerminated */) {
226    if (fileChanged) {
227        awt_refresh_all_pt_server_selection_lists();
228    }
229}
230
231void awt_edit_arbtcpdat_cb(AW_window *aww, GBDATA *gb_main) {
232    char *filename = GB_arbtcpdat_path();
233    AW_edit(filename, arb_tcp_dat_changed_cb, aww, gb_main);
234    free(filename);
235}
236
237#if !defined(ARB_GTK)
238static char *readable_pt_servername(int index, int maxlength) {
239    char *fullname = GBS_ptserver_id_to_choice(index, 0);
240    if (!fullname) {
241#ifdef DEBUG
242        printf("awar given to awt_create_selection_list_on_pt_servers() does not contain a valid index\n");
243#endif
244        GB_clear_error();
245        return strdup("-undefined-");
246    }
247
248    int len = strlen(fullname);
249    if (len <= maxlength) {
250        return fullname;
251    }
252
253    int remove  = len-maxlength;
254    fullname[0] = '.';
255    fullname[1] = '.';
256    strcpy(fullname+2, fullname+2+remove);
257
258    return fullname;
259}
260
261static void update_ptserver_button(AW_root *aw_root, const char *varname) {
262    char *awar_buttontext_name = GBS_global_string_copy("/tmp/%s_BUTTON", varname);
263    char *readable_name        = readable_pt_servername(aw_root->awar(varname)->read_int(), PT_SERVERNAME_LENGTH);
264
265    aw_root->awar(awar_buttontext_name)->write_string(readable_name);
266
267    free(readable_name);
268    free(awar_buttontext_name);
269}
270
271static AW_window *create_selection_list_on_pt_servers_window(AW_root *aw_root, const char *varname) {
272    AW_window_simple *aw_popup = new AW_window_simple;
273
274    aw_popup->init(aw_root, "SELECT_PT_SERVER", "Select a PT-Server");
275    aw_popup->auto_space(10, 10);
276
277    aw_popup->at_newline();
278    aw_popup->callback((AW_CB0)AW_POPDOWN);
279    AW_selection_list *sellist = aw_popup->create_selection_list(varname, PT_SERVERNAME_SELLIST_WIDTH, 20, true);
280
281    aw_popup->at_newline();
282    aw_popup->callback((AW_CB0)AW_POPDOWN);
283    aw_popup->create_button("CLOSE", "CLOSE", "C");
284
285    aw_popup->window_fit();
286    aw_popup->recalc_pos_atShow(AW_REPOS_TO_MOUSE);
287
288    (new AWT_ptserver_selection(sellist))->refresh();
289
290    return aw_popup;
291}
292#endif // ARB_GTK
293
294void awt_create_selection_list_on_pt_servers(AW_window *aws, const char *varname, bool popup) {
295    if (popup) {
296#ifdef ARB_GTK
297        (new AWT_ptserver_selection(aws->create_option_menu(varname, true)))->refresh();
298
299        int old_button_length = aws->get_button_length();
300        aws->button_length(PT_SERVERNAME_LENGTH+1);
301        aws->update_option_menu();
302        aws->button_length(old_button_length);
303#else
304
305        AW_root *aw_root              = aws->get_root();
306        char    *awar_buttontext_name = GBS_global_string_copy("/tmp/%s_BUTTON", varname);
307        int      ptserver_index       = aw_root->awar(varname)->read_int();
308
309        if (ptserver_index<0) { // fix invalid pt_server indices
310            ptserver_index = 0;
311            aw_root->awar(varname)->write_int(ptserver_index);
312        }
313
314        char        *readable_name = readable_pt_servername(ptserver_index, PT_SERVERNAME_LENGTH);
315        char *const  varnameDup    = strdup(varname);
316
317        awt_assert(!GB_have_error());
318
319        aw_root->awar_string(awar_buttontext_name, readable_name, AW_ROOT_DEFAULT);
320        aw_root->awar(varname)->add_callback(makeRootCallback(update_ptserver_button, varnameDup));
321
322        int old_button_length = aws->get_button_length();
323
324        aws->button_length(PT_SERVERNAME_LENGTH+1);
325        aws->callback(makeCreateWindowCallback(create_selection_list_on_pt_servers_window, varnameDup));
326        aws->create_button("CURR_PT_SERVER", awar_buttontext_name);
327
328        aws->button_length(old_button_length);
329
330        free(readable_name);
331        free(awar_buttontext_name);
332#endif
333    }
334    else {
335        (new AWT_ptserver_selection(aws->create_selection_list(varname, true)))->refresh();
336    }
337}
338
339// ----------------------------------
340//      selection boxes on tables
341
342
343#if defined(WARN_TODO)
344#warning derive awt_sel_list_for_tables from AW_DB_selection
345#endif
346
347struct awt_sel_list_for_tables {
348    AW_window         *aws;
349    GBDATA            *gb_main;
350    AW_selection_list *id;
351    const char        *table_name;
352};
353
354static void awt_create_selection_list_on_tables_cb(GBDATA *, struct awt_sel_list_for_tables *cbs) {
355    cbs->id->clear();
356    GBDATA *gb_table;
357    for (gb_table = GBT_first_table(cbs->gb_main);
358         gb_table;
359         gb_table = GBT_next_table(gb_table)) {
360
361        GBDATA *gb_name = GB_entry(gb_table, "name");
362        GBDATA *gb_description = GB_search(gb_table, "description", GB_STRING);
363        if (!gb_name) continue;
364        char *table_name = GB_read_string(gb_name);
365        char *description = GB_read_string(gb_description);
366        const char *info_text = GBS_global_string("%s: %s", table_name, description);
367        cbs->id->insert(info_text, table_name);
368        free(table_name);
369        free(description);
370    }
371    cbs->id->insert_default("", "");
372    cbs->id->update();
373}
374
375void awt_create_selection_list_on_tables(GBDATA *gb_main, AW_window *aws, const char *varname)
376{
377    AW_selection_list *id;
378    GBDATA  *gb_table_data;
379    struct awt_sel_list_for_tables *cbs;
380    GB_push_transaction(gb_main);
381
382    id = aws->create_selection_list(varname, 40, 8, true);
383    cbs = new awt_sel_list_for_tables;
384    cbs->aws = aws;
385    cbs->gb_main = gb_main;
386    cbs->id = id;
387
388    awt_create_selection_list_on_tables_cb(0, cbs);
389
390    gb_table_data = GB_search(gb_main, "table_data", GB_CREATE_CONTAINER);
391    GB_add_callback(gb_table_data, GB_CB_CHANGED, makeDatabaseCallback(awt_create_selection_list_on_tables_cb, cbs));
392
393    GB_pop_transaction(gb_main);
394}
395
396static void awt_create_selection_list_on_table_fields_cb(GBDATA *, struct awt_sel_list_for_tables *cbs) {
397    cbs->id->clear();
398    GBDATA  *gb_table = GBT_open_table(cbs->gb_main, cbs->table_name, true); // read only
399    GBDATA *gb_table_field;
400    for (gb_table_field = GBT_first_table_field(gb_table);
401         gb_table_field;
402         gb_table_field = GBT_next_table_field(gb_table_field))
403    {
404        GBDATA *gb_name = GB_entry(gb_table_field, "name");
405        GBDATA *gb_description = GB_search(gb_table_field, "description", GB_STRING);
406        if (!gb_name) continue;
407        char *table_name = GB_read_string(gb_name);
408        char *description = GB_read_string(gb_description);
409        const char *info_text = GBS_global_string("%s: %s", table_name, description);
410        cbs->id->insert(info_text, table_name);
411        free(table_name);
412        free(description);
413    }
414    cbs->id->insert_default("", "");
415    cbs->id->update();
416}
417
418void awt_create_selection_list_on_table_fields(GBDATA *gb_main, AW_window *aws, const char *table_name, const char *varname) {
419    // if tablename == 0 -> take fields from species table
420
421    AW_selection_list              *id;
422    struct awt_sel_list_for_tables *cbs;
423    GB_push_transaction(gb_main);
424
425    id = aws->create_selection_list(varname, 40, 8, true);
426    cbs = new awt_sel_list_for_tables;
427    cbs->aws = aws;
428    cbs->gb_main = gb_main;
429    cbs->id = id;
430    cbs->table_name = strdup(table_name);
431
432    awt_create_selection_list_on_table_fields_cb(0, cbs);
433
434    GBDATA  *gb_table = GBT_open_table(gb_main, table_name, true); // read only
435    if (gb_table) {
436        GB_add_callback(gb_table, GB_CB_CHANGED, makeDatabaseCallback(awt_create_selection_list_on_table_fields_cb, cbs));
437    }
438    GB_pop_transaction(gb_main);
439}
440
441// -------------------------------------------------
442//      selection boxes on editor configurations
443
444struct AWT_configuration_selection : public AW_DB_selection {
445    AWT_configuration_selection(AW_selection_list *sellist_, GBDATA *gb_configuration_data)
446        : AW_DB_selection(sellist_, gb_configuration_data)
447    {}
448
449    void fill() OVERRIDE {
450        ConstStrArray config;
451        GBT_get_configuration_names(config, get_gb_main());
452
453        if (!config.empty()) {
454            for (int c = 0; config[c]; c++) insert(config[c], config[c]);
455        }
456        insert_default(DISPLAY_NONE, NO_CONFIG_SELECTED);
457    }
458};
459
460void awt_create_selection_list_on_configurations(GBDATA *gb_main, AW_window *aws, const char *varname, bool fallback2default) {
461    GBDATA *gb_configuration_data;
462    {
463        GB_transaction ta(gb_main);
464        gb_configuration_data = GB_search(gb_main, CONFIG_DATA_PATH, GB_CREATE_CONTAINER);
465    }
466    AW_selection_list *sellist = aws->create_selection_list(varname, 40, 15, fallback2default);
467    (new AWT_configuration_selection(sellist, gb_configuration_data))->refresh();
468}
469
470char *awt_create_string_on_configurations(GBDATA *gb_main) {
471    // returns semicolon-separated string containing configuration names
472    // (or NULL if no configs exist)
473
474    GB_push_transaction(gb_main);
475
476    ConstStrArray config;
477    GBT_get_configuration_names(config, gb_main);
478
479    char *result = 0;
480
481    if (!config.empty()) {
482        GBS_strstruct *out = GBS_stropen(1000);
483        for (int c = 0; config[c]; c++) {
484            if (c>0) GBS_chrcat(out, ';');
485            GBS_strcat(out, config[c]);
486        }
487        result = GBS_strclose(out);
488    }
489
490    GB_pop_transaction(gb_main);
491    return result;
492}
493
494// ----------------------
495//      SAI selection
496
497
498class AWT_sai_selection : public AW_DB_selection { // derived from a Noncopyable
499    awt_sai_sellist_filter filter_poc;
500    AW_CL                  filter_cd;
501
502public:
503
504    AWT_sai_selection(AW_selection_list *sellist_, GBDATA *gb_sai_data, awt_sai_sellist_filter filter_poc_, AW_CL filter_cd_)
505        : AW_DB_selection(sellist_, gb_sai_data),
506          filter_poc(filter_poc_),
507          filter_cd(filter_cd_)
508    {}
509
510    void fill() OVERRIDE;
511};
512
513void AWT_sai_selection::fill() {
514    AW_selection_list *sel = get_sellist();
515    sel->clear();
516
517    GBDATA         *gb_main = get_gb_main();
518    GB_transaction  ta(gb_main);
519
520    for (GBDATA *gb_extended = GBT_first_SAI(gb_main);
521         gb_extended;
522         gb_extended = GBT_next_SAI(gb_extended))
523    {
524        if (filter_poc) {
525            char *res = filter_poc(gb_extended, filter_cd);
526            if (res) {
527                sel->insert(res, GBT_read_name(gb_extended));
528                free(res);
529            }
530        }
531        else {
532            const char *name     = GBT_read_name(gb_extended);
533            GBDATA     *gb_group = GB_entry(gb_extended, "sai_group");
534
535            if (gb_group) {
536                const char *group          = GB_read_char_pntr(gb_group);
537                char       *group_and_name = GBS_global_string_copy("[%s] %s", group, name);
538
539                sel->insert(group_and_name, name);
540                free(group_and_name);
541            }
542            else {
543                sel->insert(name, name);
544            }
545        }
546    }
547    sel->sort(false, false);
548
549    sel->insert_default(DISPLAY_NONE, "");
550    sel->update();
551}
552
553void awt_selection_list_on_sai_update_cb(UNFIXED, AWT_sai_selection *saisel) {
554    /* update the selection box defined by awt_create_selection_list_on_sai
555     *
556     * useful only when filterproc is defined
557     * (changes to SAIs will automatically callback this function)
558     */
559
560    saisel->refresh();
561}
562
563AWT_sai_selection *SAI_selection_list_spec::create_list(AW_window *aws, bool fallback2default) const {
564    GB_transaction ta(gb_main);
565
566    AW_selection_list *sellist     = aws->create_selection_list(awar_name, 40, 4, fallback2default);
567    GBDATA            *gb_sai_data = GBT_get_SAI_data(gb_main);
568    AWT_sai_selection *saisel      = new AWT_sai_selection(sellist, gb_sai_data, filter_poc, filter_cd);
569
570    awt_selection_list_on_sai_update_cb(0, saisel);
571    GB_add_callback(gb_sai_data, GB_CB_CHANGED, makeDatabaseCallback(awt_selection_list_on_sai_update_cb, saisel));
572
573    return saisel;
574}
575
576static void popup_filtered_sai_selection_list(AW_root *aw_root, const SAI_selection_list_spec *spec) {
577    const char *awar_name = spec->get_awar_name();
578
579    static GB_HASH *SAI_window_hash       = 0;
580    if (!SAI_window_hash) SAI_window_hash = GBS_create_hash(10, GB_MIND_CASE);
581
582    AW_window_simple *aws = reinterpret_cast<AW_window_simple *>(GBS_read_hash(SAI_window_hash, awar_name));
583
584    if (!aws) {
585        aws = new AW_window_simple;
586        aws->init(aw_root, "SELECT_SAI", "SELECT SAI");
587        aws->load_xfig("select_simple.fig");
588
589        aws->at("selection");
590        aws->callback((AW_CB0)AW_POPDOWN);
591        spec->create_list(aws, true);
592
593        aws->at("button");
594        aws->callback(AW_POPDOWN);
595        aws->create_button("CLOSE", "CLOSE", "C");
596
597        aws->window_fit();
598
599        GBS_write_hash(SAI_window_hash, awar_name, reinterpret_cast<long>(aws));
600    }
601
602    aws->activate();
603}
604static void popup_filtered_sai_selection_list(AW_window *aww, const SAI_selection_list_spec *spec) {
605    popup_filtered_sai_selection_list(aww->get_root(), spec);
606}
607
608void awt_popup_sai_selection_list(AW_window *aww, const char *awar_name, GBDATA *gb_main) {
609    SAI_selection_list_spec spec(awar_name, gb_main);
610    popup_filtered_sai_selection_list(aww, &spec);
611}
612
613AWT_sai_selection *awt_create_selection_list_on_sai(GBDATA *gb_main, AW_window *aws, const char *varname, bool fallback2default, awt_sai_sellist_filter filter_poc, AW_CL filter_cd) {
614    /* Selection list for SAIs
615     *
616     * if filter_proc is set then show only those items on which
617     * filter_proc returns a string (string must be a heap copy)
618     */
619    SAI_selection_list_spec spec(varname, gb_main);
620    spec.define_filter(filter_poc, filter_cd);
621    return spec.create_list(aws, fallback2default);
622}
623
624void awt_create_SAI_selection_button(GBDATA *gb_main, AW_window *aws, const char *varname, awt_sai_sellist_filter filter_poc, AW_CL filter_cd) {
625    SAI_selection_list_spec *spec = new SAI_selection_list_spec(varname, gb_main);
626    spec->define_filter(filter_poc, filter_cd);
627    aws->callback(makeWindowCallback(popup_filtered_sai_selection_list, spec));
628    aws->create_button("SELECT_SAI", varname);
629}
630
631// --------------------------------------------------
632//      save/load selection content to/from file
633
634static GB_ERROR standard_list2file(const CharPtrArray& display, const CharPtrArray& value, StrArray& line) {
635    GB_ERROR error = NULL;
636    for (size_t i = 0; i<display.size() && !error; ++i) {
637        const char *disp = display[i];
638
639        if (disp[0] == '#') { // would interpret as comment when loaded
640            error = "Invalid character '#' at start of displayed text (won't load)";
641        }
642        else {
643            if (strchr(disp, ',')) {
644                // would be interpreted as separator between display and value on load
645                error = "Invalid character ',' in displayed text (won't load correctly)";
646            }
647            else {
648                awt_assert(strchr(disp, '\n') == 0);
649
650                const char *val = value[i];
651                if (strcmp(disp, val) == 0) {
652                    line.put(strdup(disp));
653                }
654                else {
655                    char *escaped = GBS_escape_string(val, "\n", '\\');
656                    line.put(GBS_global_string_copy("%s,%s", disp, escaped));
657                    free(escaped);
658                }
659            }
660        }
661    }
662    return NULL;
663}
664
665
666
667static GB_ERROR standard_file2list(const CharPtrArray& line, StrArray& display, StrArray& value) {
668    for (size_t i = 0; i<line.size(); ++i) {
669        if (line[i][0] == '#') continue; // ignore comments
670
671        const char *comma = strchr(line[i], ',');
672        if (comma) {
673            display.put(GB_strpartdup(line[i], comma-1));
674
675            comma++;
676            const char *rest      = comma+strspn(comma, " \t");
677            char       *unescaped = GBS_unescape_string(rest, "\n", '\\');
678            value.put(unescaped);
679        }
680        else {
681            display.put(strdup(line[i]));
682            value.put(strdup(line[i]));
683        }
684    }
685
686    return NULL;
687}
688
689StorableSelectionList::StorableSelectionList(const TypedSelectionList& tsl_)
690    : tsl(tsl_),
691      list2file(standard_list2file), 
692      file2list(standard_file2list)
693{}
694
695inline char *get_shared_sellist_awar_base(const TypedSelectionList& typedsellst) {
696    return GBS_global_string_copy("tmp/sellist/%s", typedsellst.get_shared_id());
697}
698inline char *get_shared_sellist_awar_name(const TypedSelectionList& typedsellst, const char *name) {
699    char *base      = get_shared_sellist_awar_base(typedsellst);
700    char *awar_name = GBS_global_string_copy("%s/%s", base, name);
701    free(base);
702    return awar_name;
703}
704
705GB_ERROR StorableSelectionList::save(const char *filename, long number_of_lines) const {
706    // number_of_lines == 0 -> save all lines (otherwise truncate after 'number_of_lines')
707
708    StrArray           display, values;
709    AW_selection_list *sellist = tsl.get_sellist();
710
711    sellist->to_array(display, false);
712    sellist->to_array(values, true);
713
714    awt_assert(display.size() == values.size());
715
716    if (number_of_lines>0) { // limit number of lines?
717        display.resize(number_of_lines);
718        values.resize(number_of_lines);
719    }
720
721    GB_ERROR error = NULL;
722    if (display.size()<1) {
723        error = "List is empty (did not save)";
724    }
725    else {
726        StrArray line;
727        error = list2file(display, values, line);
728        if (!error) {
729            if (line.size()<1) {
730                error = "list>file conversion produced nothing (internal error)";
731            }
732            else {
733                FILE *out = fopen(filename, "wt");
734                if (!out) {
735                    error = GB_IO_error("writing", filename);
736                }
737                else {
738                    const char *warning = NULL;
739                    for (size_t i = 0; i<line.size(); ++i) {
740                        if (!warning && strchr(line[i], '\n')) {
741                            warning = "Warning: Saved content contains LFs (loading will be impossible)";
742                        }
743                        fputs(line[i], out);
744                        fputc('\n', out);
745                    }
746                    fclose(out);
747                    error = warning;
748                }
749            }
750        }
751    }
752
753    return error;
754}
755
756
757
758inline char *string2heapcopy(const string& s) {
759    char *copy = (char*)malloc(s.length()+1);
760    memcpy(copy, s.c_str(), s.length()+1);
761    return copy;
762}
763
764GB_ERROR StorableSelectionList::load(const char *filemask, bool append) const {
765    GB_ERROR error = NULL;
766    StrArray fnames;
767
768    if (GB_is_directory(filemask)) {
769        error = GBS_global_string("refusing to load all files from directory\n"
770                                  "'%s'\n"
771                                  "(one possibility is to enter '*.%s')'",
772                                  filemask, get_filter());
773    }
774    else {
775        GBS_read_dir(fnames, filemask, NULL);
776        if (fnames.empty() && GB_have_error()) {
777            error = GB_await_error();
778        }
779    }
780
781    StrArray lines;
782    for (int f = 0; fnames[f] && !error; ++f) {
783        FILE *in = fopen(fnames[f], "rb");
784        if (!in) {
785            error = GB_IO_error("reading", fnames[f]);
786        }
787        else {
788            BufferedFileReader file(fnames[f], in);
789            string line;
790            while (file.getLine(line)) {
791                if (!line.empty()) lines.put(string2heapcopy(line));
792            }
793        }
794    }
795
796    AW_selection_list *sellist = tsl.get_sellist();
797    if (!append) sellist->clear();
798
799    if (!error) {
800        StrArray displayed, values;
801        error = file2list(lines, displayed, values);
802        if (!error) {
803            int dsize = displayed.size();
804            int vsize = values.size();
805
806            if (dsize != vsize) {
807                error = GBS_global_string("Error in translation (value/display mismatch: %i!=%i)", vsize, dsize);
808            }
809            else {
810                for (int i = 0; i<dsize; ++i) {
811                    sellist->insert(displayed[i], values[i]);
812                }
813                sellist->insert_default("", "");
814            }
815        }
816    }
817
818    if (error) {
819        sellist->insert_default(GBS_global_string("Error: %s", error), "");
820    }
821    sellist->update();
822
823    return error;
824}
825
826static void save_list_cb(AW_window *aww, const StorableSelectionList *storabsellist) {
827    const TypedSelectionList& typedsellist = storabsellist->get_typedsellist();
828
829    char    *awar_prefix = get_shared_sellist_awar_base(typedsellist);
830    char    *bline_anz   = get_shared_sellist_awar_name(typedsellist, "line_anz");
831    AW_root *aw_root     = aww->get_root();
832    char    *filename    = AW_get_selected_fullname(aw_root, awar_prefix);
833
834    long     lineLimit = aw_root->awar(bline_anz)->read_int();
835    GB_ERROR error     = storabsellist->save(filename, lineLimit);
836
837    if (!error) AW_refresh_fileselection(aw_root, awar_prefix);
838    aww->hide_or_notify(error);
839
840    free(filename);
841    free(bline_anz);
842    free(awar_prefix);
843}
844
845static void load_list_cb(AW_window *aww, const StorableSelectionList *storabsellist) {
846    const TypedSelectionList& typedsellist = storabsellist->get_typedsellist();
847
848    AW_root  *aw_root     = aww->get_root();
849    char     *awar_prefix = get_shared_sellist_awar_base(typedsellist);
850    char     *awar_append = get_shared_sellist_awar_name(typedsellist, "append");
851    bool      append      = aw_root->awar(awar_append)->read_int();
852    char     *filename    = AW_get_selected_fullname(aw_root, awar_prefix);
853    GB_ERROR  error       = storabsellist->load(filename, append);
854
855    aww->hide_or_notify(error);
856
857    free(filename);
858    free(awar_append);
859    free(awar_prefix);
860}
861
862AW_window *create_save_box_for_selection_lists(AW_root *aw_root, const StorableSelectionList *storabsellist) {
863    const TypedSelectionList& typedsellist = storabsellist->get_typedsellist();
864
865    char *awar_base     = get_shared_sellist_awar_base(typedsellist);
866    char *awar_line_anz = get_shared_sellist_awar_name(typedsellist, "line_anz");
867    {
868        char *def_name = GBS_string_2_key(typedsellist.whats_contained());
869        AW_create_fileselection_awars(aw_root, awar_base, ".", storabsellist->get_filter(), def_name);
870        free(def_name);
871        aw_root->awar_int(awar_line_anz, 0, AW_ROOT_DEFAULT);
872    }
873
874    AW_window_simple *aws = new AW_window_simple;
875
876    char *window_id    = GBS_global_string_copy("SAVE_SELECTION_BOX_%s", typedsellist.get_unique_id());
877    char *window_title = GBS_global_string_copy("Save %s", typedsellist.whats_contained());
878
879    aws->init(aw_root, window_id, window_title);
880    aws->load_xfig("sl_s_box.fig");
881
882    aws->button_length(10);
883
884    aws->at("cancel");
885    aws->callback((AW_CB0)AW_POPDOWN);
886    aws->create_button("CANCEL", "CANCEL", "C");
887
888    aws->at("save");
889    aws->highlight();
890    aws->callback(makeWindowCallback(save_list_cb, storabsellist));
891    aws->create_button("SAVE", "SAVE", "S");
892
893    aws->at("nlines");
894    aws->create_option_menu(awar_line_anz, true);
895    aws->insert_default_option("all",   "a", 0);
896    aws->insert_option        ("10",    "",  10);
897    aws->insert_option        ("50",    "",  50);
898    aws->insert_option        ("100",   "",  100);
899    aws->insert_option        ("500",   "",  500);
900    aws->insert_option        ("1000",  "",  1000);
901    aws->insert_option        ("5000",  "",  5000);
902    aws->insert_option        ("10000", "",  10000);
903    aws->update_option_menu();
904
905    AW_create_standard_fileselection(aws, awar_base);
906
907    free(window_title);
908    free(window_id);
909    free(awar_line_anz);
910    free(awar_base);
911
912    aws->recalc_pos_atShow(AW_REPOS_TO_MOUSE);
913
914    return aws;
915}
916
917AW_window *create_load_box_for_selection_lists(AW_root *aw_root, const StorableSelectionList *storabsellist) {
918    const TypedSelectionList& typedsellist = storabsellist->get_typedsellist();
919
920    char *awar_base_name = get_shared_sellist_awar_base(typedsellist);
921    char *awar_append    = get_shared_sellist_awar_name(typedsellist, "append");
922
923    AW_create_fileselection_awars(aw_root, awar_base_name, ".", storabsellist->get_filter(), "");
924    aw_root->awar_int(awar_append, 1); // append is default ( = old behavior)
925
926    AW_window_simple *aws = new AW_window_simple;
927
928    char *window_id    = GBS_global_string_copy("LOAD_SELECTION_BOX_%s", typedsellist.get_unique_id());
929    char *window_title = GBS_global_string_copy("Load %s", typedsellist.whats_contained());
930
931    aws->init(aw_root, window_id, window_title);
932    aws->load_xfig("sl_l_box.fig");
933
934    aws->at("cancel");
935    aws->callback((AW_CB0)AW_POPDOWN);
936    aws->create_button("CANCEL", "CANCEL", "C");
937
938    aws->at("load");
939    aws->highlight();
940    aws->callback(makeWindowCallback(load_list_cb, storabsellist));
941    aws->create_button("LOAD", "LOAD", "L");
942
943    aws->at("append");
944    aws->label("Append?");
945    aws->create_toggle(awar_append);
946
947    AW_create_fileselection(aws, awar_base_name, "", "PWD", ANY_DIR, true);
948
949    aws->recalc_pos_atShow(AW_REPOS_TO_MOUSE);
950
951    free(window_title);
952    free(window_id);
953    free(awar_append);
954    free(awar_base_name);
955
956    return aws;
957}
958
959void awt_clear_selection_list_cb(AW_window *, AW_selection_list *sellist) {
960    sellist->clear();
961    sellist->insert_default("", "");
962    sellist->update();
963}
964
965void create_print_box_for_selection_lists(AW_window *aw_window, const TypedSelectionList *typedsellist) {
966    char *data = typedsellist->get_sellist()->get_content_as_string(0);
967    AWT_create_ascii_print_window(aw_window->get_root(), data, typedsellist->whats_contained());
968    free(data);
969}
970
971AW_window *awt_create_load_box(AW_root     *aw_root,
972                               const char  *action,
973                               const char  *what,
974                               const char  *default_directory,
975                               const char  *file_extension,
976                               char       **set_file_name_awar,
977                               const WindowCallback& ok_cb,
978                               const WindowCallback& close_cb,
979                               const char *close_button_text)
980{
981    /* general purpose file selection box
982     *
983     * 'action' describes what is intended to be done (e.g. "Load").
984     * used for window title and button.
985     *
986     * 'what' describes what is going to be loaded (e.g. "destination database")
987     * It is also used to create the awars for the filebox, i.e. same description for multiple
988     * fileboxes makes them share the awars.
989     *
990     * if 'set_file_name_awar' is non-NULL, it'll be set to a heap-copy of the awar-name
991     * containing the full selected filename.
992     *
993     * 'default_directory' specifies the directory opened in the filebox
994     *
995     * 'file_extension' specifies the filter to be used (which files are shown)
996     *
997     * You have to provide an 'ok_cb', which will be called when 'OK' is pressed.
998     * Optionally you may pass a 'close_cb' which will be called when 'CLOSE' is pressed.
999     * If not given, AW_POPDOWN will be called.
1000     *
1001     * Both callbacks will be called as callbacks of the load-box-window.
1002     * The load-box does not popdown, the callback has to do that.
1003     *
1004     * Optionally you may also pass the button text for the 'CLOSE'-button (e.g. 'EXIT' or 'Abort')
1005     */
1006
1007
1008    char *what_key  = GBS_string_2_key(what);
1009    char *base_name = GBS_global_string_copy("tmp/load_box_%s", what_key);
1010
1011    AW_create_fileselection_awars(aw_root, base_name, default_directory, file_extension, "");
1012
1013    if (set_file_name_awar) {
1014        *set_file_name_awar = GBS_global_string_copy("%s/file_name", base_name);
1015    }
1016
1017    AW_window_simple *aws = new AW_window_simple;
1018    {
1019        char title[100];
1020        sprintf(title, "%s %s", action, what);
1021        aws->init(aw_root, title, title);
1022        aws->load_xfig("load_box.fig");
1023    }
1024
1025    aws->at("close");
1026    aws->callback(close_cb);
1027    if (close_button_text) {
1028        aws->create_button("CLOSE", close_button_text, "");
1029    }
1030    else {
1031        aws->create_button("CLOSE", "CLOSE", "C");
1032    }
1033#if defined(ARB_GTK)
1034    aws->set_close_action("CLOSE");
1035#endif
1036
1037#if 0
1038    // @@@ allow to pass helpfile
1039    aws->at("help");
1040    aws->callback(makeHelpCallback(""));
1041    aws->create_button("HELP", "HELP");
1042#endif
1043
1044    aws->at("go");
1045    aws->callback(ok_cb);
1046    aws->create_button("GO", action);
1047
1048    AW_create_standard_fileselection(aws, base_name);
1049    free(base_name);
1050    free(what_key);
1051    aws->recalc_pos_atShow(AW_REPOS_TO_MOUSE);
1052
1053    return aws;
1054}
1055
1056// --------------------------------------------------------------------------------
1057
1058#define SUBSET_NOELEM_DISPLAY "<none>"
1059
1060class AW_subset_selection : public AW_selection {
1061    AW_selection_list& parent_sellist;
1062
1063    static void finish_fill_box(AW_selection_list *parent_sellist, AW_selection_list *sub_sellist) {
1064        sub_sellist->insert_default(parent_sellist->get_default_display(), parent_sellist->get_default_value());
1065        sub_sellist->update();
1066    }
1067
1068    static AW_selection_list *create_box(AW_window *aww, AW_selection_list& parent_sellist) {
1069        const char *parent_awar_name = parent_sellist.get_awar_name();
1070        awt_assert(parent_awar_name[0] != '/');
1071        awt_assert(parent_sellist.get_awar_type() == GB_STRING); // only impl for strings
1072
1073        AW_root *aw_root   = aww->get_root();
1074        char    *awar_name = GBS_global_string_copy("tmp/subsel/%s", parent_awar_name);
1075
1076        aw_root->awar_string(awar_name);
1077
1078        AW_selection_list *sub_sellist = aww->create_selection_list(awar_name, true);
1079        finish_fill_box(&parent_sellist, sub_sellist);
1080
1081        free(awar_name);
1082
1083        return sub_sellist;
1084    }
1085
1086public:
1087    AW_subset_selection(AW_window *aww, AW_selection_list& parent_sellist_)
1088        : AW_selection(create_box(aww, parent_sellist_)),
1089          parent_sellist(parent_sellist_)
1090    {}
1091
1092    AW_selection_list *get_parent_sellist() const { return &parent_sellist; }
1093
1094    const char *default_select_value() const { return parent_sellist.get_default_value(); }
1095    const char *default_select_display() const { return parent_sellist.get_default_display(); }
1096
1097    void get_subset(StrArray& subset) {
1098        get_sellist()->to_array(subset, true);
1099    }
1100
1101    void fill() OVERRIDE { awt_assert(0); } // unused
1102
1103    void collect_subset_cb(awt_collect_mode what) {
1104        AW_selection_list *subset_list = get_sellist();
1105        AW_selection_list *whole_list  = get_parent_sellist();
1106
1107        switch(what) {
1108            case ACM_FILL:
1109                for (AW_selection_list_iterator listEntry(whole_list); listEntry; ++listEntry) {
1110                    if (subset_list->get_index_of(listEntry.get_value()) == -1) { // only add not already existing elements
1111                        subset_list->insert(listEntry.get_displayed(), listEntry.get_value());
1112                    }
1113                }
1114                finish_fill_box(whole_list, subset_list);
1115                break;
1116
1117            case ACM_ADD: {
1118                if (!whole_list->default_is_selected()) {
1119                    const char *selected   = whole_list->get_awar_value();
1120                    int         src_index = whole_list->get_index_of(selected);
1121                   
1122                    if (subset_list->get_index_of(selected) == -1) { // not yet in subset_list
1123                        AW_selection_list_iterator entry(whole_list, src_index);
1124                        subset_list->insert(entry.get_displayed(), entry.get_value());
1125                        subset_list->update();
1126                    }
1127
1128                    subset_list->set_awar_value(selected); // position right side to newly added or already existing alignment
1129                    whole_list->select_element_at(src_index+1);    // go down 1 position on left side
1130                }
1131
1132                break;
1133            }
1134            case ACM_REMOVE: {
1135                if (!subset_list->default_is_selected()) {
1136                    char *selected     = strdup(subset_list->get_awar_value());
1137                    int   old_position = subset_list->get_index_of(selected);
1138
1139                    subset_list->delete_element_at(old_position);
1140                    finish_fill_box(whole_list, subset_list);
1141
1142                    subset_list->select_element_at(old_position);
1143                    whole_list->set_awar_value(selected); // set left selection to deleted alignment
1144                    free(selected);
1145                }
1146                break;
1147            }
1148            case ACM_EMPTY:
1149                subset_list->clear();
1150                finish_fill_box(whole_list, subset_list);
1151                break;
1152        }
1153    }
1154    void reorder_subset_cb(awt_reorder_mode dest) {
1155        AW_selection_list *subset_list = get_sellist();
1156
1157        if (!subset_list->default_is_selected()) {
1158            const char *selected = subset_list->get_awar_value();
1159
1160            StrArray listContent;
1161            subset_list->to_array(listContent, true);
1162
1163            int old_pos = GBT_names_index_of(listContent, selected);
1164            if (old_pos >= 0) {
1165                int new_pos = 0;
1166                switch (dest) {
1167                    case ARM_TOP:    new_pos= 0;         break;
1168                    case ARM_UP:     new_pos= old_pos-1; break;
1169                    case ARM_DOWN:   new_pos= old_pos+1; break;
1170                    case ARM_BOTTOM: new_pos= -1;        break;
1171                }
1172                if (old_pos != new_pos) {
1173                    GBT_names_move(listContent, old_pos, new_pos);
1174                    subset_list->init_from_array(listContent, subset_list->get_default_value());
1175                }
1176            }
1177        }
1178    }
1179};
1180
1181static void collect_subset_cb(AW_window *, awt_collect_mode what, AW_CL cl_subsel) { ((AW_subset_selection*)cl_subsel)->collect_subset_cb(what); }
1182static void reorder_subset_cb(AW_window *, awt_reorder_mode dest, AW_CL cl_subsel) { ((AW_subset_selection*)cl_subsel)->reorder_subset_cb(dest); }
1183
1184AW_selection *awt_create_subset_selection_list(AW_window *aww, AW_selection_list *parent_selection, const char *at_box, const char *at_add, const char *at_sort) {
1185    awt_assert(parent_selection);
1186
1187    aww->at(at_box);
1188    int x_list = aww->get_at_xposition();
1189
1190    AW_subset_selection *subsel = new AW_subset_selection(aww, *parent_selection);
1191
1192    aww->button_length(0);
1193
1194    aww->at(at_add);
1195    int x_buttons = aww->get_at_xposition();
1196
1197    bool move_rightwards = x_list>x_buttons;
1198    awt_create_collect_buttons(aww, move_rightwards, collect_subset_cb, (AW_CL)subsel);
1199
1200    aww->at(at_sort);
1201    awt_create_order_buttons(aww, reorder_subset_cb, (AW_CL)subsel);
1202
1203    return subsel;
1204}
1205
1206
Note: See TracBrowser for help on using the repository browser.