source: branches/help/AWTI/AWTI_edit.cxx

Last change on this file was 18159, checked in by westram, 5 years ago
  • full update from child 'fix' into 'trunk'
    • fix item name accessors (GBT_get_name + GBT_get_name_or_description)
    • add null2empty
  • adds: log:branches/fix@18140:18158
File size: 20.1 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : AWTI_edit.cxx                                     //
4//   Purpose   : test and modify import/export filters             //
5//                                                                 //
6//   Coded by Ralf Westram (coder@reallysoft.de) in October 2017   //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include "awti_edit.hxx"
12#include "awti_exp_local.hxx"
13#include "awti_imp_local.hxx"
14
15#include <seqio.hxx>
16#include <db_scanner.hxx>
17
18#include <awt_prompt.hxx>
19
20#include <aw_root.hxx>
21#include <aw_edit.hxx>
22#include <aw_msg.hxx>
23#include <aw_awar_defs.hxx>
24#include <aw_select.hxx>
25
26#include <BufferedFileReader.h>
27#include <FileWatch.h>
28
29#include <arb_strbuf.h>
30#include <arb_progress.h>
31#include <arb_misc.h>
32
33
34enum FormatType { FT_IMPORT, FT_EXPORT };
35enum FormatAction { EDIT, COPY, RENAME, DELETE };
36
37static const char *action_name[] = {
38    "edit",
39    "copy",
40    "rename",
41    "delete",
42};
43
44class FormatTester : virtual Noncopyable {
45    FormatType  type;
46    AW_window  *aws;             // filter test window
47    AW_awar    *awar_filtername; // contains full path of selected (=tested) filter
48
49    const char *get_awarname() const { return type == FT_IMPORT ? AWAR_IMPORT_FORMATNAME : AWAR_EXPORT_FORMATNAME; }
50    const char *ieport()       const { return type == FT_IMPORT ? "import" : "export"; }
51    const char *get_suffix()   const { return type == FT_IMPORT ? "ift" : "eft"; }
52
53    const char *get_selected_filter() const { return awar_filtername->read_char_pntr(); }
54
55    char *user_filter_fullname(const char *name) {
56        char       *name_suf = ARB_strdup(GB_append_suffix(name, get_suffix()));
57        const char *user_dir = GB_path_in_arbprop("filter");
58        char       *fullpath = ARB_strdup(GB_concat_path(user_dir, name_suf));
59        free(name_suf);
60        return fullpath;
61    }
62
63    // management button callbacks:
64    GB_ERROR nameEntered_handler(FormatAction action, const char *targetName) {
65        GB_ERROR    error          = NULp;
66        char       *fullTargetName = user_filter_fullname(targetName);
67        const char *fullSourceName = get_selected_filter();
68
69        if (strcmp(fullSourceName, fullTargetName) == 0) {
70            error = "source and destination are the same";
71        }
72        else if (action == RENAME) {
73            error = GB_safe_rename_file(fullSourceName, fullTargetName);
74        }
75        else {
76            awti_assert(action == COPY);
77            error = GB_safe_copy_file(fullSourceName, fullTargetName);
78        }
79        if (!error) {
80            awar_filtername->write_string(fullTargetName);
81        }
82        free(fullTargetName);
83        return error;
84    }
85    static GB_ERROR nameEntered_wrapper(const char *targetName, FormatAction action, FormatTester *const tester) {
86        return tester->nameEntered_handler(action, targetName);
87    }
88    void handle_copyRename(FormatAction action) {
89        char *Action = ARB_strdup(action_name[action]);
90        Action[0]    = toupper(Action[0]);
91
92        char *title  = GBS_global_string_copy("%s %s format", Action, ieport());
93        char *prompt = GBS_global_string_copy("Enter name of %s format:", ieport());
94
95        char *nameOnly;
96        GB_split_full_path(get_selected_filter(), NULp, NULp, &nameOnly, NULp);
97        if (!nameOnly) nameOnly = ARB_strdup("");
98
99        AWT_activate_prompt(title, prompt, nameOnly, Action, makeResultHandler(nameEntered_wrapper, action, this));
100
101        free(nameOnly);
102        free(prompt);
103        free(title);
104    }
105
106public:
107    FormatTester(FormatType type_, AW_window *aws_) :
108        type(type_),
109        aws(aws_)
110    {
111        awar_filtername = aws->get_root()->awar(get_awarname());
112        awti_assert(awar_filtername);
113    }
114
115    void create_common_gui(const char *helpfile);
116
117    void handle_action_cb(FormatAction action) {
118        char *filter_name = awar_filtername->read_string(); // use copy (may disappear)
119        if (!GB_is_regularfile(filter_name)) {
120            aw_message(GBS_global_string("Please select the filter to %s", action_name[action]));
121        }
122        else {
123            if (action == COPY || action == RENAME) {
124                handle_copyRename(action);
125            }
126            else {
127                bool is_writeable = GB_is_writeablefile(filter_name);
128                if (action == EDIT) {
129                    if (!is_writeable) {
130                        aw_message("The filter is write-protected (use COPY to create a local copy)");
131                    }
132                    else {
133                        AW_edit(filter_name);
134                    }
135                }
136                else if (action == DELETE) {
137                    if (!is_writeable) {
138                        aw_message("The filter is write-protected");
139                    }
140                    else {
141                        awar_filtername->write_string(""); // deselect
142                        if (GB_unlink(filter_name)<0) {
143                            awar_filtername->write_string(filter_name); // re-select
144                            aw_message(GB_await_error());
145                        }
146                    }
147                }
148                else {
149                    awti_assert(0); // unhandled FormatAction
150                }
151            }
152        }
153        free(filter_name);
154    }
155};
156
157typedef SmartPtr<FormatTester> FormatTesterPtr;
158
159static void action_cb_wrapper(AW_window*, FormatTester *const tester, FormatAction action) {
160    tester->handle_action_cb(action);
161}
162
163void FormatTester::create_common_gui(const char *helpfile) {
164    aws->at("close");
165    aws->callback(AW_POPDOWN);
166    aws->create_button("CLOSE", "CLOSE", "C");
167
168    aws->at("help");
169    aws->callback(makeHelpCallback(helpfile));
170    aws->create_button("HELP", "HELP", "H");
171
172    aws->at("filter");
173    aws->create_button(NULp, awar_filtername->awar_name, NULp, "+");
174
175    aws->at("buttons");
176
177    aws->auto_space(5, 5);
178
179    aws->callback(makeWindowCallback(action_cb_wrapper, this, EDIT));   aws->create_button("EDIT",   "EDIT",   "E");
180    aws->callback(makeWindowCallback(action_cb_wrapper, this, COPY));   aws->create_button("COPY",   "COPY",   "C");
181    aws->callback(makeWindowCallback(action_cb_wrapper, this, RENAME)); aws->create_button("RENAME", "RENAME", "R");
182    aws->callback(makeWindowCallback(action_cb_wrapper, this, DELETE)); aws->create_button("DELETE", "DELETE", "D");
183}
184
185static char *get_file_content_for_viewer(const char *filename) {
186    char *result = NULp;
187    FILE *in     = fopen(filename, "rt");
188    if (in) {
189        BufferedFileReader reader(filename, in);
190        GBS_strstruct      view(10000);
191
192        string line;
193        while (reader.getLine(line)) {
194            view.ncat(line.c_str(), line.size());
195            view.put('\n');
196        }
197
198        result = view.release();
199    }
200    else {
201        result = ARB_strdup(GB_IO_error("reading", filename));
202    }
203    return result;
204}
205
206
207#define TESTER_AWAR_PREFIX          "tmp/tester/"
208#define AWAR_TESTER_LINK_EX2IMPORT  TESTER_AWAR_PREFIX "link"
209#define AWAR_TESTER_EXPORT_RESULT   TESTER_AWAR_PREFIX "result"
210#define AWAR_TESTER_IMPORT_FILENAME TESTER_AWAR_PREFIX "filename"
211#define AWAR_TESTER_IMPORT_STATUS   TESTER_AWAR_PREFIX "status"
212#define AWAR_TESTER_IMPORT_SPECIES  TESTER_AWAR_PREFIX "species"
213
214static bool test_import_active = false;
215static bool test_export_active = false;
216
217static void disable_test_import(AW_window*) {
218    test_import_active = false;
219}
220static void disable_test_export(AW_window *aww) {
221    aww->get_root()->awar(AWAR_TESTER_LINK_EX2IMPORT)->write_int(0); // avoid confusion in export-test
222    test_export_active = false;
223}
224
225static void create_tester_awars(AW_root *awr) {
226    static bool initialized = false;
227    if (!initialized) {
228        awr->awar_string(AWAR_TESTER_EXPORT_RESULT,   "<undefined>");
229        awr->awar_string(AWAR_TESTER_IMPORT_STATUS,   "<undefined>");
230        awr->awar_string(AWAR_TESTER_IMPORT_FILENAME, "");
231        awr->awar_string(AWAR_TESTER_IMPORT_SPECIES,  "");
232        awr->awar_int   (AWAR_TESTER_LINK_EX2IMPORT,  0);
233        initialized = true;
234    }
235}
236
237static void update_exportTest_result_cb(AW_root *awr, GBDATA *gb_main, adfiltercbstruct *acbs) {
238    if (test_export_active) {
239        GB_transaction ta(gb_main);
240
241        AW_awar *awar_result      = awr->awar(AWAR_TESTER_EXPORT_RESULT);
242        char    *selected_species = awr->awar(AWAR_SPECIES_NAME)->read_string();
243        bool     have_species     = GBT_find_species(gb_main, selected_species);
244
245        if (have_species) {
246            AP_filter *filter = awt_get_filter(acbs);
247
248            int cut_stop_codon = awr->awar(AWAR_EXPORT_CUTSTOP)->read_int();
249            int compress       = awr->awar(AWAR_EXPORT_COMPRESS)->read_int();
250            int linked         = awr->awar(AWAR_TESTER_LINK_EX2IMPORT)->read_int();
251
252            char *formname     = awr->awar(AWAR_EXPORT_FORMATNAME)->read_string();
253            char *db_name      = awr->awar(AWAR_DB_NAME)->read_string();
254            char *outname      = GB_create_tempfile("test_export");
255            char *real_outname = NULp;
256
257            const char *ftsname = XFER_getFullFTS(awr->awar(AWAR_EXPORT_FTS)->read_char_pntr());
258
259            arb_suppress_progress here;
260
261            GB_ERROR error = SEQIO::export_by_format(gb_main, SEQIO::EBF_ONE, selected_species,
262                                                     filter, cut_stop_codon, compress,
263                                                     db_name, formname, ftsname,
264                                                     outname, 0, &real_outname);
265
266            if (error) {
267                awar_result->write_string(GBS_global_string("Error during export:\n%s", error));
268            }
269            else {
270                char *content = get_file_content_for_viewer(real_outname);
271                awar_result->write_string(content);
272                free(content);
273
274                if (linked) {
275                    awr->awar(AWAR_TESTER_IMPORT_FILENAME)->write_string(real_outname);
276                }
277                else {
278                    GB_unlink_or_warn(real_outname, NULp);
279                }
280            }
281
282            free(real_outname);
283            free(outname);
284            free(selected_species);
285            free(db_name);
286            free(formname);
287        }
288        else {
289            awar_result->write_string("<no species selected>");
290        }
291    }
292}
293
294static void exportImportLinkChanged_cb(AW_root *awr, GBDATA *gb_main, adfiltercbstruct *acbs) {
295    if (awr->awar(AWAR_TESTER_LINK_EX2IMPORT)->read_int()) { // link activated
296        update_exportTest_result_cb(awr, gb_main, acbs); // run export test again (will trigger AWAR_TESTER_IMPORT_FILENAME on success)
297    }
298    else { // link de-activated
299        AW_awar *awar_ifilename = awr->awar_no_error(AWAR_IMPORT_FILENAME);
300        if (awar_ifilename) { // does not exist if import window was not opened yet
301            awar_ifilename->touch(); // reset AWAR_TESTER_IMPORT_FILENAME to "unlinked" value
302        }
303    }
304}
305
306struct ImportTestData : virtual Noncopyable {
307    AW_selection_list *species_sellist;
308    DbScanner         *field_scanner;
309    GBDATA            *gb_main_lastImport;
310
311    ImportTestData() :
312        species_sellist(NULp),
313        field_scanner(NULp),
314        gb_main_lastImport(NULp)
315    {
316    }
317    ~ImportTestData() {
318        if (gb_main_lastImport) {
319            GB_close(gb_main_lastImport);
320        }
321    }
322
323    void forgetLastImport() {
324        if (gb_main_lastImport) {
325            GB_close(gb_main_lastImport);
326            gb_main_lastImport = NULp;
327        }
328        species_sellist->clear();
329        species_sellist->insert_default("", "");
330        species_sellist->update();
331    }
332    void setNewImport(GBDATA *gb_new_main) {
333        gb_main_lastImport = gb_new_main;
334        field_scanner->RemapToDatabase(gb_main_lastImport);
335    }
336
337    void refill_species_list() {
338        GB_transaction ta(gb_main_lastImport);
339        for (GBDATA *gb_species = GBT_first_species(gb_main_lastImport);
340             gb_species;
341             gb_species = GBT_next_species(gb_species))
342        {
343            const char *name = GBT_get_name(gb_species);
344            if (name) {
345                species_sellist->insert(name, name);
346            }
347            else {
348                species_sellist->insert("<unnamed species>", "");
349            }
350        }
351        species_sellist->insert_default("", "");
352        species_sellist->update();
353    }
354
355    void remap_scanner(AW_root *awr);
356
357    void countSpeciesAndData(const char *aliName, long& speciesCount, long& dataCount) {
358        speciesCount = 0;
359        dataCount    = 0;
360
361        GB_transaction ta(gb_main_lastImport);
362        for (GBDATA *gb_species = GBT_first_species(gb_main_lastImport);
363             gb_species;
364             gb_species = GBT_next_species(gb_species))
365        {
366            ++speciesCount;
367
368            GBDATA *gb_seq = GBT_find_sequence(gb_species, aliName);
369            awti_assert(gb_seq);
370            const char *seq = GB_read_char_pntr(gb_seq);
371            for (int p = 0; seq[p]; ++p) {
372                dataCount += !!isalpha(seq[p]);
373            }
374        }
375    }
376
377};
378
379static void neverCalledDummy_cb(AW_root*) { awti_assert(0); }
380
381static void rerun_importTest_cb(AW_root *awr, ImportTestData *tdata) {
382    if (test_import_active) {
383        ArbImporter importer(makeRootCallback(neverCalledDummy_cb));
384
385        arb_suppress_progress here;
386
387        tdata->forgetLastImport();
388
389        char     *mask           = awr->awar(AWAR_TESTER_IMPORT_FILENAME)->read_string(); // will use result of export (if linked)
390        GB_ERROR  error          = importer.import_data(awr, mask, true);
391        AW_awar  *awar_source    = awr->awar(AWAR_TESTER_IMPORT_STATUS);
392        AW_awar  *awar_selected  = awr->awar(AWAR_TESTER_IMPORT_SPECIES);
393        bool      touch_selected = true;
394
395        if (error) {
396            awar_source->write_string(error);
397        }
398        else {
399            tdata->setNewImport(importer.takeImportDB());
400            tdata->refill_species_list();
401
402            const char *aliName = awr->awar(AWAR_IMPORT_ALI)->read_char_pntr();
403            long        speciesCount, dataCount;
404            tdata->countSpeciesAndData(aliName, speciesCount, dataCount);
405
406            const char *status = GBS_global_string("Species imported: %li\n"
407                                                   "Base count: %s",
408                                                   speciesCount,
409                                                   GBS_readable_size(dataCount, "bp"));
410            awar_source->write_string(status);
411
412            {
413                GB_transaction ta(tdata->gb_main_lastImport);
414                char *previously_selected = awar_selected->read_string();
415                if (!GBT_find_species(tdata->gb_main_lastImport, previously_selected)) {
416                    GBDATA *gb_first = GBT_first_species(tdata->gb_main_lastImport);
417                    if (gb_first) {
418                        awar_selected->write_string(null2empty(GBT_get_name(gb_first)));
419                        touch_selected = false;
420                    }
421                }
422                free(previously_selected);
423            }
424        }
425        if (touch_selected) awar_selected->touch(); // remaps species fields
426        free(mask);
427    }
428}
429
430void ImportTestData::remap_scanner(AW_root *awr) {
431    if (gb_main_lastImport) {
432        GB_transaction ta(gb_main_lastImport);
433        const ItemSelector&  selector   = field_scanner->get_selector();
434        GBDATA              *gb_species = selector.get_selected_item(gb_main_lastImport, awr);
435        field_scanner->Map(gb_species, selector.change_key_path);
436    }
437}
438static void remap_scanner_cb(AW_root *awr, ImportTestData *tdata) { tdata->remap_scanner(awr); }
439
440static GBDATA* get_selected_imported_species(GBDATA *gb_main, AW_root *aw_root) {
441    char   *species_name = aw_root->awar(AWAR_TESTER_IMPORT_SPECIES)->read_string();
442    GBDATA *gb_species   = NULp;
443    if (species_name[0]) {
444        gb_species = GBT_find_species(gb_main, species_name);
445    }
446    free(species_name);
447    return gb_species;
448}
449static const ItemSelector& get_importedSpecies_selector() {
450    static struct MutableItemSelector spec_sel = SPECIES_get_selector(); // copy species selector
451    spec_sel.get_selected_item = get_selected_imported_species;
452    return spec_sel;
453}
454
455static void update_import_filename_cb(AW_root *awr) {
456    const char *currImportSource = awr->awar(AWAR_IMPORT_FILENAME)->read_char_pntr();
457    awr->awar(AWAR_TESTER_IMPORT_FILENAME)->write_string(currImportSource);
458}
459
460static void import_file_changed_cb(const char *, ChangeReason, ImportTestData *tdata) {
461    rerun_importTest_cb(AW_root::SINGLETON, tdata);
462}
463
464void AWTI_activate_import_test_window(AW_window *awp) {
465    static AW_window_simple *aws = NULp;
466
467    test_import_active = true;
468
469    AW_root *awr = awp->get_root();
470    if (!aws) {
471        create_tester_awars(awr);
472
473        aws = new AW_window_simple;
474        aws->init(awr, "ARB_IMPORT_TEST", "Test import filter");
475        aws->load_xfig("awt/import_test.fig");
476
477        static FormatTesterPtr tester = new FormatTester(FT_IMPORT, aws);
478
479        tester->create_common_gui("import_test.hlp");
480
481        aws->at("stat");
482        aws->create_text_field(AWAR_TESTER_IMPORT_STATUS);
483
484        static SmartPtr<ImportTestData> tdataPtr = new ImportTestData; // (cleaned up on exit)
485        ImportTestData *const           tdata    = &*tdataPtr;
486
487        aws->at("spec");
488        tdata->species_sellist = aws->create_selection_list(AWAR_TESTER_IMPORT_SPECIES, true);
489
490        tdata->field_scanner = DbScanner::create(NULp, "test_import", aws, "fields", NULp, NULp, DB_SCANNER, NULp, get_importedSpecies_selector());
491
492        RootCallback test_import_cb = makeRootCallback(rerun_importTest_cb, tdata);
493        awr->awar(AWAR_IMPORT_FORMATNAME)->add_callback(test_import_cb);
494        awr->awar(AWAR_IMPORT_ALI)       ->add_callback(test_import_cb);
495        awr->awar(AWAR_IMPORT_FTS)       ->add_callback(test_import_cb);
496
497        awr->awar(AWAR_IMPORT_FILENAME)->add_callback(update_import_filename_cb);
498        static SmartPtr<FileWatch> fwatch = new FileWatch(AWAR_TESTER_IMPORT_FILENAME, makeFileChangedCallback(import_file_changed_cb, tdata));
499
500        awr->awar(AWAR_TESTER_IMPORT_SPECIES)->add_callback(makeRootCallback(remap_scanner_cb, tdata));
501
502        aws->on_hide(disable_test_import);
503    }
504
505    update_import_filename_cb(awr); // avoid error message after startup
506    awr->awar(AWAR_IMPORT_FORMATNAME)->touch(); // trigger callback once (needed after re-opening window)
507    aws->activate();
508}
509
510void AWTI_activate_export_test_window(AW_window *awp, GBDATA *gb_main, adfiltercbstruct *acbs) {
511    static AW_window_simple *aws = NULp;
512
513    test_export_active = true;
514
515    AW_root *awr = awp->get_root();
516    if (!aws) {
517        create_tester_awars(awr);
518
519        aws = new AW_window_simple;
520        aws->init(awr, "ARB_EXPORT_TEST", "Test export filter");
521        aws->load_xfig("awt/export_test.fig");
522
523        static FormatTesterPtr tester = new FormatTester(FT_EXPORT, aws);
524
525        tester->create_common_gui("export_test.hlp");
526
527        aws->label("Link to import");
528        aws->create_toggle(AWAR_TESTER_LINK_EX2IMPORT);
529
530        aws->at("res");
531        aws->create_text_field(AWAR_TESTER_EXPORT_RESULT);
532
533        RootCallback test_export_cb = makeRootCallback(update_exportTest_result_cb, gb_main, acbs);
534        awr->awar(AWAR_SPECIES_NAME)          ->add_callback(test_export_cb);
535        awr->awar(AWAR_EXPORT_FORMATNAME)     ->add_callback(test_export_cb);
536        awr->awar(AWAR_EXPORT_CUTSTOP)        ->add_callback(test_export_cb);
537        awr->awar(AWAR_EXPORT_COMPRESS)       ->add_callback(test_export_cb);
538        awr->awar(AWAR_TESTER_LINK_EX2IMPORT) ->add_callback(makeRootCallback(exportImportLinkChanged_cb, gb_main, acbs));
539        awr->awar(acbs->def_filter)           ->add_callback(test_export_cb); // filter string
540        awr->awar(AWAR_EXPORT_FTS)            ->add_callback(test_export_cb);
541
542        aws->on_hide(disable_test_export);
543    }
544
545    awr->awar(AWAR_EXPORT_FORMATNAME)->touch(); // trigger callback once (needed after re-opening window)
546    aws->activate();
547}
548
549
Note: See TracBrowser for help on using the repository browser.